Import r-cran-s2_1.0.7.orig.tar.gz
authorÉtienne Mollier <emollier@debian.org>
Mon, 4 Oct 2021 19:37:06 +0000 (20:37 +0100)
committerÉtienne Mollier <emollier@debian.org>
Mon, 4 Oct 2021 19:37:06 +0000 (20:37 +0100)
[dgit import orig r-cran-s2_1.0.7.orig.tar.gz]

631 files changed:
DESCRIPTION [new file with mode: 0644]
MD5 [new file with mode: 0644]
NAMESPACE [new file with mode: 0644]
NEWS.md [new file with mode: 0644]
R/RcppExports.R [new file with mode: 0644]
R/data.R [new file with mode: 0644]
R/s2-accessors.R [new file with mode: 0644]
R/s2-bounds.R [new file with mode: 0644]
R/s2-cell.R [new file with mode: 0644]
R/s2-constructors-formatters.R [new file with mode: 0644]
R/s2-earth.R [new file with mode: 0644]
R/s2-geography.R [new file with mode: 0644]
R/s2-lnglat.R [new file with mode: 0644]
R/s2-matrix.R [new file with mode: 0644]
R/s2-options.R [new file with mode: 0644]
R/s2-package.R [new file with mode: 0644]
R/s2-point.R [new file with mode: 0644]
R/s2-predicates.R [new file with mode: 0644]
R/s2-transformers.R [new file with mode: 0644]
R/s2-xptr.R [new file with mode: 0644]
R/utils.R [new file with mode: 0644]
R/vctrs.R [new file with mode: 0644]
R/wk-utils.R [new file with mode: 0644]
R/zzz.R [new file with mode: 0644]
README.md [new file with mode: 0644]
build/partial.rdb [new file with mode: 0644]
cleanup [new file with mode: 0755]
configure [new file with mode: 0755]
configure.win [new file with mode: 0755]
data/s2_data_tbl_cities.rda [new file with mode: 0644]
data/s2_data_tbl_countries.rda [new file with mode: 0644]
data/s2_data_tbl_timezones.rda [new file with mode: 0644]
inst/extdata/emptyfile [new file with mode: 0644]
man/as_s2_geography.Rd [new file with mode: 0644]
man/figures/rc300.png [new file with mode: 0644]
man/s2-package.Rd [new file with mode: 0644]
man/s2_boundary.Rd [new file with mode: 0644]
man/s2_bounds_cap.Rd [new file with mode: 0644]
man/s2_cell.Rd [new file with mode: 0644]
man/s2_cell_is_valid.Rd [new file with mode: 0644]
man/s2_closest_feature.Rd [new file with mode: 0644]
man/s2_contains.Rd [new file with mode: 0644]
man/s2_data_tbl_countries.Rd [new file with mode: 0644]
man/s2_earth_radius_meters.Rd [new file with mode: 0644]
man/s2_geog_point.Rd [new file with mode: 0644]
man/s2_interpolate.Rd [new file with mode: 0644]
man/s2_is_collection.Rd [new file with mode: 0644]
man/s2_lnglat.Rd [new file with mode: 0644]
man/s2_options.Rd [new file with mode: 0644]
man/s2_point.Rd [new file with mode: 0644]
man/s2_unprojection_filter.Rd [new file with mode: 0644]
src/Makevars.in [new file with mode: 0644]
src/Makevars.ucrt [new file with mode: 0644]
src/Makevars.win [new file with mode: 0644]
src/RcppExports.cpp [new file with mode: 0644]
src/absl/algorithm/algorithm.h [new file with mode: 0644]
src/absl/algorithm/container.h [new file with mode: 0644]
src/absl/base/attributes.h [new file with mode: 0644]
src/absl/base/call_once.h [new file with mode: 0644]
src/absl/base/casts.h [new file with mode: 0644]
src/absl/base/config.h [new file with mode: 0644]
src/absl/base/const_init.h [new file with mode: 0644]
src/absl/base/dynamic_annotations.h [new file with mode: 0644]
src/absl/base/internal/atomic_hook.h [new file with mode: 0644]
src/absl/base/internal/cycleclock.cc [new file with mode: 0644]
src/absl/base/internal/cycleclock.h [new file with mode: 0644]
src/absl/base/internal/direct_mmap.h [new file with mode: 0644]
src/absl/base/internal/dynamic_annotations.h [new file with mode: 0644]
src/absl/base/internal/endian.h [new file with mode: 0644]
src/absl/base/internal/errno_saver.h [new file with mode: 0644]
src/absl/base/internal/exponential_biased.cc [new file with mode: 0644]
src/absl/base/internal/exponential_biased.h [new file with mode: 0644]
src/absl/base/internal/fast_type_id.h [new file with mode: 0644]
src/absl/base/internal/hide_ptr.h [new file with mode: 0644]
src/absl/base/internal/identity.h [new file with mode: 0644]
src/absl/base/internal/inline_variable.h [new file with mode: 0644]
src/absl/base/internal/invoke.h [new file with mode: 0644]
src/absl/base/internal/low_level_alloc.cc [new file with mode: 0644]
src/absl/base/internal/low_level_alloc.h [new file with mode: 0644]
src/absl/base/internal/low_level_scheduling.h [new file with mode: 0644]
src/absl/base/internal/per_thread_tls.h [new file with mode: 0644]
src/absl/base/internal/periodic_sampler.cc [new file with mode: 0644]
src/absl/base/internal/periodic_sampler.h [new file with mode: 0644]
src/absl/base/internal/pretty_function.h [new file with mode: 0644]
src/absl/base/internal/raw_logging.cc [new file with mode: 0644]
src/absl/base/internal/raw_logging.h [new file with mode: 0644]
src/absl/base/internal/scheduling_mode.h [new file with mode: 0644]
src/absl/base/internal/scoped_set_env.cc [new file with mode: 0644]
src/absl/base/internal/scoped_set_env.h [new file with mode: 0644]
src/absl/base/internal/spinlock.cc [new file with mode: 0644]
src/absl/base/internal/spinlock.h [new file with mode: 0644]
src/absl/base/internal/spinlock_akaros.inc [new file with mode: 0644]
src/absl/base/internal/spinlock_linux.inc [new file with mode: 0644]
src/absl/base/internal/spinlock_posix.inc [new file with mode: 0644]
src/absl/base/internal/spinlock_wait.cc [new file with mode: 0644]
src/absl/base/internal/spinlock_wait.h [new file with mode: 0644]
src/absl/base/internal/spinlock_win32.inc [new file with mode: 0644]
src/absl/base/internal/strerror.cc [new file with mode: 0644]
src/absl/base/internal/strerror.h [new file with mode: 0644]
src/absl/base/internal/sysinfo.cc [new file with mode: 0644]
src/absl/base/internal/sysinfo.h [new file with mode: 0644]
src/absl/base/internal/thread_annotations.h [new file with mode: 0644]
src/absl/base/internal/thread_identity.cc [new file with mode: 0644]
src/absl/base/internal/thread_identity.h [new file with mode: 0644]
src/absl/base/internal/throw_delegate.cc [new file with mode: 0644]
src/absl/base/internal/throw_delegate.h [new file with mode: 0644]
src/absl/base/internal/tsan_mutex_interface.h [new file with mode: 0644]
src/absl/base/internal/unaligned_access.h [new file with mode: 0644]
src/absl/base/internal/unscaledcycleclock.cc [new file with mode: 0644]
src/absl/base/internal/unscaledcycleclock.h [new file with mode: 0644]
src/absl/base/log_severity.cc [new file with mode: 0644]
src/absl/base/log_severity.h [new file with mode: 0644]
src/absl/base/macros.h [new file with mode: 0644]
src/absl/base/optimization.h [new file with mode: 0644]
src/absl/base/options.h [new file with mode: 0644]
src/absl/base/policy_checks.h [new file with mode: 0644]
src/absl/base/port.h [new file with mode: 0644]
src/absl/base/thread_annotations.h [new file with mode: 0644]
src/absl/container/btree_map.h [new file with mode: 0644]
src/absl/container/btree_set.h [new file with mode: 0644]
src/absl/container/fixed_array.h [new file with mode: 0644]
src/absl/container/flat_hash_map.h [new file with mode: 0644]
src/absl/container/flat_hash_set.h [new file with mode: 0644]
src/absl/container/inlined_vector.h [new file with mode: 0644]
src/absl/container/internal/btree.h [new file with mode: 0644]
src/absl/container/internal/btree_container.h [new file with mode: 0644]
src/absl/container/internal/common.h [new file with mode: 0644]
src/absl/container/internal/compressed_tuple.h [new file with mode: 0644]
src/absl/container/internal/container_memory.h [new file with mode: 0644]
src/absl/container/internal/counting_allocator.h [new file with mode: 0644]
src/absl/container/internal/hash_function_defaults.h [new file with mode: 0644]
src/absl/container/internal/hash_policy_traits.h [new file with mode: 0644]
src/absl/container/internal/hashtable_debug.h [new file with mode: 0644]
src/absl/container/internal/hashtable_debug_hooks.h [new file with mode: 0644]
src/absl/container/internal/hashtablez_sampler.cc [new file with mode: 0644]
src/absl/container/internal/hashtablez_sampler.h [new file with mode: 0644]
src/absl/container/internal/hashtablez_sampler_force_weak_definition.cc [new file with mode: 0644]
src/absl/container/internal/have_sse.h [new file with mode: 0644]
src/absl/container/internal/inlined_vector.h [new file with mode: 0644]
src/absl/container/internal/layout.h [new file with mode: 0644]
src/absl/container/internal/node_hash_policy.h [new file with mode: 0644]
src/absl/container/internal/raw_hash_map.h [new file with mode: 0644]
src/absl/container/internal/raw_hash_set.cc [new file with mode: 0644]
src/absl/container/internal/raw_hash_set.h [new file with mode: 0644]
src/absl/container/internal/tracked.h [new file with mode: 0644]
src/absl/container/node_hash_map.h [new file with mode: 0644]
src/absl/container/node_hash_set.h [new file with mode: 0644]
src/absl/debugging/failure_signal_handler.cc [new file with mode: 0644]
src/absl/debugging/failure_signal_handler.h [new file with mode: 0644]
src/absl/debugging/internal/address_is_readable.cc [new file with mode: 0644]
src/absl/debugging/internal/address_is_readable.h [new file with mode: 0644]
src/absl/debugging/internal/demangle.cc [new file with mode: 0644]
src/absl/debugging/internal/demangle.h [new file with mode: 0644]
src/absl/debugging/internal/elf_mem_image.cc [new file with mode: 0644]
src/absl/debugging/internal/elf_mem_image.h [new file with mode: 0644]
src/absl/debugging/internal/examine_stack.cc [new file with mode: 0644]
src/absl/debugging/internal/examine_stack.h [new file with mode: 0644]
src/absl/debugging/internal/stack_consumption.cc [new file with mode: 0644]
src/absl/debugging/internal/stack_consumption.h [new file with mode: 0644]
src/absl/debugging/internal/stacktrace_aarch64-inl.inc [new file with mode: 0644]
src/absl/debugging/internal/stacktrace_arm-inl.inc [new file with mode: 0644]
src/absl/debugging/internal/stacktrace_config.h [new file with mode: 0644]
src/absl/debugging/internal/stacktrace_generic-inl.inc [new file with mode: 0644]
src/absl/debugging/internal/stacktrace_powerpc-inl.inc [new file with mode: 0644]
src/absl/debugging/internal/stacktrace_unimplemented-inl.inc [new file with mode: 0644]
src/absl/debugging/internal/stacktrace_win32-inl.inc [new file with mode: 0644]
src/absl/debugging/internal/stacktrace_x86-inl.inc [new file with mode: 0644]
src/absl/debugging/internal/symbolize.h [new file with mode: 0644]
src/absl/debugging/internal/vdso_support.cc [new file with mode: 0644]
src/absl/debugging/internal/vdso_support.h [new file with mode: 0644]
src/absl/debugging/leak_check.cc [new file with mode: 0644]
src/absl/debugging/leak_check.h [new file with mode: 0644]
src/absl/debugging/leak_check_disable.cc [new file with mode: 0644]
src/absl/debugging/stacktrace.cc [new file with mode: 0644]
src/absl/debugging/stacktrace.h [new file with mode: 0644]
src/absl/debugging/symbolize.cc [new file with mode: 0644]
src/absl/debugging/symbolize.h [new file with mode: 0644]
src/absl/debugging/symbolize_darwin.inc [new file with mode: 0644]
src/absl/debugging/symbolize_elf.inc [new file with mode: 0644]
src/absl/debugging/symbolize_unimplemented.inc [new file with mode: 0644]
src/absl/debugging/symbolize_win32.inc [new file with mode: 0644]
src/absl/functional/bind_front.h [new file with mode: 0644]
src/absl/functional/function_ref.h [new file with mode: 0644]
src/absl/functional/internal/front_binder.h [new file with mode: 0644]
src/absl/functional/internal/function_ref.h [new file with mode: 0644]
src/absl/memory/memory.h [new file with mode: 0644]
src/absl/meta/type_traits.h [new file with mode: 0644]
src/absl/numeric/bits.h [new file with mode: 0644]
src/absl/numeric/int128.cc [new file with mode: 0644]
src/absl/numeric/int128.h [new file with mode: 0644]
src/absl/numeric/int128_have_intrinsic.inc [new file with mode: 0644]
src/absl/numeric/int128_no_intrinsic.inc [new file with mode: 0644]
src/absl/numeric/internal/bits.h [new file with mode: 0644]
src/absl/numeric/internal/representation.h [new file with mode: 0644]
src/absl/strings/ascii.cc [new file with mode: 0644]
src/absl/strings/ascii.h [new file with mode: 0644]
src/absl/strings/charconv.cc [new file with mode: 0644]
src/absl/strings/charconv.h [new file with mode: 0644]
src/absl/strings/cord.cc [new file with mode: 0644]
src/absl/strings/cord.h [new file with mode: 0644]
src/absl/strings/escaping.cc [new file with mode: 0644]
src/absl/strings/escaping.h [new file with mode: 0644]
src/absl/strings/internal/char_map.h [new file with mode: 0644]
src/absl/strings/internal/charconv_bigint.cc [new file with mode: 0644]
src/absl/strings/internal/charconv_bigint.h [new file with mode: 0644]
src/absl/strings/internal/charconv_parse.cc [new file with mode: 0644]
src/absl/strings/internal/charconv_parse.h [new file with mode: 0644]
src/absl/strings/internal/cord_internal.cc [new file with mode: 0644]
src/absl/strings/internal/cord_internal.h [new file with mode: 0644]
src/absl/strings/internal/cord_rep_flat.h [new file with mode: 0644]
src/absl/strings/internal/cord_rep_ring.cc [new file with mode: 0644]
src/absl/strings/internal/cord_rep_ring.h [new file with mode: 0644]
src/absl/strings/internal/cord_rep_ring_reader.h [new file with mode: 0644]
src/absl/strings/internal/escaping.cc [new file with mode: 0644]
src/absl/strings/internal/escaping.h [new file with mode: 0644]
src/absl/strings/internal/memutil.cc [new file with mode: 0644]
src/absl/strings/internal/memutil.h [new file with mode: 0644]
src/absl/strings/internal/ostringstream.cc [new file with mode: 0644]
src/absl/strings/internal/ostringstream.h [new file with mode: 0644]
src/absl/strings/internal/pow10_helper.cc [new file with mode: 0644]
src/absl/strings/internal/pow10_helper.h [new file with mode: 0644]
src/absl/strings/internal/resize_uninitialized.h [new file with mode: 0644]
src/absl/strings/internal/stl_type_traits.h [new file with mode: 0644]
src/absl/strings/internal/str_format/arg.cc [new file with mode: 0644]
src/absl/strings/internal/str_format/arg.h [new file with mode: 0644]
src/absl/strings/internal/str_format/bind.cc [new file with mode: 0644]
src/absl/strings/internal/str_format/bind.h [new file with mode: 0644]
src/absl/strings/internal/str_format/checker.h [new file with mode: 0644]
src/absl/strings/internal/str_format/extension.cc [new file with mode: 0644]
src/absl/strings/internal/str_format/extension.h [new file with mode: 0644]
src/absl/strings/internal/str_format/float_conversion.cc [new file with mode: 0644]
src/absl/strings/internal/str_format/float_conversion.h [new file with mode: 0644]
src/absl/strings/internal/str_format/output.cc [new file with mode: 0644]
src/absl/strings/internal/str_format/output.h [new file with mode: 0644]
src/absl/strings/internal/str_format/parser.cc [new file with mode: 0644]
src/absl/strings/internal/str_format/parser.h [new file with mode: 0644]
src/absl/strings/internal/str_join_internal.h [new file with mode: 0644]
src/absl/strings/internal/str_split_internal.h [new file with mode: 0644]
src/absl/strings/internal/string_constant.h [new file with mode: 0644]
src/absl/strings/internal/utf8.cc [new file with mode: 0644]
src/absl/strings/internal/utf8.h [new file with mode: 0644]
src/absl/strings/match.cc [new file with mode: 0644]
src/absl/strings/match.h [new file with mode: 0644]
src/absl/strings/numbers.cc [new file with mode: 0644]
src/absl/strings/numbers.h [new file with mode: 0644]
src/absl/strings/str_cat.cc [new file with mode: 0644]
src/absl/strings/str_cat.h [new file with mode: 0644]
src/absl/strings/str_format.h [new file with mode: 0644]
src/absl/strings/str_join.h [new file with mode: 0644]
src/absl/strings/str_replace.cc [new file with mode: 0644]
src/absl/strings/str_replace.h [new file with mode: 0644]
src/absl/strings/str_split.cc [new file with mode: 0644]
src/absl/strings/str_split.h [new file with mode: 0644]
src/absl/strings/string_view.cc [new file with mode: 0644]
src/absl/strings/string_view.h [new file with mode: 0644]
src/absl/strings/strip.h [new file with mode: 0644]
src/absl/strings/substitute.cc [new file with mode: 0644]
src/absl/strings/substitute.h [new file with mode: 0644]
src/absl/synchronization/barrier.cc [new file with mode: 0644]
src/absl/synchronization/barrier.h [new file with mode: 0644]
src/absl/synchronization/blocking_counter.cc [new file with mode: 0644]
src/absl/synchronization/blocking_counter.h [new file with mode: 0644]
src/absl/synchronization/internal/create_thread_identity.cc [new file with mode: 0644]
src/absl/synchronization/internal/create_thread_identity.h [new file with mode: 0644]
src/absl/synchronization/internal/futex.h [new file with mode: 0644]
src/absl/synchronization/internal/graphcycles.cc [new file with mode: 0644]
src/absl/synchronization/internal/graphcycles.h [new file with mode: 0644]
src/absl/synchronization/internal/kernel_timeout.h [new file with mode: 0644]
src/absl/synchronization/internal/per_thread_sem.cc [new file with mode: 0644]
src/absl/synchronization/internal/per_thread_sem.h [new file with mode: 0644]
src/absl/synchronization/internal/thread_pool.h [new file with mode: 0644]
src/absl/synchronization/internal/waiter.cc [new file with mode: 0644]
src/absl/synchronization/internal/waiter.h [new file with mode: 0644]
src/absl/synchronization/mutex.cc [new file with mode: 0644]
src/absl/synchronization/mutex.h [new file with mode: 0644]
src/absl/synchronization/notification.cc [new file with mode: 0644]
src/absl/synchronization/notification.h [new file with mode: 0644]
src/absl/time/civil_time.cc [new file with mode: 0644]
src/absl/time/civil_time.h [new file with mode: 0644]
src/absl/time/clock.cc [new file with mode: 0644]
src/absl/time/clock.h [new file with mode: 0644]
src/absl/time/duration.cc [new file with mode: 0644]
src/absl/time/format.cc [new file with mode: 0644]
src/absl/time/internal/cctz/include/cctz/civil_time.h [new file with mode: 0644]
src/absl/time/internal/cctz/include/cctz/civil_time_detail.h [new file with mode: 0644]
src/absl/time/internal/cctz/include/cctz/time_zone.h [new file with mode: 0644]
src/absl/time/internal/cctz/include/cctz/zone_info_source.h [new file with mode: 0644]
src/absl/time/internal/cctz/src/civil_time_detail.cc [new file with mode: 0644]
src/absl/time/internal/cctz/src/time_zone_fixed.cc [new file with mode: 0644]
src/absl/time/internal/cctz/src/time_zone_fixed.h [new file with mode: 0644]
src/absl/time/internal/cctz/src/time_zone_format.cc [new file with mode: 0644]
src/absl/time/internal/cctz/src/time_zone_if.cc [new file with mode: 0644]
src/absl/time/internal/cctz/src/time_zone_if.h [new file with mode: 0644]
src/absl/time/internal/cctz/src/time_zone_impl.cc [new file with mode: 0644]
src/absl/time/internal/cctz/src/time_zone_impl.h [new file with mode: 0644]
src/absl/time/internal/cctz/src/time_zone_info.cc [new file with mode: 0644]
src/absl/time/internal/cctz/src/time_zone_info.h [new file with mode: 0644]
src/absl/time/internal/cctz/src/time_zone_libc.cc [new file with mode: 0644]
src/absl/time/internal/cctz/src/time_zone_libc.h [new file with mode: 0644]
src/absl/time/internal/cctz/src/time_zone_lookup.cc [new file with mode: 0644]
src/absl/time/internal/cctz/src/time_zone_posix.cc [new file with mode: 0644]
src/absl/time/internal/cctz/src/time_zone_posix.h [new file with mode: 0644]
src/absl/time/internal/cctz/src/tzfile.h [new file with mode: 0644]
src/absl/time/internal/cctz/src/zone_info_source.cc [new file with mode: 0644]
src/absl/time/internal/get_current_time_chrono.inc [new file with mode: 0644]
src/absl/time/internal/get_current_time_posix.inc [new file with mode: 0644]
src/absl/time/internal/zoneinfo.inc [new file with mode: 0644]
src/absl/time/time.cc [new file with mode: 0644]
src/absl/time/time.h [new file with mode: 0644]
src/absl/types/any.h [new file with mode: 0644]
src/absl/types/bad_any_cast.cc [new file with mode: 0644]
src/absl/types/bad_any_cast.h [new file with mode: 0644]
src/absl/types/bad_optional_access.cc [new file with mode: 0644]
src/absl/types/bad_optional_access.h [new file with mode: 0644]
src/absl/types/bad_variant_access.cc [new file with mode: 0644]
src/absl/types/bad_variant_access.h [new file with mode: 0644]
src/absl/types/compare.h [new file with mode: 0644]
src/absl/types/internal/conformance_aliases.h [new file with mode: 0644]
src/absl/types/internal/conformance_archetype.h [new file with mode: 0644]
src/absl/types/internal/conformance_profile.h [new file with mode: 0644]
src/absl/types/internal/conformance_testing_helpers.h [new file with mode: 0644]
src/absl/types/internal/optional.h [new file with mode: 0644]
src/absl/types/internal/parentheses.h [new file with mode: 0644]
src/absl/types/internal/span.h [new file with mode: 0644]
src/absl/types/internal/transform_args.h [new file with mode: 0644]
src/absl/types/internal/variant.h [new file with mode: 0644]
src/absl/types/optional.h [new file with mode: 0644]
src/absl/types/span.h [new file with mode: 0644]
src/absl/types/variant.h [new file with mode: 0644]
src/absl/utility/utility.h [new file with mode: 0644]
src/cpp-compat.cpp [new file with mode: 0644]
src/cpp-compat.h [new file with mode: 0644]
src/geography-collection.h [new file with mode: 0644]
src/geography-operator.h [new file with mode: 0644]
src/geography.h [new file with mode: 0644]
src/init.cpp [new file with mode: 0644]
src/point-geography.h [new file with mode: 0644]
src/polygon-geography.h [new file with mode: 0644]
src/polyline-geography.h [new file with mode: 0644]
src/s2-accessors.cpp [new file with mode: 0644]
src/s2-bounds.cpp [new file with mode: 0644]
src/s2-c-api.cpp [new file with mode: 0644]
src/s2-cell.cpp [new file with mode: 0644]
src/s2-constructors-formatters.cpp [new file with mode: 0644]
src/s2-geography.cpp [new file with mode: 0644]
src/s2-lnglat.cpp [new file with mode: 0644]
src/s2-matrix.cpp [new file with mode: 0644]
src/s2-options.h [new file with mode: 0644]
src/s2-point.cpp [new file with mode: 0644]
src/s2-predicates.cpp [new file with mode: 0644]
src/s2-transformers.cpp [new file with mode: 0644]
src/s2-xptr.cpp [new file with mode: 0644]
src/s2/_fp_contract_off.h [new file with mode: 0644]
src/s2/base/casts.h [new file with mode: 0644]
src/s2/base/commandlineflags.h [new file with mode: 0644]
src/s2/base/integral_types.h [new file with mode: 0644]
src/s2/base/log_severity.h [new file with mode: 0644]
src/s2/base/logging.h [new file with mode: 0644]
src/s2/base/mutex.h [new file with mode: 0644]
src/s2/base/port.h [new file with mode: 0644]
src/s2/base/spinlock.h [new file with mode: 0644]
src/s2/base/stringprintf.cc [new file with mode: 0644]
src/s2/base/stringprintf.h [new file with mode: 0644]
src/s2/base/strtoint.cc [new file with mode: 0644]
src/s2/base/strtoint.h [new file with mode: 0644]
src/s2/base/timer.h [new file with mode: 0644]
src/s2/encoded_s2cell_id_vector.cc [new file with mode: 0644]
src/s2/encoded_s2cell_id_vector.h [new file with mode: 0644]
src/s2/encoded_s2point_vector.cc [new file with mode: 0644]
src/s2/encoded_s2point_vector.h [new file with mode: 0644]
src/s2/encoded_s2shape_index.cc [new file with mode: 0644]
src/s2/encoded_s2shape_index.h [new file with mode: 0644]
src/s2/encoded_string_vector.cc [new file with mode: 0644]
src/s2/encoded_string_vector.h [new file with mode: 0644]
src/s2/encoded_uint_vector.h [new file with mode: 0644]
src/s2/id_set_lexicon.cc [new file with mode: 0644]
src/s2/id_set_lexicon.h [new file with mode: 0644]
src/s2/mutable_s2shape_index.cc [new file with mode: 0644]
src/s2/mutable_s2shape_index.h [new file with mode: 0644]
src/s2/r1interval.h [new file with mode: 0644]
src/s2/r2.h [new file with mode: 0644]
src/s2/r2rect.cc [new file with mode: 0644]
src/s2/r2rect.h [new file with mode: 0644]
src/s2/s1angle.cc [new file with mode: 0644]
src/s2/s1angle.h [new file with mode: 0644]
src/s2/s1chord_angle.cc [new file with mode: 0644]
src/s2/s1chord_angle.h [new file with mode: 0644]
src/s2/s1interval.cc [new file with mode: 0644]
src/s2/s1interval.h [new file with mode: 0644]
src/s2/s2boolean_operation.cc [new file with mode: 0644]
src/s2/s2boolean_operation.h [new file with mode: 0644]
src/s2/s2builder.cc [new file with mode: 0644]
src/s2/s2builder.h [new file with mode: 0644]
src/s2/s2builder_graph.cc [new file with mode: 0644]
src/s2/s2builder_graph.h [new file with mode: 0644]
src/s2/s2builder_layer.h [new file with mode: 0644]
src/s2/s2builderutil_closed_set_normalizer.cc [new file with mode: 0644]
src/s2/s2builderutil_closed_set_normalizer.h [new file with mode: 0644]
src/s2/s2builderutil_find_polygon_degeneracies.cc [new file with mode: 0644]
src/s2/s2builderutil_find_polygon_degeneracies.h [new file with mode: 0644]
src/s2/s2builderutil_graph_shape.h [new file with mode: 0644]
src/s2/s2builderutil_lax_polygon_layer.cc [new file with mode: 0644]
src/s2/s2builderutil_lax_polygon_layer.h [new file with mode: 0644]
src/s2/s2builderutil_s2point_vector_layer.cc [new file with mode: 0644]
src/s2/s2builderutil_s2point_vector_layer.h [new file with mode: 0644]
src/s2/s2builderutil_s2polygon_layer.cc [new file with mode: 0644]
src/s2/s2builderutil_s2polygon_layer.h [new file with mode: 0644]
src/s2/s2builderutil_s2polyline_layer.cc [new file with mode: 0644]
src/s2/s2builderutil_s2polyline_layer.h [new file with mode: 0644]
src/s2/s2builderutil_s2polyline_vector_layer.cc [new file with mode: 0644]
src/s2/s2builderutil_s2polyline_vector_layer.h [new file with mode: 0644]
src/s2/s2builderutil_snap_functions.cc [new file with mode: 0644]
src/s2/s2builderutil_snap_functions.h [new file with mode: 0644]
src/s2/s2builderutil_testing.cc [new file with mode: 0644]
src/s2/s2builderutil_testing.h [new file with mode: 0644]
src/s2/s2cap.cc [new file with mode: 0644]
src/s2/s2cap.h [new file with mode: 0644]
src/s2/s2cell.cc [new file with mode: 0644]
src/s2/s2cell.h [new file with mode: 0644]
src/s2/s2cell_id.cc [new file with mode: 0644]
src/s2/s2cell_id.h [new file with mode: 0644]
src/s2/s2cell_index.cc [new file with mode: 0644]
src/s2/s2cell_index.h [new file with mode: 0644]
src/s2/s2cell_union.cc [new file with mode: 0644]
src/s2/s2cell_union.h [new file with mode: 0644]
src/s2/s2centroids.cc [new file with mode: 0644]
src/s2/s2centroids.h [new file with mode: 0644]
src/s2/s2closest_cell_query.cc [new file with mode: 0644]
src/s2/s2closest_cell_query.h [new file with mode: 0644]
src/s2/s2closest_cell_query_base.h [new file with mode: 0644]
src/s2/s2closest_edge_query.cc [new file with mode: 0644]
src/s2/s2closest_edge_query.h [new file with mode: 0644]
src/s2/s2closest_edge_query_base.h [new file with mode: 0644]
src/s2/s2closest_edge_query_testing.h [new file with mode: 0644]
src/s2/s2closest_point_query.cc [new file with mode: 0644]
src/s2/s2closest_point_query.h [new file with mode: 0644]
src/s2/s2closest_point_query_base.h [new file with mode: 0644]
src/s2/s2contains_point_query.h [new file with mode: 0644]
src/s2/s2contains_vertex_query.cc [new file with mode: 0644]
src/s2/s2contains_vertex_query.h [new file with mode: 0644]
src/s2/s2convex_hull_query.cc [new file with mode: 0644]
src/s2/s2convex_hull_query.h [new file with mode: 0644]
src/s2/s2coords.cc [new file with mode: 0644]
src/s2/s2coords.h [new file with mode: 0644]
src/s2/s2coords_internal.h [new file with mode: 0644]
src/s2/s2crossing_edge_query.cc [new file with mode: 0644]
src/s2/s2crossing_edge_query.h [new file with mode: 0644]
src/s2/s2debug.cc [new file with mode: 0644]
src/s2/s2debug.h [new file with mode: 0644]
src/s2/s2distance_target.h [new file with mode: 0644]
src/s2/s2earth.cc [new file with mode: 0644]
src/s2/s2earth.h [new file with mode: 0644]
src/s2/s2edge_clipping.cc [new file with mode: 0644]
src/s2/s2edge_clipping.h [new file with mode: 0644]
src/s2/s2edge_crosser.cc [new file with mode: 0644]
src/s2/s2edge_crosser.h [new file with mode: 0644]
src/s2/s2edge_crossings.cc [new file with mode: 0644]
src/s2/s2edge_crossings.h [new file with mode: 0644]
src/s2/s2edge_crossings_internal.h [new file with mode: 0644]
src/s2/s2edge_distances.cc [new file with mode: 0644]
src/s2/s2edge_distances.h [new file with mode: 0644]
src/s2/s2edge_tessellator.cc [new file with mode: 0644]
src/s2/s2edge_tessellator.h [new file with mode: 0644]
src/s2/s2edge_vector_shape.h [new file with mode: 0644]
src/s2/s2error.cc [new file with mode: 0644]
src/s2/s2error.h [new file with mode: 0644]
src/s2/s2furthest_edge_query.cc [new file with mode: 0644]
src/s2/s2furthest_edge_query.h [new file with mode: 0644]
src/s2/s2latlng.cc [new file with mode: 0644]
src/s2/s2latlng.h [new file with mode: 0644]
src/s2/s2latlng_rect.cc [new file with mode: 0644]
src/s2/s2latlng_rect.h [new file with mode: 0644]
src/s2/s2latlng_rect_bounder.cc [new file with mode: 0644]
src/s2/s2latlng_rect_bounder.h [new file with mode: 0644]
src/s2/s2lax_loop_shape.cc [new file with mode: 0644]
src/s2/s2lax_loop_shape.h [new file with mode: 0644]
src/s2/s2lax_polygon_shape.cc [new file with mode: 0644]
src/s2/s2lax_polygon_shape.h [new file with mode: 0644]
src/s2/s2lax_polyline_shape.cc [new file with mode: 0644]
src/s2/s2lax_polyline_shape.h [new file with mode: 0644]
src/s2/s2loop.cc [new file with mode: 0644]
src/s2/s2loop.h [new file with mode: 0644]
src/s2/s2loop_measures.cc [new file with mode: 0644]
src/s2/s2loop_measures.h [new file with mode: 0644]
src/s2/s2max_distance_targets.cc [new file with mode: 0644]
src/s2/s2max_distance_targets.h [new file with mode: 0644]
src/s2/s2measures.cc [new file with mode: 0644]
src/s2/s2measures.h [new file with mode: 0644]
src/s2/s2metrics.cc [new file with mode: 0644]
src/s2/s2metrics.h [new file with mode: 0644]
src/s2/s2min_distance_targets.cc [new file with mode: 0644]
src/s2/s2min_distance_targets.h [new file with mode: 0644]
src/s2/s2padded_cell.cc [new file with mode: 0644]
src/s2/s2padded_cell.h [new file with mode: 0644]
src/s2/s2point.h [new file with mode: 0644]
src/s2/s2point_compression.cc [new file with mode: 0644]
src/s2/s2point_compression.h [new file with mode: 0644]
src/s2/s2point_index.h [new file with mode: 0644]
src/s2/s2point_region.cc [new file with mode: 0644]
src/s2/s2point_region.h [new file with mode: 0644]
src/s2/s2point_span.h [new file with mode: 0644]
src/s2/s2point_vector_shape.h [new file with mode: 0644]
src/s2/s2pointutil.cc [new file with mode: 0644]
src/s2/s2pointutil.h [new file with mode: 0644]
src/s2/s2polygon.cc [new file with mode: 0644]
src/s2/s2polygon.h [new file with mode: 0644]
src/s2/s2polyline.cc [new file with mode: 0644]
src/s2/s2polyline.h [new file with mode: 0644]
src/s2/s2polyline_alignment.cc [new file with mode: 0644]
src/s2/s2polyline_alignment.h [new file with mode: 0644]
src/s2/s2polyline_alignment_internal.h [new file with mode: 0644]
src/s2/s2polyline_measures.cc [new file with mode: 0644]
src/s2/s2polyline_measures.h [new file with mode: 0644]
src/s2/s2polyline_simplifier.cc [new file with mode: 0644]
src/s2/s2polyline_simplifier.h [new file with mode: 0644]
src/s2/s2predicates.cc [new file with mode: 0644]
src/s2/s2predicates.h [new file with mode: 0644]
src/s2/s2predicates_internal.h [new file with mode: 0644]
src/s2/s2projections.cc [new file with mode: 0644]
src/s2/s2projections.h [new file with mode: 0644]
src/s2/s2r2rect.cc [new file with mode: 0644]
src/s2/s2r2rect.h [new file with mode: 0644]
src/s2/s2region.cc [new file with mode: 0644]
src/s2/s2region.h [new file with mode: 0644]
src/s2/s2region_coverer.cc [new file with mode: 0644]
src/s2/s2region_coverer.h [new file with mode: 0644]
src/s2/s2region_intersection.cc [new file with mode: 0644]
src/s2/s2region_intersection.h [new file with mode: 0644]
src/s2/s2region_term_indexer.cc [new file with mode: 0644]
src/s2/s2region_term_indexer.h [new file with mode: 0644]
src/s2/s2region_union.cc [new file with mode: 0644]
src/s2/s2region_union.h [new file with mode: 0644]
src/s2/s2shape.h [new file with mode: 0644]
src/s2/s2shape_index.cc [new file with mode: 0644]
src/s2/s2shape_index.h [new file with mode: 0644]
src/s2/s2shape_index_buffered_region.cc [new file with mode: 0644]
src/s2/s2shape_index_buffered_region.h [new file with mode: 0644]
src/s2/s2shape_index_measures.cc [new file with mode: 0644]
src/s2/s2shape_index_measures.h [new file with mode: 0644]
src/s2/s2shape_index_region.h [new file with mode: 0644]
src/s2/s2shape_measures.cc [new file with mode: 0644]
src/s2/s2shape_measures.h [new file with mode: 0644]
src/s2/s2shapeutil_build_polygon_boundaries.cc [new file with mode: 0644]
src/s2/s2shapeutil_build_polygon_boundaries.h [new file with mode: 0644]
src/s2/s2shapeutil_coding.cc [new file with mode: 0644]
src/s2/s2shapeutil_coding.h [new file with mode: 0644]
src/s2/s2shapeutil_contains_brute_force.cc [new file with mode: 0644]
src/s2/s2shapeutil_contains_brute_force.h [new file with mode: 0644]
src/s2/s2shapeutil_count_edges.h [new file with mode: 0644]
src/s2/s2shapeutil_edge_iterator.cc [new file with mode: 0644]
src/s2/s2shapeutil_edge_iterator.h [new file with mode: 0644]
src/s2/s2shapeutil_get_reference_point.cc [new file with mode: 0644]
src/s2/s2shapeutil_get_reference_point.h [new file with mode: 0644]
src/s2/s2shapeutil_range_iterator.cc [new file with mode: 0644]
src/s2/s2shapeutil_range_iterator.h [new file with mode: 0644]
src/s2/s2shapeutil_shape_edge.h [new file with mode: 0644]
src/s2/s2shapeutil_shape_edge_id.h [new file with mode: 0644]
src/s2/s2shapeutil_testing.h [new file with mode: 0644]
src/s2/s2shapeutil_visit_crossing_edge_pairs.cc [new file with mode: 0644]
src/s2/s2shapeutil_visit_crossing_edge_pairs.h [new file with mode: 0644]
src/s2/s2testing.cc [new file with mode: 0644]
src/s2/s2testing.h [new file with mode: 0644]
src/s2/s2text_format.cc [new file with mode: 0644]
src/s2/s2text_format.h [new file with mode: 0644]
src/s2/s2wedge_relations.cc [new file with mode: 0644]
src/s2/s2wedge_relations.h [new file with mode: 0644]
src/s2/sequence_lexicon.h [new file with mode: 0644]
src/s2/strings/ostringstream.cc [new file with mode: 0644]
src/s2/strings/ostringstream.h [new file with mode: 0644]
src/s2/strings/serialize.cc [new file with mode: 0644]
src/s2/strings/serialize.h [new file with mode: 0644]
src/s2/util/bits/bit-interleave.cc [new file with mode: 0644]
src/s2/util/bits/bit-interleave.h [new file with mode: 0644]
src/s2/util/bits/bits.cc [new file with mode: 0644]
src/s2/util/bits/bits.h [new file with mode: 0644]
src/s2/util/coding/coder.cc [new file with mode: 0644]
src/s2/util/coding/coder.h [new file with mode: 0644]
src/s2/util/coding/nth-derivative.h [new file with mode: 0644]
src/s2/util/coding/transforms.h [new file with mode: 0644]
src/s2/util/coding/varint.cc [new file with mode: 0644]
src/s2/util/coding/varint.h [new file with mode: 0644]
src/s2/util/endian/endian.h [new file with mode: 0644]
src/s2/util/gtl/btree.h [new file with mode: 0644]
src/s2/util/gtl/btree_container.h [new file with mode: 0644]
src/s2/util/gtl/btree_map.h [new file with mode: 0644]
src/s2/util/gtl/btree_set.h [new file with mode: 0644]
src/s2/util/gtl/compact_array.h [new file with mode: 0644]
src/s2/util/gtl/container_logging.h [new file with mode: 0644]
src/s2/util/gtl/dense_hash_set.h [new file with mode: 0644]
src/s2/util/gtl/densehashtable.h [new file with mode: 0644]
src/s2/util/gtl/hashtable_common.h [new file with mode: 0644]
src/s2/util/gtl/layout.h [new file with mode: 0644]
src/s2/util/gtl/legacy_random_shuffle.h [new file with mode: 0644]
src/s2/util/hash/mix.h [new file with mode: 0644]
src/s2/util/math/exactfloat/exactfloat.cc [new file with mode: 0644]
src/s2/util/math/exactfloat/exactfloat.h [new file with mode: 0644]
src/s2/util/math/mathutil.cc [new file with mode: 0644]
src/s2/util/math/mathutil.h [new file with mode: 0644]
src/s2/util/math/matrix3x3.h [new file with mode: 0644]
src/s2/util/math/vector.h [new file with mode: 0644]
src/s2/util/math/vector3_hash.h [new file with mode: 0644]
src/s2/util/units/length-units.cc [new file with mode: 0644]
src/s2/util/units/length-units.h [new file with mode: 0644]
src/s2/util/units/physical-units.h [new file with mode: 0644]
src/s2/value_lexicon.h [new file with mode: 0644]
src/tests/soname.h [new file with mode: 0644]
src/wk-c-utils.c [new file with mode: 0644]
src/wk-geography.h [new file with mode: 0644]
src/wk-impl.c [new file with mode: 0644]
tests/area.R [new file with mode: 0644]
tests/area.Rout [new file with mode: 0644]
tests/testthat.R [new file with mode: 0644]
tests/testthat/test-data.R [new file with mode: 0644]
tests/testthat/test-s2-accessors.R [new file with mode: 0644]
tests/testthat/test-s2-bounds.R [new file with mode: 0644]
tests/testthat/test-s2-cell.R [new file with mode: 0644]
tests/testthat/test-s2-constructors-formatters.R [new file with mode: 0644]
tests/testthat/test-s2-earth.R [new file with mode: 0644]
tests/testthat/test-s2-geography.R [new file with mode: 0644]
tests/testthat/test-s2-lnglat.R [new file with mode: 0644]
tests/testthat/test-s2-matrix.R [new file with mode: 0644]
tests/testthat/test-s2-options.R [new file with mode: 0644]
tests/testthat/test-s2-point.R [new file with mode: 0644]
tests/testthat/test-s2-predicates.R [new file with mode: 0644]
tests/testthat/test-s2-transformers.R [new file with mode: 0644]
tests/testthat/test-s2-xptr.R [new file with mode: 0644]
tests/testthat/test-utils.R [new file with mode: 0644]
tests/testthat/test-vctrs.R [new file with mode: 0644]
tests/testthat/test-wk-utils.R [new file with mode: 0644]
tools/version.c [new file with mode: 0644]
tools/winlibs.R [new file with mode: 0644]

diff --git a/DESCRIPTION b/DESCRIPTION
new file mode 100644 (file)
index 0000000..29f09da
--- /dev/null
@@ -0,0 +1,45 @@
+Package: s2
+Title: Spherical Geometry Operators Using the S2 Geometry Library
+Version: 1.0.7
+Authors@R: c(
+     person(given = "Dewey",
+           family = "Dunnington",
+           role = c("aut"),
+           email = "dewey@fishandwhistle.net",
+           comment = c(ORCID = "0000-0002-9415-4582")),
+     person(given = "Edzer",
+             family = "Pebesma",
+             role = c("aut", "cre"),
+             email = "edzer.pebesma@uni-muenster.de",
+             comment = c(ORCID = "0000-0001-8049-7069")),
+    person("Ege", "Rubak", email="rubak@math.aau.dk", role = c("aut")),
+    person("Jeroen", "Ooms", , "jeroen.ooms@stat.ucla.edu", role = "ctb", comment = "configure script"),
+    person(family = "Google, Inc.", role = "cph", comment = "Original s2geometry.io source code")
+  )
+Description: Provides R bindings for Google's s2 library for geometric calculations on
+    the sphere. High-performance constructors and exporters provide high compatibility
+    with existing spatial packages, transformers construct new geometries from existing
+    geometries, predicates provide a means to select geometries based on spatial 
+    relationships, and accessors extract information about geometries.
+License: Apache License (== 2.0)
+Encoding: UTF-8
+LazyData: true
+RoxygenNote: 7.1.2
+SystemRequirements: OpenSSL >= 1.0.1
+LinkingTo: Rcpp, wk
+Imports: Rcpp, wk (>= 0.5.0)
+Suggests: testthat, vctrs
+URL: https://r-spatial.github.io/s2/, https://github.com/r-spatial/s2,
+        https://s2geometry.io/
+BugReports: https://github.com/r-spatial/s2/issues
+Depends: R (>= 3.0.0)
+NeedsCompilation: yes
+Packaged: 2021-09-22 15:42:08 UTC; edzer
+Author: Dewey Dunnington [aut] (<https://orcid.org/0000-0002-9415-4582>),
+  Edzer Pebesma [aut, cre] (<https://orcid.org/0000-0001-8049-7069>),
+  Ege Rubak [aut],
+  Jeroen Ooms [ctb] (configure script),
+  Google, Inc. [cph] (Original s2geometry.io source code)
+Maintainer: Edzer Pebesma <edzer.pebesma@uni-muenster.de>
+Repository: CRAN
+Date/Publication: 2021-09-28 09:40:02 UTC
diff --git a/MD5 b/MD5
new file mode 100644 (file)
index 0000000..2249f56
--- /dev/null
+++ b/MD5
@@ -0,0 +1,630 @@
+81b168cfcec3ee13f46dcdb577c17cf5 *DESCRIPTION
+c2cf7412597f5a006b397f17534e4926 *NAMESPACE
+00d4b6d276793ebb734e49773c6cf8ee *NEWS.md
+c2684d1f0a404bc345a324f7da698415 *R/RcppExports.R
+8567a6b7a3c75cad01a581303546fced *R/data.R
+b783a368a460bcae5d174c575d863e59 *R/s2-accessors.R
+4ba8ec7d16efeadbc21c3ab5ac3dc6a6 *R/s2-bounds.R
+e4b9443bce55208a66db5e2270e3b39e *R/s2-cell.R
+a9b85fd1af5d8ffba7f46f9d16b333ee *R/s2-constructors-formatters.R
+0968515e318a2c7a7372bddad1be6c23 *R/s2-earth.R
+9b49bdbca96d37c94db186cac76c12f4 *R/s2-geography.R
+f7370a030a2faf0fb9a79166fc012ea2 *R/s2-lnglat.R
+98df8e5c809782b58b54ec16b7e1e47f *R/s2-matrix.R
+e960477e2e4f889c85831e3d438bfe0f *R/s2-options.R
+1bab90d590a0e66114c86739ba0d6ce4 *R/s2-package.R
+e78c2f5f3bc790e3fa91d3f5e037754e *R/s2-point.R
+447d319c0cbec576de0695a518292089 *R/s2-predicates.R
+57f21ccb0ebe8ce32a1a8c2677e28766 *R/s2-transformers.R
+3b4c3f3354c7dc58491cf0ec7b21a869 *R/s2-xptr.R
+4dc8dfdd1b91963c25b41c106a439978 *R/utils.R
+f47605a30d14896490f2b587097b7d64 *R/vctrs.R
+9c82a07787347c391042dbb9b1c7fabe *R/wk-utils.R
+f73f271153285cff50aca1aea7d273aa *R/zzz.R
+e9fb7b9570945530c4833c91310084f6 *README.md
+c5b12c2075a2b01b74abcbcd51301950 *build/partial.rdb
+cc6eebf14a3f516ec74168f3ea416fb2 *cleanup
+9401515addc6f00f403443fd0715fcf9 *configure
+d41d8cd98f00b204e9800998ecf8427e *configure.win
+6d0a8453b0e12b4654d468d1e7248961 *data/s2_data_tbl_cities.rda
+b0b89f3499ca649d9a78f77096e4f5da *data/s2_data_tbl_countries.rda
+5bbeed937d4c3e766c02ce396f77cefc *data/s2_data_tbl_timezones.rda
+d41d8cd98f00b204e9800998ecf8427e *inst/extdata/emptyfile
+229cd1481362f4fa2c4c3769886f6cfd *man/as_s2_geography.Rd
+ed01c59b91c1a9c3382d1f2ab67e60cc *man/figures/rc300.png
+0d32af4cce70305a4ad68adb26e7c89f *man/s2-package.Rd
+d5798affb398838bd20ed59853a68a41 *man/s2_boundary.Rd
+a906d7f9956940ceebe0bd879c14e5f2 *man/s2_bounds_cap.Rd
+198a89e9bd9be11ca5d34e0d79aaabba *man/s2_cell.Rd
+11547e36b46a12a3adbcfcb3a6d0104c *man/s2_cell_is_valid.Rd
+8f98d4539e0aa509666786e0e12bdda8 *man/s2_closest_feature.Rd
+d96650f409fa8eb02fe4d5f54d00eb7d *man/s2_contains.Rd
+addd614791ada510339317f68202d348 *man/s2_data_tbl_countries.Rd
+d7a1ee72a69458a577921e02c2f4142f *man/s2_earth_radius_meters.Rd
+b7d61946f176fbfc08dcb89df81b8bed *man/s2_geog_point.Rd
+9676c31cb07674f1d6935a5b0462f3ca *man/s2_interpolate.Rd
+32c6a0bb1280c25f7da7dc9781315d92 *man/s2_is_collection.Rd
+e1a47506a896f0144af3c34265fef2b1 *man/s2_lnglat.Rd
+43d061044e95b05b97b7cdb01d392708 *man/s2_options.Rd
+a86f2581e1af6031167a29956341993c *man/s2_point.Rd
+e2e7f612cb4705ee22e059404c24be46 *man/s2_unprojection_filter.Rd
+f684c84e3ef6a090c5560ff816af3977 *src/Makevars.in
+2cec33791efd347cbcb051402d7cf9c4 *src/Makevars.ucrt
+75eba20be555de5ca4e072f20f6ddf07 *src/Makevars.win
+7a2ec09d8e7950ea34ca0cd01a31f10e *src/RcppExports.cpp
+642c7be2ce45690aea290338fec0675b *src/absl/algorithm/algorithm.h
+abbb3beafcfd12ec8de50f69f3a47b28 *src/absl/algorithm/container.h
+64d93e215a141d272b707e7c3e3d686c *src/absl/base/attributes.h
+daad8899b1d374f22c26521512c3a8bb *src/absl/base/call_once.h
+e8dea424b99773eaa10eb115f38a8020 *src/absl/base/casts.h
+ac9b1e3f0c06e773e4ba0f3992e12990 *src/absl/base/config.h
+f787189f34e273f4314344b53f5ccae9 *src/absl/base/const_init.h
+1f5620fada3335961e01206ff444b0ae *src/absl/base/dynamic_annotations.h
+376abfbcc035fb5ddd76fb513589a1e9 *src/absl/base/internal/atomic_hook.h
+5c0507fc9e5c3bc17ce202b48782021c *src/absl/base/internal/cycleclock.cc
+b116912ccd85e3a9430818e4c3036ea3 *src/absl/base/internal/cycleclock.h
+23a9c55200d0af9d9c8cef12c90dd2a6 *src/absl/base/internal/direct_mmap.h
+3c6051b3b1895802b42fd070e0739173 *src/absl/base/internal/dynamic_annotations.h
+7db02f9ac5f988a004333c9f3d87b41d *src/absl/base/internal/endian.h
+1ad6b95fe99ebc367d31ff7a9a8dd1fa *src/absl/base/internal/errno_saver.h
+8ee24334738ffd8e7b3e8fbcc05cf6d2 *src/absl/base/internal/exponential_biased.cc
+99bdbfd7a69988307f49350c499dcd6d *src/absl/base/internal/exponential_biased.h
+05a1a4ed552e4e9950477ddccf4e60f2 *src/absl/base/internal/fast_type_id.h
+bf927fee390f1b62989522868b3104ec *src/absl/base/internal/hide_ptr.h
+83cc5f6d80a853694ccd21d49215b38a *src/absl/base/internal/identity.h
+ca95d2f7ac2c07926c2935004bab2077 *src/absl/base/internal/inline_variable.h
+3d66e2273f9898834248c42c49792f1f *src/absl/base/internal/invoke.h
+f75b6817d994658a3311ae68b3f695f4 *src/absl/base/internal/low_level_alloc.cc
+b193e771e15968a65b708776c1952cd8 *src/absl/base/internal/low_level_alloc.h
+99efd333efc4cc6a44a9abf4de89b2de *src/absl/base/internal/low_level_scheduling.h
+cd26ae8fafb346728a1759160d46495e *src/absl/base/internal/per_thread_tls.h
+da0b534ac124fa816d87a32283635e41 *src/absl/base/internal/periodic_sampler.cc
+fa58280b181168b79b2fa73da55d7210 *src/absl/base/internal/periodic_sampler.h
+cff9e9f5e90b5e4455317dddbda47753 *src/absl/base/internal/pretty_function.h
+127a6bca2c255766410d509ee66a1727 *src/absl/base/internal/raw_logging.cc
+3fd701b86b88ea265e9081cf813dfa63 *src/absl/base/internal/raw_logging.h
+bb74d44f7e47edcd1d865adb924db224 *src/absl/base/internal/scheduling_mode.h
+fb9f075189d06957e1ae00ceefa34ee5 *src/absl/base/internal/scoped_set_env.cc
+80dbd6581eea81b45ba532470673e777 *src/absl/base/internal/scoped_set_env.h
+38f62404cbcc87c6c59dac883fa17efe *src/absl/base/internal/spinlock.cc
+8c633f51e341ada2cfcec5dcb284306e *src/absl/base/internal/spinlock.h
+5e1d7bbdbd633f5f9e26bc6000d7bdc5 *src/absl/base/internal/spinlock_akaros.inc
+19fd194fffce5af31f4b04948bc0bbce *src/absl/base/internal/spinlock_linux.inc
+63f56ff5eab205a2ba5a852dbd6276f2 *src/absl/base/internal/spinlock_posix.inc
+3917a541890f75bcb371b26c11491bec *src/absl/base/internal/spinlock_wait.cc
+fcd0670efcd90e57a5d8636e18c12466 *src/absl/base/internal/spinlock_wait.h
+d3c5fb1ed8db28e9fc573aa2939af254 *src/absl/base/internal/spinlock_win32.inc
+f04df5e54b2977788e030fb2c44735c3 *src/absl/base/internal/strerror.cc
+8c75ee873aa3e514edd1390f3056f89a *src/absl/base/internal/strerror.h
+6cecc85fd4065b9bb247be733215a66e *src/absl/base/internal/sysinfo.cc
+89920866f6792bd96338cb6f9587f3a9 *src/absl/base/internal/sysinfo.h
+af1f8d88b67b54f7302728488ddb98a0 *src/absl/base/internal/thread_annotations.h
+1daa68c6e9939a0c80dfa0be8d0156b7 *src/absl/base/internal/thread_identity.cc
+efc69770bbf3e706d68f5c03291e7fcd *src/absl/base/internal/thread_identity.h
+94e874964762b519d4e59b796466116b *src/absl/base/internal/throw_delegate.cc
+c1f9f8e9ee944f3b8a2640096b37f61f *src/absl/base/internal/throw_delegate.h
+8c803550a22ccece7660ca6ad9a89560 *src/absl/base/internal/tsan_mutex_interface.h
+c2045a4b16b8b7efce39c96a88adc6da *src/absl/base/internal/unaligned_access.h
+523d89add712826c5dcdba48080a18dc *src/absl/base/internal/unscaledcycleclock.cc
+277e4d3d077af7616e5f168c11a06333 *src/absl/base/internal/unscaledcycleclock.h
+fdf34f719b5db2e3779db336a9f4aeb5 *src/absl/base/log_severity.cc
+44df01285eed64cac786953b0bbe0584 *src/absl/base/log_severity.h
+9a7add8647ed73b494f794f18c11270d *src/absl/base/macros.h
+a17b980f549b27ac31509baa0c32a1d9 *src/absl/base/optimization.h
+5366ef14082b53cb6d2ee8cb34df7b9c *src/absl/base/options.h
+30a55e8729c05984884801d5f5fa1422 *src/absl/base/policy_checks.h
+c942a5d8341ce35b666c8a2e3625aed9 *src/absl/base/port.h
+1ae44e59aef073449d4de7f6db67f9ef *src/absl/base/thread_annotations.h
+8be292b5a266737b84d1d06a2dcffd6d *src/absl/container/btree_map.h
+6f70ed3485af0133d0d7f416c47cb791 *src/absl/container/btree_set.h
+4f04d47ba2a8c9d6dbddb09d47bb7715 *src/absl/container/fixed_array.h
+3fee50e5fc0e01a674590d0badfb7c1a *src/absl/container/flat_hash_map.h
+a635f4eb9fb36a55aa12db2a30cb1e78 *src/absl/container/flat_hash_set.h
+e958494ec88a99a23c51ad906c0f0b4f *src/absl/container/inlined_vector.h
+91da9f3b5057f01bd875d0068f18dc51 *src/absl/container/internal/btree.h
+d6fc5b4500396f8ce82c2bc2d3e40503 *src/absl/container/internal/btree_container.h
+7558fa6e6027b296784a64a46bc6d788 *src/absl/container/internal/common.h
+013341274845cbce0b85a94bc2984b38 *src/absl/container/internal/compressed_tuple.h
+b2adaced46957e3053d08bce85129f7a *src/absl/container/internal/container_memory.h
+6e0d77985136113b115286f526da43d9 *src/absl/container/internal/counting_allocator.h
+99dd086eeb57d74fa2e74ea720122b6e *src/absl/container/internal/hash_function_defaults.h
+2091e3185f7126b826ce099f50f5fdc9 *src/absl/container/internal/hash_policy_traits.h
+ed69e77d87d7e4c2b42f5248904cd6d6 *src/absl/container/internal/hashtable_debug.h
+85a576cfb12917cd7126d9e76e13309b *src/absl/container/internal/hashtable_debug_hooks.h
+6e68e5b0ad7c4699102c22804ff1b02a *src/absl/container/internal/hashtablez_sampler.cc
+71181538daeffa65c94b97bf5c93cd3d *src/absl/container/internal/hashtablez_sampler.h
+fcc5f2abdf1fd0edb18d122a846e84f0 *src/absl/container/internal/hashtablez_sampler_force_weak_definition.cc
+67787367372189cf47eecccc554522bd *src/absl/container/internal/have_sse.h
+b4a83c63277eb5904e8d8ef68378d138 *src/absl/container/internal/inlined_vector.h
+dde28d12969cb6df933b96f90b287506 *src/absl/container/internal/layout.h
+08ec3770b73818067921e384d882113b *src/absl/container/internal/node_hash_policy.h
+6bebca16955352c224454bad2947a1af *src/absl/container/internal/raw_hash_map.h
+330143d7b11b49fb5cc4790e16e23b25 *src/absl/container/internal/raw_hash_set.cc
+6cc10694c755f45efb3d940d24e5bf65 *src/absl/container/internal/raw_hash_set.h
+b2c91b1fd5a05ea12fd76abd5e7401bc *src/absl/container/internal/tracked.h
+45e358ab0306337b76b37d58cefff3fc *src/absl/container/node_hash_map.h
+4587399b24c39753dc9c0597dc88c86c *src/absl/container/node_hash_set.h
+fd227e1bc37c98bf705ff468ddccbbc4 *src/absl/debugging/failure_signal_handler.cc
+c527b83e449ee568a4c8f837fb743831 *src/absl/debugging/failure_signal_handler.h
+030a9a4b376aef8d3e17a5b7653e79c1 *src/absl/debugging/internal/address_is_readable.cc
+91ad1bd868606c791022ba6aa6ef4860 *src/absl/debugging/internal/address_is_readable.h
+79749a7ac0197c336804adacba36e3b9 *src/absl/debugging/internal/demangle.cc
+de5e466a575d551be06c658446b26ca9 *src/absl/debugging/internal/demangle.h
+377661945fc750fd86c51d19fd5687e2 *src/absl/debugging/internal/elf_mem_image.cc
+7b5efa6e38540db0e97555ab96be25cd *src/absl/debugging/internal/elf_mem_image.h
+ae3b4548cb22eed77938f806c6a7f595 *src/absl/debugging/internal/examine_stack.cc
+bf6d2ad74f838b382b9b1ac74a3a9859 *src/absl/debugging/internal/examine_stack.h
+4e46a9f2039e409ad9bff7a60cdb2812 *src/absl/debugging/internal/stack_consumption.cc
+612671a5e770431c91f673f764547f9d *src/absl/debugging/internal/stack_consumption.h
+915b1fdf07f8dd394c197b1df232e707 *src/absl/debugging/internal/stacktrace_aarch64-inl.inc
+4f46976f36e6cee9a1891e5e1f3a9194 *src/absl/debugging/internal/stacktrace_arm-inl.inc
+c8798257ab865349a90f7d399601c70f *src/absl/debugging/internal/stacktrace_config.h
+31136485c4ae4719146fe310d09794b3 *src/absl/debugging/internal/stacktrace_generic-inl.inc
+0e9dc2311a8c9adc0566d9e6ea2be586 *src/absl/debugging/internal/stacktrace_powerpc-inl.inc
+e7ced4e67444a66063312dc27d7bb17d *src/absl/debugging/internal/stacktrace_unimplemented-inl.inc
+36cbcb6faf6816b2fd3db94ed61e077d *src/absl/debugging/internal/stacktrace_win32-inl.inc
+1a7b1161b715ea1e760779d3eea3e519 *src/absl/debugging/internal/stacktrace_x86-inl.inc
+a89779a76eed6b7d48929f476c38ee00 *src/absl/debugging/internal/symbolize.h
+1e154851ddc7945372bcc284a8562d63 *src/absl/debugging/internal/vdso_support.cc
+32da4040ebc4e635623be36e861380d4 *src/absl/debugging/internal/vdso_support.h
+65dc6fd0275e5453f5de91e1914adf47 *src/absl/debugging/leak_check.cc
+cb4faa082b9cb79436905b6e28cec041 *src/absl/debugging/leak_check.h
+112d7181da9d011fc1dc76cadf5682af *src/absl/debugging/leak_check_disable.cc
+1183382775768ec8cdc4d12afc5cd5a6 *src/absl/debugging/stacktrace.cc
+54920d74c95e9623f986ca3bf9a49c14 *src/absl/debugging/stacktrace.h
+7618dc5ae1e244e987c2b4cf75699b11 *src/absl/debugging/symbolize.cc
+2a4f1e90fdc9a56d8812afd0f0291876 *src/absl/debugging/symbolize.h
+e1ff8c65c67e769e4d929d70b4c315a4 *src/absl/debugging/symbolize_darwin.inc
+9febce3cf87a802ec2cced1cf1f043bd *src/absl/debugging/symbolize_elf.inc
+37d1355403219402fa4d888e9be56fca *src/absl/debugging/symbolize_unimplemented.inc
+479e5ee9044294e4a9f41d617bea785a *src/absl/debugging/symbolize_win32.inc
+ebe446f8b54b238875a33dbc70ca9f4c *src/absl/functional/bind_front.h
+5d7da8b88dbb9d2f99382941fd131c4c *src/absl/functional/function_ref.h
+ca707a4761ddef188eefa1c47a49305d *src/absl/functional/internal/front_binder.h
+acc1da8f94634fb69d04d64af189f7d9 *src/absl/functional/internal/function_ref.h
+b4ffb4f58d0c4a4f17aa860ee04aad53 *src/absl/memory/memory.h
+7af9293692a48df008af9d0611d9c31c *src/absl/meta/type_traits.h
+858e460c788d7de02ff13b0b233126db *src/absl/numeric/bits.h
+145175b518d1adbb5fb0dce36a5f8899 *src/absl/numeric/int128.cc
+8644673633a9dfc079968b5176ea2f7f *src/absl/numeric/int128.h
+d47ee4c02e33ef2807f31e1d0dd583d8 *src/absl/numeric/int128_have_intrinsic.inc
+73c8313fb617cfb81256ddf3435068e1 *src/absl/numeric/int128_no_intrinsic.inc
+cda33272dc55c7d4e85c050048ac3b68 *src/absl/numeric/internal/bits.h
+b71517976c0230c0f0be9e102124708b *src/absl/numeric/internal/representation.h
+d8fbe682d7f971ad41cf3585695e5b8c *src/absl/strings/ascii.cc
+3df34b80366fc927b32ca23aa02e84a7 *src/absl/strings/ascii.h
+8116da12e911ccc43c42e9625d66649d *src/absl/strings/charconv.cc
+952b5d3677d49520668071e34ce45dec *src/absl/strings/charconv.h
+31bbaeb6b8a559bebb814a464a12636c *src/absl/strings/cord.cc
+398bbd3109f1a19fbba1bf1e6580d451 *src/absl/strings/cord.h
+3d3ee945b740992e7977948f64d37abf *src/absl/strings/escaping.cc
+ca2211cce011d818358126d737a1b960 *src/absl/strings/escaping.h
+9d688a5ba34606869bbb97318c6e3583 *src/absl/strings/internal/char_map.h
+9ba44e5ca0ab3eaf2eea1c1d1135cbd2 *src/absl/strings/internal/charconv_bigint.cc
+effc6ae35cf71076cb6d243984ef02db *src/absl/strings/internal/charconv_bigint.h
+aed0b804c0b6fafc249045d6e813d977 *src/absl/strings/internal/charconv_parse.cc
+bbb89ffd31b13599454ac66c7fca1021 *src/absl/strings/internal/charconv_parse.h
+eba3000b493bf919ab4f1ea0fcc893b3 *src/absl/strings/internal/cord_internal.cc
+3265151e70bb7085b8d90f73d12e7cb7 *src/absl/strings/internal/cord_internal.h
+f86d2d94553fd7178bb408aa16114558 *src/absl/strings/internal/cord_rep_flat.h
+fbef4ad540f3c3695543431c759598f3 *src/absl/strings/internal/cord_rep_ring.cc
+5b638ed5240f87c07804ed0d8bab607e *src/absl/strings/internal/cord_rep_ring.h
+1ffe84c3144080125bbe543e185b47cc *src/absl/strings/internal/cord_rep_ring_reader.h
+dabafab078d1bac10b0098727d403546 *src/absl/strings/internal/escaping.cc
+dd1f4cd55816cd3df569601375e19dd6 *src/absl/strings/internal/escaping.h
+bbcc2e8ef020b2ce6fd2e17e7e019dd7 *src/absl/strings/internal/memutil.cc
+73102cf47e4f94aee5dd43faa699eed5 *src/absl/strings/internal/memutil.h
+3708fdf5b90a9c3172473ce0d9604d17 *src/absl/strings/internal/ostringstream.cc
+f4dd448efcf57c35b09e4ecf12ba595a *src/absl/strings/internal/ostringstream.h
+0f79e5539614bead9e8b2899109414f2 *src/absl/strings/internal/pow10_helper.cc
+a2710593664b501447140371f8f2910b *src/absl/strings/internal/pow10_helper.h
+fc6ff54a84bb558a5a7c777e23e5a920 *src/absl/strings/internal/resize_uninitialized.h
+0b127a362be3ed6ce297a9bd6704b6f5 *src/absl/strings/internal/stl_type_traits.h
+b9c8cf14b3a279effbaa20556c88fb4a *src/absl/strings/internal/str_format/arg.cc
+4da0477be5eb4f92ad99365211d18e3b *src/absl/strings/internal/str_format/arg.h
+56f76b7caadb708b9acc64a806c51a9c *src/absl/strings/internal/str_format/bind.cc
+124a202275e971bc9a66fd7bd2a9b2cd *src/absl/strings/internal/str_format/bind.h
+d840ba11bac79cfb5949e0e2f8e747f8 *src/absl/strings/internal/str_format/checker.h
+82b6f25110cfaf6029f695d476d2df40 *src/absl/strings/internal/str_format/extension.cc
+53cf33dd9171df9b28885c98684f1ac9 *src/absl/strings/internal/str_format/extension.h
+602d5b81943933d209d9347e2138e031 *src/absl/strings/internal/str_format/float_conversion.cc
+1775ec23d1a0b61c9c3cbc2786e20b9d *src/absl/strings/internal/str_format/float_conversion.h
+38f00d24ace7d912f9410c77298f9450 *src/absl/strings/internal/str_format/output.cc
+e11e12d5a8451faafdfa9055ee790517 *src/absl/strings/internal/str_format/output.h
+a230208d6294cd6023b8f3a4a2e29ded *src/absl/strings/internal/str_format/parser.cc
+42cf8fd14b9709ce8bd291d3e85c47cb *src/absl/strings/internal/str_format/parser.h
+0da27066225bcdc3b6f03bc778f189ad *src/absl/strings/internal/str_join_internal.h
+b1a532cd4b0d5ad6de67b268208a44d4 *src/absl/strings/internal/str_split_internal.h
+471b6b7154083c7597fedb2ebcb4f7f9 *src/absl/strings/internal/string_constant.h
+3f62ae65e3b560df6dce5b898e18a77e *src/absl/strings/internal/utf8.cc
+da238e6d26546310d03ce815a181f9c3 *src/absl/strings/internal/utf8.h
+c26d8dc3c6998d1e4adb73b7b3e7307d *src/absl/strings/match.cc
+d78b85f24f13f203df715033ebbedac4 *src/absl/strings/match.h
+be764738922372e43aaab2abb84522e9 *src/absl/strings/numbers.cc
+1e14203552b13db98e369a5f52567d7b *src/absl/strings/numbers.h
+36af19ea6cb1761e464e0539e0a55e96 *src/absl/strings/str_cat.cc
+65cd83cd3f60b592cefb41074e3372a8 *src/absl/strings/str_cat.h
+578172c22291b2e3f8a32d4717e3f362 *src/absl/strings/str_format.h
+1dce8f996516f3a9600a23d7b3c4953d *src/absl/strings/str_join.h
+2b56176c8350695b37d0d810fe705486 *src/absl/strings/str_replace.cc
+4cfe52299b13b659b0b79e926310859c *src/absl/strings/str_replace.h
+0e0684d40f7ebcfa5e3ee516d602bc1b *src/absl/strings/str_split.cc
+adac09a2c5742680794a6b7401ddd125 *src/absl/strings/str_split.h
+c13fbe924649e26b18213d3baff68cf8 *src/absl/strings/string_view.cc
+dcdc37362ca77fda83f4d7ecfcf46021 *src/absl/strings/string_view.h
+7839fb4d9bc896e90a45cd792c871cad *src/absl/strings/strip.h
+9c0638dd36d893e583935a2380cde1be *src/absl/strings/substitute.cc
+7f3fb4b82a9281066f1424b8efc030bb *src/absl/strings/substitute.h
+e8a0e5ed8343c44e8d414a72596dbde9 *src/absl/synchronization/barrier.cc
+104730dc624a422f9e0610e357d1d319 *src/absl/synchronization/barrier.h
+735eaedd4692093fc3174a3103dd1b0e *src/absl/synchronization/blocking_counter.cc
+d1b19aa573dbe35fe8a42f94c7de6026 *src/absl/synchronization/blocking_counter.h
+f3983cd18ac57c01888f64fc5684a526 *src/absl/synchronization/internal/create_thread_identity.cc
+d73963f1c926ad5c88a684bd9dda5908 *src/absl/synchronization/internal/create_thread_identity.h
+edbc4b6b4c303dd6a1c8856356bbdccf *src/absl/synchronization/internal/futex.h
+39446c3969b401efba5b1b875a97ba17 *src/absl/synchronization/internal/graphcycles.cc
+98204bc87786a909620b798d82b44258 *src/absl/synchronization/internal/graphcycles.h
+0c51cca58de692a4dbe0f95750a20512 *src/absl/synchronization/internal/kernel_timeout.h
+40c3dece09e0b615dd79dcd7840f846f *src/absl/synchronization/internal/per_thread_sem.cc
+22f2bf8ff660c4439e8f668dc29537cf *src/absl/synchronization/internal/per_thread_sem.h
+dcd3d301b476895c2de035ae9f4a9c2f *src/absl/synchronization/internal/thread_pool.h
+a216ef1d1164cc1b11d8220f2dc72821 *src/absl/synchronization/internal/waiter.cc
+69e148f20aea7defb0ce5aa05d10afa3 *src/absl/synchronization/internal/waiter.h
+53f2cd2a12bdffe2a12e402926cf98ac *src/absl/synchronization/mutex.cc
+7a9e707ce21026cd9e2ede33571a75c5 *src/absl/synchronization/mutex.h
+18f40d74c189e4cb3bade5bbfac62eac *src/absl/synchronization/notification.cc
+f1503caa5d24b585b51e7e3f43b73bf7 *src/absl/synchronization/notification.h
+4ca503c31ce61fd3d3c0e838cba8618c *src/absl/time/civil_time.cc
+21f77d9a8b12daee08647a79fa2f1c24 *src/absl/time/civil_time.h
+f21e0ee98ace2abfa28852ce87a60fff *src/absl/time/clock.cc
+7669a9d4fb695b4bdf63f2199778b7da *src/absl/time/clock.h
+c80757466714981bbd771a5d1683f939 *src/absl/time/duration.cc
+1029367259d746995cfcc86300cb550e *src/absl/time/format.cc
+153fe848b8d395acdc4d7188b6b1f7bb *src/absl/time/internal/cctz/include/cctz/civil_time.h
+27de12f307456658f389c758397935e7 *src/absl/time/internal/cctz/include/cctz/civil_time_detail.h
+37eda67bdf4f83d1f892815fb45cfb81 *src/absl/time/internal/cctz/include/cctz/time_zone.h
+6f945a703ababb99477bff55062287ec *src/absl/time/internal/cctz/include/cctz/zone_info_source.h
+65ca6d96e925b084e0d56180aa5fe84d *src/absl/time/internal/cctz/src/civil_time_detail.cc
+59c65df1b08bc63ffa7a35c7837a89e2 *src/absl/time/internal/cctz/src/time_zone_fixed.cc
+3afdc610576df58fccc41a7029f1591b *src/absl/time/internal/cctz/src/time_zone_fixed.h
+ea69205e8e9f1e129590f2174e3807d8 *src/absl/time/internal/cctz/src/time_zone_format.cc
+977f9a0fc17a72093bc4c8a87784f632 *src/absl/time/internal/cctz/src/time_zone_if.cc
+8dd51e1e69ed86f3530b53f3eb63045b *src/absl/time/internal/cctz/src/time_zone_if.h
+b9933f8f7ea6ef25b5ca3ff1bf3e0ac9 *src/absl/time/internal/cctz/src/time_zone_impl.cc
+5b006ce94d5395cbd204c8eb42aa673a *src/absl/time/internal/cctz/src/time_zone_impl.h
+9efbeccc7ce7a4bd7edbf051a9bcc66b *src/absl/time/internal/cctz/src/time_zone_info.cc
+39446561973c7f453d351f8dd0bfc947 *src/absl/time/internal/cctz/src/time_zone_info.h
+9be74d3b67a28a954fc5f9cb9721e173 *src/absl/time/internal/cctz/src/time_zone_libc.cc
+6205d25a90cd16fe6fef686eac98a13b *src/absl/time/internal/cctz/src/time_zone_libc.h
+907aa719095f45114e565d7cd766126c *src/absl/time/internal/cctz/src/time_zone_lookup.cc
+e54d65914d1f72e412abe32cb94b12df *src/absl/time/internal/cctz/src/time_zone_posix.cc
+21a06775679a372f33ac8918b0b03dfe *src/absl/time/internal/cctz/src/time_zone_posix.h
+b8aa420258080dab2f2c04570842ba10 *src/absl/time/internal/cctz/src/tzfile.h
+b5acdb5d367ee97af0bea4a6f8f98cd4 *src/absl/time/internal/cctz/src/zone_info_source.cc
+f510c27e928680c4df82fcd584b13620 *src/absl/time/internal/get_current_time_chrono.inc
+921b6cfae31d6e15730d211d301f5bed *src/absl/time/internal/get_current_time_posix.inc
+ea2464a434c72678c0874bb09ed1ac22 *src/absl/time/internal/zoneinfo.inc
+8893c1ef798bfa8c6a3421eafd82d0aa *src/absl/time/time.cc
+f37a53793ed7fb319028b7d326e1056e *src/absl/time/time.h
+a445019a19bf877dc01db45c01557a67 *src/absl/types/any.h
+31416a5f0241128632dde299c016fe61 *src/absl/types/bad_any_cast.cc
+e57304b355027637c47fa5b4138b5ef0 *src/absl/types/bad_any_cast.h
+76faa97137f7f2f4eb70152889e11227 *src/absl/types/bad_optional_access.cc
+21cac14882c183c5c65cad134cd8d21b *src/absl/types/bad_optional_access.h
+339cb16d4f7c125ef6f9975e9c70e2fd *src/absl/types/bad_variant_access.cc
+b95c41fee3ab3f3b45b6b4202327652a *src/absl/types/bad_variant_access.h
+216ae502b816cc541789db0915e4dd76 *src/absl/types/compare.h
+2466c511230ee6497dc26dd3633f7702 *src/absl/types/internal/conformance_aliases.h
+aa319c2077664d2c39a6bd0813c79c18 *src/absl/types/internal/conformance_archetype.h
+e1e8f52038f942c2bad3abc5475cd692 *src/absl/types/internal/conformance_profile.h
+a87cad8cf13eaebb402020f8d7fe4119 *src/absl/types/internal/conformance_testing_helpers.h
+ca3dcfcfd2f2f870064028fe7498b1df *src/absl/types/internal/optional.h
+9d178054161b76df535a760be34d6213 *src/absl/types/internal/parentheses.h
+27f0c5818e53bdc944c73938edf49a15 *src/absl/types/internal/span.h
+599feda2b9b004573e161a9550054e99 *src/absl/types/internal/transform_args.h
+229db9d6e5909ee0117e64404f72f433 *src/absl/types/internal/variant.h
+cc6e8fbfb65176747af2e03bb8538497 *src/absl/types/optional.h
+2848d44a5e03fa22209585de1315c79b *src/absl/types/span.h
+1d24f87c9fb98d810977a981043d8201 *src/absl/types/variant.h
+9b15fdb150cb72ea63d34d08fffd39c2 *src/absl/utility/utility.h
+5f46d29bc94bcdfc28e2a4df442310de *src/cpp-compat.cpp
+afabc65ce7a01abdb14efb1abccd7247 *src/cpp-compat.h
+2d84b8be2c1d5dd660edc6e0e90617df *src/geography-collection.h
+5ee693f87c151f5f94ec383914992136 *src/geography-operator.h
+95002ec40eccb735a1705fec9b04128e *src/geography.h
+0365ec85c22784d83cce5b84d71d794a *src/init.cpp
+d9466b6083ab42ccd4d48fdfb54c3725 *src/point-geography.h
+be0819cf0b1ce418b7fd58f72ca8ef57 *src/polygon-geography.h
+ae93138b66e63d703a72e48d47ca7b18 *src/polyline-geography.h
+429b72a0714edd2015799bcc067ee748 *src/s2-accessors.cpp
+40989d3a6148de2a42117013f098d21c *src/s2-bounds.cpp
+10857401a812bd1e9f7c2bdbd626d3ab *src/s2-c-api.cpp
+fa945115915fc66fa695861fd0475f47 *src/s2-cell.cpp
+f5c6f18bef0fa2647fb6870d5c72177b *src/s2-constructors-formatters.cpp
+148db936b49095d6352bfae506bba472 *src/s2-geography.cpp
+2a18a33f6a16832c371549cee3ef1829 *src/s2-lnglat.cpp
+34c555d3c53b6304835a25d6dc53b452 *src/s2-matrix.cpp
+093210195ecdda6a7435575128bc5e85 *src/s2-options.h
+26da724d2fb9ccb3b7579e9a7f49001e *src/s2-point.cpp
+980e286c3b8ad05def8cb5729e83a98f *src/s2-predicates.cpp
+22dc6e98f2e9d0afc941164bac1ef411 *src/s2-transformers.cpp
+2a3ac9aacf9ff1513a19f70b91902c83 *src/s2-xptr.cpp
+8428235fc1165d0c32375e2e21a686fe *src/s2/_fp_contract_off.h
+28e49579436bf834cd114aa6f01f396e *src/s2/base/casts.h
+4c10c37f35c3ea32da84e18e427e0a8f *src/s2/base/commandlineflags.h
+95d68a4bda8ac1ed1238c06999c7fe8f *src/s2/base/integral_types.h
+188fa699db99f7b32bf12c8f5d49afab *src/s2/base/log_severity.h
+e6796dc6fac7834af2337a6298f6b4f2 *src/s2/base/logging.h
+84003e3ea7ed2316b94891afd7d425f0 *src/s2/base/mutex.h
+bc87e8d47e0131c7f3b2e943823c79f8 *src/s2/base/port.h
+7217ae2988c45fe3c657a6fbb5a01334 *src/s2/base/spinlock.h
+4c6c57a3c08c66211d519f387ea8e972 *src/s2/base/stringprintf.cc
+df6c98233d53cb881136f5f52d2c8012 *src/s2/base/stringprintf.h
+c10c3c7ca58239c0915bacffc70e37e1 *src/s2/base/strtoint.cc
+ac9edc4a5c5139604384d611a9d5686f *src/s2/base/strtoint.h
+8a23b88128feaefecac82381870b7e1b *src/s2/base/timer.h
+a85315a801220cea6aedb7545bed0675 *src/s2/encoded_s2cell_id_vector.cc
+ae93520447e17b7a5ee570e973b14058 *src/s2/encoded_s2cell_id_vector.h
+d7cc642275acd754dd38bc1db012beb8 *src/s2/encoded_s2point_vector.cc
+d7870427a21d7a4288a82ef3d9002404 *src/s2/encoded_s2point_vector.h
+1c9eda503a7610170bb7b20b221a8123 *src/s2/encoded_s2shape_index.cc
+8c71134bbac741ab14ad58645c587efd *src/s2/encoded_s2shape_index.h
+7ded14eeab5eba2a2cca20c71b837d1c *src/s2/encoded_string_vector.cc
+2b5b150cb6a9356b9360ab4bed8fb9e0 *src/s2/encoded_string_vector.h
+9e444256aa6a7b5e5c3eb73ba1708065 *src/s2/encoded_uint_vector.h
+788f48e5bbfca22ed1e396d4bd675ad3 *src/s2/id_set_lexicon.cc
+e7cbe5a6c88b9a286b17adb5e690286f *src/s2/id_set_lexicon.h
+e77194370c1950bc155ee61708af57b0 *src/s2/mutable_s2shape_index.cc
+f2106aebeef507adcbc699ee5bb2ae5b *src/s2/mutable_s2shape_index.h
+a5fd0e84e01c56c79c50f208ae1b08b9 *src/s2/r1interval.h
+e363bde392175774fc26dcde1c3b5076 *src/s2/r2.h
+da84b9bfc2aeabd4f8ae0f84343623e7 *src/s2/r2rect.cc
+4b12844b6a0327fbc6f0488b4fbea0b3 *src/s2/r2rect.h
+e7ca7f23a7e8fe6f707e4169f1aadb77 *src/s2/s1angle.cc
+0e9a83acf9613dc68174c6575afa373d *src/s2/s1angle.h
+d9387a9af7477f6b82ec73d206cfd8d9 *src/s2/s1chord_angle.cc
+7b2a01d9f67a03390a0f34b03a46fef8 *src/s2/s1chord_angle.h
+34874873bee5edbf9af38cd7692ab3ae *src/s2/s1interval.cc
+2a46bfae65f4a24dbbc0c8a7df478c4c *src/s2/s1interval.h
+ad8719b6e9e1c836e9f4c59b216739c9 *src/s2/s2boolean_operation.cc
+99423d6009cb68d7879793f9311e1bb7 *src/s2/s2boolean_operation.h
+aead3947dd83dd0ed2d4becb7d14d426 *src/s2/s2builder.cc
+5cf1544718ecb4046621e2b0b89a0222 *src/s2/s2builder.h
+bbdb9da0943cf55e60e846d2b0e7187b *src/s2/s2builder_graph.cc
+cc61ae8fff8370c728bf6de7513e06d9 *src/s2/s2builder_graph.h
+0558b2bb40025b583974ac1a5d2b5857 *src/s2/s2builder_layer.h
+485fed02d2c102ef03502c959735152c *src/s2/s2builderutil_closed_set_normalizer.cc
+4b17df092dd21d0d5b22499a7a0d8d63 *src/s2/s2builderutil_closed_set_normalizer.h
+128b04413654742d9655bc2b12dfeda7 *src/s2/s2builderutil_find_polygon_degeneracies.cc
+dc965c407adeb3070db3510de3b1f0bd *src/s2/s2builderutil_find_polygon_degeneracies.h
+59390c82ae51ffd8dc8a2154c7f5cc6b *src/s2/s2builderutil_graph_shape.h
+85e926aef77aeccd2d0384001b3e7c09 *src/s2/s2builderutil_lax_polygon_layer.cc
+8d156a2b07ddd94dd53ed45a086ddabd *src/s2/s2builderutil_lax_polygon_layer.h
+6c0c3e9f73a2d693d25392a6f053cca9 *src/s2/s2builderutil_s2point_vector_layer.cc
+5bcdb1842aff634eb86151c41aa92942 *src/s2/s2builderutil_s2point_vector_layer.h
+338a73e56e2a0406bc308dcb7ae2a1db *src/s2/s2builderutil_s2polygon_layer.cc
+d0f7d3975bf12ad12e5a453b1c664879 *src/s2/s2builderutil_s2polygon_layer.h
+bc24648fc1ba139430b08df68cc45004 *src/s2/s2builderutil_s2polyline_layer.cc
+0c78a6937a60f24a9896a4d411b68e90 *src/s2/s2builderutil_s2polyline_layer.h
+9ed299b94f9fd05d3b228cbbb77a29e9 *src/s2/s2builderutil_s2polyline_vector_layer.cc
+8177eb92bdd7082985e5e2cef2cbb57e *src/s2/s2builderutil_s2polyline_vector_layer.h
+41c634fe2532fd5946349947743d9b0b *src/s2/s2builderutil_snap_functions.cc
+14fae38b064b536a50fd99090bf2bb80 *src/s2/s2builderutil_snap_functions.h
+0e7eb31b407e02950751a990c528833d *src/s2/s2builderutil_testing.cc
+e91fca8f2ddf6c1826122f601803cf6f *src/s2/s2builderutil_testing.h
+15661d854ecdbd9b5adb37f4fa38e7fd *src/s2/s2cap.cc
+1aaf20b1794973131d85bbd6d16fc296 *src/s2/s2cap.h
+d89508276ed169153d1e80d85989bfd5 *src/s2/s2cell.cc
+cc050d60fc6b31479ad2cfc444aebc2b *src/s2/s2cell.h
+df582edaa44ad77d7a5d8e9fb7c34262 *src/s2/s2cell_id.cc
+2b7fcd907f3904fa8e8fedf12fd79303 *src/s2/s2cell_id.h
+b77c66885dd9ce9decb058448a53bf2b *src/s2/s2cell_index.cc
+c967db283c31cf3b04720da4aaf951be *src/s2/s2cell_index.h
+2df8fa84fabd7e103ecbcf3dddec4ab7 *src/s2/s2cell_union.cc
+b1877f966f026dafb27bd156d26d8194 *src/s2/s2cell_union.h
+cf1a07e72197832f2b1302f7b3630f98 *src/s2/s2centroids.cc
+b0e46b1f9b0302bf28993c83b1c29952 *src/s2/s2centroids.h
+d23a0e7ec3560f1191df801a3ded25e4 *src/s2/s2closest_cell_query.cc
+1022d523b50d2186b166ca68dc0deb11 *src/s2/s2closest_cell_query.h
+1b857efbfb27e180b3cb9a554e64048d *src/s2/s2closest_cell_query_base.h
+16334d3128469be0f498a5e1a6427659 *src/s2/s2closest_edge_query.cc
+a239c16e1797acb32e845a6da24ca0b0 *src/s2/s2closest_edge_query.h
+a4484a9f30e74392ad90ac037b3404d3 *src/s2/s2closest_edge_query_base.h
+0974a6dabc5a7541eebf0e81656e522c *src/s2/s2closest_edge_query_testing.h
+09e2f693ad6e491a4d50eb8b5d966840 *src/s2/s2closest_point_query.cc
+e982b798e56156c65fb5ddf919a0520c *src/s2/s2closest_point_query.h
+ffdeee92985536a16b5a6212547872ba *src/s2/s2closest_point_query_base.h
+c5ac9b7327a1f2eb8c9b8683973bc48c *src/s2/s2contains_point_query.h
+8cea937d5d1881cdb71d1287f5474cff *src/s2/s2contains_vertex_query.cc
+0a9a1857a2e79884b600de88b69cefbe *src/s2/s2contains_vertex_query.h
+06d65d3cca94ccb99beb7e33f5267e10 *src/s2/s2convex_hull_query.cc
+7c2da76e9c9917194d48939ee919f088 *src/s2/s2convex_hull_query.h
+effdbbf64bb7f235381201657e021ea6 *src/s2/s2coords.cc
+e2a5abdcf611242bdf5cf0edf0eea5ad *src/s2/s2coords.h
+28c4af3631469e232aab685be3e33122 *src/s2/s2coords_internal.h
+48655b45fa96f0da0b234ca68fe4b54d *src/s2/s2crossing_edge_query.cc
+28b59ab0651bf933d5271393e3313deb *src/s2/s2crossing_edge_query.h
+cbeeb65a7261dc8430dcf6edc24deb94 *src/s2/s2debug.cc
+12e9446c9a552088c70b7b3062c1ba5b *src/s2/s2debug.h
+7298228fc7e23751181ad62e211a81b8 *src/s2/s2distance_target.h
+a863fc668a334819762480cc0646c898 *src/s2/s2earth.cc
+b90e02812e7d1afa32d15de3a0245dd8 *src/s2/s2earth.h
+d58b020152efbe99f672b8952460d2ce *src/s2/s2edge_clipping.cc
+cb59ea7179d978f41ecac9ff2ab101c5 *src/s2/s2edge_clipping.h
+c5fd68f5fab9c30285a9d1995be3ddde *src/s2/s2edge_crosser.cc
+91b536b7351c85048ac5f4fc8f9c36f3 *src/s2/s2edge_crosser.h
+69bb6ff8072fe88be08b2e693071ea65 *src/s2/s2edge_crossings.cc
+6de8f9979a94b2001e3134b4b10391a5 *src/s2/s2edge_crossings.h
+482bff39a41ea67b1073b9cfdc11400b *src/s2/s2edge_crossings_internal.h
+2afc2b3b5d5c5eee69d662c490aeac3a *src/s2/s2edge_distances.cc
+525ad6e536828fd0f783a532962bde59 *src/s2/s2edge_distances.h
+75acbcdde0e718a3a990fa63c78c3423 *src/s2/s2edge_tessellator.cc
+0f223cfa5b4b1153617bd64d47f68212 *src/s2/s2edge_tessellator.h
+99195e00ed62fc8127a6de6305730930 *src/s2/s2edge_vector_shape.h
+483c797be9c9eb4b9a9059577e548e7b *src/s2/s2error.cc
+30c2e0bb485124026064b8a6e680c60a *src/s2/s2error.h
+fe0c39101c8c58f45b75fc4c36261a82 *src/s2/s2furthest_edge_query.cc
+9ab743cac7f27a70e2f49f6a8d659c49 *src/s2/s2furthest_edge_query.h
+fe5f7037943d797d93f4d2be3d1119b0 *src/s2/s2latlng.cc
+f86006f14f82fb5fb2dc61b217d79be0 *src/s2/s2latlng.h
+e42ec23a4fdf8b6aea983db2ca3cc4d9 *src/s2/s2latlng_rect.cc
+bd642eda609967162d94ac500632e454 *src/s2/s2latlng_rect.h
+f8689b6a3eef9053601d310ca6146f5c *src/s2/s2latlng_rect_bounder.cc
+486a11f20722a978644e99ec990516ad *src/s2/s2latlng_rect_bounder.h
+6ea59dae602c6e87765068c7c4357baf *src/s2/s2lax_loop_shape.cc
+6aaf1e13f42ac06794d6179a45992a12 *src/s2/s2lax_loop_shape.h
+fc760f9c0ff8545929b4a1e0da1e6ff5 *src/s2/s2lax_polygon_shape.cc
+35b22571a5ddbe1e7b91e6497b39e111 *src/s2/s2lax_polygon_shape.h
+56c7b3c6c942d0cffe353b03ee605a8f *src/s2/s2lax_polyline_shape.cc
+4d4f60c49166c8657258de45884c4087 *src/s2/s2lax_polyline_shape.h
+818253e9f331b59caf71a9e18f7dfd12 *src/s2/s2loop.cc
+da57f0c9e0f4c2cdf2599e0de097dbd9 *src/s2/s2loop.h
+2f78e2f1e0911445a0ffe5e5b0fe014a *src/s2/s2loop_measures.cc
+eef153a4e7bb190f620c250f78ac7c1c *src/s2/s2loop_measures.h
+2e54cb10538dee0beadcfcf774875b64 *src/s2/s2max_distance_targets.cc
+ad2641cab77de9fe057639d5afdf4edd *src/s2/s2max_distance_targets.h
+66d7e4a5a3700d4b5a8c7e013fcfc370 *src/s2/s2measures.cc
+b230afb1b144cfe2dfa5241d0d935cc1 *src/s2/s2measures.h
+b70ef8989674552ca3d0e0c9fcb754a8 *src/s2/s2metrics.cc
+c974a90f9d2ed8199af139ad33147aa4 *src/s2/s2metrics.h
+582857ac635543b496cf93ee1bbe133b *src/s2/s2min_distance_targets.cc
+49d8a47ed9a0f58dd97b2258b1764e77 *src/s2/s2min_distance_targets.h
+94bd23bc709062647f0bdc993dfc7933 *src/s2/s2padded_cell.cc
+b2841070cce458abff94905776f74eae *src/s2/s2padded_cell.h
+af4bfede404056bb6ecc81a6ec4ed141 *src/s2/s2point.h
+caf1d4962bb43ca5e3bfdc9d17640b49 *src/s2/s2point_compression.cc
+0261a1c5b0ed5a8fec6b797ec53b5f30 *src/s2/s2point_compression.h
+127b57a24cfa7ea2c78bc0fb7c9f446b *src/s2/s2point_index.h
+7b88d7113b91cd8d5f0c1ad5bbacc7c4 *src/s2/s2point_region.cc
+1c40d79d4102f56ec2301b62d2767a0e *src/s2/s2point_region.h
+291c8ec7baef072cb29bc341fb3cb5c1 *src/s2/s2point_span.h
+7d75a6945e15b9c78a713a59bd85f199 *src/s2/s2point_vector_shape.h
+0475a05e50a35ca03b06e084178cd31a *src/s2/s2pointutil.cc
+5d2100a54f4302ee75608d48d586fe3c *src/s2/s2pointutil.h
+3272d4e15adf23b8b98b7fe50ca6e43a *src/s2/s2polygon.cc
+dad5e0faba176fe983c613c3d6a60d07 *src/s2/s2polygon.h
+12ef96f03b504ccf5c7523d15448b882 *src/s2/s2polyline.cc
+16ea03d777619f1e59a47cbf83d53071 *src/s2/s2polyline.h
+2914934120ec55346427958e5f73fb5e *src/s2/s2polyline_alignment.cc
+c0f9b77a9439bc0c84d9dfe2dcbcc25b *src/s2/s2polyline_alignment.h
+8a2d7dedff6ee98faf1edcc694a07a19 *src/s2/s2polyline_alignment_internal.h
+c206c2fa52e4a5588b1024f45c63595b *src/s2/s2polyline_measures.cc
+3b78b40b711bc148a7cc8f01f044d9a7 *src/s2/s2polyline_measures.h
+eab00b14b7643e320f8044521eaa16e4 *src/s2/s2polyline_simplifier.cc
+a12b87a494ef6e98dd8b19091ebf8cd8 *src/s2/s2polyline_simplifier.h
+ff7549a0d6195b34b24867fff4cc6d06 *src/s2/s2predicates.cc
+3e580e8e5db3954a6918420df5d50630 *src/s2/s2predicates.h
+7dd5ac042f3403c26f10e8bc6bfcc8ac *src/s2/s2predicates_internal.h
+7478e1714d9dcaf520159458d10e383b *src/s2/s2projections.cc
+fa7c158fb73fced84c86e73bc40a4215 *src/s2/s2projections.h
+8baa87c45aa11148a5207f367237e753 *src/s2/s2r2rect.cc
+eef1eb7446a79b5b6430af8eede7a698 *src/s2/s2r2rect.h
+57778c7c84ae75e67ed68e76f9026ec0 *src/s2/s2region.cc
+2234c6d0d865cc61ca6959c01e0015e4 *src/s2/s2region.h
+e12692516fc6b52c237e16cf16f11e19 *src/s2/s2region_coverer.cc
+fc15e353fdbb3c76de73bf5fa5a713d8 *src/s2/s2region_coverer.h
+f622c31665d97c607e1cb5106c295959 *src/s2/s2region_intersection.cc
+d146a90111cd2d2b33b1526d5d1eab9e *src/s2/s2region_intersection.h
+4bedf29698cbce5a1d755b5d9f0e5312 *src/s2/s2region_term_indexer.cc
+ba4411f3cbd9ffe23482ec22e2045b31 *src/s2/s2region_term_indexer.h
+f8232c70a590ed11666c93181c9d7343 *src/s2/s2region_union.cc
+7acd16e242bad3bf6f8651417f6940c2 *src/s2/s2region_union.h
+9e0666e7c03402dbf71fec6da5aa9244 *src/s2/s2shape.h
+25ac091ec0963d3216b86e86a050eae9 *src/s2/s2shape_index.cc
+1b8ddf576bde4dc6647dcec8341a18a3 *src/s2/s2shape_index.h
+906e1e16bc8aa9f5d4e99651a6cdf0fe *src/s2/s2shape_index_buffered_region.cc
+2f6f557e792611c362fee453ca16eb88 *src/s2/s2shape_index_buffered_region.h
+c0543285953743a9605aa3ef63ad6127 *src/s2/s2shape_index_measures.cc
+1caf918a11c8bafc0835861870fbd0ea *src/s2/s2shape_index_measures.h
+b095a57fa9ad2adfa3cc31f6b8d6fffd *src/s2/s2shape_index_region.h
+23c94c388142e68594cbf29b677d2bbc *src/s2/s2shape_measures.cc
+ce9d81e0539f9c3a136e07d12c46cb05 *src/s2/s2shape_measures.h
+c5794119535ecf13d27f5ae34c58f8b0 *src/s2/s2shapeutil_build_polygon_boundaries.cc
+36f49316d02ac4f5c1124d7a3365419f *src/s2/s2shapeutil_build_polygon_boundaries.h
+2b6d1731185a9ff771d2f150cf6c66f2 *src/s2/s2shapeutil_coding.cc
+3c7dde9ddf64c467729e08fb30741bbe *src/s2/s2shapeutil_coding.h
+afd2720bf07ba0aa5f94dfe9ba0c4d3a *src/s2/s2shapeutil_contains_brute_force.cc
+f6d89268f04abb12ccd63236d4362060 *src/s2/s2shapeutil_contains_brute_force.h
+1344b756712c76ac8c390abdb5a5886e *src/s2/s2shapeutil_count_edges.h
+a699c9e30b9f8eaea6b9308c099c2285 *src/s2/s2shapeutil_edge_iterator.cc
+79c3c7d45f832a4b348116e5b9ec993d *src/s2/s2shapeutil_edge_iterator.h
+ae2b2addb5cb94cd24c57c195e1b0b49 *src/s2/s2shapeutil_get_reference_point.cc
+53160e1333206256c06775aceb56ff6e *src/s2/s2shapeutil_get_reference_point.h
+6d1353bb32206db05048ee50a073c0e7 *src/s2/s2shapeutil_range_iterator.cc
+d12c9628c73beb0f42bb462060facbe7 *src/s2/s2shapeutil_range_iterator.h
+a249fc71604963665d21c311c0e1c391 *src/s2/s2shapeutil_shape_edge.h
+bdf516e73992d5a15fdaa074596f8d6f *src/s2/s2shapeutil_shape_edge_id.h
+007fda069d8144645da7f2c7462a8359 *src/s2/s2shapeutil_testing.h
+2d43581ce7e9638ee9d4390016d422df *src/s2/s2shapeutil_visit_crossing_edge_pairs.cc
+f21bfbc04ce2d1d819512176b45954bb *src/s2/s2shapeutil_visit_crossing_edge_pairs.h
+489cf62e6b1d3e3ff20b67aa19975130 *src/s2/s2testing.cc
+fd1b7e4602b2f79e66496c81232f9cb1 *src/s2/s2testing.h
+b504a72745dbeab05a8f198831eebb7d *src/s2/s2text_format.cc
+294d80e1f4a307f03d84e66ae11767a1 *src/s2/s2text_format.h
+518f25738bd53f6439d3708f56a85435 *src/s2/s2wedge_relations.cc
+3c1f74157144820e8e5008fdc433e018 *src/s2/s2wedge_relations.h
+d3ffa54eb4cab5a70d23bee5cbc17b3e *src/s2/sequence_lexicon.h
+9b6952846f960ce7c8f86d425a6cfc53 *src/s2/strings/ostringstream.cc
+a7553d41936a6491b5e79bad88a676b9 *src/s2/strings/ostringstream.h
+33d32d088678a9117a40a020df05e8fc *src/s2/strings/serialize.cc
+ae996ef21b8b910fc64050493a0595ae *src/s2/strings/serialize.h
+c90e431dac905cc9e596e1b1071b7ea1 *src/s2/util/bits/bit-interleave.cc
+3bfcb45aa9bfa89827d30afba984f79c *src/s2/util/bits/bit-interleave.h
+ce0ab9919f6091c79c677b39c23f8b00 *src/s2/util/bits/bits.cc
+37c9da7e1a7d27c20ca04a3a8ef559ec *src/s2/util/bits/bits.h
+c0d70edbf2ac3f698c17d89959e326f9 *src/s2/util/coding/coder.cc
+92ada6509b11d1a90ec200c2adf9e0dd *src/s2/util/coding/coder.h
+c4fe67fd8a294e03bfc46ce9fb1134d1 *src/s2/util/coding/nth-derivative.h
+2e711fab16d3ec015ecc12d522b8b0ae *src/s2/util/coding/transforms.h
+90d94cda2cd92a02c4851ebb93d7453e *src/s2/util/coding/varint.cc
+9a4e580abf363f1e0bb4bded873514cd *src/s2/util/coding/varint.h
+9e59dc6aad536cbce24eedfb658d8716 *src/s2/util/endian/endian.h
+4525710cda51323baa3327ac57ed3106 *src/s2/util/gtl/btree.h
+118e86e589e0fae520e30c18dc1f3e08 *src/s2/util/gtl/btree_container.h
+52e6fdc3fa81363e043d7e5a35a697ef *src/s2/util/gtl/btree_map.h
+81e2de007193adce24cd9d5f5739bf5e *src/s2/util/gtl/btree_set.h
+d3ee6aee2a2c316240faa7a33434a23e *src/s2/util/gtl/compact_array.h
+09f417c582f54941a864fcbae7d93397 *src/s2/util/gtl/container_logging.h
+6868f5ef7082e686952ee034c62a6cce *src/s2/util/gtl/dense_hash_set.h
+e6d5083ac705a0300e77fe096a7a0589 *src/s2/util/gtl/densehashtable.h
+fa56660fc40be26b3dbfc7115c56674e *src/s2/util/gtl/hashtable_common.h
+8e531532de42f1c1f7cd4adb553fe486 *src/s2/util/gtl/layout.h
+8c80e94bcdfb52740a0b8c0561845642 *src/s2/util/gtl/legacy_random_shuffle.h
+a36fbccb7e3c064e5a16b4ac1e7842f3 *src/s2/util/hash/mix.h
+a3e2ab5873a9c7890d0e6e23fbbc3e72 *src/s2/util/math/exactfloat/exactfloat.cc
+828d0024dcc62675ab2be8b6f3cc3f93 *src/s2/util/math/exactfloat/exactfloat.h
+2037118f434c6f41bc8014de2eb18c92 *src/s2/util/math/mathutil.cc
+0c3be461d027e0cccb9c0facb12cd046 *src/s2/util/math/mathutil.h
+160830f8d1d1983f1b773f953abff72d *src/s2/util/math/matrix3x3.h
+c07f92fe336b33334c46895999a4c62a *src/s2/util/math/vector.h
+5b091051cad1329e1e2b535e40e9c142 *src/s2/util/math/vector3_hash.h
+2aba55dd12417d944cd91a2f02b1d946 *src/s2/util/units/length-units.cc
+1bdf37d9bef7eba2b40d5baad2403f8d *src/s2/util/units/length-units.h
+bdfd79c04de7e7893d9cadb9dd9d2f63 *src/s2/util/units/physical-units.h
+400af05643ac08d897c2100a0a68f1aa *src/s2/value_lexicon.h
+4495750656420f7cd041bf0bf27ec020 *src/tests/soname.h
+4b45b27837b35f28530c827cd798931f *src/wk-c-utils.c
+c4146b7691c20e506a2cd4a013ca6218 *src/wk-geography.h
+3ff04996080488941707e8fd75d50d02 *src/wk-impl.c
+a9ffa55303a6dcba9c5c9c9d322e2009 *tests/area.R
+960ec65d25d1018d2084d81ed3324fdd *tests/area.Rout
+6a0d9b8264490c375aab2554285f41ec *tests/testthat.R
+2852576d235eb67783d7b1118d8d9800 *tests/testthat/test-data.R
+81045befe336a5386a8634dc25bb7230 *tests/testthat/test-s2-accessors.R
+1047ccf796c487587c03286eb8ad3eb2 *tests/testthat/test-s2-bounds.R
+ca886c0f51abb2c6a3783edfef8e9a95 *tests/testthat/test-s2-cell.R
+cfb96b2f1b55571dd58adcbeb254950f *tests/testthat/test-s2-constructors-formatters.R
+75ad7009cf6227ca8239c31198787956 *tests/testthat/test-s2-earth.R
+76193fff2215eaa3c484556c88b490f6 *tests/testthat/test-s2-geography.R
+adfd5e8008ceeea58ba3ee5e71ca040b *tests/testthat/test-s2-lnglat.R
+37c763db9f669b79c2deb559f2e59b76 *tests/testthat/test-s2-matrix.R
+589616aabb1c291a3984f521274815bf *tests/testthat/test-s2-options.R
+9be8d6955daa3c211af562f4f41c639a *tests/testthat/test-s2-point.R
+0688d88be5a5f999507d227ee30c99dc *tests/testthat/test-s2-predicates.R
+b560db419b2b933fa6f9ed51859266c7 *tests/testthat/test-s2-transformers.R
+e0de43269c8f8eb622ef3aa6c6d6f01a *tests/testthat/test-s2-xptr.R
+a7de1183f03382626ca2b46bf1c4e781 *tests/testthat/test-utils.R
+940f3bf944538a6dbfc2d786d12f2d67 *tests/testthat/test-vctrs.R
+2203aa8a7e91a47ba75217c156e3b352 *tests/testthat/test-wk-utils.R
+0ec27c181a66ce5b72bc8c3940e9e00e *tools/version.c
+1f90833745efcd8c2e13769eef3fb57a *tools/winlibs.R
diff --git a/NAMESPACE b/NAMESPACE
new file mode 100644 (file)
index 0000000..87ee9ea
--- /dev/null
+++ b/NAMESPACE
@@ -0,0 +1,178 @@
+# Generated by roxygen2: do not edit by hand
+
+S3method("[",s2_xptr)
+S3method("[<-",s2_cell)
+S3method("[<-",s2_geography)
+S3method("[<-",s2_lnglat)
+S3method("[<-",s2_point)
+S3method("[[",s2_xptr)
+S3method("[[<-",s2_cell)
+S3method("[[<-",s2_geography)
+S3method("[[<-",s2_lnglat)
+S3method("[[<-",s2_point)
+S3method(Math,s2_cell)
+S3method(Ops,s2_cell)
+S3method(Summary,s2_cell)
+S3method(as.character,s2_cell)
+S3method(as.character,s2_geography)
+S3method(as.data.frame,s2_lnglat)
+S3method(as.data.frame,s2_point)
+S3method(as.data.frame,s2_xptr)
+S3method(as.matrix,s2_lnglat)
+S3method(as.matrix,s2_point)
+S3method(as_s2_cell,character)
+S3method(as_s2_cell,s2_cell)
+S3method(as_s2_cell,s2_geography)
+S3method(as_s2_cell,s2_lnglat)
+S3method(as_s2_cell,s2_point)
+S3method(as_s2_geography,WKB)
+S3method(as_s2_geography,blob)
+S3method(as_s2_geography,character)
+S3method(as_s2_geography,logical)
+S3method(as_s2_geography,s2_geography)
+S3method(as_s2_geography,s2_lnglat)
+S3method(as_s2_geography,s2_point)
+S3method(as_s2_geography,wk_wkb)
+S3method(as_s2_geography,wk_wkt)
+S3method(as_s2_lnglat,character)
+S3method(as_s2_lnglat,matrix)
+S3method(as_s2_lnglat,s2_geography)
+S3method(as_s2_lnglat,s2_lnglat)
+S3method(as_s2_lnglat,s2_point)
+S3method(as_s2_lnglat,wk_wkb)
+S3method(as_s2_lnglat,wk_wkt)
+S3method(as_s2_point,matrix)
+S3method(as_s2_point,s2_geography)
+S3method(as_s2_point,s2_lnglat)
+S3method(as_s2_point,s2_point)
+S3method(as_wkb,s2_geography)
+S3method(as_wkb,s2_lnglat)
+S3method(as_wkt,s2_geography)
+S3method(as_wkt,s2_lnglat)
+S3method(c,s2_xptr)
+S3method(format,s2_cell)
+S3method(format,s2_geography)
+S3method(format,s2_lnglat)
+S3method(format,s2_point)
+S3method(is.na,s2_cell)
+S3method(is.numeric,s2_cell)
+S3method(print,s2_xptr)
+S3method(rep,s2_xptr)
+S3method(rep_len,s2_xptr)
+S3method(sort,s2_cell)
+S3method(str,s2_xptr)
+S3method(unique,s2_cell)
+export(as_s2_cell)
+export(as_s2_geography)
+export(as_s2_lnglat)
+export(as_s2_point)
+export(new_s2_cell)
+export(s2_area)
+export(s2_as_binary)
+export(s2_as_text)
+export(s2_boundary)
+export(s2_bounds_cap)
+export(s2_bounds_rect)
+export(s2_buffer_cells)
+export(s2_cell)
+export(s2_cell_area)
+export(s2_cell_area_approx)
+export(s2_cell_boundary)
+export(s2_cell_center)
+export(s2_cell_child)
+export(s2_cell_contains)
+export(s2_cell_debug_string)
+export(s2_cell_distance)
+export(s2_cell_edge_neighbour)
+export(s2_cell_invalid)
+export(s2_cell_is_face)
+export(s2_cell_is_leaf)
+export(s2_cell_is_valid)
+export(s2_cell_level)
+export(s2_cell_max_distance)
+export(s2_cell_may_intersect)
+export(s2_cell_parent)
+export(s2_cell_polygon)
+export(s2_cell_sentinel)
+export(s2_cell_to_lnglat)
+export(s2_cell_vertex)
+export(s2_centroid)
+export(s2_centroid_agg)
+export(s2_closest_edges)
+export(s2_closest_feature)
+export(s2_closest_point)
+export(s2_contains)
+export(s2_contains_matrix)
+export(s2_coverage_union_agg)
+export(s2_covered_by)
+export(s2_covered_by_matrix)
+export(s2_covers)
+export(s2_covers_matrix)
+export(s2_data_cities)
+export(s2_data_countries)
+export(s2_data_timezones)
+export(s2_difference)
+export(s2_dimension)
+export(s2_disjoint)
+export(s2_disjoint_matrix)
+export(s2_distance)
+export(s2_distance_matrix)
+export(s2_dwithin)
+export(s2_dwithin_matrix)
+export(s2_earth_radius_meters)
+export(s2_equals)
+export(s2_equals_matrix)
+export(s2_farthest_feature)
+export(s2_geog_from_text)
+export(s2_geog_from_wkb)
+export(s2_geog_point)
+export(s2_geography)
+export(s2_interpolate)
+export(s2_interpolate_normalized)
+export(s2_intersection)
+export(s2_intersects)
+export(s2_intersects_box)
+export(s2_intersects_matrix)
+export(s2_is_collection)
+export(s2_is_empty)
+export(s2_is_valid)
+export(s2_is_valid_detail)
+export(s2_length)
+export(s2_lnglat)
+export(s2_make_line)
+export(s2_make_polygon)
+export(s2_max_distance)
+export(s2_max_distance_matrix)
+export(s2_may_intersect_matrix)
+export(s2_minimum_clearance_line_between)
+export(s2_num_points)
+export(s2_options)
+export(s2_perimeter)
+export(s2_point)
+export(s2_project)
+export(s2_project_normalized)
+export(s2_projection_filter)
+export(s2_projection_mercator)
+export(s2_projection_plate_carree)
+export(s2_rebuild)
+export(s2_rebuild_agg)
+export(s2_simplify)
+export(s2_snap_distance)
+export(s2_snap_identity)
+export(s2_snap_level)
+export(s2_snap_precision)
+export(s2_snap_to_grid)
+export(s2_sym_difference)
+export(s2_touches)
+export(s2_touches_matrix)
+export(s2_union)
+export(s2_union_agg)
+export(s2_unprojection_filter)
+export(s2_within)
+export(s2_within_matrix)
+export(s2_x)
+export(s2_y)
+importFrom(Rcpp,sourceCpp)
+importFrom(wk,as_wkb)
+importFrom(wk,as_wkt)
+useDynLib(s2, .registration = TRUE)
diff --git a/NEWS.md b/NEWS.md
new file mode 100644 (file)
index 0000000..347e8c0
--- /dev/null
+++ b/NEWS.md
@@ -0,0 +1,80 @@
+# s2 1.0.7
+
+- Update the internal copy of s2geometry to use updated Abseil,
+  fixing a compiler warning on gcc-11 (#79, #134).
+
+# s2 1.0.6
+
+- Added support for `STRICT_R_HEADERS` (@eddelbuettel, #118).
+- Fixed a bug where the result of `s2_centroid_agg()` did not
+  behave like a normal point in distance calculations (#119, #121).
+- Fixed a Windows UCRT check failure and updated openssl linking
+  (@jeroen, #122).
+
+# s2 1.0.5
+
+* Added `s2_projection_filter()` and `s2_unprojection_filter()` to
+  expose the S2 edge tessellator, which can be used to make Cartesian
+  or great circle assumptions of line segments explicit by adding
+  points where necessary (#115).
+* Added an `s2_cell()` vector class to expose a subset of the S2
+  indexing system to R users (#85, #114).
+* Added `s2_closest_edges()` to make k-nearest neighbours calculation
+  possible on the sphere (#111, #112).
+* Added `s2_interpolate()`, `s2_interpolate_normalized()`, 
+  `s2_project()`, and `s2_project_normalized()` to provide linear
+  referencing support on the sphere (#96, #110).
+* Fixed import of empty points from WKB (#109).
+* Added argument `dimensions` to `s2_options()` to constrain the
+  output dimensions of a boolean or rebuild operation (#105, #104, #110).
+* Added `s2_is_valid()` and `s2_is_valid_detail()` to help find invalid
+  spherical geometries when importing data into S2 (#100).
+* Improved error messages when importing and processing data such that
+  errors can be debugged more readily (#100, #98).
+* The unary version of `s2_union()` can now handle MULTIPOLYGON
+  geometries with overlapping rings in addition to other invalid
+  polygons. `s2_union()` can now sanitize
+  almost any input to be valid spherical geometry with
+  minimal modification (#100, #99).
+* Renamed the existing implementation of `s2_union_agg()` to
+  `s2_coverage_union_agg()` to make clear that the function only
+  works when the individual geometries do not have overlapping
+  interiors. `s2_union_agg()` was replaced with a
+  true aggregate union that can handle unions of most geometries
+  (#100, #97).
+* Added `s2_rebuild_agg()` to match `s2_union_agg()`. Like
+  `s2_rebuild()`, `s2_rebuild_agg()` collects the edges in the input
+  and builds them into a feature, optionally snapping or simplifying
+  vertices in the process (#100).
+
+# s2 1.0.4
+
+* Fixed errors that resulted from compilation on clang 12.2 (#88, #89).
+
+# s2 1.0.3
+
+* Fixed CRAN check errors (#80).
+
+# s2 1.0.2
+
+* Fixed CRAN check errors (#71, #75, #72).
+
+# s2 1.0.1
+
+* Added layer creation options to `s2_options()`, which now uses strings
+  rather than numeric codes to specify boolean operation options, geography
+  construction options, and builder options (#70).
+* Added `s2_rebuild()` and `s2_simplify()`, which wrap the S2 C++ `S2Builder`
+  class to provide simplification and fixing of invalid geographies (#70).
+* The s2 package now builds and passes the CMD check on Solaris (#66, #67).
+* Renamed `s2_latlng()` to `s2_lnglat()` to keep axis order consistent
+  throughout the package (#69).
+* Added `s2_bounds_cap()` and `s2_bounds_rect()` to compute bounding areas
+  using geographic coordinates (@edzer, #63).
+* `s2_*_matrix()` predicates now efficiently use indexing to compute the 
+  results of many predicate comparisons (#61).
+
+# s2 1.0.0
+
+This version is a complete rewrite of the former s2 CRAN package, entirely 
+backwards incompatible with previous versions.
diff --git a/R/RcppExports.R b/R/RcppExports.R
new file mode 100644 (file)
index 0000000..22d8884
--- /dev/null
@@ -0,0 +1,423 @@
+# Generated by using Rcpp::compileAttributes() -> do not edit by hand
+# Generator token: 10BE3573-1514-4C36-9D1C-5A225CD40393
+
+cpp_s2_init <- function() {
+    invisible(.Call(`_s2_cpp_s2_init`))
+}
+
+cpp_s2_is_collection <- function(geog) {
+    .Call(`_s2_cpp_s2_is_collection`, geog)
+}
+
+cpp_s2_is_valid <- function(geog) {
+    .Call(`_s2_cpp_s2_is_valid`, geog)
+}
+
+cpp_s2_is_valid_reason <- function(geog) {
+    .Call(`_s2_cpp_s2_is_valid_reason`, geog)
+}
+
+cpp_s2_dimension <- function(geog) {
+    .Call(`_s2_cpp_s2_dimension`, geog)
+}
+
+cpp_s2_num_points <- function(geog) {
+    .Call(`_s2_cpp_s2_num_points`, geog)
+}
+
+cpp_s2_is_empty <- function(geog) {
+    .Call(`_s2_cpp_s2_is_empty`, geog)
+}
+
+cpp_s2_area <- function(geog) {
+    .Call(`_s2_cpp_s2_area`, geog)
+}
+
+cpp_s2_length <- function(geog) {
+    .Call(`_s2_cpp_s2_length`, geog)
+}
+
+cpp_s2_perimeter <- function(geog) {
+    .Call(`_s2_cpp_s2_perimeter`, geog)
+}
+
+cpp_s2_x <- function(geog) {
+    .Call(`_s2_cpp_s2_x`, geog)
+}
+
+cpp_s2_y <- function(geog) {
+    .Call(`_s2_cpp_s2_y`, geog)
+}
+
+cpp_s2_project_normalized <- function(geog1, geog2) {
+    .Call(`_s2_cpp_s2_project_normalized`, geog1, geog2)
+}
+
+cpp_s2_distance <- function(geog1, geog2) {
+    .Call(`_s2_cpp_s2_distance`, geog1, geog2)
+}
+
+cpp_s2_max_distance <- function(geog1, geog2) {
+    .Call(`_s2_cpp_s2_max_distance`, geog1, geog2)
+}
+
+cpp_s2_bounds_cap <- function(geog) {
+    .Call(`_s2_cpp_s2_bounds_cap`, geog)
+}
+
+cpp_s2_bounds_rect <- function(geog) {
+    .Call(`_s2_cpp_s2_bounds_rect`, geog)
+}
+
+cpp_s2_cell_sentinel <- function() {
+    .Call(`_s2_cpp_s2_cell_sentinel`)
+}
+
+cpp_s2_cell_from_string <- function(cellString) {
+    .Call(`_s2_cpp_s2_cell_from_string`, cellString)
+}
+
+cpp_s2_cell_from_lnglat <- function(lnglat) {
+    .Call(`_s2_cpp_s2_cell_from_lnglat`, lnglat)
+}
+
+cpp_s2_cell_to_lnglat <- function(cellId) {
+    .Call(`_s2_cpp_s2_cell_to_lnglat`, cellId)
+}
+
+cpp_s2_cell_is_na <- function(cellIdVector) {
+    .Call(`_s2_cpp_s2_cell_is_na`, cellIdVector)
+}
+
+cpp_s2_cell_sort <- function(cellIdVector, decreasing) {
+    .Call(`_s2_cpp_s2_cell_sort`, cellIdVector, decreasing)
+}
+
+cpp_s2_cell_range <- function(cellIdVector, naRm) {
+    .Call(`_s2_cpp_s2_cell_range`, cellIdVector, naRm)
+}
+
+cpp_s2_cell_unique <- function(cellIdVector) {
+    .Call(`_s2_cpp_s2_cell_unique`, cellIdVector)
+}
+
+cpp_s2_cell_to_string <- function(cellIdVector) {
+    .Call(`_s2_cpp_s2_cell_to_string`, cellIdVector)
+}
+
+cpp_s2_cell_debug_string <- function(cellIdVector) {
+    .Call(`_s2_cpp_s2_cell_debug_string`, cellIdVector)
+}
+
+cpp_s2_cell_is_valid <- function(cellIdVector) {
+    .Call(`_s2_cpp_s2_cell_is_valid`, cellIdVector)
+}
+
+cpp_s2_cell_center <- function(cellIdVector) {
+    .Call(`_s2_cpp_s2_cell_center`, cellIdVector)
+}
+
+cpp_s2_cell_polygon <- function(cellIdVector) {
+    .Call(`_s2_cpp_s2_cell_polygon`, cellIdVector)
+}
+
+cpp_s2_cell_vertex <- function(cellIdVector, k) {
+    .Call(`_s2_cpp_s2_cell_vertex`, cellIdVector, k)
+}
+
+cpp_s2_cell_level <- function(cellIdVector) {
+    .Call(`_s2_cpp_s2_cell_level`, cellIdVector)
+}
+
+cpp_s2_cell_area <- function(cellIdVector) {
+    .Call(`_s2_cpp_s2_cell_area`, cellIdVector)
+}
+
+cpp_s2_cell_area_approx <- function(cellIdVector) {
+    .Call(`_s2_cpp_s2_cell_area_approx`, cellIdVector)
+}
+
+cpp_s2_cell_parent <- function(cellIdVector, level) {
+    .Call(`_s2_cpp_s2_cell_parent`, cellIdVector, level)
+}
+
+cpp_s2_cell_child <- function(cellIdVector, k) {
+    .Call(`_s2_cpp_s2_cell_child`, cellIdVector, k)
+}
+
+cpp_s2_cell_edge_neighbour <- function(cellIdVector, k) {
+    .Call(`_s2_cpp_s2_cell_edge_neighbour`, cellIdVector, k)
+}
+
+cpp_s2_cell_cummax <- function(cellIdVector) {
+    .Call(`_s2_cpp_s2_cell_cummax`, cellIdVector)
+}
+
+cpp_s2_cell_cummin <- function(cellIdVector) {
+    .Call(`_s2_cpp_s2_cell_cummin`, cellIdVector)
+}
+
+cpp_s2_cell_eq <- function(cellIdVector1, cellIdVector2) {
+    .Call(`_s2_cpp_s2_cell_eq`, cellIdVector1, cellIdVector2)
+}
+
+cpp_s2_cell_neq <- function(cellIdVector1, cellIdVector2) {
+    .Call(`_s2_cpp_s2_cell_neq`, cellIdVector1, cellIdVector2)
+}
+
+cpp_s2_cell_lt <- function(cellIdVector1, cellIdVector2) {
+    .Call(`_s2_cpp_s2_cell_lt`, cellIdVector1, cellIdVector2)
+}
+
+cpp_s2_cell_lte <- function(cellIdVector1, cellIdVector2) {
+    .Call(`_s2_cpp_s2_cell_lte`, cellIdVector1, cellIdVector2)
+}
+
+cpp_s2_cell_gte <- function(cellIdVector1, cellIdVector2) {
+    .Call(`_s2_cpp_s2_cell_gte`, cellIdVector1, cellIdVector2)
+}
+
+cpp_s2_cell_gt <- function(cellIdVector1, cellIdVector2) {
+    .Call(`_s2_cpp_s2_cell_gt`, cellIdVector1, cellIdVector2)
+}
+
+cpp_s2_cell_contains <- function(cellIdVector1, cellIdVector2) {
+    .Call(`_s2_cpp_s2_cell_contains`, cellIdVector1, cellIdVector2)
+}
+
+cpp_s2_cell_may_intersect <- function(cellIdVector1, cellIdVector2) {
+    .Call(`_s2_cpp_s2_cell_may_intersect`, cellIdVector1, cellIdVector2)
+}
+
+cpp_s2_cell_distance <- function(cellIdVector1, cellIdVector2) {
+    .Call(`_s2_cpp_s2_cell_distance`, cellIdVector1, cellIdVector2)
+}
+
+cpp_s2_cell_max_distance <- function(cellIdVector1, cellIdVector2) {
+    .Call(`_s2_cpp_s2_cell_max_distance`, cellIdVector1, cellIdVector2)
+}
+
+cpp_s2_geog_point <- function(x, y) {
+    .Call(`_s2_cpp_s2_geog_point`, x, y)
+}
+
+cpp_s2_make_line <- function(x, y, featureId) {
+    .Call(`_s2_cpp_s2_make_line`, x, y, featureId)
+}
+
+cpp_s2_make_polygon <- function(x, y, featureId, ringId, oriented, check) {
+    .Call(`_s2_cpp_s2_make_polygon`, x, y, featureId, ringId, oriented, check)
+}
+
+s2_geography_from_wkb <- function(wkb, oriented, check) {
+    .Call(`_s2_s2_geography_from_wkb`, wkb, oriented, check)
+}
+
+s2_geography_from_wkt <- function(wkt, oriented, check) {
+    .Call(`_s2_s2_geography_from_wkt`, wkt, oriented, check)
+}
+
+s2_geography_full <- function(x) {
+    .Call(`_s2_s2_geography_full`, x)
+}
+
+s2_geography_to_wkt <- function(s2_geography, precision, trim) {
+    .Call(`_s2_s2_geography_to_wkt`, s2_geography, precision, trim)
+}
+
+s2_geography_to_wkb <- function(s2_geography, endian) {
+    .Call(`_s2_s2_geography_to_wkb`, s2_geography, endian)
+}
+
+s2_geography_format <- function(s2_geography, maxCoords, precision, trim) {
+    .Call(`_s2_s2_geography_format`, s2_geography, maxCoords, precision, trim)
+}
+
+s2_lnglat_from_numeric <- function(lng, lat) {
+    .Call(`_s2_s2_lnglat_from_numeric`, lng, lat)
+}
+
+s2_lnglat_from_s2_point <- function(s2_point) {
+    .Call(`_s2_s2_lnglat_from_s2_point`, s2_point)
+}
+
+data_frame_from_s2_lnglat <- function(xptr) {
+    .Call(`_s2_data_frame_from_s2_lnglat`, xptr)
+}
+
+cpp_s2_closest_feature <- function(geog1, geog2) {
+    .Call(`_s2_cpp_s2_closest_feature`, geog1, geog2)
+}
+
+cpp_s2_farthest_feature <- function(geog1, geog2) {
+    .Call(`_s2_cpp_s2_farthest_feature`, geog1, geog2)
+}
+
+cpp_s2_closest_edges <- function(geog1, geog2, n, min_distance) {
+    .Call(`_s2_cpp_s2_closest_edges`, geog1, geog2, n, min_distance)
+}
+
+cpp_s2_may_intersect_matrix <- function(geog1, geog2, maxEdgesPerCell, maxFeatureCells, s2options) {
+    .Call(`_s2_cpp_s2_may_intersect_matrix`, geog1, geog2, maxEdgesPerCell, maxFeatureCells, s2options)
+}
+
+cpp_s2_contains_matrix <- function(geog1, geog2, s2options) {
+    .Call(`_s2_cpp_s2_contains_matrix`, geog1, geog2, s2options)
+}
+
+cpp_s2_within_matrix <- function(geog1, geog2, s2options) {
+    .Call(`_s2_cpp_s2_within_matrix`, geog1, geog2, s2options)
+}
+
+cpp_s2_intersects_matrix <- function(geog1, geog2, s2options) {
+    .Call(`_s2_cpp_s2_intersects_matrix`, geog1, geog2, s2options)
+}
+
+cpp_s2_equals_matrix <- function(geog1, geog2, s2options) {
+    .Call(`_s2_cpp_s2_equals_matrix`, geog1, geog2, s2options)
+}
+
+cpp_s2_touches_matrix <- function(geog1, geog2, s2options) {
+    .Call(`_s2_cpp_s2_touches_matrix`, geog1, geog2, s2options)
+}
+
+cpp_s2_dwithin_matrix <- function(geog1, geog2, distance) {
+    .Call(`_s2_cpp_s2_dwithin_matrix`, geog1, geog2, distance)
+}
+
+cpp_s2_distance_matrix <- function(geog1, geog2) {
+    .Call(`_s2_cpp_s2_distance_matrix`, geog1, geog2)
+}
+
+cpp_s2_max_distance_matrix <- function(geog1, geog2) {
+    .Call(`_s2_cpp_s2_max_distance_matrix`, geog1, geog2)
+}
+
+cpp_s2_contains_matrix_brute_force <- function(geog1, geog2, s2options) {
+    .Call(`_s2_cpp_s2_contains_matrix_brute_force`, geog1, geog2, s2options)
+}
+
+cpp_s2_within_matrix_brute_force <- function(geog1, geog2, s2options) {
+    .Call(`_s2_cpp_s2_within_matrix_brute_force`, geog1, geog2, s2options)
+}
+
+cpp_s2_intersects_matrix_brute_force <- function(geog1, geog2, s2options) {
+    .Call(`_s2_cpp_s2_intersects_matrix_brute_force`, geog1, geog2, s2options)
+}
+
+cpp_s2_disjoint_matrix_brute_force <- function(geog1, geog2, s2options) {
+    .Call(`_s2_cpp_s2_disjoint_matrix_brute_force`, geog1, geog2, s2options)
+}
+
+cpp_s2_equals_matrix_brute_force <- function(geog1, geog2, s2options) {
+    .Call(`_s2_cpp_s2_equals_matrix_brute_force`, geog1, geog2, s2options)
+}
+
+s2_point_from_numeric <- function(x, y, z) {
+    .Call(`_s2_s2_point_from_numeric`, x, y, z)
+}
+
+s2_point_from_s2_lnglat <- function(s2_lnglat) {
+    .Call(`_s2_s2_point_from_s2_lnglat`, s2_lnglat)
+}
+
+data_frame_from_s2_point <- function(s2_point) {
+    .Call(`_s2_data_frame_from_s2_point`, s2_point)
+}
+
+cpp_s2_intersects <- function(geog1, geog2, s2options) {
+    .Call(`_s2_cpp_s2_intersects`, geog1, geog2, s2options)
+}
+
+cpp_s2_equals <- function(geog1, geog2, s2options) {
+    .Call(`_s2_cpp_s2_equals`, geog1, geog2, s2options)
+}
+
+cpp_s2_contains <- function(geog1, geog2, s2options) {
+    .Call(`_s2_cpp_s2_contains`, geog1, geog2, s2options)
+}
+
+cpp_s2_touches <- function(geog1, geog2, s2options) {
+    .Call(`_s2_cpp_s2_touches`, geog1, geog2, s2options)
+}
+
+cpp_s2_dwithin <- function(geog1, geog2, distance) {
+    .Call(`_s2_cpp_s2_dwithin`, geog1, geog2, distance)
+}
+
+cpp_s2_intersects_box <- function(geog, lng1, lat1, lng2, lat2, detail, s2options) {
+    .Call(`_s2_cpp_s2_intersects_box`, geog, lng1, lat1, lng2, lat2, detail, s2options)
+}
+
+cpp_s2_intersection <- function(geog1, geog2, s2options) {
+    .Call(`_s2_cpp_s2_intersection`, geog1, geog2, s2options)
+}
+
+cpp_s2_union <- function(geog1, geog2, s2options) {
+    .Call(`_s2_cpp_s2_union`, geog1, geog2, s2options)
+}
+
+cpp_s2_difference <- function(geog1, geog2, s2options) {
+    .Call(`_s2_cpp_s2_difference`, geog1, geog2, s2options)
+}
+
+cpp_s2_sym_difference <- function(geog1, geog2, s2options) {
+    .Call(`_s2_cpp_s2_sym_difference`, geog1, geog2, s2options)
+}
+
+cpp_s2_coverage_union_agg <- function(geog, s2options, naRm) {
+    .Call(`_s2_cpp_s2_coverage_union_agg`, geog, s2options, naRm)
+}
+
+cpp_s2_union_agg <- function(geog, s2options, naRm) {
+    .Call(`_s2_cpp_s2_union_agg`, geog, s2options, naRm)
+}
+
+cpp_s2_centroid_agg <- function(geog, naRm) {
+    .Call(`_s2_cpp_s2_centroid_agg`, geog, naRm)
+}
+
+cpp_s2_rebuild_agg <- function(geog, s2options, naRm) {
+    .Call(`_s2_cpp_s2_rebuild_agg`, geog, s2options, naRm)
+}
+
+cpp_s2_closest_point <- function(geog1, geog2) {
+    .Call(`_s2_cpp_s2_closest_point`, geog1, geog2)
+}
+
+cpp_s2_minimum_clearance_line_between <- function(geog1, geog2) {
+    .Call(`_s2_cpp_s2_minimum_clearance_line_between`, geog1, geog2)
+}
+
+cpp_s2_centroid <- function(geog) {
+    .Call(`_s2_cpp_s2_centroid`, geog)
+}
+
+cpp_s2_boundary <- function(geog) {
+    .Call(`_s2_cpp_s2_boundary`, geog)
+}
+
+cpp_s2_rebuild <- function(geog, s2options) {
+    .Call(`_s2_cpp_s2_rebuild`, geog, s2options)
+}
+
+cpp_s2_unary_union <- function(geog, s2options) {
+    .Call(`_s2_cpp_s2_unary_union`, geog, s2options)
+}
+
+cpp_s2_interpolate_normalized <- function(geog, distanceNormalized) {
+    .Call(`_s2_cpp_s2_interpolate_normalized`, geog, distanceNormalized)
+}
+
+cpp_s2_buffer_cells <- function(geog, distance, maxCells, minLevel) {
+    .Call(`_s2_cpp_s2_buffer_cells`, geog, distance, maxCells, minLevel)
+}
+
+s2_xptr_test <- function(size) {
+    .Call(`_s2_s2_xptr_test`, size)
+}
+
+s2_xptr_test_op <- function(s2_xptr_test) {
+    invisible(.Call(`_s2_s2_xptr_test_op`, s2_xptr_test))
+}
+
diff --git a/R/data.R b/R/data.R
new file mode 100644 (file)
index 0000000..80afa35
--- /dev/null
+++ b/R/data.R
@@ -0,0 +1,72 @@
+
+#' Low-resolution world boundaries, timezones, and cities
+#'
+#' Well-known binary versions of the [Natural Earth](https://www.naturalearthdata.com/)
+#' low-resolution world boundaries and timezone boundaries.
+#'
+#' @param name The name of a country, continent, city, or `NULL`
+#'   for all features.
+#' @param utc_offset_min,utc_offset_max Minimum and/or maximum timezone
+#'   offsets.
+#'
+#' @format A data.frame with columns `name` (character), and
+#'   `geometry` (wk_wkb)
+#' @source [Natural Earth Data](https://www.naturalearthdata.com/)
+#' @examples
+#' head(s2_data_countries())
+#' s2_data_countries("Germany")
+#' s2_data_countries("Europe")
+#'
+#' head(s2_data_timezones())
+#' s2_data_timezones(-4)
+#'
+#' head(s2_data_cities())
+#' s2_data_cities("Cairo")
+#'
+"s2_data_tbl_countries"
+
+#' @rdname s2_data_tbl_countries
+"s2_data_tbl_timezones"
+
+#' @rdname s2_data_tbl_countries
+"s2_data_tbl_cities"
+
+#' @rdname s2_data_tbl_countries
+#' @export
+s2_data_countries <- function(name = NULL) {
+  df <- s2::s2_data_tbl_countries
+  if (is.null(name)) {
+    wkb <- df$geometry
+  } else {
+    wkb <- structure(df$geometry[(df$name %in% name) | (df$continent %in% name)], class = "wk_wkb")
+  }
+
+  as_s2_geography(wkb)
+}
+
+#' @rdname s2_data_tbl_countries
+#' @export
+s2_data_timezones <- function(utc_offset_min = NULL, utc_offset_max = utc_offset_min) {
+  df <- s2::s2_data_tbl_timezones
+  if (is.null(utc_offset_min)) {
+    wkb <- df$geometry
+  } else {
+    matches <- (df$utc_offset >= utc_offset_min) & (df$utc_offset <= utc_offset_max)
+    wkb <- structure(df$geometry[matches], class = "wk_wkb")
+  }
+
+  as_s2_geography(wkb)
+}
+
+#' @rdname s2_data_tbl_countries
+#' @export
+s2_data_cities <- function(name = NULL) {
+  df <- s2::s2_data_tbl_cities
+  if (is.null(name)) {
+    wkb <- df$geometry
+  } else {
+    wkb <- structure(df$geometry[(df$name %in% name)], class = "wk_wkb")
+  }
+
+  as_s2_geography(wkb)
+}
diff --git a/R/s2-accessors.R b/R/s2-accessors.R
new file mode 100644 (file)
index 0000000..961de37
--- /dev/null
@@ -0,0 +1,169 @@
+
+#' S2 Geography Accessors
+#'
+#' Accessors extract information about [geography vectors][as_s2_geography].
+#'
+#' @param x,y [geography vectors][as_s2_geography]. These inputs
+#'   are passed to [as_s2_geography()], so you can pass other objects
+#'   (e.g., character vectors of well-known text) directly.
+#' @param radius Radius of the earth. Defaults to the average radius of
+#'   the earth in meters as defined by [s2_earth_radius_meters()].
+#'
+#' @export
+#'
+#' @seealso
+#' BigQuery's geography function reference:
+#'
+#' - [ST_ISCOLLECTION](https://cloud.google.com/bigquery/docs/reference/standard-sql/geography_functions#st_iscollection)
+#' - [ST_DIMENSION](https://cloud.google.com/bigquery/docs/reference/standard-sql/geography_functions#st_dimension)
+#' - [ST_NUMPOINTS](https://cloud.google.com/bigquery/docs/reference/standard-sql/geography_functions#st_numpoints)
+#' - [ST_ISEMPTY](https://cloud.google.com/bigquery/docs/reference/standard-sql/geography_functions#st_isempty)
+#' - [ST_AREA](https://cloud.google.com/bigquery/docs/reference/standard-sql/geography_functions#st_area)
+#' - [ST_LENGTH](https://cloud.google.com/bigquery/docs/reference/standard-sql/geography_functions#st_length)
+#' - [ST_PERIMETER](https://cloud.google.com/bigquery/docs/reference/standard-sql/geography_functions#st_perimeter)
+#' - [ST_X](https://cloud.google.com/bigquery/docs/reference/standard-sql/geography_functions#st_x)
+#' - [ST_Y](https://cloud.google.com/bigquery/docs/reference/standard-sql/geography_functions#st_y)
+#' - [ST_DISTANCE](https://cloud.google.com/bigquery/docs/reference/standard-sql/geography_functions#st_distance)
+#' - [ST_MAXDISTANCE](https://cloud.google.com/bigquery/docs/reference/standard-sql/geography_functions#st_maxdistance)
+#'
+#' @examples
+#' # s2_is_collection() tests for multiple geometries in one feature
+#' s2_is_collection(c("POINT (-64 45)", "MULTIPOINT ((-64 45), (8 72))"))
+#'
+#' # s2_dimension() returns 0 for point, 1  for line, 2 for polygon
+#' s2_dimension(
+#'   c(
+#'     "GEOMETRYCOLLECTION EMPTY",
+#'     "POINT (-64 45)",
+#'     "LINESTRING (-64 45, 8 72)",
+#'     "POLYGON ((0 0, 0 10, 10 10, 10 0, 0 0))",
+#'     "GEOMETRYCOLLECTION (POINT (-64 45), LINESTRING (-64 45, 8 72))"
+#'    )
+#' )
+#'
+#' # s2_num_points() counts points
+#' s2_num_points(c("POINT (-64 45)", "LINESTRING (-64 45, 8 72)"))
+#'
+#' # s2_is_empty tests for emptiness
+#' s2_is_empty(c("POINT (-64 45)", "POINT EMPTY"))
+#'
+#' # calculate area, length, and perimeter
+#' s2_area("POLYGON ((0 0, 0 10, 10 10, 10 0, 0 0))")
+#' s2_perimeter("POLYGON ((0 0, 0 10, 10 10, 10 0, 0 0))")
+#' s2_length(s2_boundary("POLYGON ((0 0, 0 10, 10 10, 10 0, 0 0))"))
+#'
+#' # extract x and y coordinates from points
+#' s2_x(c("POINT (-64 45)", "POINT EMPTY"))
+#' s2_y(c("POINT (-64 45)", "POINT EMPTY"))
+#'
+#' # calculate minimum and maximum distance between two geometries
+#' s2_distance(
+#'   "POLYGON ((0 0, 0 10, 10 10, 10 0, 0 0))",
+#'   "POINT (-64 45)"
+#' )
+#' s2_max_distance(
+#'   "POLYGON ((0 0, 0 10, 10 10, 10 0, 0 0))",
+#'   "POINT (-64 45)"
+#' )
+#'
+s2_is_collection <- function(x) {
+  cpp_s2_is_collection(as_s2_geography(x))
+}
+
+#' @rdname s2_is_collection
+#' @export
+s2_is_valid <- function(x) {
+  cpp_s2_is_valid(as_s2_geography(x, check = FALSE))
+}
+
+#' @rdname s2_is_collection
+#' @export
+s2_is_valid_detail <- function(x) {
+  x <- as_s2_geography(x, check = FALSE)
+  data.frame(
+    is_valid = cpp_s2_is_valid(x),
+    reason = cpp_s2_is_valid_reason(x),
+    stringsAsFactors = FALSE
+  )
+}
+
+#' @rdname s2_is_collection
+#' @export
+s2_dimension <- function(x) {
+  cpp_s2_dimension(as_s2_geography(x))
+}
+
+#' @rdname s2_is_collection
+#' @export
+s2_num_points <- function(x) {
+  cpp_s2_num_points(as_s2_geography(x))
+}
+
+#' @rdname s2_is_collection
+#' @export
+s2_is_empty <- function(x) {
+  cpp_s2_is_empty(as_s2_geography(x))
+}
+
+#' @rdname s2_is_collection
+#' @export
+s2_area <- function(x, radius = s2_earth_radius_meters()) {
+  recycled <- recycle_common(as_s2_geography(x), radius)
+  cpp_s2_area(recycled[[1]]) * radius ^ 2
+}
+
+#' @rdname s2_is_collection
+#' @export
+s2_length <- function(x, radius = s2_earth_radius_meters()) {
+  recycled <- recycle_common(as_s2_geography(x), radius)
+  cpp_s2_length(recycled[[1]]) * radius
+}
+
+#' @rdname s2_is_collection
+#' @export
+s2_perimeter <- function(x, radius = s2_earth_radius_meters()) {
+  recycled <- recycle_common(as_s2_geography(x), radius)
+  cpp_s2_perimeter(recycled[[1]]) * radius
+}
+
+#' @rdname s2_is_collection
+#' @export
+s2_x <- function(x) {
+  cpp_s2_x(as_s2_geography(x))
+}
+
+#' @rdname s2_is_collection
+#' @export
+s2_y <- function(x) {
+  cpp_s2_y(as_s2_geography(x))
+}
+
+# document these with the other linear referencers
+#' @rdname s2_interpolate
+#' @export
+s2_project <- function(x, y, radius = s2_earth_radius_meters()) {
+  recycled <- recycle_common(as_s2_geography(x), as_s2_geography(y), radius)
+  length <- cpp_s2_length(recycled[[1]]) * radius
+  cpp_s2_project_normalized(recycled[[1]], recycled[[2]]) * length
+}
+
+#' @rdname s2_interpolate
+#' @export
+s2_project_normalized <- function(x, y) {
+  recycled <- recycle_common(as_s2_geography(x), as_s2_geography(y))
+  cpp_s2_project_normalized(recycled[[1]], recycled[[2]])
+}
+
+#' @rdname s2_is_collection
+#' @export
+s2_distance <- function(x, y, radius = s2_earth_radius_meters()) {
+  recycled <- recycle_common(as_s2_geography(x), as_s2_geography(y), radius)
+  cpp_s2_distance(recycled[[1]], recycled[[2]]) * radius
+}
+
+#' @rdname s2_is_collection
+#' @export
+s2_max_distance <- function(x, y, radius = s2_earth_radius_meters()) {
+  recycled <- recycle_common(as_s2_geography(x), as_s2_geography(y), radius)
+  cpp_s2_max_distance(recycled[[1]], recycled[[2]]) * radius
+}
diff --git a/R/s2-bounds.R b/R/s2-bounds.R
new file mode 100644 (file)
index 0000000..6c4f792
--- /dev/null
@@ -0,0 +1,35 @@
+
+#' Compute feature-wise and aggregate bounds
+#'
+#' [s2_bounds_rect()] returns a bounding latitude-longitude
+#' rectangle that contains the region; [s2_bounds_cap()] returns a bounding circle
+#' represented by a centre point (lat, lng) and an angle. The bound may not be tight
+#' for points, polylines and geometry collections. The rectangle returned may depend on
+#' the order of points or polylines. `lng_lo` values larger than `lng_hi` indicate
+#' regions that span the antimeridian, see the Fiji example.
+#'
+#' @inheritParams s2_is_collection
+#' @export
+#' @return Both functions return a `data.frame`:
+#'
+#' - [s2_bounds_rect()]: Columns `minlng`, `minlat`, `maxlng`, `maxlat` (degrees)
+#' - [s2_bounds_cap()]: Columns `lng`, `lat`, `angle` (degrees)
+#'
+#' @examples
+#' s2_bounds_cap(s2_data_countries("Antarctica"))
+#' s2_bounds_cap(s2_data_countries("Netherlands"))
+#' s2_bounds_cap(s2_data_countries("Fiji"))
+#'
+#' s2_bounds_rect(s2_data_countries("Antarctica"))
+#' s2_bounds_rect(s2_data_countries("Netherlands"))
+#' s2_bounds_rect(s2_data_countries("Fiji"))
+#'
+s2_bounds_cap <- function(x) {
+  cpp_s2_bounds_cap(as_s2_geography(x))
+}
+
+#' @rdname s2_bounds_cap
+#' @export
+s2_bounds_rect <- function(x) {
+  cpp_s2_bounds_rect(as_s2_geography(x))
+}
diff --git a/R/s2-cell.R b/R/s2-cell.R
new file mode 100644 (file)
index 0000000..553f77b
--- /dev/null
@@ -0,0 +1,315 @@
+
+#' Create S2 Cell vectors
+#'
+#' The S2 cell indexing system forms the basis for spatial indexing
+#' in the S2 library. On their own, S2 cells can represent points
+#' or areas. As a union, a vector of S2 cells can approximate a
+#' line or polygon. These functions allow direct access to the
+#' S2 cell indexing system and are designed to have minimal overhead
+#' such that looping and recursion have acceptable performance
+#' when used within R code.
+#'
+#' Under the hood, S2 cell vectors are represented in R as vectors
+#' of type [double()]. This works because S2 cell identifiers are
+#' 64 bits wide, as are `double`s on all systems where R runs (The
+#' same trick is used by the bit64 package to represent signed
+#' 64-bit integers). As a happy accident, `NA_real_` is not a valid
+#' or meaningful cell identifier, so missing value support in the
+#' way R users might expect is preserved. It is worth noting that
+#' the underlying value of `s2_cell_sentinel()` would normally be
+#' considered `NA`; however, as it is meaningful and useful when
+#' programming with S2 cells, custom `is.na()` and comparison methods
+#' are implemented such that `s2_cell_sentinel()` is greater than
+#' all valid S2 cells and not considered missing. Users can and should
+#' implement compiled code that uses the underlying bytes of the
+#' vector, ensuring that the class of any returned object that should
+#' be interpreted in this way is constructed with `new_s2_cell()`.
+#'
+#' @param x The canonical S2 cell identifier as a character vector.
+#' @param ... Passed to methods
+#'
+#' @return An object of class s2_cell
+#' @export
+#'
+#' @examples
+#' s2_cell("4b59a0cd83b5de49")
+#' as_s2_cell(s2_lnglat(-64, 45))
+#' as_s2_cell(s2_data_cities("Ottawa"))
+#'
+s2_cell <- function(x = character()) {
+  new_s2_cell(cpp_s2_cell_from_string(x))
+}
+
+#' @rdname s2_cell
+#' @export
+s2_cell_sentinel <- function() {
+  cpp_s2_cell_sentinel()
+}
+
+#' @rdname s2_cell
+#' @export
+s2_cell_invalid <- function() {
+  new_s2_cell(0)
+}
+
+#' @rdname s2_cell
+#' @export
+s2_cell_sentinel <- function() {
+  cpp_s2_cell_sentinel()
+}
+
+#' @rdname s2_cell
+#' @export
+as_s2_cell <- function(x, ...) {
+  UseMethod("as_s2_cell")
+}
+
+#' @rdname s2_cell
+#' @export
+as_s2_cell.s2_cell <- function(x, ...) {
+  x
+}
+
+#' @rdname s2_cell
+#' @export
+as_s2_cell.character <- function(x, ...) {
+  s2_cell(x)
+}
+
+#' @rdname s2_cell
+#' @export
+as_s2_cell.s2_geography <- function(x, ...) {
+  cpp_s2_cell_from_lnglat(list(s2_x(x), s2_y(x)))
+}
+
+#' @rdname s2_cell
+#' @export
+as_s2_cell.s2_lnglat <- function(x, ...) {
+  cpp_s2_cell_from_lnglat(as.data.frame(x))
+}
+
+#' @rdname s2_cell
+#' @export
+as_s2_cell.s2_point <- function(x, ...) {
+  as_s2_cell(as_s2_lnglat(x))
+}
+
+#' @rdname s2_cell
+#' @export
+new_s2_cell <- function(x) {
+  structure(x, class = c("s2_cell", "wk_vctr"))
+}
+
+#' @export
+as.character.s2_cell <- function(x, ...) {
+  cpp_s2_cell_to_string(x)
+}
+
+#' @export
+format.s2_cell <- function(x, ...) {
+  format(as.character(x), quote = FALSE, ...)
+}
+
+#' @export
+`[<-.s2_cell` <- function(x, i, value) {
+  replacement <- as_s2_cell(value)
+  x <- unclass(x)
+  x[i] <- replacement
+  new_s2_cell(x)
+}
+
+#' @export
+`[[<-.s2_cell` <- function(x, i, value) {
+  x[i] <- value
+  x
+}
+
+#' @export
+unique.s2_cell <- function(x, ...) {
+  cpp_s2_cell_unique(x)
+}
+
+#' @export
+sort.s2_cell <- function(x, decreasing = FALSE, ...) {
+  cpp_s2_cell_sort(x, decreasing)
+}
+
+#' @export
+is.na.s2_cell <- function(x) {
+  cpp_s2_cell_is_na(x)
+}
+
+#' @export
+is.numeric.s2_cell <- function(x, ...) {
+  FALSE
+}
+
+#' @export
+Ops.s2_cell <- function(e1, e2) {
+  switch(
+    .Generic,
+    "==" = cpp_s2_cell_eq(e1, e2),
+    "!=" = cpp_s2_cell_neq(e1, e2),
+    "<" = cpp_s2_cell_lt(e1, e2),
+    "<=" = cpp_s2_cell_lte(e1, e2),
+    ">=" = cpp_s2_cell_gte(e1, e2),
+    ">" = cpp_s2_cell_gt(e1, e2),
+    stop("Arithmetic operations are not meaningful for type 's2_cell'", call. = FALSE)
+  )
+}
+
+#' @export
+Math.s2_cell <- function(x, ...) {
+  switch(
+    .Generic,
+    "cummax" = cpp_s2_cell_cummax(x),
+    "cummin" = cpp_s2_cell_cummin(x),
+    stop("Arithmetic operations are not meaningful for type 's2_cell'", call. = FALSE)
+  )
+}
+
+#' @export
+Summary.s2_cell <- function(x, ..., na.rm = FALSE) {
+  switch(
+    .Generic,
+    "min" = cpp_s2_cell_range(x, na.rm)[1],
+    "max" = cpp_s2_cell_range(x, na.rm)[2],
+    "range" = cpp_s2_cell_range(x, na.rm),
+    stop("Arithmetic operations are not meaningful for type 's2_cell'", call. = FALSE)
+  )
+}
+
+#' S2 cell operators
+#'
+#' @param x,y An [s2_cell()] vector
+#' @param level An integer between 0 and 30, inclusive.
+#' @param k An integer between 1 and 4
+#' @param radius The radius to use (e.g., [s2_earth_radius_meters()])
+#' @export
+#'
+s2_cell_is_valid <- function(x) {
+  cpp_s2_cell_is_valid(x)
+}
+
+# exporters
+
+#' @rdname s2_cell_is_valid
+#' @export
+s2_cell_debug_string <- function(x) {
+  cpp_s2_cell_debug_string(x)
+}
+
+#' @rdname s2_cell_is_valid
+#' @export
+s2_cell_to_lnglat <- function(x) {
+  lnglat <- cpp_s2_cell_to_lnglat(x)
+  s2_lnglat(lnglat[[1]], lnglat[[2]])
+}
+
+#' @rdname s2_cell_is_valid
+#' @export
+s2_cell_center <- function(x) {
+  cpp_s2_cell_center(x)
+}
+
+#' @rdname s2_cell_is_valid
+#' @export
+s2_cell_boundary <- function(x) {
+  s2_boundary(cpp_s2_cell_polygon(x))
+}
+
+#' @rdname s2_cell_is_valid
+#' @export
+s2_cell_polygon <- function(x) {
+  cpp_s2_cell_polygon(x)
+}
+
+#' @rdname s2_cell_is_valid
+#' @export
+s2_cell_vertex <- function(x, k) {
+  recycled <- recycle_common(x, k)
+  cpp_s2_cell_vertex(recycled[[1]], recycled[[2]])
+}
+
+# accessors
+
+#' @rdname s2_cell_is_valid
+#' @export
+s2_cell_level <- function(x) {
+  cpp_s2_cell_level(x)
+}
+
+#' @rdname s2_cell_is_valid
+#' @export
+s2_cell_is_leaf <- function(x) {
+  s2_cell_level(x) == 30L
+}
+
+#' @rdname s2_cell_is_valid
+#' @export
+s2_cell_is_face <- function(x) {
+  s2_cell_level(x) == 0L
+}
+
+#' @rdname s2_cell_is_valid
+#' @export
+s2_cell_area <- function(x, radius = s2_earth_radius_meters()) {
+  cpp_s2_cell_area(x) * radius ^ 2
+}
+
+#' @rdname s2_cell_is_valid
+#' @export
+s2_cell_area_approx <- function(x, radius = s2_earth_radius_meters()) {
+  cpp_s2_cell_area_approx(x) * radius ^ 2
+}
+
+# transversers
+
+#' @rdname s2_cell_is_valid
+#' @export
+s2_cell_parent <- function(x, level = -1L) {
+  recycled <- recycle_common(x, level)
+  cpp_s2_cell_parent(recycled[[1]], recycled[[2]])
+}
+
+#' @rdname s2_cell_is_valid
+#' @export
+s2_cell_child <- function(x, k) {
+  recycled <- recycle_common(x, k)
+  cpp_s2_cell_child(recycled[[1]], recycled[[2]])
+}
+
+#' @rdname s2_cell_is_valid
+#' @export
+s2_cell_edge_neighbour <- function(x, k) {
+  recycled <- recycle_common(x, k)
+  cpp_s2_cell_edge_neighbour(recycled[[1]], recycled[[2]])
+}
+
+# binary operators
+
+#' @rdname s2_cell_is_valid
+#' @export
+s2_cell_contains <- function(x, y) {
+  cpp_s2_cell_contains(x, y)
+}
+
+#' @rdname s2_cell_is_valid
+#' @export
+s2_cell_distance <- function(x, y, radius = s2_earth_radius_meters()) {
+  recycled <- recycle_common(x, y, radius)
+  cpp_s2_cell_distance(recycled[[1]], recycled[[2]]) * radius
+}
+
+#' @rdname s2_cell_is_valid
+#' @export
+s2_cell_max_distance <- function(x, y, radius = s2_earth_radius_meters()) {
+  recycled <- recycle_common(x, y, radius)
+  cpp_s2_cell_max_distance(recycled[[1]], recycled[[2]]) * radius
+}
+
+#' @rdname s2_cell_is_valid
+#' @export
+s2_cell_may_intersect <- function(x, y) {
+  cpp_s2_cell_may_intersect(x, y)
+}
diff --git a/R/s2-constructors-formatters.R b/R/s2-constructors-formatters.R
new file mode 100644 (file)
index 0000000..46c1496
--- /dev/null
@@ -0,0 +1,139 @@
+
+#' Create and Format Geography Vectors
+#'
+#' These functions create and export [geography vectors][as_s2_geography].
+#' Unlike the BigQuery geography constructors, these functions do not sanitize
+#' invalid or redundant input using [s2_union()]. Note that when creating polygons
+#' using [s2_make_polygon()], rings can be open or closed.
+#'
+#' @inheritParams s2_is_collection
+#' @inheritParams as_s2_geography
+#' @param precision The number of significant digits to export when
+#'   writing well-known text. If `trim = FALSE`, the number of
+#'   digits after the decimal place.
+#' @param trim Should trailing zeroes be included after the decimal place?
+#' @param endian The endian-ness of the well-known binary. See [wk::wkb_translate_wkb()].
+#' @param longitude,latitude Vectors of latitude and longitude
+#' @param wkt_string Well-known text
+#' @param wkb_bytes A `list()` of `raw()`
+#' @param feature_id,ring_id Vectors for which a change in
+#'   sequential values indicates a new feature or ring. Use [factor()]
+#'   to convert from a character vector.
+#'
+#' @export
+#'
+#' @seealso
+#' See [as_s2_geography()] for other ways to construct geography vectors.
+#'
+#' BigQuery's geography function reference:
+#'
+#' - [ST_GEOGPOINT](https://cloud.google.com/bigquery/docs/reference/standard-sql/geography_functions#st_geogpoint)
+#' - [ST_MAKELINE](https://cloud.google.com/bigquery/docs/reference/standard-sql/geography_functions#st_makeline)
+#' - [ST_MAKEPOLYGON](https://cloud.google.com/bigquery/docs/reference/standard-sql/geography_functions#st_makepolygon)
+#' - [ST_GEOGFROMTEXT](https://cloud.google.com/bigquery/docs/reference/standard-sql/geography_functions#st_geogfromtext)
+#' - [ST_GEOGFROMWKB](https://cloud.google.com/bigquery/docs/reference/standard-sql/geography_functions#st_geogfromwkb)
+#' - [ST_ASTEXT](https://cloud.google.com/bigquery/docs/reference/standard-sql/geography_functions#st_astext)
+#' - [ST_ASBINARY](https://cloud.google.com/bigquery/docs/reference/standard-sql/geography_functions#st_asbinary)
+#'
+#' @examples
+#' # create point geographies using coordinate values:
+#' s2_geog_point(-64, 45)
+#'
+#' # create line geographies using coordinate values:
+#' s2_make_line(c(-64, 8), c(45, 71))
+#'
+#' # optionally, separate features using feature_id:
+#' s2_make_line(
+#'   c(-64, 8, -27, -27), c(45, 71, 0, 45),
+#'   feature_id = c(1, 1, 2, 2)
+#' )
+#'
+#' # create polygon geographies using coordinate values:
+#' # (rings can be open or closed)
+#' s2_make_polygon(c(-45, 8, 0), c(64, 71, 90))
+#'
+#' # optionally, separate rings and/or features using
+#' # ring_id and/or feature_id
+#' s2_make_polygon(
+#'   c(20, 10, 10, 30, 45, 30, 20, 20, 40, 20, 45),
+#'   c(35, 30, 10, 5, 20, 20, 15, 25, 40, 45, 30),
+#'   feature_id = c(rep(1, 8), rep(2, 3)),
+#'   ring_id = c(1, 1, 1, 1, 1, 2, 2, 2, 1, 1, 1)
+#' )
+#'
+#' # import and export well-known text
+#' (geog <- s2_geog_from_text("POINT (-64 45)"))
+#' s2_as_text(geog)
+#'
+#' # import and export well-known binary
+#' (geog <- s2_geog_from_wkb(wk::as_wkb("POINT (-64 45)")))
+#' s2_as_binary(geog)
+#'
+s2_geog_point <- function(longitude, latitude) {
+  recycled <- recycle_common(longitude, latitude)
+  new_s2_xptr(cpp_s2_geog_point(recycled[[1]], recycled[[2]]), "s2_geography")
+}
+
+#' @rdname s2_geog_point
+#' @export
+s2_make_line <- function(longitude, latitude, feature_id = 1L) {
+  recycled <- recycle_common(longitude, latitude, feature_id)
+  new_s2_xptr(cpp_s2_make_line(recycled[[1]], recycled[[2]], featureId = recycled[[3]]), "s2_geography")
+}
+
+#' @rdname s2_geog_point
+#' @export
+s2_make_polygon <- function(longitude, latitude, feature_id = 1L, ring_id = 1L,
+                            oriented = FALSE, check = TRUE) {
+  recycled <- recycle_common(longitude, latitude, feature_id, ring_id)
+  new_s2_xptr(
+    cpp_s2_make_polygon(
+      recycled[[1]], recycled[[2]],
+      featureId = recycled[[3]],
+      ringId = recycled[[4]],
+      oriented = oriented,
+      check = check
+    ),
+    "s2_geography"
+  )
+}
+
+#' @rdname s2_geog_point
+#' @export
+s2_geog_from_text <- function(wkt_string, oriented = FALSE, check = TRUE) {
+  wk::validate_wk_wkt(wkt_string)
+  new_s2_xptr(
+    s2_geography_from_wkt(
+      wkt_string,
+      oriented = oriented,
+      check = check
+    ),
+    "s2_geography"
+  )
+}
+
+#' @rdname s2_geog_point
+#' @export
+s2_geog_from_wkb <- function(wkb_bytes, oriented = FALSE, check = TRUE) {
+  wk::validate_wk_wkb(wkb_bytes)
+  new_s2_xptr(
+    s2_geography_from_wkb(
+      wkb_bytes,
+      oriented = oriented,
+      check = check
+    ),
+    "s2_geography"
+  )
+}
+
+#' @rdname s2_geog_point
+#' @export
+s2_as_text <- function(x, precision = 16, trim = TRUE) {
+  s2_geography_to_wkt(as_s2_geography(x), precision = precision, trim = trim)
+}
+
+#' @rdname s2_geog_point
+#' @export
+s2_as_binary <- function(x, endian = wk::wk_platform_endian()) {
+  structure(s2_geography_to_wkb(as_s2_geography(x), endian = endian), class = "blob")
+}
diff --git a/R/s2-earth.R b/R/s2-earth.R
new file mode 100644 (file)
index 0000000..4814130
--- /dev/null
@@ -0,0 +1,23 @@
+
+#' Earth Constants
+#'
+#' According to Yoder (1995), the radius of the earth is
+#' 6371.01 km. These functions are used to set the
+#' default radis for functions that return a distance
+#' or accept a distance as input
+#' (e.g., [s2_distance()] and [s2_dwithin()]).
+#'
+#' @export
+#'
+#' @references
+#' Yoder, C.F. 1995. "Astrometric and Geodetic Properties of Earth and the
+#' Solar System" in Global Earth Physics, A Handbook of Physical Constants,
+#' AGU Reference Shelf 1, American Geophysical Union, Table 2.
+#' \doi{10.1029/RF001p0001}
+#'
+#' @examples
+#' s2_earth_radius_meters()
+#'
+s2_earth_radius_meters <- function() {
+  6371.01 * 1000
+}
diff --git a/R/s2-geography.R b/R/s2-geography.R
new file mode 100644 (file)
index 0000000..ac8dfe9
--- /dev/null
@@ -0,0 +1,151 @@
+
+#' Create an S2 Geography Vector
+#'
+#' Geography vectors are arrays of points, lines, polygons, and/or collections
+#' of these. Geography vectors assume coordinates are longitude and latitude
+#' on a perfect sphere.
+#'
+#' The coercion function [as_s2_geography()] is used to wrap the input
+#' of most functions in the s2 package so that you can use other objects with
+#' an unambiguious interpretation as a geography vector. Geography vectors
+#' have a minimal [vctrs][vctrs::vctrs-package] implementation, so you can
+#' use these objects in tibble, dplyr, and other packages that use the vctrs
+#' framework.
+#'
+#' @param x An object that can be converted to an s2_geography vector
+#' @param oriented TRUE if polygon ring directions are known to be correct
+#'   (i.e., exterior rings are defined counter clockwise and interior
+#'   rings are defined clockwise).
+#' @param check Use `check = FALSE` to skip error on invalid geometries
+#' @param ... Unused
+#'
+#' @return An object with class s2_geography
+#' @export
+#'
+#' @seealso
+#' [s2_geog_from_wkb()], [s2_geog_from_text()], [s2_geog_point()],
+#' [s2_make_line()], [s2_make_polygon()] for other ways to
+#' create geography vectors, and [s2_as_binary()] and [s2_as_text()]
+#' for other ways to export them.
+#'
+as_s2_geography <- function(x, ...) {
+  UseMethod("as_s2_geography")
+}
+
+#' @rdname as_s2_geography
+#' @export
+s2_geography <- function() {
+  new_s2_xptr(list(), "s2_geography")
+}
+
+#' @rdname as_s2_geography
+#' @export
+as_s2_geography.s2_geography <- function(x, ...) {
+  x
+}
+
+#' @rdname as_s2_geography
+#' @export
+as_s2_geography.s2_lnglat <- function(x, ...) {
+  df <- data_frame_from_s2_lnglat(x)
+  new_s2_xptr(cpp_s2_geog_point(df[[1]], df[[2]]), "s2_geography")
+}
+
+#' @rdname as_s2_geography
+#' @export
+as_s2_geography.s2_point <- function(x, ...) {
+  as_s2_geography(as_s2_lnglat(x))
+}
+
+#' @rdname as_s2_geography
+#' @export
+as_s2_geography.wk_wkb <- function(x, ..., oriented = FALSE, check = TRUE) {
+  new_s2_xptr(
+    s2_geography_from_wkb(x, oriented = oriented, check = check),
+    "s2_geography"
+  )
+}
+
+#' @rdname as_s2_geography
+#' @export
+as_s2_geography.WKB <- function(x, ..., oriented = FALSE, check = TRUE) {
+  new_s2_xptr(
+    s2_geography_from_wkb(x, oriented = oriented, check = check),
+    "s2_geography"
+  )
+}
+
+#' @rdname as_s2_geography
+#' @export
+as_s2_geography.blob <- function(x, ..., oriented = FALSE, check = TRUE) {
+  new_s2_xptr(
+    s2_geography_from_wkb(x, oriented = oriented, check = check),
+    "s2_geography"
+  )
+}
+
+#' @rdname as_s2_geography
+#' @export
+as_s2_geography.wk_wkt <- function(x, ..., oriented = FALSE, check = TRUE) {
+  new_s2_xptr(
+    s2_geography_from_wkt(x, oriented = oriented, check = check),
+    "s2_geography"
+  )
+}
+
+#' @rdname as_s2_geography
+#' @export
+as_s2_geography.character <- function(x, ..., oriented = FALSE, check = TRUE) {
+  new_s2_xptr(
+    s2_geography_from_wkt(x, oriented = oriented, check = check),
+    "s2_geography"
+  )
+}
+
+#' @rdname as_s2_geography
+#' @export
+as_s2_geography.logical <- function(x, ...) {
+  stopifnot(isTRUE(x))
+  new_s2_xptr(s2_geography_full(TRUE), "s2_geography")
+}
+
+#' @importFrom wk as_wkb
+#' @rdname as_s2_geography
+#' @export
+as_wkb.s2_geography <- function(x, ...) {
+  wk::new_wk_wkb(s2_geography_to_wkb(x, wk::wk_platform_endian()))
+}
+
+#' @importFrom wk as_wkt
+#' @rdname as_s2_geography
+#' @export
+as_wkt.s2_geography <- function(x, ...) {
+  wk::new_wk_wkt(s2_geography_to_wkt(x, precision = 16, trim = TRUE))
+}
+
+
+#' @export
+`[<-.s2_geography` <- function(x, i, value) {
+  x <- unclass(x)
+  x[i] <- as_s2_geography(value)
+  new_s2_xptr(x, "s2_geography")
+}
+
+#' @export
+`[[<-.s2_geography` <- function(x, i, value) {
+  x <- unclass(x)
+  x[i] <- as_s2_geography(value)
+  new_s2_xptr(x, "s2_geography")
+}
+
+#' @export
+format.s2_geography <- function(x, ..., max_coords = 5, precision = 9, trim = TRUE) {
+  paste0("<", s2_geography_format(x, max_coords, precision, trim), ">")
+}
+
+# this is what gets called by the RStudio viewer, for which
+# format() is best suited (s2_as_text() is more explicit for WKT output)
+#' @export
+as.character.s2_geography <- function(x, ..., max_coords = 5, precision = 9, trim = TRUE) {
+  format(x, ..., max_coords = max_coords, precision = precision, trim = trim)
+}
diff --git a/R/s2-lnglat.R b/R/s2-lnglat.R
new file mode 100644 (file)
index 0000000..59ceaad
--- /dev/null
@@ -0,0 +1,113 @@
+
+#' Create an S2 LngLat Vector
+#'
+#' This class represents a latitude and longitude on the Earth's surface.
+#' Most calculations in S2 convert this to a [as_s2_point()], which is a
+#' unit vector representation of this value.
+#'
+#' @param lat,lng Vectors of latitude and longitude values in degrees.
+#' @param x A [s2_lnglat()] vector or an object that can be coerced to one.
+#' @param ... Unused
+#'
+#' @return An object with class s2_lnglat
+#' @export
+#'
+#' @examples
+#' s2_lnglat(45, -64) # Halifax, Nova Scotia!
+#' as.data.frame(s2_lnglat(45, -64))
+#'
+s2_lnglat <- function(lng, lat) {
+  recycled <- recycle_common(as.double(lng), as.double(lat))
+  new_s2_xptr(s2_lnglat_from_numeric(recycled[[1]], recycled[[2]]), "s2_lnglat")
+}
+
+#' @rdname s2_lnglat
+#' @export
+as_s2_lnglat <- function(x, ...) {
+  UseMethod("as_s2_lnglat")
+}
+
+#' @rdname s2_lnglat
+#' @export
+as_s2_lnglat.s2_lnglat <- function(x, ...) {
+  x
+}
+
+#' @rdname s2_lnglat
+#' @export
+as_s2_lnglat.s2_point <- function(x, ...) {
+  new_s2_xptr(s2_lnglat_from_s2_point(x), "s2_lnglat")
+}
+
+#' @rdname s2_lnglat
+#' @export
+as_s2_lnglat.s2_geography <- function(x, ...) {
+  new_s2_xptr(s2_lnglat_from_numeric(cpp_s2_x(x), cpp_s2_y(x)), "s2_lnglat")
+}
+
+#' @rdname s2_lnglat
+#' @export
+as_s2_lnglat.matrix <- function(x, ...) {
+  s2_lnglat(x[, 1, drop = TRUE], x[, 2, drop = TRUE])
+}
+
+#' @export
+as_s2_lnglat.character <- function(x, ...) {
+  as_s2_lnglat.wk_wkt(x)
+}
+
+#' @export
+as_s2_lnglat.wk_wkt <- function(x, ...) {
+  as_s2_lnglat(as_s2_geography(x), ...)
+}
+
+#' @export
+as_s2_lnglat.wk_wkb <- function(x, ...) {
+  as_s2_lnglat(as_s2_geography(x), ...)
+}
+
+#' @rdname s2_lnglat
+#' @export
+as.data.frame.s2_lnglat <- function(x, ...) {
+  as.data.frame(data_frame_from_s2_lnglat(x))
+}
+
+#' @rdname s2_lnglat
+#' @export
+as.matrix.s2_lnglat <- function(x, ...) {
+  as.matrix(as.data.frame(data_frame_from_s2_lnglat(x)))
+}
+
+#' @rdname s2_lnglat
+#' @importFrom wk as_wkb
+#' @export
+as_wkb.s2_lnglat <- function(x, ...) {
+  as_wkb(as_s2_geography(x), ...)
+}
+
+#' @rdname s2_lnglat
+#' @importFrom wk as_wkt
+#' @export
+as_wkt.s2_lnglat <- function(x, ...) {
+  as_wkt(as_s2_geography(x), ...)
+}
+
+#' @export
+`[<-.s2_lnglat` <- function(x, i, value) {
+  x <- unclass(x)
+  x[i] <- as_s2_lnglat(value)
+  new_s2_xptr(x, "s2_lnglat")
+}
+
+#' @export
+`[[<-.s2_lnglat` <- function(x, i, value) {
+  x <- unclass(x)
+  x[i] <- as_s2_lnglat(value)
+  new_s2_xptr(x, "s2_lnglat")
+}
+
+#' @export
+format.s2_lnglat <- function(x, ...) {
+  df <- as.data.frame(x)
+  sprintf("(%s, %s)", format(df$lng, trim = TRUE), format(df$lat, trim = TRUE))
+}
diff --git a/R/s2-matrix.R b/R/s2-matrix.R
new file mode 100644 (file)
index 0000000..efa7a6a
--- /dev/null
@@ -0,0 +1,187 @@
+
+#' Matrix Functions
+#'
+#' These functions are similar to accessors and predicates, but instead of
+#' recycling `x` and `y` to a common length and returning a vector of that
+#' length, these functions return a vector of length `x` with each element
+#' `i` containing information about how the entire vector `y` relates to
+#' the feature at `x[i]`.
+#'
+#' @inheritParams s2_is_collection
+#' @inheritParams s2_contains
+#' @param x,y Geography vectors, coerced using [as_s2_geography()].
+#'   `x` is considered the source, where as `y` is considered the target.
+#' @param k The number of closest edges to consider when searching. Note
+#'   that in S2 a point is also considered an edge.
+#' @param min_distance The minimum distance to consider when searching for
+#'   edges. This filter is applied after the search is complete (i.e.,
+#'   may cause fewer than `k` values to be returned).
+#' @param max_edges_per_cell For [s2_may_intersect_matrix()],
+#'   this values controls the nature of the index on `y`, with higher values
+#'   leading to coarser index. Values should be between 10 and 50; the default
+#'   of 50 is adequate for most use cases, but for specialized operations users
+#'   may wish to use a lower value to increase performance.
+#' @param max_feature_cells For [s2_may_intersect_matrix()], this value
+#'   controls the approximation of `x` used to identify potential intersections
+#'   on `y`. The default value of 4 gives the best performance for most operations,
+#'   but for specialized operations users may wish to use a higher value to increase
+#'   performance.
+#'
+#' @return A vector of length `x`.
+#' @export
+#'
+#' @seealso
+#' See pairwise predicate functions (e.g., [s2_intersects()]).
+#'
+#' @examples
+#' city_names <- c("Vatican City", "San Marino", "Luxembourg")
+#' cities <- s2_data_cities(city_names)
+#' country_names <- s2_data_tbl_countries$name
+#' countries <- s2_data_countries()
+#'
+#' # closest feature returns y indices of the closest feature
+#' # for each feature in x
+#' country_names[s2_closest_feature(cities, countries)]
+#'
+#' # farthest feature returns y indices of the farthest feature
+#' # for each feature in x
+#' country_names[s2_farthest_feature(cities, countries)]
+#'
+#' # use s2_closest_edges() to find the k-nearest neighbours
+#' nearest <- s2_closest_edges(cities, cities, k = 2, min_distance = 0)
+#' city_names
+#' city_names[unlist(nearest)]
+#'
+#' # predicate matrices
+#' country_names[s2_intersects_matrix(cities, countries)[[1]]]
+#'
+#' # distance matrices
+#' s2_distance_matrix(cities, cities)
+#' s2_max_distance_matrix(cities, countries[1:4])
+#'
+s2_closest_feature <- function(x, y) {
+  cpp_s2_closest_feature(as_s2_geography(x), as_s2_geography(y))
+}
+
+#' @rdname s2_closest_feature
+#' @export
+s2_closest_edges <- function(x, y, k, min_distance = -1, radius = s2_earth_radius_meters()) {
+  stopifnot(k >= 1)
+  cpp_s2_closest_edges(as_s2_geography(x), as_s2_geography(y), k, min_distance / radius)
+}
+
+#' @rdname s2_closest_feature
+#' @export
+s2_farthest_feature <- function(x, y) {
+  cpp_s2_farthest_feature(as_s2_geography(x), as_s2_geography(y))
+}
+
+#' @rdname s2_closest_feature
+#' @export
+s2_distance_matrix <- function(x, y, radius = s2_earth_radius_meters()) {
+  cpp_s2_distance_matrix(as_s2_geography(x), as_s2_geography(y)) * radius
+}
+
+#' @rdname s2_closest_feature
+#' @export
+s2_max_distance_matrix <- function(x, y, radius = s2_earth_radius_meters()) {
+  cpp_s2_max_distance_matrix(as_s2_geography(x), as_s2_geography(y)) * radius
+}
+
+#' @rdname s2_closest_feature
+#' @export
+s2_contains_matrix <- function(x, y, options = s2_options(model = "open")) {
+  cpp_s2_contains_matrix(as_s2_geography(x), as_s2_geography(y), options)
+}
+
+#' @rdname s2_closest_feature
+#' @export
+s2_within_matrix <- function(x, y, options = s2_options(model = "open")) {
+  cpp_s2_within_matrix(as_s2_geography(x), as_s2_geography(y), options)
+}
+
+#' @rdname s2_closest_feature
+#' @export
+s2_covers_matrix <- function(x, y, options = s2_options(model = "closed")) {
+  cpp_s2_contains_matrix(as_s2_geography(x), as_s2_geography(y), options)
+}
+
+#' @rdname s2_closest_feature
+#' @export
+s2_covered_by_matrix <- function(x, y, options = s2_options(model = "closed")) {
+  cpp_s2_within_matrix(as_s2_geography(x), as_s2_geography(y), options)
+}
+
+#' @rdname s2_closest_feature
+#' @export
+s2_intersects_matrix <- function(x, y, options = s2_options()) {
+  cpp_s2_intersects_matrix(as_s2_geography(x), as_s2_geography(y), options)
+}
+
+#' @rdname s2_closest_feature
+#' @export
+s2_disjoint_matrix <- function(x, y, options = s2_options()) {
+  # disjoint is the odd one out, in that it requires a negation of intersects
+  # this is inconvenient to do on the C++ level, and is easier to maintain
+  # with setdiff() here (unless somebody complains that this is slow)
+  intersection <- cpp_s2_intersects_matrix(as_s2_geography(x), as_s2_geography(y), options)
+  Map(setdiff, list(seq_along(y)), intersection)
+}
+
+#' @rdname s2_closest_feature
+#' @export
+s2_equals_matrix <- function(x, y, options = s2_options()) {
+  cpp_s2_equals_matrix(as_s2_geography(x), as_s2_geography(y), options)
+}
+
+#' @rdname s2_closest_feature
+#' @export
+s2_touches_matrix <- function(x, y, options = s2_options()) {
+  cpp_s2_touches_matrix(as_s2_geography(x), as_s2_geography(y), options)
+}
+
+#' @rdname s2_closest_feature
+#' @export
+s2_dwithin_matrix <- function(x, y, distance, radius = s2_earth_radius_meters()) {
+  cpp_s2_dwithin_matrix(as_s2_geography(x), as_s2_geography(y), distance / radius)
+}
+
+#' @rdname s2_closest_feature
+#' @export
+s2_may_intersect_matrix <- function(x, y, max_edges_per_cell = 50, max_feature_cells = 4) {
+  cpp_s2_may_intersect_matrix(
+    as_s2_geography(x), as_s2_geography(y),
+    max_edges_per_cell, max_feature_cells,
+    s2_options()
+  )
+}
+
+# ------- for testing, non-indexed versions of matrix operators -------
+
+s2_contains_matrix_brute_force <- function(x, y, options = s2_options()) {
+  cpp_s2_contains_matrix_brute_force(as_s2_geography(x), as_s2_geography(y), options)
+}
+
+s2_within_matrix_brute_force <- function(x, y, options = s2_options()) {
+  cpp_s2_within_matrix_brute_force(as_s2_geography(x), as_s2_geography(y), options)
+}
+
+s2_covers_matrix_brute_force <- function(x, y, options = s2_options(model = "closed")) {
+  cpp_s2_contains_matrix_brute_force(as_s2_geography(x), as_s2_geography(y), options)
+}
+
+s2_covered_by_matrix_brute_force <- function(x, y, options = s2_options(model = "closed")) {
+  cpp_s2_within_matrix_brute_force(as_s2_geography(x), as_s2_geography(y), options)
+}
+
+s2_intersects_matrix_brute_force <- function(x, y, options = s2_options()) {
+  cpp_s2_intersects_matrix_brute_force(as_s2_geography(x), as_s2_geography(y), options)
+}
+
+s2_disjoint_matrix_brute_force <- function(x, y, options = s2_options()) {
+  cpp_s2_disjoint_matrix_brute_force(as_s2_geography(x), as_s2_geography(y), options)
+}
+
+s2_equals_matrix_brute_force <- function(x, y, options = s2_options()) {
+  cpp_s2_equals_matrix_brute_force(as_s2_geography(x), as_s2_geography(y), options)
+}
diff --git a/R/s2-options.R b/R/s2-options.R
new file mode 100644 (file)
index 0000000..f8b3672
--- /dev/null
@@ -0,0 +1,147 @@
+
+#' Geography Operation Options
+#'
+#' These functions specify defaults for options used to perform operations
+#' and construct geometries. These are used in predicates (e.g., [s2_intersects()]),
+#' and boolean operations (e.g., [s2_intersection()]) to specify the model for
+#' containment and how new geometries should be constructed.
+#'
+#' @param model One of 'open', 'semi-open' (default for polygons),
+#'   or 'closed' (default for polylines). See section 'Model'
+#' @param snap Use `s2_snap_identity()`, `s2_snap_distance()`, `s2_snap_level()`,
+#'   or `s2_snap_precision()` to specify how or if coordinate rounding should
+#'   occur.
+#' @param snap_radius As opposed to the snap function, which specifies
+#'   the maximum distance a vertex should move, the snap radius (in radians) sets
+#'   the minimum distance between vertices of the output that don't cause vertices
+#'   to move more than the distance specified by the snap function. This can be used
+#'   to simplify the result of a boolean operation. Use -1 to specify that any
+#'   minimum distance is acceptable.
+#' @param duplicate_edges Use `TRUE` to keep duplicate edges (e.g., duplicate
+#'   points).
+#' @param edge_type One of 'directed' (default) or 'undirected'.
+#' @param polyline_type One of 'path' (default) or 'walk'. If 'walk',
+#'   polylines that backtrack are preserved.
+#' @param polyline_sibling_pairs One of 'discard' (default) or 'keep'.
+#' @param simplify_edge_chains Use `TRUE` to remove vertices that are within
+#'   `snap_radius` of the original vertex.
+#' @param split_crossing_edges Use `TRUE` to split crossing polyline edges
+#'   when creating geometries.
+#' @param idempotent Use `FALSE` to apply snap even if snapping is not necessary
+#'   to satisfy vertex constraints.
+#' @param validate Use `TRUE` to validate the result from the builder.
+#' @param level A value from 0 to 30 corresponding to the cell level
+#'   at which snapping should occur.
+#' @param distance A distance (in radians) denoting the maximum
+#'   distance a vertex should move in the snapping process.
+#' @param precision A number by which coordinates should be multiplied
+#'   before being rounded. Rounded to the nearest exponent of 10.
+#' @param dimensions A combination of 'point', 'polyline', and/or 'polygon'
+#'   that can used to constrain the output of [s2_rebuild()] or a
+#'   boolean operation.
+#'
+#' @section Model:
+#' The geometry model indicates whether or not a geometry includes its boundaries.
+#' Boundaries of line geometries are its end points.
+#' OPEN geometries do not contain their boundary (`model = "open"`); CLOSED
+#' geometries (`model = "closed"`) contain their boundary; SEMI-OPEN geometries
+#' (`model = "semi-open"`) contain half of their boundaries, such that when two polygons
+#' do not overlap or two lines do not cross, no point exist that belong to
+#' more than one of the geometries. (This latter form, half-closed, is
+#' not present in the OpenGIS "simple feature access" (SFA) standard nor DE9-IM on
+#' which that is based). The default values for [s2_contains()] (open)
+#' and covers/covered_by (closed) correspond to the SFA standard specification
+#' of these operators.
+#'
+#' @export
+#'
+#' @examples
+#' # use s2_options() to specify containment models, snap level
+#' # layer creation options, and builder options
+#' s2_options(model = "closed", snap = s2_snap_level(30))
+#'
+s2_options <- function(model = NULL,
+                       snap = s2_snap_identity(),
+                       snap_radius = -1,
+                       duplicate_edges = FALSE,
+                       edge_type = "directed",
+                       validate = FALSE,
+                       polyline_type = "path",
+                       polyline_sibling_pairs = "keep",
+                       simplify_edge_chains = FALSE,
+                       split_crossing_edges = FALSE,
+                       idempotent = FALSE,
+                       dimensions = c("point", "polyline", "polygon")) {
+  # check snap radius (passing in a huge snap radius can cause problems)
+  if (snap_radius > 3) {
+    stop(
+      "Snap radius is too large. Did you pass in a snap radius in meters instead of radians?",
+      call. = FALSE
+    )
+  }
+
+  structure(
+    list(
+      # model needs to be "unset" by default because there are differences in polygon
+      # and polyline handling by default that are good defaults to preserve
+      model = if (is.null(model)) -1 else match_option(model[1], c("open", "semi-open", "closed"), "model"),
+      snap = snap,
+      snap_radius = snap_radius,
+      duplicate_edges = duplicate_edges,
+      edge_type = match_option(edge_type[1], c("directed", "undirected"), "edge_type"),
+      validate = validate,
+      polyline_type = match_option(polyline_type[1], c("path", "walk"), "polyline_type"),
+      polyline_sibling_pairs = match_option(
+        polyline_sibling_pairs,
+        c("discard", "keep"),
+        "polyline_sibling_pairs"
+      ),
+      simplify_edge_chains = simplify_edge_chains,
+      split_crossing_edges = split_crossing_edges,
+      idempotent = idempotent,
+      dimensions = match_option(dimensions, c("point", "polyline", "polygon"), "dimensions")
+    ),
+    class = "s2_options"
+  )
+}
+
+#' @rdname s2_options
+#' @export
+s2_snap_identity <- function() {
+  structure(list(), class = "snap_identity")
+}
+
+#' @rdname s2_options
+#' @export
+s2_snap_level <- function(level) {
+  if (level > 30) {
+    stop("`level` must be an intger between 1 and 30", call. = FALSE)
+  }
+
+  structure(list(level = level), class = "snap_level")
+}
+
+#' @rdname s2_options
+#' @export
+s2_snap_precision <- function(precision)  {
+  structure(list(exponent = round(log10(precision))), class = "snap_precision")
+}
+
+#' @rdname s2_options
+#' @export
+s2_snap_distance <- function(distance)  {
+  structure(list(distance = distance), class = "snap_distance")
+}
+
+
+match_option <- function(x, options, arg) {
+  result <- match(x, options)
+  if (any(is.na(result))) {
+    stop(
+      sprintf("`%s` must be one of %s", arg, paste0('"', options, '"', collapse = ", ")),
+      call. = FALSE
+    )
+  }
+
+  result
+}
diff --git a/R/s2-package.R b/R/s2-package.R
new file mode 100644 (file)
index 0000000..6c757a5
--- /dev/null
@@ -0,0 +1,10 @@
+#' @keywords internal
+"_PACKAGE"
+
+# The following block is used by usethis to automatically manage
+# roxygen namespace tags. Modify with care!
+## usethis namespace: start
+#' @useDynLib s2, .registration = TRUE
+#' @importFrom Rcpp sourceCpp
+## usethis namespace: end
+NULL
diff --git a/R/s2-point.R b/R/s2-point.R
new file mode 100644 (file)
index 0000000..681f3ba
--- /dev/null
@@ -0,0 +1,89 @@
+
+#' Create an S2 Point Vector
+#'
+#' In S2 terminology, a "point" is a 3-dimensional unit vector representation
+#' of an [s2_lnglat()]. Internally, all s2 objects are stored as
+#' 3-dimensional unit vectors.
+#'
+#' @param x,y,z Vectors of latitude and longitude values in degrees.
+#' @param ... Unused
+#'
+#' @return An object with class s2_point
+#' @export
+#'
+#' @examples
+#' lnglat <- s2_lnglat(-64, 45) # Halifax, Nova Scotia!
+#' as_s2_point(lnglat)
+#' as.data.frame(as_s2_point(lnglat))
+#'
+s2_point <- function(x, y, z) {
+  recycled <- recycle_common(as.double(x), as.double(y), as.double(z))
+  new_s2_xptr(s2_point_from_numeric(recycled[[1]], recycled[[2]], recycled[[3]]), "s2_point")
+}
+
+#' @rdname s2_point
+#' @export
+as_s2_point <- function(x, ...) {
+  UseMethod("as_s2_point")
+}
+
+#' @rdname s2_point
+#' @export
+as_s2_point.s2_point <- function(x, ...) {
+  x
+}
+
+#' @rdname s2_point
+#' @export
+as_s2_point.s2_lnglat <- function(x, ...) {
+  new_s2_xptr(s2_point_from_s2_lnglat(x), "s2_point")
+}
+
+#' @rdname s2_point
+#' @export
+as_s2_point.s2_geography <- function(x, ...) {
+  as_s2_point(as_s2_lnglat(x))
+}
+
+#' @rdname s2_point
+#' @export
+as_s2_point.matrix <- function(x, ...) {
+  s2_point(x[, 1, drop = TRUE], x[, 2, drop = TRUE], x[, 3, drop = TRUE])
+}
+
+#' @rdname s2_point
+#' @export
+as.data.frame.s2_point <- function(x, ...) {
+  as.data.frame(data_frame_from_s2_point(x))
+}
+
+#' @rdname s2_point
+#' @export
+as.matrix.s2_point <- function(x, ...) {
+  as.matrix(as.data.frame(data_frame_from_s2_point(x)))
+}
+
+#' @export
+`[<-.s2_point` <- function(x, i, value) {
+  x <- unclass(x)
+  x[i] <- as_s2_point(value)
+  new_s2_xptr(x, "s2_point")
+}
+
+#' @export
+`[[<-.s2_point` <- function(x, i, value) {
+  x <- unclass(x)
+  x[i] <- as_s2_point(value)
+  new_s2_xptr(x, "s2_point")
+}
+
+#' @export
+format.s2_point <- function(x, ...) {
+  df <- as.data.frame(x)
+  sprintf(
+    "[%s %s %s]",
+    format(df$x, trim = TRUE),
+    format(df$y, trim = TRUE),
+    format(df$z, trim = TRUE)
+  )
+}
diff --git a/R/s2-predicates.R b/R/s2-predicates.R
new file mode 100644 (file)
index 0000000..45701f0
--- /dev/null
@@ -0,0 +1,171 @@
+
+#' S2 Geography Predicates
+#'
+#' These functions operate two geography vectors (pairwise), and return
+#' a logical vector.
+#'
+#' @inheritParams s2_is_collection
+#' @inheritParams s2_boundary
+#' @param distance A distance on the surface of the earth in the same units
+#'   as `radius`.
+#' @param lng1,lat1,lng2,lat2 A latitude/longitude range
+#' @param detail The number of points with which to approximate
+#'   non-geodesic edges.
+#'
+#' @inheritSection s2_options Model
+#'
+#' @export
+#'
+#' @seealso
+#' Matrix versions of these predicates (e.g., [s2_intersects_matrix()]).
+#'
+#' BigQuery's geography function reference:
+#'
+#' - [ST_CONTAINS](https://cloud.google.com/bigquery/docs/reference/standard-sql/geography_functions#st_contains)
+#' - [ST_COVEREDBY](https://cloud.google.com/bigquery/docs/reference/standard-sql/geography_functions#st_coveredby)
+#' - [ST_COVERS](https://cloud.google.com/bigquery/docs/reference/standard-sql/geography_functions#st_covers)
+#' - [ST_DISJOINT](https://cloud.google.com/bigquery/docs/reference/standard-sql/geography_functions#st_disjoint)
+#' - [ST_EQUALS](https://cloud.google.com/bigquery/docs/reference/standard-sql/geography_functions#st_equals)
+#' - [ST_INTERSECTS](https://cloud.google.com/bigquery/docs/reference/standard-sql/geography_functions#st_intersects)
+#' - [ST_INTERSECTSBOX](https://cloud.google.com/bigquery/docs/reference/standard-sql/geography_functions#st_intersectsbox)
+#' - [ST_TOUCHES](https://cloud.google.com/bigquery/docs/reference/standard-sql/geography_functions#st_touches)
+#' - [ST_WITHIN](https://cloud.google.com/bigquery/docs/reference/standard-sql/geography_functions#st_within)
+#' - [ST_DWITHIN](https://cloud.google.com/bigquery/docs/reference/standard-sql/geography_functions#st_dwithin)
+#'
+#' @examples
+#' s2_contains(
+#'   "POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0))",
+#'   c("POINT (5 5)", "POINT (-1 1)")
+#' )
+#'
+#' s2_within(
+#'   c("POINT (5 5)", "POINT (-1 1)"),
+#'   "POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0))"
+#' )
+#'
+#' s2_covered_by(
+#'   "POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0))",
+#'   c("POINT (5 5)", "POINT (-1 1)")
+#' )
+#'
+#' s2_covers(
+#'   "POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0))",
+#'   c("POINT (5 5)", "POINT (-1 1)")
+#' )
+#'
+#' s2_disjoint(
+#'   "POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0))",
+#'   c("POINT (5 5)", "POINT (-1 1)")
+#' )
+#'
+#' s2_intersects(
+#'   "POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0))",
+#'   c("POINT (5 5)", "POINT (-1 1)")
+#' )
+#'
+#' s2_equals(
+#'   "POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0))",
+#'   c(
+#'     "POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0))",
+#'     "POLYGON ((10 0, 10 10, 0 10, 0 0, 10 0))",
+#'     "POLYGON ((-1 -1, 10 0, 10 10, 0 10, -1 -1))"
+#'   )
+#' )
+#'
+#' s2_intersects(
+#'   "POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0))",
+#'   c("POINT (5 5)", "POINT (-1 1)")
+#' )
+#'
+#' s2_intersects_box(
+#'   c("POINT (5 5)", "POINT (-1 1)"),
+#'   0, 0, 10, 10
+#' )
+#'
+#' s2_touches(
+#'   "POLYGON ((0 0, 0 1, 1 1, 0 0))",
+#'   c("POINT (0 0)", "POINT (0.5 0.75)", "POINT (0 0.5)")
+#' )
+#'
+#' s2_dwithin(
+#'   "POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0))",
+#'   c("POINT (5 5)", "POINT (-1 1)"),
+#'   0 # distance in meters
+#' )
+#'
+#' s2_dwithin(
+#'   "POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0))",
+#'   c("POINT (5 5)", "POINT (-1 1)"),
+#'   1e6 # distance in meters
+#' )
+#'
+s2_contains <- function(x, y, options = s2_options(model = "open")) {
+  recycled <- recycle_common(as_s2_geography(x), as_s2_geography(y))
+  cpp_s2_contains(recycled[[1]], recycled[[2]], options)
+}
+
+#' @rdname s2_contains
+#' @export
+s2_within <- function(x, y, options = s2_options(model = "open")) {
+  s2_contains(y, x, options)
+}
+
+#' @rdname s2_contains
+#' @export
+s2_covered_by <- function(x, y, options = s2_options(model = "closed")) {
+  s2_covers(y, x, options)
+}
+
+#' @rdname s2_contains
+#' @export
+s2_covers <- function(x, y, options = s2_options(model = "closed")) {
+  recycled <- recycle_common(as_s2_geography(x), as_s2_geography(y))
+  cpp_s2_contains(recycled[[1]], recycled[[2]], options)
+}
+
+#' @rdname s2_contains
+#' @export
+s2_disjoint <- function(x, y, options = s2_options()) {
+  !s2_intersects(x, y, options)
+}
+
+#' @rdname s2_contains
+#' @export
+s2_intersects <- function(x, y, options = s2_options()) {
+  recycled <- recycle_common(as_s2_geography(x), as_s2_geography(y))
+  cpp_s2_intersects(recycled[[1]], recycled[[2]], options)
+}
+
+#' @rdname s2_contains
+#' @export
+s2_equals <- function(x, y, options = s2_options()) {
+  recycled <- recycle_common(as_s2_geography(x), as_s2_geography(y))
+  cpp_s2_equals(recycled[[1]], recycled[[2]], options)
+}
+
+#' @rdname s2_contains
+#' @export
+s2_intersects_box <- function(x, lng1, lat1, lng2, lat2, detail = 1000, options = s2_options()) {
+  recycled <- recycle_common(as_s2_geography(x), lng1, lat1, lng2, lat2, detail)
+  cpp_s2_intersects_box(
+    recycled[[1]],
+    recycled[[2]], recycled[[3]],
+    recycled[[4]], recycled[[5]],
+    detail = recycled[[6]],
+         s2options = options
+  )
+}
+
+#' @rdname s2_contains
+#' @export
+s2_touches <- function(x, y, options = s2_options()) {
+  recycled <- recycle_common(as_s2_geography(x), as_s2_geography(y))
+  cpp_s2_touches(recycled[[1]], recycled[[2]], options)
+}
+
+#' @rdname s2_contains
+#' @export
+s2_dwithin <- function(x, y, distance, radius = s2_earth_radius_meters()) {
+  recycled <- recycle_common(as_s2_geography(x), as_s2_geography(y), distance / radius)
+  cpp_s2_dwithin(recycled[[1]], recycled[[2]], recycled[[3]])
+}
diff --git a/R/s2-transformers.R b/R/s2-transformers.R
new file mode 100644 (file)
index 0000000..ca97620
--- /dev/null
@@ -0,0 +1,269 @@
+
+#' S2 Geography Transformations
+#'
+#' These functions operate on one or more geography vectors and
+#' return a geography vector.
+#'
+#' @inheritParams s2_is_collection
+#' @param na.rm For aggregate calculations use `na.rm = TRUE`
+#'   to drop missing values.
+#' @param grid_size The grid size to which coordinates should be snapped;
+#'   will be rounded to the nearest power of 10.
+#' @param options An [s2_options()] object describing the polygon/polyline
+#'   model to use and the snap level.
+#' @param distance The distance to buffer, in units of `radius`.
+#' @param max_cells The maximum number of cells to approximate a buffer.
+#' @param min_level The minimum cell level used to approximate a buffer
+#'   (1 - 30). Setting this value too high will result in unnecessarily
+#'   large geographies, but may help improve buffers along long, narrow
+#'   regions.
+#' @param tolerance The minimum distance between vertexes to use when
+#'   simplifying a geography.
+#'
+#' @inheritSection s2_options Model
+#'
+#' @export
+#'
+#' @seealso
+#' BigQuery's geography function reference:
+#'
+#' - [ST_BOUNDARY](https://cloud.google.com/bigquery/docs/reference/standard-sql/geography_functions#st_boundary)
+#' - [ST_CENTROID](https://cloud.google.com/bigquery/docs/reference/standard-sql/geography_functions#st_centroid)
+#' - [ST_CLOSESTPOINT](https://cloud.google.com/bigquery/docs/reference/standard-sql/geography_functions#st_closestpoint)
+#' - [ST_DIFFERENCE](https://cloud.google.com/bigquery/docs/reference/standard-sql/geography_functions#st_difference)
+#' - [ST_INTERSECTION](https://cloud.google.com/bigquery/docs/reference/standard-sql/geography_functions#st_intersection)
+#' - [ST_UNION](https://cloud.google.com/bigquery/docs/reference/standard-sql/geography_functions#st_union)
+#' - [ST_SNAPTOGRID](https://cloud.google.com/bigquery/docs/reference/standard-sql/geography_functions#st_snaptogrid)
+#' - [ST_SIMPLIFY](https://cloud.google.com/bigquery/docs/reference/standard-sql/geography_functions#st_simplify)
+#' - [ST_UNION_AGG](https://cloud.google.com/bigquery/docs/reference/standard-sql/geography_functions#st_union_agg)
+#' - [ST_CENTROID_AGG](https://cloud.google.com/bigquery/docs/reference/standard-sql/geography_functions#s2_centroid_agg)
+#'
+#' @examples
+#' # returns the boundary:
+#' # empty for point, endpoints of a linestring,
+#' # perimeter of a polygon
+#' s2_boundary("POINT (-64 45)")
+#' s2_boundary("LINESTRING (0 0, 10 0)")
+#' s2_boundary("POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0))")
+#'
+#' # returns the area-weighted centroid, element-wise
+#' s2_centroid("POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0))")
+#' s2_centroid("LINESTRING (0 0, 10 0)")
+#'
+#' # returns the unweighted centroid of the entire input
+#' s2_centroid_agg(c("POINT (0 0)", "POINT (10 0)"))
+#'
+#' # returns the closest point on x to y
+#' s2_closest_point(
+#'   "POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0))",
+#'   "POINT (0 90)" # north pole!
+#' )
+#'
+#' # returns the shortest possible line between x and y
+#' s2_minimum_clearance_line_between(
+#'   "POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0))",
+#'   "POINT (0 90)" # north pole!
+#' )
+#'
+#' # binary operations: difference, symmetric difference, intersection and union
+#' s2_difference(
+#'   "POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0))",
+#'   "POLYGON ((5 5, 15 5, 15 15, 5 15, 5 5))",
+#'   # 32 bit platforms may need to set snap rounding
+#'   s2_options(snap = s2_snap_level(30))
+#' )
+#'
+#' s2_sym_difference(
+#'   "POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0))",
+#'   "POLYGON ((5 5, 15 5, 15 15, 5 15, 5 5))",
+#'   # 32 bit platforms may need to set snap rounding
+#'   s2_options(snap = s2_snap_level(30))
+#' )
+#'
+#' s2_intersection(
+#'   "POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0))",
+#'   "POLYGON ((5 5, 15 5, 15 15, 5 15, 5 5))",
+#'   # 32 bit platforms may need to set snap rounding
+#'   s2_options(snap = s2_snap_level(30))
+#' )
+#'
+#' s2_union(
+#'   "POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0))",
+#'   "POLYGON ((5 5, 15 5, 15 15, 5 15, 5 5))",
+#'   # 32 bit platforms may need to set snap rounding
+#'   s2_options(snap = s2_snap_level(30))
+#' )
+#'
+#' # use s2_union_agg() to aggregate geographies in a vector
+#' s2_coverage_union_agg(
+#'   c(
+#'     "POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0))",
+#'     "POLYGON ((5 5, 15 5, 15 15, 5 15, 5 5))"
+#'   ),
+#'   # 32 bit platforms may need to set snap rounding
+#'   s2_options(snap = s2_snap_level(30))
+#' )
+#'
+#' # snap to grid rounds coordinates to a specified grid size
+#' s2_snap_to_grid("POINT (0.333333333333 0.666666666666)", 1e-2)
+#'
+s2_boundary <- function(x) {
+  new_s2_xptr(cpp_s2_boundary(as_s2_geography(x)), "s2_geography")
+}
+
+#' @rdname s2_boundary
+#' @export
+s2_centroid <- function(x) {
+  new_s2_xptr(cpp_s2_centroid(as_s2_geography(x)), "s2_geography")
+}
+
+#' @rdname s2_boundary
+#' @export
+s2_closest_point <- function(x, y) {
+  recycled <- recycle_common(as_s2_geography(x), as_s2_geography(y))
+  new_s2_xptr(cpp_s2_closest_point(recycled[[1]], recycled[[2]]), "s2_geography")
+}
+
+#' @rdname s2_boundary
+#' @export
+s2_minimum_clearance_line_between <- function(x, y) {
+  recycled <- recycle_common(as_s2_geography(x), as_s2_geography(y))
+  new_s2_xptr(cpp_s2_minimum_clearance_line_between(recycled[[1]], recycled[[2]]), "s2_geography")
+}
+
+#' @rdname s2_boundary
+#' @export
+s2_difference <- function(x, y, options = s2_options()) {
+  recycled <- recycle_common(as_s2_geography(x), as_s2_geography(y))
+  new_s2_xptr(cpp_s2_difference(recycled[[1]], recycled[[2]], options), "s2_geography")
+}
+
+#' @rdname s2_boundary
+#' @export
+s2_sym_difference <- function(x, y, options = s2_options()) {
+  recycled <- recycle_common(as_s2_geography(x), as_s2_geography(y))
+  new_s2_xptr(cpp_s2_sym_difference(recycled[[1]], recycled[[2]], options), "s2_geography")
+}
+
+#' @rdname s2_boundary
+#' @export
+s2_intersection <- function(x, y, options = s2_options()) {
+  recycled <- recycle_common(as_s2_geography(x), as_s2_geography(y))
+  new_s2_xptr(cpp_s2_intersection(recycled[[1]], recycled[[2]], options), "s2_geography")
+}
+
+#' @rdname s2_boundary
+#' @export
+s2_union <- function(x, y = NULL, options = s2_options()) {
+  x <- as_s2_geography(x)
+
+  if (is.null(y)) {
+    new_s2_xptr(cpp_s2_unary_union(x, options), "s2_geography")
+  } else {
+    recycled <- recycle_common(x, as_s2_geography(y))
+    new_s2_xptr(cpp_s2_union(recycled[[1]], recycled[[2]], options), "s2_geography")
+  }
+}
+
+#' @rdname s2_boundary
+#' @export
+s2_snap_to_grid <- function(x, grid_size) {
+  s2_rebuild(
+    x,
+    options = s2_options(
+      snap = s2_snap_precision(10^(-log10(grid_size))),
+      duplicate_edges = TRUE
+    )
+  )
+}
+
+#' @rdname s2_boundary
+#' @export
+s2_simplify <- function(x, tolerance, radius = s2_earth_radius_meters()) {
+  s2_rebuild(x, options = s2_options(snap_radius = tolerance / radius, simplify_edge_chains = TRUE))
+}
+
+#' @rdname s2_boundary
+#' @export
+s2_rebuild <- function(x, options = s2_options()) {
+  new_s2_xptr(cpp_s2_rebuild(as_s2_geography(x), options), "s2_geography")
+}
+
+#' @rdname s2_boundary
+#' @export
+s2_buffer_cells <- function(x, distance, max_cells = 1000, min_level = -1,
+                            radius = s2_earth_radius_meters()) {
+  recycled <- recycle_common(as_s2_geography(x), distance / radius)
+  new_s2_xptr(cpp_s2_buffer_cells(recycled[[1]], recycled[[2]], max_cells, min_level), "s2_geography")
+}
+
+#' @rdname s2_boundary
+#' @export
+s2_centroid_agg <- function(x, na.rm = FALSE) {
+  new_s2_xptr(cpp_s2_centroid_agg(as_s2_geography(x), naRm = na.rm), "s2_geography")
+}
+
+#' @rdname s2_boundary
+#' @export
+s2_coverage_union_agg <- function(x, options = s2_options(), na.rm = FALSE) {
+  new_s2_xptr(cpp_s2_coverage_union_agg(as_s2_geography(x), options, na.rm), "s2_geography")
+}
+
+#' @rdname s2_boundary
+#' @export
+s2_rebuild_agg <- function(x, options = s2_options(), na.rm = FALSE) {
+  new_s2_xptr(cpp_s2_rebuild_agg(as_s2_geography(x), options, na.rm), "s2_geography")
+}
+
+#' @rdname s2_boundary
+#' @export
+s2_union_agg <- function(x, options = s2_options(), na.rm = FALSE) {
+  new_s2_xptr(cpp_s2_union_agg(s2_union(x, options = options), options, na.rm), "s2_geography")
+}
+
+
+#' Linear referencing
+#'
+#' @param x A simple polyline geography vector
+#' @param y A simple point geography vector. The point will be
+#'   snapped to the nearest point on `x` for the purposes of
+#'   interpolation.
+#' @param distance A distance along `x` in `radius` units.
+#' @param distance_normalized A `distance` normalized to [s2_length()] of
+#'   `x`.
+#' @inheritParams s2_is_collection
+#'
+#' @return
+#'   - `s2_interpolate()` returns the point on `x`, `distance` meters
+#'     along the line.
+#'   - `s2_interpolate_normalized()` returns the point on `x` interpolated
+#'     to a fraction along the line.
+#'   - `s2_project()` returns the `distance` that `point` occurs along `x`.
+#'   - `s2_project_normalized()` returns the `distance_normalized` along `x`
+#'     where `point` occurs.
+#' @export
+#'
+#' @examples
+#' s2_project_normalized("LINESTRING (0 0, 0 90)", "POINT (0 22.5)")
+#' s2_project("LINESTRING (0 0, 0 90)", "POINT (0 22.5)")
+#' s2_interpolate_normalized("LINESTRING (0 0, 0 90)", 0.25)
+#' s2_interpolate("LINESTRING (0 0, 0 90)", 2501890)
+#'
+s2_interpolate <- function(x, distance, radius = s2_earth_radius_meters()) {
+  recycled <- recycle_common(as_s2_geography(x), distance / radius)
+  length <- cpp_s2_length(recycled[[1]])
+  new_s2_xptr(
+    cpp_s2_interpolate_normalized(recycled[[1]], distance / radius / length),
+    "s2_geography"
+  )
+}
+
+#' @rdname s2_interpolate
+#' @export
+s2_interpolate_normalized <- function(x, distance_normalized) {
+  recycled <- recycle_common(as_s2_geography(x), distance_normalized)
+  new_s2_xptr(
+    cpp_s2_interpolate_normalized(recycled[[1]], distance_normalized),
+    "s2_geography"
+  )
+}
diff --git a/R/s2-xptr.R b/R/s2-xptr.R
new file mode 100644 (file)
index 0000000..78cf56a
--- /dev/null
@@ -0,0 +1,116 @@
+
+#' Create vectors of XPtr objects
+#'
+#' @param x A bare `list()` of external pointers
+#' @param class A character vector subclass
+#' @param ... Unused
+#'
+#' @return An object of class s2_xptr
+#' @noRd
+#'
+new_s2_xptr <- function(x = list(), class = character()) {
+  if (!is.list(x) || is.object(x)) {
+    stop("x must be a bare list of 'externalptr' objects")
+  }
+
+  class(x) <- union(class, "s2_xptr")
+  x
+}
+
+validate_s2_xptr <- function(x) {
+  type <- vapply(unclass(x), typeof, character(1))
+  valid_items <- type %in% c("externalptr", "NULL")
+  if (any(!valid_items)) {
+    stop("Items must be externalptr objects or NULL")
+  }
+
+  invisible(x)
+}
+
+#' @export
+`[.s2_xptr` <- function(x, i) {
+  new_s2_xptr(NextMethod(), class(x))
+}
+
+# makes lapply() along these vectors possible
+#' @export
+`[[.s2_xptr` <- function(x, i) {
+  x[i]
+}
+
+#' @export
+`c.s2_xptr` <- function(...) {
+  # make sure all items inherit the same top-level class
+  dots <- list(...)
+  inherits_first <- vapply(dots, inherits, class(dots[[1]])[1], FUN.VALUE = logical(1))
+  if (!all(inherits_first)) {
+    stop(sprintf("All items must inherit from '%s'", class(dots[[1]])[1]))
+  }
+
+  xptr <- new_s2_xptr(NextMethod(), class(dots[[1]]))
+  validate_s2_xptr(xptr)
+  xptr
+}
+
+#' @export
+rep.s2_xptr <- function(x, ...) {
+  if (length(x) == 0) {
+    new_s2_xptr(list(), class(x))
+  } else {
+    new_s2_xptr(NextMethod(), class(x))
+  }
+}
+
+#' @method rep_len s2_xptr
+#' @export
+rep_len.s2_xptr <- function(x, length.out) {
+  rep(x, length.out = length.out)
+}
+
+# data.frame() will call as.data.frame() with optional = TRUE
+#' @export
+as.data.frame.s2_xptr <- function(x, ..., optional = FALSE) {
+  if (!optional) {
+    NextMethod()
+  } else {
+    new_data_frame(list(x))
+  }
+}
+
+# lifted from vctrs::obj_leaf()
+#' @export
+str.s2_xptr <- function(object, ..., indent.str = "", width = getOption("width")) {
+  if (length(object) == 0) {
+    cat(paste0(" ", class(object)[1], "[0]\n"))
+    return(invisible(object))
+  }
+
+  # estimate possible number of elements that could be displayed
+  # to avoid formatting too many
+  width <- width - nchar(indent.str) - 2
+  length <- min(length(object), ceiling(width / 5))
+  formatted <- format(object[seq_len(length)], trim = TRUE)
+
+  title <- paste0(" ", class(object)[1], "[1:", length(object), "]")
+  cat(
+    paste0(
+      title,
+      " ",
+      strtrim(paste0(formatted, collapse = ", "), width - nchar(title)),
+      "\n"
+    )
+  )
+  invisible(object)
+}
+
+#' @export
+print.s2_xptr <- function(x, ...) {
+  cat(sprintf("<%s[%s]>\n", class(x)[1], length(x)))
+  if (length(x) == 0) {
+    return(invisible(x))
+  }
+
+  out <- stats::setNames(format(x, ...), names(x))
+  print(out, quote = FALSE)
+  invisible(x)
+}
diff --git a/R/utils.R b/R/utils.R
new file mode 100644 (file)
index 0000000..8d6d38e
--- /dev/null
+++ b/R/utils.R
@@ -0,0 +1,78 @@
+
+new_data_frame <- function(x) {
+  structure(x, row.names = c(NA, length(x[[1]])), class = "data.frame")
+}
+
+recycle_common <- function(...) {
+  dots <- list(...)
+  lengths <- vapply(dots, length, integer(1))
+  non_constant_lengths <- unique(lengths[lengths != 1])
+  if (length(non_constant_lengths) == 0) {
+    final_length <- 1
+  } else if(length(non_constant_lengths) == 1) {
+    final_length <- non_constant_lengths
+  } else {
+    lengths_label <- paste0(non_constant_lengths, collapse = ", ")
+    stop(sprintf("Incompatible lengths: %s", lengths_label))
+  }
+
+  lapply(dots, rep_len, final_length)
+}
+
+# The problems object is generated when building or processing an s2_geography():
+# instead of attaching to the object as an attribute, this function is
+# called from Rcpp if there were any problems to format them in a
+# human-readable way. Theoretically one could change this to only warn
+# instead of stop (error values are set to NA/NULL).
+stop_problems_create <- function(feature_id, problem) {
+  n <- length(feature_id)
+  feature_label <- if (n != 1) "features" else "feature"
+
+  stop_problems(
+    feature_id,
+    problem,
+    sprintf("Found %d %s with invalid spherical geometry.", n, feature_label)
+  )
+}
+
+stop_problems_process <- function(feature_id, problem) {
+  n <- length(feature_id)
+  error_label <- if (n != 1) "errors" else "error"
+
+  stop_problems(
+    feature_id,
+    problem,
+    sprintf("Encountered %d processing %s.", n, error_label)
+  )
+}
+
+stop_problems <- function(feature_id, problem, header) {
+  n <- length(feature_id)
+
+  if (n > 10) {
+    feature_id <- feature_id[1:10]
+    problem <- problem[1:10]
+    more <- sprintf("\n...and %s more", n - 10)
+  } else {
+    more <- ""
+  }
+
+  msg <- paste0(
+    header, "\n",
+    paste0("[", feature_id + 1, "] ", problem , collapse = "\n"),
+    more
+  )
+
+  stop(msg, call. = FALSE)
+}
+
+expect_wkt_equal <- function(x, y, precision = 16) {
+  testthat::expect_equal(
+    s2_geography_to_wkt(as_s2_geography(x), precision = precision, trim = TRUE),
+    s2_geography_to_wkt(as_s2_geography(y), precision = precision, trim = TRUE)
+  )
+}
+
+expect_near <- function(x, y, epsilon) {
+  testthat::expect_true(abs(y - x) < epsilon)
+}
diff --git a/R/vctrs.R b/R/vctrs.R
new file mode 100644 (file)
index 0000000..d8aeaf2
--- /dev/null
+++ b/R/vctrs.R
@@ -0,0 +1,48 @@
+
+vec_proxy.s2_geography <- function(x, ...) {
+  unclass(x)
+}
+
+vec_restore.s2_geography <- function(x, ...) {
+  new_s2_xptr(x, "s2_geography")
+}
+
+vec_ptype_abbr.s2_geography <- function(x, ...) {
+  "s2_geography"
+}
+
+vec_proxy.s2_point <- function(x, ...) {
+  unclass(x)
+}
+
+vec_restore.s2_point <- function(x, ...) {
+  new_s2_xptr(x, "s2_point")
+}
+
+vec_ptype_abbr.s2_point <- function(x, ...) {
+  "s2_point"
+}
+
+vec_proxy.s2_lnglat <- function(x, ...) {
+  unclass(x)
+}
+
+vec_restore.s2_lnglat <- function(x, ...) {
+  new_s2_xptr(x, "s2_lnglat")
+}
+
+vec_ptype_abbr.s2_lnglat <- function(x, ...) {
+  "s2_lnglat"
+}
+
+vec_proxy.s2_cell <- function(x, ...) {
+  unclass(x)
+}
+
+vec_restore.s2_cell <- function(x, ...) {
+  new_s2_cell(x)
+}
+
+vec_ptype_abbr.s2_cell <- function(x, ...) {
+  "s2cell"
+}
diff --git a/R/wk-utils.R b/R/wk-utils.R
new file mode 100644 (file)
index 0000000..1372a36
--- /dev/null
@@ -0,0 +1,78 @@
+
+#' Low-level wk filters and handlers
+#'
+#' @inheritParams wk::wk_handle
+#' @param projection One of [s2_projection_plate_carree()] or
+#'   [s2_projection_mercator()]
+#' @param tessellate_tol An angle in radians. Points will not be added
+#'   if a line segment is within this distance of a point.
+#'
+#' @return
+#'   - `s2_unprojection_filter()`, `s2_projection_filter()`: A `new_wk_handler()`
+#'   - `s2_projection_plate_carree()`, `s2_projection_mercator()`: An external pointer
+#'     to an S2 projection.
+#' @export
+#'
+#' @examples
+#' library(wk)
+#'
+#' # simple conversion of individual coordinates *to* unit sphere
+#' # space
+#' wk_handle(
+#'   wkt("LINESTRING (0 0, 0 45, -60 45)"),
+#'   s2_unprojection_filter(wkt_format_handler(5))
+#' )
+#'
+#' # simple conversion of individual coordinates *from* unit sphere
+#' # space
+#' wk_handle(
+#'   wkt("LINESTRING Z (1 0 0, 0.7071 0 0.7071, 0.3536 -0.6124 0.7071)"),
+#'   s2_projection_filter(wkt_format_handler(5))
+#' )
+#'
+#' # use tessellate_tol to force points to be added to an edge
+#' # unprojection will ensure an edge maintains its cartesian
+#' # assumption when transformed to the unit sphere
+#' # (i.e., what you probably want when importing a geography)
+#' wk_handle(
+#'   wkt("LINESTRING (0 0, 0 45, -60 45)"),
+#'   s2_unprojection_filter(wkt_format_handler(5), tessellate_tol = 0.001)
+#' )
+#'
+#' # projection will ensure an edge maintains its geodesic
+#' # assumption when transformed to projected space
+#' # (i.e., what you probably want when exporting a geography)
+#' wk_handle(
+#'   wkt("LINESTRING Z (1 0 0, 0.7071 0 0.7071, 0.3536 -0.6124 0.7071)"),
+#'   s2_projection_filter(wkt_format_handler(5), tessellate_tol = 0.001)
+#' )
+#'
+s2_unprojection_filter <- function(handler, projection = s2_projection_plate_carree(),
+                                   tessellate_tol = Inf) {
+  wk::new_wk_handler(
+    .Call(c_s2_coord_filter_new, handler, projection, TRUE, tessellate_tol),
+    subclass = "s2_coord_filter"
+  )
+}
+
+#' @rdname s2_unprojection_filter
+#' @export
+s2_projection_filter <- function(handler, projection = s2_projection_plate_carree(),
+                                 tessellate_tol = Inf) {
+  wk::new_wk_handler(
+    .Call(c_s2_coord_filter_new, handler, projection, FALSE, tessellate_tol),
+    subclass = "s2_coord_filter"
+  )
+}
+
+#' @rdname s2_unprojection_filter
+#' @export
+s2_projection_plate_carree <- function() {
+  .Call(c_s2_projection_plate_carree)
+}
+
+#' @rdname s2_unprojection_filter
+#' @export
+s2_projection_mercator <- function() {
+  .Call(c_s2_projection_mercator)
+}
diff --git a/R/zzz.R b/R/zzz.R
new file mode 100644 (file)
index 0000000..83a7cd4
--- /dev/null
+++ b/R/zzz.R
@@ -0,0 +1,72 @@
+
+# nocov start
+.onLoad <- function(...) {
+  # call c++ init
+  cpp_s2_init()
+
+  # dynamically register vctrs dependencies
+  for (cls in c("s2_geography", "s2_point", "s2_lnglat", "s2_cell")) {
+    s3_register("vctrs::vec_proxy", cls)
+    s3_register("vctrs::vec_restore", cls)
+    s3_register("vctrs::vec_ptype_abbr", cls)
+  }
+}
+
+s3_register <- function(generic, class, method = NULL) {
+  stopifnot(is.character(generic), length(generic) == 1)
+  stopifnot(is.character(class), length(class) == 1)
+
+  pieces <- strsplit(generic, "::")[[1]]
+  stopifnot(length(pieces) == 2)
+  package <- pieces[[1]]
+  generic <- pieces[[2]]
+
+  caller <- parent.frame()
+
+  get_method_env <- function() {
+    top <- topenv(caller)
+    if (isNamespace(top)) {
+      asNamespace(environmentName(top))
+    } else {
+      caller
+    }
+  }
+  get_method <- function(method, env) {
+    if (is.null(method)) {
+      get(paste0(generic, ".", class), envir = get_method_env())
+    } else {
+      method
+    }
+  }
+
+  method_fn <- get_method(method)
+  stopifnot(is.function(method_fn))
+
+  # Always register hook in case package is later unloaded & reloaded
+  setHook(
+    packageEvent(package, "onLoad"),
+    function(...) {
+      ns <- asNamespace(package)
+
+      # Refresh the method, it might have been updated by `devtools::load_all()`
+      method_fn <- get_method(method)
+
+      registerS3method(generic, class, method_fn, envir = ns)
+    }
+  )
+
+  # Avoid registration failures during loading (pkgload or regular)
+  if (!isNamespaceLoaded(package)) {
+    return(invisible())
+  }
+
+  envir <- asNamespace(package)
+
+  # Only register if generic can be accessed
+  if (exists(generic, envir)) {
+    registerS3method(generic, class, method_fn, envir = envir)
+  }
+
+  invisible()
+}
+# nocov end
diff --git a/README.md b/README.md
new file mode 100644 (file)
index 0000000..4d203fc
--- /dev/null
+++ b/README.md
@@ -0,0 +1,184 @@
+
+<!-- README.md is generated from README.Rmd. Please edit that file -->
+
+# s2
+
+<!-- badges: start -->
+
+![R-CMD-check](https://github.com/r-spatial/s2/workflows/R-CMD-check/badge.svg)
+[![codecov](https://codecov.io/gh/r-spatial/s2/branch/master/graph/badge.svg)](https://codecov.io/gh/r-spatial/s2)
+[![CRAN](http://www.r-pkg.org/badges/version/s2)](https://cran.r-project.org/package=s2)
+[![Downloads](http://cranlogs.r-pkg.org/badges/s2?color=brightgreen)](https://www.r-pkg.org/pkg/s2)
+<!-- badges: end -->
+
+The s2 R package provides bindings to Google’s
+[S2Geometry](https://s2geometry.io) library. The package exposes an API
+similar to Google’s [BigQuery Geography
+API](https://cloud.google.com/bigquery/docs/reference/standard-sql/geography_functions),
+whose functions also operate on spherical geometries. Package
+[sf](https://cran.r-project.org/package=sf) uses this package by default
+for nearly all its geometrical operations on objects with ellipsoidal
+(unprojected) coordinates; in cases where it doesn’t, such as
+`st_relate()`, it emits a warning.
+
+This package is a complete rewrite of an earlier CRAN package s2 with
+versions up to 0.4-2, for which the sources are found
+[here](https://github.com/spatstat/s2/).
+
+## Installation
+
+You can install the released version of s2 from
+[CRAN](https://CRAN.R-project.org) with:
+
+``` r
+install.packages("s2")
+```
+
+And the development version from [GitHub](https://github.com/) with:
+
+``` r
+# install.packages("remotes")
+remotes::install_github("r-spatial/s2")
+```
+
+## Example
+
+The s2 package provides geometry transformers and predicates similar to
+those found in [GEOS](https://trac.osgeo.org/geos/), except instead of
+assuming a planar geometry, s2’s functions work in latitude and
+longitude and assume a spherical geometry:
+
+``` r
+library(s2)
+
+s2_contains(
+  # polygon containing much  of the northern hemisphere
+  "POLYGON ((-63.5 44.6, -149.75 61.20, 116.4 40.2, 13.5 52.51, -63.5 44.6))",
+  # ...should contain the north pole
+  "POINT (0 90)"
+)
+#> [1] TRUE
+```
+
+The [sf package](https://r-spatial.github.io/sf/) uses s2 for geographic
+coordinates with `sf::sf_use_s2(TRUE)`, and will become the default
+after sf version 1.0.0. The sf package also supports creating s2 vectors
+using `as_s2_geography()`:
+
+``` r
+library(dplyr)
+library(sf)
+
+nc_s2 <- read_sf(system.file("shape/nc.shp", package = "sf")) %>% 
+  mutate(geometry = as_s2_geography(geometry)) %>% 
+  as_tibble() %>% 
+  select(NAME, geometry)
+
+nc_s2
+#> # A tibble: 100 × 2
+#>    NAME        geometry                                                         
+#>    <chr>       <s2_geography>                                                   
+#>  1 Ashe        <POLYGON ((-81.4528885 36.2395859, -81.4310379 36.2607193, -81.4…
+#>  2 Alleghany   <POLYGON ((-81.1766739 36.4154434, -81.1533661 36.4247398, -81.1…
+#>  3 Surry       <POLYGON ((-80.4530106 36.2570877, -80.4353104 36.5510445, -80.6…
+#>  4 Currituck   <MULTIPOLYGON (((-75.9419327 36.2943382, -75.9575119 36.2594528,…
+#>  5 Northampton <POLYGON ((-77.1419601 36.4170647, -77.1393204 36.4564781, -77.1…
+#>  6 Hertford    <POLYGON ((-76.7074966 36.2661324, -76.7413483 36.3151665, -76.9…
+#>  7 Camden      <POLYGON ((-76.0173492 36.3377304, -76.0328751 36.3359756, -76.0…
+#>  8 Gates       <POLYGON ((-76.46035 36.3738976, -76.5024643 36.4522858, -76.498…
+#>  9 Warren      <POLYGON ((-78.1347198 36.2365837, -78.1096268 36.2135086, -78.0…
+#> 10 Stokes      <POLYGON ((-80.0240555 36.5450249, -80.0480957 36.5471344, -80.4…
+#> # … with 90 more rows
+```
+
+Use accessors to extract information about geometries:
+
+``` r
+nc_s2 %>% 
+  mutate(
+    area = s2_area(geometry),
+    perimeter = s2_perimeter(geometry)
+  )
+#> # A tibble: 100 × 4
+#>    NAME        geometry                                           area perimeter
+#>    <chr>       <s2_geography>                                    <dbl>     <dbl>
+#>  1 Ashe        <POLYGON ((-81.4528885 36.2395859, -81.431037…   1.14e9   141627.
+#>  2 Alleghany   <POLYGON ((-81.1766739 36.4154434, -81.153366…   6.11e8   119876.
+#>  3 Surry       <POLYGON ((-80.4530106 36.2570877, -80.435310…   1.42e9   160458.
+#>  4 Currituck   <MULTIPOLYGON (((-75.9419327 36.2943382, -75.…   6.94e8   301644.
+#>  5 Northampton <POLYGON ((-77.1419601 36.4170647, -77.139320…   1.52e9   211794.
+#>  6 Hertford    <POLYGON ((-76.7074966 36.2661324, -76.741348…   9.68e8   160780.
+#>  7 Camden      <POLYGON ((-76.0173492 36.3377304, -76.032875…   6.16e8   150430.
+#>  8 Gates       <POLYGON ((-76.46035 36.3738976, -76.5024643 …   9.03e8   123170.
+#>  9 Warren      <POLYGON ((-78.1347198 36.2365837, -78.109626…   1.18e9   141073.
+#> 10 Stokes      <POLYGON ((-80.0240555 36.5450249, -80.048095…   1.23e9   140583.
+#> # … with 90 more rows
+```
+
+Use predicates to subset vectors:
+
+``` r
+nc_s2 %>% 
+  filter(s2_contains(geometry, "POINT (-80.9313 35.6196)"))
+#> # A tibble: 1 × 2
+#>   NAME    geometry                                                              
+#>   <chr>   <s2_geography>                                                        
+#> 1 Catawba <POLYGON ((-80.9312744 35.6195908, -81.0035782 35.6970558, -81.054779…
+```
+
+Use transformers to create new geometries:
+
+``` r
+nc_s2 %>% 
+  mutate(geometry = s2_boundary(geometry))
+#> # A tibble: 100 × 2
+#>    NAME        geometry                                                         
+#>    <chr>       <s2_geography>                                                   
+#>  1 Ashe        <LINESTRING (-81.4528885 36.2395859, -81.4310379 36.2607193, -81…
+#>  2 Alleghany   <LINESTRING (-81.1766739 36.4154434, -81.1533661 36.4247398, -81…
+#>  3 Surry       <LINESTRING (-80.4530106 36.2570877, -80.4353104 36.5510445, -80…
+#>  4 Currituck   <MULTILINESTRING ((-75.9419327 36.2943382, -75.9575119 36.259452…
+#>  5 Northampton <LINESTRING (-77.1419601 36.4170647, -77.1393204 36.4564781, -77…
+#>  6 Hertford    <LINESTRING (-76.7074966 36.2661324, -76.7413483 36.3151665, -76…
+#>  7 Camden      <LINESTRING (-76.0173492 36.3377304, -76.0328751 36.3359756, -76…
+#>  8 Gates       <LINESTRING (-76.46035 36.3738976, -76.5024643 36.4522858, -76.4…
+#>  9 Warren      <LINESTRING (-78.1347198 36.2365837, -78.1096268 36.2135086, -78…
+#> 10 Stokes      <LINESTRING (-80.0240555 36.5450249, -80.0480957 36.5471344, -80…
+#> # … with 90 more rows
+```
+
+Finally, use the WKB or WKT exporters to export to sf or some other
+package:
+
+``` r
+nc_s2 %>% 
+  mutate(geometry = st_as_sfc(s2_as_binary(geometry))) %>% 
+  st_as_sf()
+#> Simple feature collection with 100 features and 1 field
+#> Geometry type: GEOMETRY
+#> Dimension:     XY
+#> Bounding box:  xmin: -84.32385 ymin: 33.88199 xmax: -75.45698 ymax: 36.58965
+#> CRS:           NA
+#> # A tibble: 100 × 2
+#>    NAME                                                                 geometry
+#>    <chr>                                                              <GEOMETRY>
+#>  1 Ashe        POLYGON ((-81.45289 36.23959, -81.43104 36.26072, -81.41233 36.2…
+#>  2 Alleghany   POLYGON ((-81.17667 36.41544, -81.15337 36.42474, -81.1384 36.41…
+#>  3 Surry       POLYGON ((-80.45301 36.25709, -80.43531 36.55104, -80.61105 36.5…
+#>  4 Currituck   MULTIPOLYGON (((-75.94193 36.29434, -75.95751 36.25945, -75.9137…
+#>  5 Northampton POLYGON ((-77.14196 36.41706, -77.13932 36.45648, -77.12733 36.4…
+#>  6 Hertford    POLYGON ((-76.7075 36.26613, -76.74135 36.31517, -76.92408 36.39…
+#>  7 Camden      POLYGON ((-76.01735 36.33773, -76.03288 36.33598, -76.04395 36.3…
+#>  8 Gates       POLYGON ((-76.46035 36.3739, -76.50246 36.45229, -76.49834 36.50…
+#>  9 Warren      POLYGON ((-78.13472 36.23658, -78.10963 36.21351, -78.05835 36.2…
+#> 10 Stokes      POLYGON ((-80.02406 36.54502, -80.0481 36.54713, -80.43531 36.55…
+#> # … with 90 more rows
+```
+
+## Acknowledgment
+
+This project gratefully acknowledges financial
+[support](https://www.r-consortium.org/projects) from the
+
+<a href="https://www.r-consortium.org/projects/awarded-projects">
+<img src="man/figures/rc300.png" width="300" /> </a>
diff --git a/build/partial.rdb b/build/partial.rdb
new file mode 100644 (file)
index 0000000..c663fde
Binary files /dev/null and b/build/partial.rdb differ
diff --git a/cleanup b/cleanup
new file mode 100755 (executable)
index 0000000..3fd9cd2
--- /dev/null
+++ b/cleanup
@@ -0,0 +1,3 @@
+#!/bin/sh
+rm -f src/Makevars configure.log autobrew
+rm `find src -name *.o`
diff --git a/configure b/configure
new file mode 100755 (executable)
index 0000000..bf20a71
--- /dev/null
+++ b/configure
@@ -0,0 +1,117 @@
+# Anticonf (tm) script by Jeroen Ooms (2020)
+# This script will query 'pkg-config' for the required cflags and ldflags.
+# If pkg-config is unavailable or does not find the library, try setting
+# INCLUDE_DIR and LIB_DIR manually via e.g:
+# R CMD INSTALL --configure-vars='INCLUDE_DIR=/.../include LIB_DIR=/.../lib'
+
+# Library settings
+PKG_CONFIG_NAME="openssl"
+PKG_DEB_NAME="libssl-dev"
+PKG_RPM_NAME="openssl-devel"
+PKG_CSW_NAME="libssl_dev"
+PKG_BREW_NAME="openssl@1.1"
+PKG_TEST_FILE="tools/version.c"
+PKG_LIBS="-lssl -lcrypto"
+PKG_CFLAGS=""
+
+# Use pkg-config if available
+pkg-config ${PKG_CONFIG_NAME} --atleast-version=1.0  2>/dev/null
+if [ $? -eq 0 ]; then
+  PKGCONFIG_CFLAGS=`pkg-config --cflags ${PKG_CONFIG_NAME}`
+  PKGCONFIG_LIBS=`pkg-config --libs ${PKG_CONFIG_NAME}`
+fi
+
+# Note that cflags may be empty in case of success
+if [ "$INCLUDE_DIR" ] || [ "$LIB_DIR" ]; then
+  echo "Found INCLUDE_DIR and/or LIB_DIR!"
+  PKG_CFLAGS="-I$INCLUDE_DIR $PKG_CFLAGS"
+  PKG_LIBS="-L$LIB_DIR $PKG_LIBS"
+elif [ "$PKGCONFIG_CFLAGS" ] || [ "$PKGCONFIG_LIBS" ]; then
+  echo "Found pkg-config cflags and libs!"
+  PKG_CFLAGS=${PKGCONFIG_CFLAGS}
+  PKG_LIBS=${PKGCONFIG_LIBS}
+elif [ `uname` = "Darwin" ]; then
+  brew --version 2>/dev/null
+  if [ $? -eq 0 ]; then
+    BREWDIR=`brew --prefix`
+    PKG_CFLAGS="-I$BREWDIR/opt/openssl/include"
+    PKG_LIBS="-L$BREWDIR/opt/openssl/lib $PKG_LIBS"
+  else
+    curl -sfL "https://autobrew.github.io/scripts/$PKG_BREW_NAME" > autobrew
+    . autobrew
+  fi
+fi
+
+# Find compiler
+CC=`${R_HOME}/bin/R CMD config CC`
+CFLAGS=`${R_HOME}/bin/R CMD config CFLAGS`
+CPPFLAGS=`${R_HOME}/bin/R CMD config CPPFLAGS`
+
+# For debugging
+echo "Testing compiler using PKG_CFLAGS=$PKG_CFLAGS"
+
+# Test configuration
+${CC} ${CPPFLAGS} ${PKG_CFLAGS} ${CFLAGS} -E ${PKG_TEST_FILE} >/dev/null 2>configure.log
+
+# Customize the error
+if [ $? -ne 0 ]; then
+  echo "--------------------------- [ANTICONF] --------------------------------"
+  echo "Configuration failed because $PKG_CONFIG_NAME was not found. Try installing:"
+  echo " * deb: $PKG_DEB_NAME (Debian, Ubuntu, etc)"
+  echo " * rpm: $PKG_RPM_NAME (Fedora, CentOS, RHEL)"
+  echo " * csw: $PKG_CSW_NAME (Solaris)"
+  echo " * brew: $PKG_BREW_NAME (Mac OSX)"
+  echo "If $PKG_CONFIG_NAME is already installed, check that 'pkg-config' is in your"
+  echo "PATH and PKG_CONFIG_PATH contains a $PKG_CONFIG_NAME.pc file. If pkg-config"
+  echo "is unavailable you can set INCLUDE_DIR and LIB_DIR manually via:"
+  echo "R CMD INSTALL --configure-vars='INCLUDE_DIR=... LIB_DIR=...'"
+  echo "-------------------------- [ERROR MESSAGE] ---------------------------"
+  cat configure.log
+  echo "--------------------------------------------------------------------"
+  exit 1
+fi
+
+# Try to link against the correct OpenSSL version
+if [ -z "$AUTOBREW" ]; then
+SONAME=`${CC} -E ${PKG_CFLAGS} src/tests/soname.h | sh | xargs`
+if [ "$SONAME" ]; then
+if [ `uname` = "Darwin" ]; then
+  PKG_LIBS_VERSIONED=`echo "${PKG_LIBS}" | sed "s/-lssl/-lssl.${SONAME}/" | sed "s/-lcrypto/-lcrypto.${SONAME}/"`
+else
+  PKG_LIBS_VERSIONED=`echo "${PKG_LIBS}" | sed "s/-lssl/-l:libssl.so.${SONAME}/" | sed "s/-lcrypto/-l:libcrypto.so.${SONAME}/"`
+fi
+
+# Test if versioned linking works
+${CC} ${PKG_CFLAGS} src/tests/main.c ${PKG_LIBS_VERSIONED} -o src/main.exe 2>/dev/null
+if [ $? -eq 0 ]; then PKG_LIBS="${PKG_LIBS_VERSIONED}"; fi
+
+# Suppress opensslv3 warnings for now
+if [ "$SONAME" = "3" ]; then
+PKG_CFLAGS="$PKG_CFLAGS -DOPENSSL_SUPPRESS_DEPRECATED"
+fi
+
+fi #SONAME
+fi #AUTOBREW
+
+# Define system endianness (compile-time endianness using system/compiler
+# defines isn't detected on Solaris)
+# based on endian detection from the feather package by @hadley
+R_ENDIAN=`${R_HOME}/bin/Rscript -e 'cat(.Platform$endian)'`
+# Trim off any warning messages that Rscript appends in front of the platform endianness
+R_ENDIAN=`expr "$R_ENDIAN" : '.*\(little\)$'`
+SYS_ENDIAN=""
+if [ "$R_ENDIAN" = "little" ]; then
+    PKG_CFLAGS="$PKG_CFLAGS -DIS_LITTLE_ENDIAN"
+else
+    PKG_CFLAGS="$PKG_CFLAGS -DIS_BIG_ENDIAN"
+fi
+
+echo "Using PKG_LIBS=$PKG_LIBS"
+echo "Using PKG_CFLAGS=$PKG_CFLAGS"
+
+
+# Write to Makevars
+sed -e "s|@cflags@|$PKG_CFLAGS|" -e "s|@libs@|$PKG_LIBS|" src/Makevars.in > src/Makevars
+
+# Success
+exit 0
diff --git a/configure.win b/configure.win
new file mode 100755 (executable)
index 0000000..e69de29
diff --git a/data/s2_data_tbl_cities.rda b/data/s2_data_tbl_cities.rda
new file mode 100644 (file)
index 0000000..317ea50
Binary files /dev/null and b/data/s2_data_tbl_cities.rda differ
diff --git a/data/s2_data_tbl_countries.rda b/data/s2_data_tbl_countries.rda
new file mode 100644 (file)
index 0000000..a94b448
Binary files /dev/null and b/data/s2_data_tbl_countries.rda differ
diff --git a/data/s2_data_tbl_timezones.rda b/data/s2_data_tbl_timezones.rda
new file mode 100644 (file)
index 0000000..1d96a0b
Binary files /dev/null and b/data/s2_data_tbl_timezones.rda differ
diff --git a/inst/extdata/emptyfile b/inst/extdata/emptyfile
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/man/as_s2_geography.Rd b/man/as_s2_geography.Rd
new file mode 100644 (file)
index 0000000..729da5b
--- /dev/null
@@ -0,0 +1,77 @@
+% Generated by roxygen2: do not edit by hand
+% Please edit documentation in R/s2-geography.R
+\name{as_s2_geography}
+\alias{as_s2_geography}
+\alias{s2_geography}
+\alias{as_s2_geography.s2_geography}
+\alias{as_s2_geography.s2_lnglat}
+\alias{as_s2_geography.s2_point}
+\alias{as_s2_geography.wk_wkb}
+\alias{as_s2_geography.WKB}
+\alias{as_s2_geography.blob}
+\alias{as_s2_geography.wk_wkt}
+\alias{as_s2_geography.character}
+\alias{as_s2_geography.logical}
+\alias{as_wkb.s2_geography}
+\alias{as_wkt.s2_geography}
+\title{Create an S2 Geography Vector}
+\usage{
+as_s2_geography(x, ...)
+
+s2_geography()
+
+\method{as_s2_geography}{s2_geography}(x, ...)
+
+\method{as_s2_geography}{s2_lnglat}(x, ...)
+
+\method{as_s2_geography}{s2_point}(x, ...)
+
+\method{as_s2_geography}{wk_wkb}(x, ..., oriented = FALSE, check = TRUE)
+
+\method{as_s2_geography}{WKB}(x, ..., oriented = FALSE, check = TRUE)
+
+\method{as_s2_geography}{blob}(x, ..., oriented = FALSE, check = TRUE)
+
+\method{as_s2_geography}{wk_wkt}(x, ..., oriented = FALSE, check = TRUE)
+
+\method{as_s2_geography}{character}(x, ..., oriented = FALSE, check = TRUE)
+
+\method{as_s2_geography}{logical}(x, ...)
+
+\method{as_wkb}{s2_geography}(x, ...)
+
+\method{as_wkt}{s2_geography}(x, ...)
+}
+\arguments{
+\item{x}{An object that can be converted to an s2_geography vector}
+
+\item{...}{Unused}
+
+\item{oriented}{TRUE if polygon ring directions are known to be correct
+(i.e., exterior rings are defined counter clockwise and interior
+rings are defined clockwise).}
+
+\item{check}{Use \code{check = FALSE} to skip error on invalid geometries}
+}
+\value{
+An object with class s2_geography
+}
+\description{
+Geography vectors are arrays of points, lines, polygons, and/or collections
+of these. Geography vectors assume coordinates are longitude and latitude
+on a perfect sphere.
+}
+\details{
+The coercion function \code{\link[=as_s2_geography]{as_s2_geography()}} is used to wrap the input
+of most functions in the s2 package so that you can use other objects with
+an unambiguious interpretation as a geography vector. Geography vectors
+have a minimal \link[vctrs:vctrs-package]{vctrs} implementation, so you can
+use these objects in tibble, dplyr, and other packages that use the vctrs
+framework.
+}
+\seealso{
+\code{\link[=s2_geog_from_wkb]{s2_geog_from_wkb()}}, \code{\link[=s2_geog_from_text]{s2_geog_from_text()}}, \code{\link[=s2_geog_point]{s2_geog_point()}},
+\code{\link[=s2_make_line]{s2_make_line()}}, \code{\link[=s2_make_polygon]{s2_make_polygon()}} for other ways to
+create geography vectors, and \code{\link[=s2_as_binary]{s2_as_binary()}} and \code{\link[=s2_as_text]{s2_as_text()}}
+for other ways to export them.
+}
diff --git a/man/figures/rc300.png b/man/figures/rc300.png
new file mode 100644 (file)
index 0000000..cdb066a
Binary files /dev/null and b/man/figures/rc300.png differ
diff --git a/man/s2-package.Rd b/man/s2-package.Rd
new file mode 100644 (file)
index 0000000..db9b662
--- /dev/null
@@ -0,0 +1,41 @@
+% Generated by roxygen2: do not edit by hand
+% Please edit documentation in R/s2-package.R
+\docType{package}
+\name{s2-package}
+\alias{s2}
+\alias{s2-package}
+\title{s2: Spherical Geometry Operators Using the S2 Geometry Library}
+\description{
+Provides R bindings for Google's s2 library for geometric calculations on
+    the sphere. High-performance constructors and exporters provide high compatibility
+    with existing spatial packages, transformers construct new geometries from existing
+    geometries, predicates provide a means to select geometries based on spatial 
+    relationships, and accessors extract information about geometries.
+}
+\seealso{
+Useful links:
+\itemize{
+  \item \url{https://r-spatial.github.io/s2/}
+  \item \url{https://github.com/r-spatial/s2}
+  \item \url{https://s2geometry.io/}
+  \item Report bugs at \url{https://github.com/r-spatial/s2/issues}
+}
+
+}
+\author{
+\strong{Maintainer}: Edzer Pebesma \email{edzer.pebesma@uni-muenster.de} (\href{https://orcid.org/0000-0001-8049-7069}{ORCID})
+
+Authors:
+\itemize{
+  \item Dewey Dunnington \email{dewey@fishandwhistle.net} (\href{https://orcid.org/0000-0002-9415-4582}{ORCID})
+  \item Ege Rubak \email{rubak@math.aau.dk}
+}
+
+Other contributors:
+\itemize{
+  \item Jeroen Ooms \email{jeroen.ooms@stat.ucla.edu} (configure script) [contributor]
+  \item  Google, Inc. (Original s2geometry.io source code) [copyright holder]
+}
+
+}
+\keyword{internal}
diff --git a/man/s2_boundary.Rd b/man/s2_boundary.Rd
new file mode 100644 (file)
index 0000000..3222577
--- /dev/null
@@ -0,0 +1,196 @@
+% Generated by roxygen2: do not edit by hand
+% Please edit documentation in R/s2-transformers.R
+\name{s2_boundary}
+\alias{s2_boundary}
+\alias{s2_centroid}
+\alias{s2_closest_point}
+\alias{s2_minimum_clearance_line_between}
+\alias{s2_difference}
+\alias{s2_sym_difference}
+\alias{s2_intersection}
+\alias{s2_union}
+\alias{s2_snap_to_grid}
+\alias{s2_simplify}
+\alias{s2_rebuild}
+\alias{s2_buffer_cells}
+\alias{s2_centroid_agg}
+\alias{s2_coverage_union_agg}
+\alias{s2_rebuild_agg}
+\alias{s2_union_agg}
+\title{S2 Geography Transformations}
+\usage{
+s2_boundary(x)
+
+s2_centroid(x)
+
+s2_closest_point(x, y)
+
+s2_minimum_clearance_line_between(x, y)
+
+s2_difference(x, y, options = s2_options())
+
+s2_sym_difference(x, y, options = s2_options())
+
+s2_intersection(x, y, options = s2_options())
+
+s2_union(x, y = NULL, options = s2_options())
+
+s2_snap_to_grid(x, grid_size)
+
+s2_simplify(x, tolerance, radius = s2_earth_radius_meters())
+
+s2_rebuild(x, options = s2_options())
+
+s2_buffer_cells(
+  x,
+  distance,
+  max_cells = 1000,
+  min_level = -1,
+  radius = s2_earth_radius_meters()
+)
+
+s2_centroid_agg(x, na.rm = FALSE)
+
+s2_coverage_union_agg(x, options = s2_options(), na.rm = FALSE)
+
+s2_rebuild_agg(x, options = s2_options(), na.rm = FALSE)
+
+s2_union_agg(x, options = s2_options(), na.rm = FALSE)
+}
+\arguments{
+\item{x}{\link[=as_s2_geography]{geography vectors}. These inputs
+are passed to \code{\link[=as_s2_geography]{as_s2_geography()}}, so you can pass other objects
+(e.g., character vectors of well-known text) directly.}
+
+\item{y}{\link[=as_s2_geography]{geography vectors}. These inputs
+are passed to \code{\link[=as_s2_geography]{as_s2_geography()}}, so you can pass other objects
+(e.g., character vectors of well-known text) directly.}
+
+\item{options}{An \code{\link[=s2_options]{s2_options()}} object describing the polygon/polyline
+model to use and the snap level.}
+
+\item{grid_size}{The grid size to which coordinates should be snapped;
+will be rounded to the nearest power of 10.}
+
+\item{tolerance}{The minimum distance between vertexes to use when
+simplifying a geography.}
+
+\item{radius}{Radius of the earth. Defaults to the average radius of
+the earth in meters as defined by \code{\link[=s2_earth_radius_meters]{s2_earth_radius_meters()}}.}
+
+\item{distance}{The distance to buffer, in units of \code{radius}.}
+
+\item{max_cells}{The maximum number of cells to approximate a buffer.}
+
+\item{min_level}{The minimum cell level used to approximate a buffer
+(1 - 30). Setting this value too high will result in unnecessarily
+large geographies, but may help improve buffers along long, narrow
+regions.}
+
+\item{na.rm}{For aggregate calculations use \code{na.rm = TRUE}
+to drop missing values.}
+}
+\description{
+These functions operate on one or more geography vectors and
+return a geography vector.
+}
+\section{Model}{
+
+The geometry model indicates whether or not a geometry includes its boundaries.
+Boundaries of line geometries are its end points.
+OPEN geometries do not contain their boundary (\code{model = "open"}); CLOSED
+geometries (\code{model = "closed"}) contain their boundary; SEMI-OPEN geometries
+(\code{model = "semi-open"}) contain half of their boundaries, such that when two polygons
+do not overlap or two lines do not cross, no point exist that belong to
+more than one of the geometries. (This latter form, half-closed, is
+not present in the OpenGIS "simple feature access" (SFA) standard nor DE9-IM on
+which that is based). The default values for \code{\link[=s2_contains]{s2_contains()}} (open)
+and covers/covered_by (closed) correspond to the SFA standard specification
+of these operators.
+}
+
+\examples{
+# returns the boundary:
+# empty for point, endpoints of a linestring,
+# perimeter of a polygon
+s2_boundary("POINT (-64 45)")
+s2_boundary("LINESTRING (0 0, 10 0)")
+s2_boundary("POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0))")
+
+# returns the area-weighted centroid, element-wise
+s2_centroid("POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0))")
+s2_centroid("LINESTRING (0 0, 10 0)")
+
+# returns the unweighted centroid of the entire input
+s2_centroid_agg(c("POINT (0 0)", "POINT (10 0)"))
+
+# returns the closest point on x to y
+s2_closest_point(
+  "POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0))",
+  "POINT (0 90)" # north pole!
+)
+
+# returns the shortest possible line between x and y
+s2_minimum_clearance_line_between(
+  "POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0))",
+  "POINT (0 90)" # north pole!
+)
+
+# binary operations: difference, symmetric difference, intersection and union
+s2_difference(
+  "POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0))",
+  "POLYGON ((5 5, 15 5, 15 15, 5 15, 5 5))",
+  # 32 bit platforms may need to set snap rounding
+  s2_options(snap = s2_snap_level(30))
+)
+
+s2_sym_difference(
+  "POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0))",
+  "POLYGON ((5 5, 15 5, 15 15, 5 15, 5 5))",
+  # 32 bit platforms may need to set snap rounding
+  s2_options(snap = s2_snap_level(30))
+)
+
+s2_intersection(
+  "POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0))",
+  "POLYGON ((5 5, 15 5, 15 15, 5 15, 5 5))",
+  # 32 bit platforms may need to set snap rounding
+  s2_options(snap = s2_snap_level(30))
+)
+
+s2_union(
+  "POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0))",
+  "POLYGON ((5 5, 15 5, 15 15, 5 15, 5 5))",
+  # 32 bit platforms may need to set snap rounding
+  s2_options(snap = s2_snap_level(30))
+)
+
+# use s2_union_agg() to aggregate geographies in a vector
+s2_coverage_union_agg(
+  c(
+    "POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0))",
+    "POLYGON ((5 5, 15 5, 15 15, 5 15, 5 5))"
+  ),
+  # 32 bit platforms may need to set snap rounding
+  s2_options(snap = s2_snap_level(30))
+)
+
+# snap to grid rounds coordinates to a specified grid size
+s2_snap_to_grid("POINT (0.333333333333 0.666666666666)", 1e-2)
+
+}
+\seealso{
+BigQuery's geography function reference:
+\itemize{
+\item \href{https://cloud.google.com/bigquery/docs/reference/standard-sql/geography_functions#st_boundary}{ST_BOUNDARY}
+\item \href{https://cloud.google.com/bigquery/docs/reference/standard-sql/geography_functions#st_centroid}{ST_CENTROID}
+\item \href{https://cloud.google.com/bigquery/docs/reference/standard-sql/geography_functions#st_closestpoint}{ST_CLOSESTPOINT}
+\item \href{https://cloud.google.com/bigquery/docs/reference/standard-sql/geography_functions#st_difference}{ST_DIFFERENCE}
+\item \href{https://cloud.google.com/bigquery/docs/reference/standard-sql/geography_functions#st_intersection}{ST_INTERSECTION}
+\item \href{https://cloud.google.com/bigquery/docs/reference/standard-sql/geography_functions#st_union}{ST_UNION}
+\item \href{https://cloud.google.com/bigquery/docs/reference/standard-sql/geography_functions#st_snaptogrid}{ST_SNAPTOGRID}
+\item \href{https://cloud.google.com/bigquery/docs/reference/standard-sql/geography_functions#st_simplify}{ST_SIMPLIFY}
+\item \href{https://cloud.google.com/bigquery/docs/reference/standard-sql/geography_functions#st_union_agg}{ST_UNION_AGG}
+\item \href{https://cloud.google.com/bigquery/docs/reference/standard-sql/geography_functions#s2_centroid_agg}{ST_CENTROID_AGG}
+}
+}
diff --git a/man/s2_bounds_cap.Rd b/man/s2_bounds_cap.Rd
new file mode 100644 (file)
index 0000000..e4bd419
--- /dev/null
@@ -0,0 +1,41 @@
+% Generated by roxygen2: do not edit by hand
+% Please edit documentation in R/s2-bounds.R
+\name{s2_bounds_cap}
+\alias{s2_bounds_cap}
+\alias{s2_bounds_rect}
+\title{Compute feature-wise and aggregate bounds}
+\usage{
+s2_bounds_cap(x)
+
+s2_bounds_rect(x)
+}
+\arguments{
+\item{x}{\link[=as_s2_geography]{geography vectors}. These inputs
+are passed to \code{\link[=as_s2_geography]{as_s2_geography()}}, so you can pass other objects
+(e.g., character vectors of well-known text) directly.}
+}
+\value{
+Both functions return a \code{data.frame}:
+\itemize{
+\item \code{\link[=s2_bounds_rect]{s2_bounds_rect()}}: Columns \code{minlng}, \code{minlat}, \code{maxlng}, \code{maxlat} (degrees)
+\item \code{\link[=s2_bounds_cap]{s2_bounds_cap()}}: Columns \code{lng}, \code{lat}, \code{angle} (degrees)
+}
+}
+\description{
+\code{\link[=s2_bounds_rect]{s2_bounds_rect()}} returns a bounding latitude-longitude
+rectangle that contains the region; \code{\link[=s2_bounds_cap]{s2_bounds_cap()}} returns a bounding circle
+represented by a centre point (lat, lng) and an angle. The bound may not be tight
+for points, polylines and geometry collections. The rectangle returned may depend on
+the order of points or polylines. \code{lng_lo} values larger than \code{lng_hi} indicate
+regions that span the antimeridian, see the Fiji example.
+}
+\examples{
+s2_bounds_cap(s2_data_countries("Antarctica"))
+s2_bounds_cap(s2_data_countries("Netherlands"))
+s2_bounds_cap(s2_data_countries("Fiji"))
+
+s2_bounds_rect(s2_data_countries("Antarctica"))
+s2_bounds_rect(s2_data_countries("Netherlands"))
+s2_bounds_rect(s2_data_countries("Fiji"))
+
+}
diff --git a/man/s2_cell.Rd b/man/s2_cell.Rd
new file mode 100644 (file)
index 0000000..986389f
--- /dev/null
@@ -0,0 +1,77 @@
+% Generated by roxygen2: do not edit by hand
+% Please edit documentation in R/s2-cell.R
+\name{s2_cell}
+\alias{s2_cell}
+\alias{s2_cell_sentinel}
+\alias{s2_cell_invalid}
+\alias{as_s2_cell}
+\alias{as_s2_cell.s2_cell}
+\alias{as_s2_cell.character}
+\alias{as_s2_cell.s2_geography}
+\alias{as_s2_cell.s2_lnglat}
+\alias{as_s2_cell.s2_point}
+\alias{new_s2_cell}
+\title{Create S2 Cell vectors}
+\usage{
+s2_cell(x = character())
+
+s2_cell_sentinel()
+
+s2_cell_invalid()
+
+s2_cell_sentinel()
+
+as_s2_cell(x, ...)
+
+\method{as_s2_cell}{s2_cell}(x, ...)
+
+\method{as_s2_cell}{character}(x, ...)
+
+\method{as_s2_cell}{s2_geography}(x, ...)
+
+\method{as_s2_cell}{s2_lnglat}(x, ...)
+
+\method{as_s2_cell}{s2_point}(x, ...)
+
+new_s2_cell(x)
+}
+\arguments{
+\item{x}{The canonical S2 cell identifier as a character vector.}
+
+\item{...}{Passed to methods}
+}
+\value{
+An object of class s2_cell
+}
+\description{
+The S2 cell indexing system forms the basis for spatial indexing
+in the S2 library. On their own, S2 cells can represent points
+or areas. As a union, a vector of S2 cells can approximate a
+line or polygon. These functions allow direct access to the
+S2 cell indexing system and are designed to have minimal overhead
+such that looping and recursion have acceptable performance
+when used within R code.
+}
+\details{
+Under the hood, S2 cell vectors are represented in R as vectors
+of type \code{\link[=double]{double()}}. This works because S2 cell identifiers are
+64 bits wide, as are \code{double}s on all systems where R runs (The
+same trick is used by the bit64 package to represent signed
+64-bit integers). As a happy accident, \code{NA_real_} is not a valid
+or meaningful cell identifier, so missing value support in the
+way R users might expect is preserved. It is worth noting that
+the underlying value of \code{s2_cell_sentinel()} would normally be
+considered \code{NA}; however, as it is meaningful and useful when
+programming with S2 cells, custom \code{is.na()} and comparison methods
+are implemented such that \code{s2_cell_sentinel()} is greater than
+all valid S2 cells and not considered missing. Users can and should
+implement compiled code that uses the underlying bytes of the
+vector, ensuring that the class of any returned object that should
+be interpreted in this way is constructed with \code{new_s2_cell()}.
+}
+\examples{
+s2_cell("4b59a0cd83b5de49")
+as_s2_cell(s2_lnglat(-64, 45))
+as_s2_cell(s2_data_cities("Ottawa"))
+
+}
diff --git a/man/s2_cell_is_valid.Rd b/man/s2_cell_is_valid.Rd
new file mode 100644 (file)
index 0000000..93e3fc8
--- /dev/null
@@ -0,0 +1,74 @@
+% Generated by roxygen2: do not edit by hand
+% Please edit documentation in R/s2-cell.R
+\name{s2_cell_is_valid}
+\alias{s2_cell_is_valid}
+\alias{s2_cell_debug_string}
+\alias{s2_cell_to_lnglat}
+\alias{s2_cell_center}
+\alias{s2_cell_boundary}
+\alias{s2_cell_polygon}
+\alias{s2_cell_vertex}
+\alias{s2_cell_level}
+\alias{s2_cell_is_leaf}
+\alias{s2_cell_is_face}
+\alias{s2_cell_area}
+\alias{s2_cell_area_approx}
+\alias{s2_cell_parent}
+\alias{s2_cell_child}
+\alias{s2_cell_edge_neighbour}
+\alias{s2_cell_contains}
+\alias{s2_cell_distance}
+\alias{s2_cell_max_distance}
+\alias{s2_cell_may_intersect}
+\title{S2 cell operators}
+\usage{
+s2_cell_is_valid(x)
+
+s2_cell_debug_string(x)
+
+s2_cell_to_lnglat(x)
+
+s2_cell_center(x)
+
+s2_cell_boundary(x)
+
+s2_cell_polygon(x)
+
+s2_cell_vertex(x, k)
+
+s2_cell_level(x)
+
+s2_cell_is_leaf(x)
+
+s2_cell_is_face(x)
+
+s2_cell_area(x, radius = s2_earth_radius_meters())
+
+s2_cell_area_approx(x, radius = s2_earth_radius_meters())
+
+s2_cell_parent(x, level = -1L)
+
+s2_cell_child(x, k)
+
+s2_cell_edge_neighbour(x, k)
+
+s2_cell_contains(x, y)
+
+s2_cell_distance(x, y, radius = s2_earth_radius_meters())
+
+s2_cell_max_distance(x, y, radius = s2_earth_radius_meters())
+
+s2_cell_may_intersect(x, y)
+}
+\arguments{
+\item{x, y}{An \code{\link[=s2_cell]{s2_cell()}} vector}
+
+\item{k}{An integer between 1 and 4}
+
+\item{radius}{The radius to use (e.g., \code{\link[=s2_earth_radius_meters]{s2_earth_radius_meters()}})}
+
+\item{level}{An integer between 0 and 30, inclusive.}
+}
+\description{
+S2 cell operators
+}
diff --git a/man/s2_closest_feature.Rd b/man/s2_closest_feature.Rd
new file mode 100644 (file)
index 0000000..9d613d1
--- /dev/null
@@ -0,0 +1,122 @@
+% Generated by roxygen2: do not edit by hand
+% Please edit documentation in R/s2-matrix.R
+\name{s2_closest_feature}
+\alias{s2_closest_feature}
+\alias{s2_closest_edges}
+\alias{s2_farthest_feature}
+\alias{s2_distance_matrix}
+\alias{s2_max_distance_matrix}
+\alias{s2_contains_matrix}
+\alias{s2_within_matrix}
+\alias{s2_covers_matrix}
+\alias{s2_covered_by_matrix}
+\alias{s2_intersects_matrix}
+\alias{s2_disjoint_matrix}
+\alias{s2_equals_matrix}
+\alias{s2_touches_matrix}
+\alias{s2_dwithin_matrix}
+\alias{s2_may_intersect_matrix}
+\title{Matrix Functions}
+\usage{
+s2_closest_feature(x, y)
+
+s2_closest_edges(x, y, k, min_distance = -1, radius = s2_earth_radius_meters())
+
+s2_farthest_feature(x, y)
+
+s2_distance_matrix(x, y, radius = s2_earth_radius_meters())
+
+s2_max_distance_matrix(x, y, radius = s2_earth_radius_meters())
+
+s2_contains_matrix(x, y, options = s2_options(model = "open"))
+
+s2_within_matrix(x, y, options = s2_options(model = "open"))
+
+s2_covers_matrix(x, y, options = s2_options(model = "closed"))
+
+s2_covered_by_matrix(x, y, options = s2_options(model = "closed"))
+
+s2_intersects_matrix(x, y, options = s2_options())
+
+s2_disjoint_matrix(x, y, options = s2_options())
+
+s2_equals_matrix(x, y, options = s2_options())
+
+s2_touches_matrix(x, y, options = s2_options())
+
+s2_dwithin_matrix(x, y, distance, radius = s2_earth_radius_meters())
+
+s2_may_intersect_matrix(x, y, max_edges_per_cell = 50, max_feature_cells = 4)
+}
+\arguments{
+\item{x, y}{Geography vectors, coerced using \code{\link[=as_s2_geography]{as_s2_geography()}}.
+\code{x} is considered the source, where as \code{y} is considered the target.}
+
+\item{k}{The number of closest edges to consider when searching. Note
+that in S2 a point is also considered an edge.}
+
+\item{min_distance}{The minimum distance to consider when searching for
+edges. This filter is applied after the search is complete (i.e.,
+may cause fewer than \code{k} values to be returned).}
+
+\item{radius}{Radius of the earth. Defaults to the average radius of
+the earth in meters as defined by \code{\link[=s2_earth_radius_meters]{s2_earth_radius_meters()}}.}
+
+\item{options}{An \code{\link[=s2_options]{s2_options()}} object describing the polygon/polyline
+model to use and the snap level.}
+
+\item{distance}{A distance on the surface of the earth in the same units
+as \code{radius}.}
+
+\item{max_edges_per_cell}{For \code{\link[=s2_may_intersect_matrix]{s2_may_intersect_matrix()}},
+this values controls the nature of the index on \code{y}, with higher values
+leading to coarser index. Values should be between 10 and 50; the default
+of 50 is adequate for most use cases, but for specialized operations users
+may wish to use a lower value to increase performance.}
+
+\item{max_feature_cells}{For \code{\link[=s2_may_intersect_matrix]{s2_may_intersect_matrix()}}, this value
+controls the approximation of \code{x} used to identify potential intersections
+on \code{y}. The default value of 4 gives the best performance for most operations,
+but for specialized operations users may wish to use a higher value to increase
+performance.}
+}
+\value{
+A vector of length \code{x}.
+}
+\description{
+These functions are similar to accessors and predicates, but instead of
+recycling \code{x} and \code{y} to a common length and returning a vector of that
+length, these functions return a vector of length \code{x} with each element
+\code{i} containing information about how the entire vector \code{y} relates to
+the feature at \code{x[i]}.
+}
+\examples{
+city_names <- c("Vatican City", "San Marino", "Luxembourg")
+cities <- s2_data_cities(city_names)
+country_names <- s2_data_tbl_countries$name
+countries <- s2_data_countries()
+
+# closest feature returns y indices of the closest feature
+# for each feature in x
+country_names[s2_closest_feature(cities, countries)]
+
+# farthest feature returns y indices of the farthest feature
+# for each feature in x
+country_names[s2_farthest_feature(cities, countries)]
+
+# use s2_closest_edges() to find the k-nearest neighbours
+nearest <- s2_closest_edges(cities, cities, k = 2, min_distance = 0)
+city_names
+city_names[unlist(nearest)]
+
+# predicate matrices
+country_names[s2_intersects_matrix(cities, countries)[[1]]]
+
+# distance matrices
+s2_distance_matrix(cities, cities)
+s2_max_distance_matrix(cities, countries[1:4])
+
+}
+\seealso{
+See pairwise predicate functions (e.g., \code{\link[=s2_intersects]{s2_intersects()}}).
+}
diff --git a/man/s2_contains.Rd b/man/s2_contains.Rd
new file mode 100644 (file)
index 0000000..8bfc9bd
--- /dev/null
@@ -0,0 +1,170 @@
+% Generated by roxygen2: do not edit by hand
+% Please edit documentation in R/s2-predicates.R
+\name{s2_contains}
+\alias{s2_contains}
+\alias{s2_within}
+\alias{s2_covered_by}
+\alias{s2_covers}
+\alias{s2_disjoint}
+\alias{s2_intersects}
+\alias{s2_equals}
+\alias{s2_intersects_box}
+\alias{s2_touches}
+\alias{s2_dwithin}
+\title{S2 Geography Predicates}
+\usage{
+s2_contains(x, y, options = s2_options(model = "open"))
+
+s2_within(x, y, options = s2_options(model = "open"))
+
+s2_covered_by(x, y, options = s2_options(model = "closed"))
+
+s2_covers(x, y, options = s2_options(model = "closed"))
+
+s2_disjoint(x, y, options = s2_options())
+
+s2_intersects(x, y, options = s2_options())
+
+s2_equals(x, y, options = s2_options())
+
+s2_intersects_box(
+  x,
+  lng1,
+  lat1,
+  lng2,
+  lat2,
+  detail = 1000,
+  options = s2_options()
+)
+
+s2_touches(x, y, options = s2_options())
+
+s2_dwithin(x, y, distance, radius = s2_earth_radius_meters())
+}
+\arguments{
+\item{x}{\link[=as_s2_geography]{geography vectors}. These inputs
+are passed to \code{\link[=as_s2_geography]{as_s2_geography()}}, so you can pass other objects
+(e.g., character vectors of well-known text) directly.}
+
+\item{y}{\link[=as_s2_geography]{geography vectors}. These inputs
+are passed to \code{\link[=as_s2_geography]{as_s2_geography()}}, so you can pass other objects
+(e.g., character vectors of well-known text) directly.}
+
+\item{options}{An \code{\link[=s2_options]{s2_options()}} object describing the polygon/polyline
+model to use and the snap level.}
+
+\item{lng1, lat1, lng2, lat2}{A latitude/longitude range}
+
+\item{detail}{The number of points with which to approximate
+non-geodesic edges.}
+
+\item{distance}{A distance on the surface of the earth in the same units
+as \code{radius}.}
+
+\item{radius}{Radius of the earth. Defaults to the average radius of
+the earth in meters as defined by \code{\link[=s2_earth_radius_meters]{s2_earth_radius_meters()}}.}
+}
+\description{
+These functions operate two geography vectors (pairwise), and return
+a logical vector.
+}
+\section{Model}{
+
+The geometry model indicates whether or not a geometry includes its boundaries.
+Boundaries of line geometries are its end points.
+OPEN geometries do not contain their boundary (\code{model = "open"}); CLOSED
+geometries (\code{model = "closed"}) contain their boundary; SEMI-OPEN geometries
+(\code{model = "semi-open"}) contain half of their boundaries, such that when two polygons
+do not overlap or two lines do not cross, no point exist that belong to
+more than one of the geometries. (This latter form, half-closed, is
+not present in the OpenGIS "simple feature access" (SFA) standard nor DE9-IM on
+which that is based). The default values for \code{\link[=s2_contains]{s2_contains()}} (open)
+and covers/covered_by (closed) correspond to the SFA standard specification
+of these operators.
+}
+
+\examples{
+s2_contains(
+  "POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0))",
+  c("POINT (5 5)", "POINT (-1 1)")
+)
+
+s2_within(
+  c("POINT (5 5)", "POINT (-1 1)"),
+  "POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0))"
+)
+
+s2_covered_by(
+  "POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0))",
+  c("POINT (5 5)", "POINT (-1 1)")
+)
+
+s2_covers(
+  "POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0))",
+  c("POINT (5 5)", "POINT (-1 1)")
+)
+
+s2_disjoint(
+  "POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0))",
+  c("POINT (5 5)", "POINT (-1 1)")
+)
+
+s2_intersects(
+  "POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0))",
+  c("POINT (5 5)", "POINT (-1 1)")
+)
+
+s2_equals(
+  "POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0))",
+  c(
+    "POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0))",
+    "POLYGON ((10 0, 10 10, 0 10, 0 0, 10 0))",
+    "POLYGON ((-1 -1, 10 0, 10 10, 0 10, -1 -1))"
+  )
+)
+
+s2_intersects(
+  "POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0))",
+  c("POINT (5 5)", "POINT (-1 1)")
+)
+
+s2_intersects_box(
+  c("POINT (5 5)", "POINT (-1 1)"),
+  0, 0, 10, 10
+)
+
+s2_touches(
+  "POLYGON ((0 0, 0 1, 1 1, 0 0))",
+  c("POINT (0 0)", "POINT (0.5 0.75)", "POINT (0 0.5)")
+)
+
+s2_dwithin(
+  "POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0))",
+  c("POINT (5 5)", "POINT (-1 1)"),
+  0 # distance in meters
+)
+
+s2_dwithin(
+  "POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0))",
+  c("POINT (5 5)", "POINT (-1 1)"),
+  1e6 # distance in meters
+)
+
+}
+\seealso{
+Matrix versions of these predicates (e.g., \code{\link[=s2_intersects_matrix]{s2_intersects_matrix()}}).
+
+BigQuery's geography function reference:
+\itemize{
+\item \href{https://cloud.google.com/bigquery/docs/reference/standard-sql/geography_functions#st_contains}{ST_CONTAINS}
+\item \href{https://cloud.google.com/bigquery/docs/reference/standard-sql/geography_functions#st_coveredby}{ST_COVEREDBY}
+\item \href{https://cloud.google.com/bigquery/docs/reference/standard-sql/geography_functions#st_covers}{ST_COVERS}
+\item \href{https://cloud.google.com/bigquery/docs/reference/standard-sql/geography_functions#st_disjoint}{ST_DISJOINT}
+\item \href{https://cloud.google.com/bigquery/docs/reference/standard-sql/geography_functions#st_equals}{ST_EQUALS}
+\item \href{https://cloud.google.com/bigquery/docs/reference/standard-sql/geography_functions#st_intersects}{ST_INTERSECTS}
+\item \href{https://cloud.google.com/bigquery/docs/reference/standard-sql/geography_functions#st_intersectsbox}{ST_INTERSECTSBOX}
+\item \href{https://cloud.google.com/bigquery/docs/reference/standard-sql/geography_functions#st_touches}{ST_TOUCHES}
+\item \href{https://cloud.google.com/bigquery/docs/reference/standard-sql/geography_functions#st_within}{ST_WITHIN}
+\item \href{https://cloud.google.com/bigquery/docs/reference/standard-sql/geography_functions#st_dwithin}{ST_DWITHIN}
+}
+}
diff --git a/man/s2_data_tbl_countries.Rd b/man/s2_data_tbl_countries.Rd
new file mode 100644 (file)
index 0000000..a2a6ce8
--- /dev/null
@@ -0,0 +1,59 @@
+% Generated by roxygen2: do not edit by hand
+% Please edit documentation in R/data.R
+\docType{data}
+\name{s2_data_tbl_countries}
+\alias{s2_data_tbl_countries}
+\alias{s2_data_tbl_timezones}
+\alias{s2_data_tbl_cities}
+\alias{s2_data_countries}
+\alias{s2_data_timezones}
+\alias{s2_data_cities}
+\title{Low-resolution world boundaries, timezones, and cities}
+\format{
+A data.frame with columns \code{name} (character), and
+\code{geometry} (wk_wkb)
+
+An object of class \code{data.frame} with 120 rows and 2 columns.
+
+An object of class \code{data.frame} with 243 rows and 3 columns.
+}
+\source{
+\href{https://www.naturalearthdata.com/}{Natural Earth Data}
+}
+\usage{
+s2_data_tbl_countries
+
+s2_data_tbl_timezones
+
+s2_data_tbl_cities
+
+s2_data_countries(name = NULL)
+
+s2_data_timezones(utc_offset_min = NULL, utc_offset_max = utc_offset_min)
+
+s2_data_cities(name = NULL)
+}
+\arguments{
+\item{name}{The name of a country, continent, city, or \code{NULL}
+for all features.}
+
+\item{utc_offset_min, utc_offset_max}{Minimum and/or maximum timezone
+offsets.}
+}
+\description{
+Well-known binary versions of the \href{https://www.naturalearthdata.com/}{Natural Earth}
+low-resolution world boundaries and timezone boundaries.
+}
+\examples{
+head(s2_data_countries())
+s2_data_countries("Germany")
+s2_data_countries("Europe")
+
+head(s2_data_timezones())
+s2_data_timezones(-4)
+
+head(s2_data_cities())
+s2_data_cities("Cairo")
+
+}
+\keyword{datasets}
diff --git a/man/s2_earth_radius_meters.Rd b/man/s2_earth_radius_meters.Rd
new file mode 100644 (file)
index 0000000..249e411
--- /dev/null
@@ -0,0 +1,25 @@
+% Generated by roxygen2: do not edit by hand
+% Please edit documentation in R/s2-earth.R
+\name{s2_earth_radius_meters}
+\alias{s2_earth_radius_meters}
+\title{Earth Constants}
+\usage{
+s2_earth_radius_meters()
+}
+\description{
+According to Yoder (1995), the radius of the earth is
+6371.01 km. These functions are used to set the
+default radis for functions that return a distance
+or accept a distance as input
+(e.g., \code{\link[=s2_distance]{s2_distance()}} and \code{\link[=s2_dwithin]{s2_dwithin()}}).
+}
+\examples{
+s2_earth_radius_meters()
+
+}
+\references{
+Yoder, C.F. 1995. "Astrometric and Geodetic Properties of Earth and the
+Solar System" in Global Earth Physics, A Handbook of Physical Constants,
+AGU Reference Shelf 1, American Geophysical Union, Table 2.
+\doi{10.1029/RF001p0001}
+}
diff --git a/man/s2_geog_point.Rd b/man/s2_geog_point.Rd
new file mode 100644 (file)
index 0000000..ef89748
--- /dev/null
@@ -0,0 +1,117 @@
+% Generated by roxygen2: do not edit by hand
+% Please edit documentation in R/s2-constructors-formatters.R
+\name{s2_geog_point}
+\alias{s2_geog_point}
+\alias{s2_make_line}
+\alias{s2_make_polygon}
+\alias{s2_geog_from_text}
+\alias{s2_geog_from_wkb}
+\alias{s2_as_text}
+\alias{s2_as_binary}
+\title{Create and Format Geography Vectors}
+\usage{
+s2_geog_point(longitude, latitude)
+
+s2_make_line(longitude, latitude, feature_id = 1L)
+
+s2_make_polygon(
+  longitude,
+  latitude,
+  feature_id = 1L,
+  ring_id = 1L,
+  oriented = FALSE,
+  check = TRUE
+)
+
+s2_geog_from_text(wkt_string, oriented = FALSE, check = TRUE)
+
+s2_geog_from_wkb(wkb_bytes, oriented = FALSE, check = TRUE)
+
+s2_as_text(x, precision = 16, trim = TRUE)
+
+s2_as_binary(x, endian = wk::wk_platform_endian())
+}
+\arguments{
+\item{longitude, latitude}{Vectors of latitude and longitude}
+
+\item{feature_id, ring_id}{Vectors for which a change in
+sequential values indicates a new feature or ring. Use \code{\link[=factor]{factor()}}
+to convert from a character vector.}
+
+\item{oriented}{TRUE if polygon ring directions are known to be correct
+(i.e., exterior rings are defined counter clockwise and interior
+rings are defined clockwise).}
+
+\item{check}{Use \code{check = FALSE} to skip error on invalid geometries}
+
+\item{wkt_string}{Well-known text}
+
+\item{wkb_bytes}{A \code{list()} of \code{raw()}}
+
+\item{x}{\link[=as_s2_geography]{geography vectors}. These inputs
+are passed to \code{\link[=as_s2_geography]{as_s2_geography()}}, so you can pass other objects
+(e.g., character vectors of well-known text) directly.}
+
+\item{precision}{The number of significant digits to export when
+writing well-known text. If \code{trim = FALSE}, the number of
+digits after the decimal place.}
+
+\item{trim}{Should trailing zeroes be included after the decimal place?}
+
+\item{endian}{The endian-ness of the well-known binary. See \code{\link[wk:deprecated]{wk::wkb_translate_wkb()}}.}
+}
+\description{
+These functions create and export \link[=as_s2_geography]{geography vectors}.
+Unlike the BigQuery geography constructors, these functions do not sanitize
+invalid or redundant input using \code{\link[=s2_union]{s2_union()}}. Note that when creating polygons
+using \code{\link[=s2_make_polygon]{s2_make_polygon()}}, rings can be open or closed.
+}
+\examples{
+# create point geographies using coordinate values:
+s2_geog_point(-64, 45)
+
+# create line geographies using coordinate values:
+s2_make_line(c(-64, 8), c(45, 71))
+
+# optionally, separate features using feature_id:
+s2_make_line(
+  c(-64, 8, -27, -27), c(45, 71, 0, 45),
+  feature_id = c(1, 1, 2, 2)
+)
+
+# create polygon geographies using coordinate values:
+# (rings can be open or closed)
+s2_make_polygon(c(-45, 8, 0), c(64, 71, 90))
+
+# optionally, separate rings and/or features using
+# ring_id and/or feature_id
+s2_make_polygon(
+  c(20, 10, 10, 30, 45, 30, 20, 20, 40, 20, 45),
+  c(35, 30, 10, 5, 20, 20, 15, 25, 40, 45, 30),
+  feature_id = c(rep(1, 8), rep(2, 3)),
+  ring_id = c(1, 1, 1, 1, 1, 2, 2, 2, 1, 1, 1)
+)
+
+# import and export well-known text
+(geog <- s2_geog_from_text("POINT (-64 45)"))
+s2_as_text(geog)
+
+# import and export well-known binary
+(geog <- s2_geog_from_wkb(wk::as_wkb("POINT (-64 45)")))
+s2_as_binary(geog)
+
+}
+\seealso{
+See \code{\link[=as_s2_geography]{as_s2_geography()}} for other ways to construct geography vectors.
+
+BigQuery's geography function reference:
+\itemize{
+\item \href{https://cloud.google.com/bigquery/docs/reference/standard-sql/geography_functions#st_geogpoint}{ST_GEOGPOINT}
+\item \href{https://cloud.google.com/bigquery/docs/reference/standard-sql/geography_functions#st_makeline}{ST_MAKELINE}
+\item \href{https://cloud.google.com/bigquery/docs/reference/standard-sql/geography_functions#st_makepolygon}{ST_MAKEPOLYGON}
+\item \href{https://cloud.google.com/bigquery/docs/reference/standard-sql/geography_functions#st_geogfromtext}{ST_GEOGFROMTEXT}
+\item \href{https://cloud.google.com/bigquery/docs/reference/standard-sql/geography_functions#st_geogfromwkb}{ST_GEOGFROMWKB}
+\item \href{https://cloud.google.com/bigquery/docs/reference/standard-sql/geography_functions#st_astext}{ST_ASTEXT}
+\item \href{https://cloud.google.com/bigquery/docs/reference/standard-sql/geography_functions#st_asbinary}{ST_ASBINARY}
+}
+}
diff --git a/man/s2_interpolate.Rd b/man/s2_interpolate.Rd
new file mode 100644 (file)
index 0000000..f59eb83
--- /dev/null
@@ -0,0 +1,53 @@
+% Generated by roxygen2: do not edit by hand
+% Please edit documentation in R/s2-accessors.R, R/s2-transformers.R
+\name{s2_project}
+\alias{s2_project}
+\alias{s2_project_normalized}
+\alias{s2_interpolate}
+\alias{s2_interpolate_normalized}
+\title{Linear referencing}
+\usage{
+s2_project(x, y, radius = s2_earth_radius_meters())
+
+s2_project_normalized(x, y)
+
+s2_interpolate(x, distance, radius = s2_earth_radius_meters())
+
+s2_interpolate_normalized(x, distance_normalized)
+}
+\arguments{
+\item{x}{A simple polyline geography vector}
+
+\item{y}{A simple point geography vector. The point will be
+snapped to the nearest point on \code{x} for the purposes of
+interpolation.}
+
+\item{radius}{Radius of the earth. Defaults to the average radius of
+the earth in meters as defined by \code{\link[=s2_earth_radius_meters]{s2_earth_radius_meters()}}.}
+
+\item{distance}{A distance along \code{x} in \code{radius} units.}
+
+\item{distance_normalized}{A \code{distance} normalized to \code{\link[=s2_length]{s2_length()}} of
+\code{x}.}
+}
+\value{
+\itemize{
+\item \code{s2_interpolate()} returns the point on \code{x}, \code{distance} meters
+along the line.
+\item \code{s2_interpolate_normalized()} returns the point on \code{x} interpolated
+to a fraction along the line.
+\item \code{s2_project()} returns the \code{distance} that \code{point} occurs along \code{x}.
+\item \code{s2_project_normalized()} returns the \code{distance_normalized} along \code{x}
+where \code{point} occurs.
+}
+}
+\description{
+Linear referencing
+}
+\examples{
+s2_project_normalized("LINESTRING (0 0, 0 90)", "POINT (0 22.5)")
+s2_project("LINESTRING (0 0, 0 90)", "POINT (0 22.5)")
+s2_interpolate_normalized("LINESTRING (0 0, 0 90)", 0.25)
+s2_interpolate("LINESTRING (0 0, 0 90)", 2501890)
+
+}
diff --git a/man/s2_is_collection.Rd b/man/s2_is_collection.Rd
new file mode 100644 (file)
index 0000000..bec93c0
--- /dev/null
@@ -0,0 +1,112 @@
+% Generated by roxygen2: do not edit by hand
+% Please edit documentation in R/s2-accessors.R
+\name{s2_is_collection}
+\alias{s2_is_collection}
+\alias{s2_is_valid}
+\alias{s2_is_valid_detail}
+\alias{s2_dimension}
+\alias{s2_num_points}
+\alias{s2_is_empty}
+\alias{s2_area}
+\alias{s2_length}
+\alias{s2_perimeter}
+\alias{s2_x}
+\alias{s2_y}
+\alias{s2_distance}
+\alias{s2_max_distance}
+\title{S2 Geography Accessors}
+\usage{
+s2_is_collection(x)
+
+s2_is_valid(x)
+
+s2_is_valid_detail(x)
+
+s2_dimension(x)
+
+s2_num_points(x)
+
+s2_is_empty(x)
+
+s2_area(x, radius = s2_earth_radius_meters())
+
+s2_length(x, radius = s2_earth_radius_meters())
+
+s2_perimeter(x, radius = s2_earth_radius_meters())
+
+s2_x(x)
+
+s2_y(x)
+
+s2_distance(x, y, radius = s2_earth_radius_meters())
+
+s2_max_distance(x, y, radius = s2_earth_radius_meters())
+}
+\arguments{
+\item{x, y}{\link[=as_s2_geography]{geography vectors}. These inputs
+are passed to \code{\link[=as_s2_geography]{as_s2_geography()}}, so you can pass other objects
+(e.g., character vectors of well-known text) directly.}
+
+\item{radius}{Radius of the earth. Defaults to the average radius of
+the earth in meters as defined by \code{\link[=s2_earth_radius_meters]{s2_earth_radius_meters()}}.}
+}
+\description{
+Accessors extract information about \link[=as_s2_geography]{geography vectors}.
+}
+\examples{
+# s2_is_collection() tests for multiple geometries in one feature
+s2_is_collection(c("POINT (-64 45)", "MULTIPOINT ((-64 45), (8 72))"))
+
+# s2_dimension() returns 0 for point, 1  for line, 2 for polygon
+s2_dimension(
+  c(
+    "GEOMETRYCOLLECTION EMPTY",
+    "POINT (-64 45)",
+    "LINESTRING (-64 45, 8 72)",
+    "POLYGON ((0 0, 0 10, 10 10, 10 0, 0 0))",
+    "GEOMETRYCOLLECTION (POINT (-64 45), LINESTRING (-64 45, 8 72))"
+   )
+)
+
+# s2_num_points() counts points
+s2_num_points(c("POINT (-64 45)", "LINESTRING (-64 45, 8 72)"))
+
+# s2_is_empty tests for emptiness
+s2_is_empty(c("POINT (-64 45)", "POINT EMPTY"))
+
+# calculate area, length, and perimeter
+s2_area("POLYGON ((0 0, 0 10, 10 10, 10 0, 0 0))")
+s2_perimeter("POLYGON ((0 0, 0 10, 10 10, 10 0, 0 0))")
+s2_length(s2_boundary("POLYGON ((0 0, 0 10, 10 10, 10 0, 0 0))"))
+
+# extract x and y coordinates from points
+s2_x(c("POINT (-64 45)", "POINT EMPTY"))
+s2_y(c("POINT (-64 45)", "POINT EMPTY"))
+
+# calculate minimum and maximum distance between two geometries
+s2_distance(
+  "POLYGON ((0 0, 0 10, 10 10, 10 0, 0 0))",
+  "POINT (-64 45)"
+)
+s2_max_distance(
+  "POLYGON ((0 0, 0 10, 10 10, 10 0, 0 0))",
+  "POINT (-64 45)"
+)
+
+}
+\seealso{
+BigQuery's geography function reference:
+\itemize{
+\item \href{https://cloud.google.com/bigquery/docs/reference/standard-sql/geography_functions#st_iscollection}{ST_ISCOLLECTION}
+\item \href{https://cloud.google.com/bigquery/docs/reference/standard-sql/geography_functions#st_dimension}{ST_DIMENSION}
+\item \href{https://cloud.google.com/bigquery/docs/reference/standard-sql/geography_functions#st_numpoints}{ST_NUMPOINTS}
+\item \href{https://cloud.google.com/bigquery/docs/reference/standard-sql/geography_functions#st_isempty}{ST_ISEMPTY}
+\item \href{https://cloud.google.com/bigquery/docs/reference/standard-sql/geography_functions#st_area}{ST_AREA}
+\item \href{https://cloud.google.com/bigquery/docs/reference/standard-sql/geography_functions#st_length}{ST_LENGTH}
+\item \href{https://cloud.google.com/bigquery/docs/reference/standard-sql/geography_functions#st_perimeter}{ST_PERIMETER}
+\item \href{https://cloud.google.com/bigquery/docs/reference/standard-sql/geography_functions#st_x}{ST_X}
+\item \href{https://cloud.google.com/bigquery/docs/reference/standard-sql/geography_functions#st_y}{ST_Y}
+\item \href{https://cloud.google.com/bigquery/docs/reference/standard-sql/geography_functions#st_distance}{ST_DISTANCE}
+\item \href{https://cloud.google.com/bigquery/docs/reference/standard-sql/geography_functions#st_maxdistance}{ST_MAXDISTANCE}
+}
+}
diff --git a/man/s2_lnglat.Rd b/man/s2_lnglat.Rd
new file mode 100644 (file)
index 0000000..5ba9cca
--- /dev/null
@@ -0,0 +1,55 @@
+% Generated by roxygen2: do not edit by hand
+% Please edit documentation in R/s2-lnglat.R
+\name{s2_lnglat}
+\alias{s2_lnglat}
+\alias{as_s2_lnglat}
+\alias{as_s2_lnglat.s2_lnglat}
+\alias{as_s2_lnglat.s2_point}
+\alias{as_s2_lnglat.s2_geography}
+\alias{as_s2_lnglat.matrix}
+\alias{as.data.frame.s2_lnglat}
+\alias{as.matrix.s2_lnglat}
+\alias{as_wkb.s2_lnglat}
+\alias{as_wkt.s2_lnglat}
+\title{Create an S2 LngLat Vector}
+\usage{
+s2_lnglat(lng, lat)
+
+as_s2_lnglat(x, ...)
+
+\method{as_s2_lnglat}{s2_lnglat}(x, ...)
+
+\method{as_s2_lnglat}{s2_point}(x, ...)
+
+\method{as_s2_lnglat}{s2_geography}(x, ...)
+
+\method{as_s2_lnglat}{matrix}(x, ...)
+
+\method{as.data.frame}{s2_lnglat}(x, ...)
+
+\method{as.matrix}{s2_lnglat}(x, ...)
+
+\method{as_wkb}{s2_lnglat}(x, ...)
+
+\method{as_wkt}{s2_lnglat}(x, ...)
+}
+\arguments{
+\item{lat, lng}{Vectors of latitude and longitude values in degrees.}
+
+\item{x}{A \code{\link[=s2_lnglat]{s2_lnglat()}} vector or an object that can be coerced to one.}
+
+\item{...}{Unused}
+}
+\value{
+An object with class s2_lnglat
+}
+\description{
+This class represents a latitude and longitude on the Earth's surface.
+Most calculations in S2 convert this to a \code{\link[=as_s2_point]{as_s2_point()}}, which is a
+unit vector representation of this value.
+}
+\examples{
+s2_lnglat(45, -64) # Halifax, Nova Scotia!
+as.data.frame(s2_lnglat(45, -64))
+
+}
diff --git a/man/s2_options.Rd b/man/s2_options.Rd
new file mode 100644 (file)
index 0000000..d1b4865
--- /dev/null
@@ -0,0 +1,109 @@
+% Generated by roxygen2: do not edit by hand
+% Please edit documentation in R/s2-options.R
+\name{s2_options}
+\alias{s2_options}
+\alias{s2_snap_identity}
+\alias{s2_snap_level}
+\alias{s2_snap_precision}
+\alias{s2_snap_distance}
+\title{Geography Operation Options}
+\usage{
+s2_options(
+  model = NULL,
+  snap = s2_snap_identity(),
+  snap_radius = -1,
+  duplicate_edges = FALSE,
+  edge_type = "directed",
+  validate = FALSE,
+  polyline_type = "path",
+  polyline_sibling_pairs = "keep",
+  simplify_edge_chains = FALSE,
+  split_crossing_edges = FALSE,
+  idempotent = FALSE,
+  dimensions = c("point", "polyline", "polygon")
+)
+
+s2_snap_identity()
+
+s2_snap_level(level)
+
+s2_snap_precision(precision)
+
+s2_snap_distance(distance)
+}
+\arguments{
+\item{model}{One of 'open', 'semi-open' (default for polygons),
+or 'closed' (default for polylines). See section 'Model'}
+
+\item{snap}{Use \code{s2_snap_identity()}, \code{s2_snap_distance()}, \code{s2_snap_level()},
+or \code{s2_snap_precision()} to specify how or if coordinate rounding should
+occur.}
+
+\item{snap_radius}{As opposed to the snap function, which specifies
+the maximum distance a vertex should move, the snap radius (in radians) sets
+the minimum distance between vertices of the output that don't cause vertices
+to move more than the distance specified by the snap function. This can be used
+to simplify the result of a boolean operation. Use -1 to specify that any
+minimum distance is acceptable.}
+
+\item{duplicate_edges}{Use \code{TRUE} to keep duplicate edges (e.g., duplicate
+points).}
+
+\item{edge_type}{One of 'directed' (default) or 'undirected'.}
+
+\item{validate}{Use \code{TRUE} to validate the result from the builder.}
+
+\item{polyline_type}{One of 'path' (default) or 'walk'. If 'walk',
+polylines that backtrack are preserved.}
+
+\item{polyline_sibling_pairs}{One of 'discard' (default) or 'keep'.}
+
+\item{simplify_edge_chains}{Use \code{TRUE} to remove vertices that are within
+\code{snap_radius} of the original vertex.}
+
+\item{split_crossing_edges}{Use \code{TRUE} to split crossing polyline edges
+when creating geometries.}
+
+\item{idempotent}{Use \code{FALSE} to apply snap even if snapping is not necessary
+to satisfy vertex constraints.}
+
+\item{dimensions}{A combination of 'point', 'polyline', and/or 'polygon'
+that can used to constrain the output of \code{\link[=s2_rebuild]{s2_rebuild()}} or a
+boolean operation.}
+
+\item{level}{A value from 0 to 30 corresponding to the cell level
+at which snapping should occur.}
+
+\item{precision}{A number by which coordinates should be multiplied
+before being rounded. Rounded to the nearest exponent of 10.}
+
+\item{distance}{A distance (in radians) denoting the maximum
+distance a vertex should move in the snapping process.}
+}
+\description{
+These functions specify defaults for options used to perform operations
+and construct geometries. These are used in predicates (e.g., \code{\link[=s2_intersects]{s2_intersects()}}),
+and boolean operations (e.g., \code{\link[=s2_intersection]{s2_intersection()}}) to specify the model for
+containment and how new geometries should be constructed.
+}
+\section{Model}{
+
+The geometry model indicates whether or not a geometry includes its boundaries.
+Boundaries of line geometries are its end points.
+OPEN geometries do not contain their boundary (\code{model = "open"}); CLOSED
+geometries (\code{model = "closed"}) contain their boundary; SEMI-OPEN geometries
+(\code{model = "semi-open"}) contain half of their boundaries, such that when two polygons
+do not overlap or two lines do not cross, no point exist that belong to
+more than one of the geometries. (This latter form, half-closed, is
+not present in the OpenGIS "simple feature access" (SFA) standard nor DE9-IM on
+which that is based). The default values for \code{\link[=s2_contains]{s2_contains()}} (open)
+and covers/covered_by (closed) correspond to the SFA standard specification
+of these operators.
+}
+
+\examples{
+# use s2_options() to specify containment models, snap level
+# layer creation options, and builder options
+s2_options(model = "closed", snap = s2_snap_level(30))
+
+}
diff --git a/man/s2_point.Rd b/man/s2_point.Rd
new file mode 100644 (file)
index 0000000..05f83bf
--- /dev/null
@@ -0,0 +1,48 @@
+% Generated by roxygen2: do not edit by hand
+% Please edit documentation in R/s2-point.R
+\name{s2_point}
+\alias{s2_point}
+\alias{as_s2_point}
+\alias{as_s2_point.s2_point}
+\alias{as_s2_point.s2_lnglat}
+\alias{as_s2_point.s2_geography}
+\alias{as_s2_point.matrix}
+\alias{as.data.frame.s2_point}
+\alias{as.matrix.s2_point}
+\title{Create an S2 Point Vector}
+\usage{
+s2_point(x, y, z)
+
+as_s2_point(x, ...)
+
+\method{as_s2_point}{s2_point}(x, ...)
+
+\method{as_s2_point}{s2_lnglat}(x, ...)
+
+\method{as_s2_point}{s2_geography}(x, ...)
+
+\method{as_s2_point}{matrix}(x, ...)
+
+\method{as.data.frame}{s2_point}(x, ...)
+
+\method{as.matrix}{s2_point}(x, ...)
+}
+\arguments{
+\item{x, y, z}{Vectors of latitude and longitude values in degrees.}
+
+\item{...}{Unused}
+}
+\value{
+An object with class s2_point
+}
+\description{
+In S2 terminology, a "point" is a 3-dimensional unit vector representation
+of an \code{\link[=s2_lnglat]{s2_lnglat()}}. Internally, all s2 objects are stored as
+3-dimensional unit vectors.
+}
+\examples{
+lnglat <- s2_lnglat(-64, 45) # Halifax, Nova Scotia!
+as_s2_point(lnglat)
+as.data.frame(as_s2_point(lnglat))
+
+}
diff --git a/man/s2_unprojection_filter.Rd b/man/s2_unprojection_filter.Rd
new file mode 100644 (file)
index 0000000..0844d40
--- /dev/null
@@ -0,0 +1,79 @@
+% Generated by roxygen2: do not edit by hand
+% Please edit documentation in R/wk-utils.R
+\name{s2_unprojection_filter}
+\alias{s2_unprojection_filter}
+\alias{s2_projection_filter}
+\alias{s2_projection_plate_carree}
+\alias{s2_projection_mercator}
+\title{Low-level wk filters and handlers}
+\usage{
+s2_unprojection_filter(
+  handler,
+  projection = s2_projection_plate_carree(),
+  tessellate_tol = Inf
+)
+
+s2_projection_filter(
+  handler,
+  projection = s2_projection_plate_carree(),
+  tessellate_tol = Inf
+)
+
+s2_projection_plate_carree()
+
+s2_projection_mercator()
+}
+\arguments{
+\item{handler}{A \link[wk:wk_handle]{wk_handler} object.}
+
+\item{projection}{One of \code{\link[=s2_projection_plate_carree]{s2_projection_plate_carree()}} or
+\code{\link[=s2_projection_mercator]{s2_projection_mercator()}}}
+
+\item{tessellate_tol}{An angle in radians. Points will not be added
+if a line segment is within this distance of a point.}
+}
+\value{
+\itemize{
+\item \code{s2_unprojection_filter()}, \code{s2_projection_filter()}: A \code{new_wk_handler()}
+\item \code{s2_projection_plate_carree()}, \code{s2_projection_mercator()}: An external pointer
+to an S2 projection.
+}
+}
+\description{
+Low-level wk filters and handlers
+}
+\examples{
+library(wk)
+
+# simple conversion of individual coordinates *to* unit sphere
+# space
+wk_handle(
+  wkt("LINESTRING (0 0, 0 45, -60 45)"),
+  s2_unprojection_filter(wkt_format_handler(5))
+)
+
+# simple conversion of individual coordinates *from* unit sphere
+# space
+wk_handle(
+  wkt("LINESTRING Z (1 0 0, 0.7071 0 0.7071, 0.3536 -0.6124 0.7071)"),
+  s2_projection_filter(wkt_format_handler(5))
+)
+
+# use tessellate_tol to force points to be added to an edge
+# unprojection will ensure an edge maintains its cartesian
+# assumption when transformed to the unit sphere
+# (i.e., what you probably want when importing a geography)
+wk_handle(
+  wkt("LINESTRING (0 0, 0 45, -60 45)"),
+  s2_unprojection_filter(wkt_format_handler(5), tessellate_tol = 0.001)
+)
+
+# projection will ensure an edge maintains its geodesic
+# assumption when transformed to projected space
+# (i.e., what you probably want when exporting a geography)
+wk_handle(
+  wkt("LINESTRING Z (1 0 0, 0.7071 0 0.7071, 0.3536 -0.6124 0.7071)"),
+  s2_projection_filter(wkt_format_handler(5), tessellate_tol = 0.001)
+)
+
+}
diff --git a/src/Makevars.in b/src/Makevars.in
new file mode 100644 (file)
index 0000000..e1df096
--- /dev/null
@@ -0,0 +1,203 @@
+PKG_CPPFLAGS = -I../src -DSTRICT_R_HEADERS
+PKG_LIBS = @libs@
+PKG_CXXFLAGS = @cflags@ -pthread
+CXX_STD = CXX11
+
+ABSL_LIBS = absl/base/internal/cycleclock.o \
+    absl/base/internal/exponential_biased.o \
+    absl/base/internal/low_level_alloc.o \
+    absl/base/internal/periodic_sampler.o \
+    absl/base/internal/raw_logging.o \
+    absl/base/internal/scoped_set_env.o \
+    absl/base/internal/spinlock_wait.o \
+    absl/base/internal/spinlock.o \
+    absl/base/internal/strerror.o \
+    absl/base/internal/sysinfo.o \
+    absl/base/internal/thread_identity.o \
+    absl/base/internal/throw_delegate.o \
+    absl/base/internal/unscaledcycleclock.o \
+    absl/base/log_severity.o \
+    absl/container/internal/hashtablez_sampler_force_weak_definition.o \
+    absl/container/internal/hashtablez_sampler.o \
+    absl/container/internal/raw_hash_set.o \
+    absl/debugging/failure_signal_handler.o \
+    absl/debugging/internal/address_is_readable.o \
+    absl/debugging/internal/demangle.o \
+    absl/debugging/internal/elf_mem_image.o \
+    absl/debugging/internal/examine_stack.o \
+    absl/debugging/internal/stack_consumption.o \
+    absl/debugging/internal/vdso_support.o \
+    absl/debugging/leak_check_disable.o \
+    absl/debugging/leak_check.o \
+    absl/debugging/stacktrace.o \
+    absl/debugging/symbolize.o \
+    absl/numeric/int128.o \
+    absl/strings/ascii.o \
+    absl/strings/charconv.o \
+    absl/strings/cord.o \
+    absl/strings/escaping.o \
+    absl/strings/internal/charconv_bigint.o \
+    absl/strings/internal/charconv_parse.o \
+    absl/strings/internal/cord_internal.o \
+    absl/strings/internal/cord_rep_ring.o \
+    absl/strings/internal/escaping.o \
+    absl/strings/internal/memutil.o \
+    absl/strings/internal/ostringstream.o \
+    absl/strings/internal/pow10_helper.o \
+    absl/strings/internal/str_format/arg.o \
+    absl/strings/internal/str_format/bind.o \
+    absl/strings/internal/str_format/extension.o \
+    absl/strings/internal/str_format/float_conversion.o \
+    absl/strings/internal/str_format/output.o \
+    absl/strings/internal/str_format/parser.o \
+    absl/strings/internal/utf8.o \
+    absl/strings/match.o \
+    absl/strings/numbers.o \
+    absl/strings/str_cat.o \
+    absl/strings/str_replace.o \
+    absl/strings/str_split.o \
+    absl/strings/string_view.o \
+    absl/strings/substitute.o \
+    absl/synchronization/barrier.o \
+    absl/synchronization/blocking_counter.o \
+    absl/synchronization/internal/create_thread_identity.o \
+    absl/synchronization/internal/graphcycles.o \
+    absl/synchronization/internal/per_thread_sem.o \
+    absl/synchronization/internal/waiter.o \
+    absl/synchronization/mutex.o \
+    absl/synchronization/notification.o \
+    absl/time/civil_time.o \
+    absl/time/clock.o \
+    absl/time/duration.o \
+    absl/time/format.o \
+    absl/time/internal/cctz/src/civil_time_detail.o \
+    absl/time/internal/cctz/src/time_zone_fixed.o \
+    absl/time/internal/cctz/src/time_zone_format.o \
+    absl/time/internal/cctz/src/time_zone_if.o \
+    absl/time/internal/cctz/src/time_zone_impl.o \
+    absl/time/internal/cctz/src/time_zone_info.o \
+    absl/time/internal/cctz/src/time_zone_libc.o \
+    absl/time/internal/cctz/src/time_zone_lookup.o \
+    absl/time/internal/cctz/src/time_zone_posix.o \
+    absl/time/internal/cctz/src/zone_info_source.o \
+    absl/time/time.o \
+    absl/types/bad_any_cast.o \
+    absl/types/bad_optional_access.o \
+    absl/types/bad_variant_access.o
+
+OBJECTS = $(ABSL_LIBS) \
+     cpp-compat.o \
+     s2-accessors.o \
+     s2-bounds.o \
+     s2-cell.o \
+     s2-constructors-formatters.o \
+     s2-predicates.o \
+     s2-transformers.o \
+     init.o \
+     RcppExports.o \
+     s2-geography.o \
+     s2-lnglat.o \
+     s2-matrix.o \
+     s2-point.o \
+     s2-xptr.o \
+     wk-impl.o \
+     wk-c-utils.o \
+     s2-c-api.o \
+     s2/base/stringprintf.o \
+     s2/base/strtoint.o \
+     s2/encoded_s2cell_id_vector.o \
+     s2/encoded_s2point_vector.o \
+     s2/encoded_s2shape_index.o \
+     s2/encoded_string_vector.o \
+     s2/id_set_lexicon.o \
+     s2/mutable_s2shape_index.o \
+     s2/r2rect.o \
+     s2/s1angle.o \
+     s2/s1chord_angle.o \
+     s2/s1interval.o \
+     s2/s2boolean_operation.o \
+     s2/s2builder_graph.o \
+     s2/s2builder.o \
+     s2/s2builderutil_closed_set_normalizer.o \
+     s2/s2builderutil_find_polygon_degeneracies.o \
+     s2/s2builderutil_lax_polygon_layer.o \
+     s2/s2builderutil_s2point_vector_layer.o \
+     s2/s2builderutil_s2polygon_layer.o \
+     s2/s2builderutil_s2polyline_layer.o \
+     s2/s2builderutil_s2polyline_vector_layer.o \
+     s2/s2builderutil_snap_functions.o \
+     s2/s2builderutil_testing.o \
+     s2/s2cap.o \
+     s2/s2cell_id.o \
+     s2/s2cell_index.o \
+     s2/s2cell_union.o \
+     s2/s2cell.o \
+     s2/s2centroids.o \
+     s2/s2closest_cell_query.o \
+     s2/s2closest_edge_query.o \
+     s2/s2closest_point_query.o \
+     s2/s2contains_vertex_query.o \
+     s2/s2convex_hull_query.o \
+     s2/s2coords.o \
+     s2/s2crossing_edge_query.o \
+     s2/s2debug.o \
+     s2/s2earth.o \
+     s2/s2edge_clipping.o \
+     s2/s2edge_crosser.o \
+     s2/s2edge_crossings.o \
+     s2/s2edge_distances.o \
+     s2/s2edge_tessellator.o \
+     s2/s2error.o \
+     s2/s2furthest_edge_query.o \
+     s2/s2latlng_rect_bounder.o \
+     s2/s2latlng_rect.o \
+     s2/s2latlng.o \
+     s2/s2lax_loop_shape.o \
+     s2/s2lax_polygon_shape.o \
+     s2/s2lax_polyline_shape.o \
+     s2/s2loop_measures.o \
+     s2/s2loop.o \
+     s2/s2max_distance_targets.o \
+     s2/s2measures.o \
+     s2/s2metrics.o \
+     s2/s2min_distance_targets.o \
+     s2/s2padded_cell.o \
+     s2/s2point_compression.o \
+     s2/s2point_region.o \
+     s2/s2pointutil.o \
+     s2/s2polygon.o \
+     s2/s2polyline_alignment.o \
+     s2/s2polyline_measures.o \
+     s2/s2polyline_simplifier.o \
+     s2/s2polyline.o \
+     s2/s2predicates.o \
+     s2/s2projections.o \
+     s2/s2r2rect.o \
+     s2/s2region_coverer.o \
+     s2/s2region_intersection.o \
+     s2/s2region_term_indexer.o \
+     s2/s2region_union.o \
+     s2/s2region.o \
+     s2/s2shape_index_buffered_region.o \
+     s2/s2shape_index_measures.o \
+     s2/s2shape_index.o \
+     s2/s2shape_measures.o \
+     s2/s2shapeutil_build_polygon_boundaries.o \
+     s2/s2shapeutil_coding.o \
+     s2/s2shapeutil_contains_brute_force.o \
+     s2/s2shapeutil_edge_iterator.o \
+     s2/s2shapeutil_get_reference_point.o \
+     s2/s2shapeutil_range_iterator.o \
+     s2/s2shapeutil_visit_crossing_edge_pairs.o \
+     s2/s2testing.o \
+     s2/s2text_format.o \
+     s2/s2wedge_relations.o \
+     s2/strings/ostringstream.o \
+     s2/strings/serialize.o \
+     s2/util/bits/bit-interleave.o \
+     s2/util/bits/bits.o \
+     s2/util/coding/coder.o \
+     s2/util/coding/varint.o \
+     s2/util/math/exactfloat/exactfloat.o \
+     s2/util/math/mathutil.o \
+     s2/util/units/length-units.o
diff --git a/src/Makevars.ucrt b/src/Makevars.ucrt
new file mode 100644 (file)
index 0000000..1a2e101
--- /dev/null
@@ -0,0 +1,2 @@
+CRT=-ucrt
+include Makevars.win
diff --git a/src/Makevars.win b/src/Makevars.win
new file mode 100644 (file)
index 0000000..a3c91ab
--- /dev/null
@@ -0,0 +1,206 @@
+PKG_CPPFLAGS = -DS2_USE_EXACTFLOAT -D_USE_MATH_DEFINES -DNDEBUG -DIS_LITTLE_ENDIAN -I../windows/openssl-1.1.1k/include -I../src
+PKG_LIBS = -Ls2 -ls2static -L../windows/openssl-1.1.1k/lib${R_ARCH}${CRT} -lssl -lcrypto -lcrypt32 -lws2_32
+
+CXX_STD = CXX11
+
+STATLIB = s2/libs2static.a
+
+ABSL_LIBS = absl/base/internal/cycleclock.o \
+    absl/base/internal/exponential_biased.o \
+    absl/base/internal/low_level_alloc.o \
+    absl/base/internal/periodic_sampler.o \
+    absl/base/internal/raw_logging.o \
+    absl/base/internal/scoped_set_env.o \
+    absl/base/internal/spinlock_wait.o \
+    absl/base/internal/spinlock.o \
+    absl/base/internal/strerror.o \
+    absl/base/internal/sysinfo.o \
+    absl/base/internal/thread_identity.o \
+    absl/base/internal/throw_delegate.o \
+    absl/base/internal/unscaledcycleclock.o \
+    absl/base/log_severity.o \
+    absl/container/internal/hashtablez_sampler_force_weak_definition.o \
+    absl/container/internal/hashtablez_sampler.o \
+    absl/container/internal/raw_hash_set.o \
+    absl/debugging/failure_signal_handler.o \
+    absl/debugging/internal/address_is_readable.o \
+    absl/debugging/internal/demangle.o \
+    absl/debugging/internal/elf_mem_image.o \
+    absl/debugging/internal/examine_stack.o \
+    absl/debugging/internal/stack_consumption.o \
+    absl/debugging/internal/vdso_support.o \
+    absl/debugging/leak_check_disable.o \
+    absl/debugging/leak_check.o \
+    absl/debugging/stacktrace.o \
+    absl/debugging/symbolize.o \
+    absl/numeric/int128.o \
+    absl/strings/ascii.o \
+    absl/strings/charconv.o \
+    absl/strings/cord.o \
+    absl/strings/escaping.o \
+    absl/strings/internal/charconv_bigint.o \
+    absl/strings/internal/charconv_parse.o \
+    absl/strings/internal/cord_internal.o \
+    absl/strings/internal/cord_rep_ring.o \
+    absl/strings/internal/escaping.o \
+    absl/strings/internal/memutil.o \
+    absl/strings/internal/ostringstream.o \
+    absl/strings/internal/pow10_helper.o \
+    absl/strings/internal/str_format/arg.o \
+    absl/strings/internal/str_format/bind.o \
+    absl/strings/internal/str_format/extension.o \
+    absl/strings/internal/str_format/float_conversion.o \
+    absl/strings/internal/str_format/output.o \
+    absl/strings/internal/str_format/parser.o \
+    absl/strings/internal/utf8.o \
+    absl/strings/match.o \
+    absl/strings/numbers.o \
+    absl/strings/str_cat.o \
+    absl/strings/str_replace.o \
+    absl/strings/str_split.o \
+    absl/strings/string_view.o \
+    absl/strings/substitute.o \
+    absl/synchronization/barrier.o \
+    absl/synchronization/blocking_counter.o \
+    absl/synchronization/internal/create_thread_identity.o \
+    absl/synchronization/internal/graphcycles.o \
+    absl/synchronization/internal/per_thread_sem.o \
+    absl/synchronization/internal/waiter.o \
+    absl/synchronization/mutex.o \
+    absl/synchronization/notification.o \
+    absl/time/civil_time.o \
+    absl/time/clock.o \
+    absl/time/duration.o \
+    absl/time/format.o \
+    absl/time/internal/cctz/src/civil_time_detail.o \
+    absl/time/internal/cctz/src/time_zone_fixed.o \
+    absl/time/internal/cctz/src/time_zone_format.o \
+    absl/time/internal/cctz/src/time_zone_if.o \
+    absl/time/internal/cctz/src/time_zone_impl.o \
+    absl/time/internal/cctz/src/time_zone_info.o \
+    absl/time/internal/cctz/src/time_zone_libc.o \
+    absl/time/internal/cctz/src/time_zone_lookup.o \
+    absl/time/internal/cctz/src/time_zone_posix.o \
+    absl/time/internal/cctz/src/zone_info_source.o \
+    absl/time/time.o \
+    absl/types/bad_any_cast.o \
+    absl/types/bad_optional_access.o \
+    absl/types/bad_variant_access.o
+
+S2LIBS = $(ABSL_LIBS) \
+     s2-c-api.o \
+     s2/base/stringprintf.o \
+     s2/base/strtoint.o \
+     s2/encoded_s2cell_id_vector.o \
+     s2/encoded_s2point_vector.o \
+     s2/encoded_s2shape_index.o \
+     s2/encoded_string_vector.o \
+     s2/id_set_lexicon.o \
+     s2/mutable_s2shape_index.o \
+     s2/r2rect.o \
+     s2/s1angle.o \
+     s2/s1chord_angle.o \
+     s2/s1interval.o \
+     s2/s2boolean_operation.o \
+     s2/s2builder_graph.o \
+     s2/s2builder.o \
+     s2/s2builderutil_closed_set_normalizer.o \
+     s2/s2builderutil_find_polygon_degeneracies.o \
+     s2/s2builderutil_lax_polygon_layer.o \
+     s2/s2builderutil_s2point_vector_layer.o \
+     s2/s2builderutil_s2polygon_layer.o \
+     s2/s2builderutil_s2polyline_layer.o \
+     s2/s2builderutil_s2polyline_vector_layer.o \
+     s2/s2builderutil_snap_functions.o \
+     s2/s2builderutil_testing.o \
+     s2/s2cap.o \
+     s2/s2cell_id.o \
+     s2/s2cell_index.o \
+     s2/s2cell_union.o \
+     s2/s2cell.o \
+     s2/s2centroids.o \
+     s2/s2closest_cell_query.o \
+     s2/s2closest_edge_query.o \
+     s2/s2closest_point_query.o \
+     s2/s2contains_vertex_query.o \
+     s2/s2convex_hull_query.o \
+     s2/s2coords.o \
+     s2/s2crossing_edge_query.o \
+     s2/s2debug.o \
+     s2/s2earth.o \
+     s2/s2edge_clipping.o \
+     s2/s2edge_crosser.o \
+     s2/s2edge_crossings.o \
+     s2/s2edge_distances.o \
+     s2/s2edge_tessellator.o \
+     s2/s2error.o \
+     s2/s2furthest_edge_query.o \
+     s2/s2latlng_rect_bounder.o \
+     s2/s2latlng_rect.o \
+     s2/s2latlng.o \
+     s2/s2lax_loop_shape.o \
+     s2/s2lax_polygon_shape.o \
+     s2/s2lax_polyline_shape.o \
+     s2/s2loop_measures.o \
+     s2/s2loop.o \
+     s2/s2max_distance_targets.o \
+     s2/s2measures.o \
+     s2/s2metrics.o \
+     s2/s2min_distance_targets.o \
+     s2/s2padded_cell.o \
+     s2/s2point_compression.o \
+     s2/s2point_region.o \
+     s2/s2pointutil.o \
+     s2/s2polygon.o \
+     s2/s2polyline_alignment.o \
+     s2/s2polyline_measures.o \
+     s2/s2polyline_simplifier.o \
+     s2/s2polyline.o \
+     s2/s2predicates.o \
+     s2/s2projections.o \
+     s2/s2r2rect.o \
+     s2/s2region_coverer.o \
+     s2/s2region_intersection.o \
+     s2/s2region_term_indexer.o \
+     s2/s2region_union.o \
+     s2/s2region.o \
+     s2/s2shape_index_buffered_region.o \
+     s2/s2shape_index_measures.o \
+     s2/s2shape_index.o \
+     s2/s2shape_measures.o \
+     s2/s2shapeutil_build_polygon_boundaries.o \
+     s2/s2shapeutil_coding.o \
+     s2/s2shapeutil_contains_brute_force.o \
+     s2/s2shapeutil_edge_iterator.o \
+     s2/s2shapeutil_get_reference_point.o \
+     s2/s2shapeutil_range_iterator.o \
+     s2/s2shapeutil_visit_crossing_edge_pairs.o \
+     s2/s2testing.o \
+     s2/s2text_format.o \
+     s2/s2wedge_relations.o \
+     s2/strings/ostringstream.o \
+     s2/strings/serialize.o \
+     s2/util/bits/bit-interleave.o \
+     s2/util/bits/bits.o \
+     s2/util/coding/coder.o \
+     s2/util/coding/varint.o \
+     s2/util/math/exactfloat/exactfloat.o \
+     s2/util/math/mathutil.o \
+     s2/util/units/length-units.o
+
+$(SHLIB): $(STATLIB)
+
+$(STATLIB): $(S2LIBS)
+
+$(S2LIBS): winlibs
+
+#all: clean
+
+winlibs:
+       mkdir -p ../inst
+       "${R_HOME}/bin${R_ARCH_BIN}/Rscript.exe" --vanilla "../tools/winlibs.R"
+
+clean:
+       rm -f $(SHLIB) $(STATLIB) $(OBJECTS) $(S2LIBS)
+
+.PHONY: all winlibs clean
diff --git a/src/RcppExports.cpp b/src/RcppExports.cpp
new file mode 100644 (file)
index 0000000..e7ff9bb
--- /dev/null
@@ -0,0 +1,1396 @@
+// Generated by using Rcpp::compileAttributes() -> do not edit by hand
+// Generator token: 10BE3573-1514-4C36-9D1C-5A225CD40393
+
+#include <Rcpp.h>
+
+using namespace Rcpp;
+
+#ifdef RCPP_USE_GLOBAL_ROSTREAM
+Rcpp::Rostream<true>&  Rcpp::Rcout = Rcpp::Rcpp_cout_get();
+Rcpp::Rostream<false>& Rcpp::Rcerr = Rcpp::Rcpp_cerr_get();
+#endif
+
+// cpp_s2_init
+void cpp_s2_init();
+RcppExport SEXP _s2_cpp_s2_init() {
+BEGIN_RCPP
+    Rcpp::RNGScope rcpp_rngScope_gen;
+    cpp_s2_init();
+    return R_NilValue;
+END_RCPP
+}
+// cpp_s2_is_collection
+LogicalVector cpp_s2_is_collection(List geog);
+RcppExport SEXP _s2_cpp_s2_is_collection(SEXP geogSEXP) {
+BEGIN_RCPP
+    Rcpp::RObject rcpp_result_gen;
+    Rcpp::RNGScope rcpp_rngScope_gen;
+    Rcpp::traits::input_parameter< List >::type geog(geogSEXP);
+    rcpp_result_gen = Rcpp::wrap(cpp_s2_is_collection(geog));
+    return rcpp_result_gen;
+END_RCPP
+}
+// cpp_s2_is_valid
+LogicalVector cpp_s2_is_valid(List geog);
+RcppExport SEXP _s2_cpp_s2_is_valid(SEXP geogSEXP) {
+BEGIN_RCPP
+    Rcpp::RObject rcpp_result_gen;
+    Rcpp::RNGScope rcpp_rngScope_gen;
+    Rcpp::traits::input_parameter< List >::type geog(geogSEXP);
+    rcpp_result_gen = Rcpp::wrap(cpp_s2_is_valid(geog));
+    return rcpp_result_gen;
+END_RCPP
+}
+// cpp_s2_is_valid_reason
+CharacterVector cpp_s2_is_valid_reason(List geog);
+RcppExport SEXP _s2_cpp_s2_is_valid_reason(SEXP geogSEXP) {
+BEGIN_RCPP
+    Rcpp::RObject rcpp_result_gen;
+    Rcpp::RNGScope rcpp_rngScope_gen;
+    Rcpp::traits::input_parameter< List >::type geog(geogSEXP);
+    rcpp_result_gen = Rcpp::wrap(cpp_s2_is_valid_reason(geog));
+    return rcpp_result_gen;
+END_RCPP
+}
+// cpp_s2_dimension
+IntegerVector cpp_s2_dimension(List geog);
+RcppExport SEXP _s2_cpp_s2_dimension(SEXP geogSEXP) {
+BEGIN_RCPP
+    Rcpp::RObject rcpp_result_gen;
+    Rcpp::RNGScope rcpp_rngScope_gen;
+    Rcpp::traits::input_parameter< List >::type geog(geogSEXP);
+    rcpp_result_gen = Rcpp::wrap(cpp_s2_dimension(geog));
+    return rcpp_result_gen;
+END_RCPP
+}
+// cpp_s2_num_points
+IntegerVector cpp_s2_num_points(List geog);
+RcppExport SEXP _s2_cpp_s2_num_points(SEXP geogSEXP) {
+BEGIN_RCPP
+    Rcpp::RObject rcpp_result_gen;
+    Rcpp::RNGScope rcpp_rngScope_gen;
+    Rcpp::traits::input_parameter< List >::type geog(geogSEXP);
+    rcpp_result_gen = Rcpp::wrap(cpp_s2_num_points(geog));
+    return rcpp_result_gen;
+END_RCPP
+}
+// cpp_s2_is_empty
+LogicalVector cpp_s2_is_empty(List geog);
+RcppExport SEXP _s2_cpp_s2_is_empty(SEXP geogSEXP) {
+BEGIN_RCPP
+    Rcpp::RObject rcpp_result_gen;
+    Rcpp::RNGScope rcpp_rngScope_gen;
+    Rcpp::traits::input_parameter< List >::type geog(geogSEXP);
+    rcpp_result_gen = Rcpp::wrap(cpp_s2_is_empty(geog));
+    return rcpp_result_gen;
+END_RCPP
+}
+// cpp_s2_area
+NumericVector cpp_s2_area(List geog);
+RcppExport SEXP _s2_cpp_s2_area(SEXP geogSEXP) {
+BEGIN_RCPP
+    Rcpp::RObject rcpp_result_gen;
+    Rcpp::RNGScope rcpp_rngScope_gen;
+    Rcpp::traits::input_parameter< List >::type geog(geogSEXP);
+    rcpp_result_gen = Rcpp::wrap(cpp_s2_area(geog));
+    return rcpp_result_gen;
+END_RCPP
+}
+// cpp_s2_length
+NumericVector cpp_s2_length(List geog);
+RcppExport SEXP _s2_cpp_s2_length(SEXP geogSEXP) {
+BEGIN_RCPP
+    Rcpp::RObject rcpp_result_gen;
+    Rcpp::RNGScope rcpp_rngScope_gen;
+    Rcpp::traits::input_parameter< List >::type geog(geogSEXP);
+    rcpp_result_gen = Rcpp::wrap(cpp_s2_length(geog));
+    return rcpp_result_gen;
+END_RCPP
+}
+// cpp_s2_perimeter
+NumericVector cpp_s2_perimeter(List geog);
+RcppExport SEXP _s2_cpp_s2_perimeter(SEXP geogSEXP) {
+BEGIN_RCPP
+    Rcpp::RObject rcpp_result_gen;
+    Rcpp::RNGScope rcpp_rngScope_gen;
+    Rcpp::traits::input_parameter< List >::type geog(geogSEXP);
+    rcpp_result_gen = Rcpp::wrap(cpp_s2_perimeter(geog));
+    return rcpp_result_gen;
+END_RCPP
+}
+// cpp_s2_x
+NumericVector cpp_s2_x(List geog);
+RcppExport SEXP _s2_cpp_s2_x(SEXP geogSEXP) {
+BEGIN_RCPP
+    Rcpp::RObject rcpp_result_gen;
+    Rcpp::RNGScope rcpp_rngScope_gen;
+    Rcpp::traits::input_parameter< List >::type geog(geogSEXP);
+    rcpp_result_gen = Rcpp::wrap(cpp_s2_x(geog));
+    return rcpp_result_gen;
+END_RCPP
+}
+// cpp_s2_y
+NumericVector cpp_s2_y(List geog);
+RcppExport SEXP _s2_cpp_s2_y(SEXP geogSEXP) {
+BEGIN_RCPP
+    Rcpp::RObject rcpp_result_gen;
+    Rcpp::RNGScope rcpp_rngScope_gen;
+    Rcpp::traits::input_parameter< List >::type geog(geogSEXP);
+    rcpp_result_gen = Rcpp::wrap(cpp_s2_y(geog));
+    return rcpp_result_gen;
+END_RCPP
+}
+// cpp_s2_project_normalized
+NumericVector cpp_s2_project_normalized(List geog1, List geog2);
+RcppExport SEXP _s2_cpp_s2_project_normalized(SEXP geog1SEXP, SEXP geog2SEXP) {
+BEGIN_RCPP
+    Rcpp::RObject rcpp_result_gen;
+    Rcpp::RNGScope rcpp_rngScope_gen;
+    Rcpp::traits::input_parameter< List >::type geog1(geog1SEXP);
+    Rcpp::traits::input_parameter< List >::type geog2(geog2SEXP);
+    rcpp_result_gen = Rcpp::wrap(cpp_s2_project_normalized(geog1, geog2));
+    return rcpp_result_gen;
+END_RCPP
+}
+// cpp_s2_distance
+NumericVector cpp_s2_distance(List geog1, List geog2);
+RcppExport SEXP _s2_cpp_s2_distance(SEXP geog1SEXP, SEXP geog2SEXP) {
+BEGIN_RCPP
+    Rcpp::RObject rcpp_result_gen;
+    Rcpp::RNGScope rcpp_rngScope_gen;
+    Rcpp::traits::input_parameter< List >::type geog1(geog1SEXP);
+    Rcpp::traits::input_parameter< List >::type geog2(geog2SEXP);
+    rcpp_result_gen = Rcpp::wrap(cpp_s2_distance(geog1, geog2));
+    return rcpp_result_gen;
+END_RCPP
+}
+// cpp_s2_max_distance
+NumericVector cpp_s2_max_distance(List geog1, List geog2);
+RcppExport SEXP _s2_cpp_s2_max_distance(SEXP geog1SEXP, SEXP geog2SEXP) {
+BEGIN_RCPP
+    Rcpp::RObject rcpp_result_gen;
+    Rcpp::RNGScope rcpp_rngScope_gen;
+    Rcpp::traits::input_parameter< List >::type geog1(geog1SEXP);
+    Rcpp::traits::input_parameter< List >::type geog2(geog2SEXP);
+    rcpp_result_gen = Rcpp::wrap(cpp_s2_max_distance(geog1, geog2));
+    return rcpp_result_gen;
+END_RCPP
+}
+// cpp_s2_bounds_cap
+DataFrame cpp_s2_bounds_cap(List geog);
+RcppExport SEXP _s2_cpp_s2_bounds_cap(SEXP geogSEXP) {
+BEGIN_RCPP
+    Rcpp::RObject rcpp_result_gen;
+    Rcpp::RNGScope rcpp_rngScope_gen;
+    Rcpp::traits::input_parameter< List >::type geog(geogSEXP);
+    rcpp_result_gen = Rcpp::wrap(cpp_s2_bounds_cap(geog));
+    return rcpp_result_gen;
+END_RCPP
+}
+// cpp_s2_bounds_rect
+DataFrame cpp_s2_bounds_rect(List geog);
+RcppExport SEXP _s2_cpp_s2_bounds_rect(SEXP geogSEXP) {
+BEGIN_RCPP
+    Rcpp::RObject rcpp_result_gen;
+    Rcpp::RNGScope rcpp_rngScope_gen;
+    Rcpp::traits::input_parameter< List >::type geog(geogSEXP);
+    rcpp_result_gen = Rcpp::wrap(cpp_s2_bounds_rect(geog));
+    return rcpp_result_gen;
+END_RCPP
+}
+// cpp_s2_cell_sentinel
+NumericVector cpp_s2_cell_sentinel();
+RcppExport SEXP _s2_cpp_s2_cell_sentinel() {
+BEGIN_RCPP
+    Rcpp::RObject rcpp_result_gen;
+    Rcpp::RNGScope rcpp_rngScope_gen;
+    rcpp_result_gen = Rcpp::wrap(cpp_s2_cell_sentinel());
+    return rcpp_result_gen;
+END_RCPP
+}
+// cpp_s2_cell_from_string
+NumericVector cpp_s2_cell_from_string(CharacterVector cellString);
+RcppExport SEXP _s2_cpp_s2_cell_from_string(SEXP cellStringSEXP) {
+BEGIN_RCPP
+    Rcpp::RObject rcpp_result_gen;
+    Rcpp::RNGScope rcpp_rngScope_gen;
+    Rcpp::traits::input_parameter< CharacterVector >::type cellString(cellStringSEXP);
+    rcpp_result_gen = Rcpp::wrap(cpp_s2_cell_from_string(cellString));
+    return rcpp_result_gen;
+END_RCPP
+}
+// cpp_s2_cell_from_lnglat
+NumericVector cpp_s2_cell_from_lnglat(List lnglat);
+RcppExport SEXP _s2_cpp_s2_cell_from_lnglat(SEXP lnglatSEXP) {
+BEGIN_RCPP
+    Rcpp::RObject rcpp_result_gen;
+    Rcpp::RNGScope rcpp_rngScope_gen;
+    Rcpp::traits::input_parameter< List >::type lnglat(lnglatSEXP);
+    rcpp_result_gen = Rcpp::wrap(cpp_s2_cell_from_lnglat(lnglat));
+    return rcpp_result_gen;
+END_RCPP
+}
+// cpp_s2_cell_to_lnglat
+List cpp_s2_cell_to_lnglat(NumericVector cellId);
+RcppExport SEXP _s2_cpp_s2_cell_to_lnglat(SEXP cellIdSEXP) {
+BEGIN_RCPP
+    Rcpp::RObject rcpp_result_gen;
+    Rcpp::RNGScope rcpp_rngScope_gen;
+    Rcpp::traits::input_parameter< NumericVector >::type cellId(cellIdSEXP);
+    rcpp_result_gen = Rcpp::wrap(cpp_s2_cell_to_lnglat(cellId));
+    return rcpp_result_gen;
+END_RCPP
+}
+// cpp_s2_cell_is_na
+LogicalVector cpp_s2_cell_is_na(NumericVector cellIdVector);
+RcppExport SEXP _s2_cpp_s2_cell_is_na(SEXP cellIdVectorSEXP) {
+BEGIN_RCPP
+    Rcpp::RObject rcpp_result_gen;
+    Rcpp::RNGScope rcpp_rngScope_gen;
+    Rcpp::traits::input_parameter< NumericVector >::type cellIdVector(cellIdVectorSEXP);
+    rcpp_result_gen = Rcpp::wrap(cpp_s2_cell_is_na(cellIdVector));
+    return rcpp_result_gen;
+END_RCPP
+}
+// cpp_s2_cell_sort
+NumericVector cpp_s2_cell_sort(NumericVector cellIdVector, bool decreasing);
+RcppExport SEXP _s2_cpp_s2_cell_sort(SEXP cellIdVectorSEXP, SEXP decreasingSEXP) {
+BEGIN_RCPP
+    Rcpp::RObject rcpp_result_gen;
+    Rcpp::RNGScope rcpp_rngScope_gen;
+    Rcpp::traits::input_parameter< NumericVector >::type cellIdVector(cellIdVectorSEXP);
+    Rcpp::traits::input_parameter< bool >::type decreasing(decreasingSEXP);
+    rcpp_result_gen = Rcpp::wrap(cpp_s2_cell_sort(cellIdVector, decreasing));
+    return rcpp_result_gen;
+END_RCPP
+}
+// cpp_s2_cell_range
+NumericVector cpp_s2_cell_range(NumericVector cellIdVector, bool naRm);
+RcppExport SEXP _s2_cpp_s2_cell_range(SEXP cellIdVectorSEXP, SEXP naRmSEXP) {
+BEGIN_RCPP
+    Rcpp::RObject rcpp_result_gen;
+    Rcpp::RNGScope rcpp_rngScope_gen;
+    Rcpp::traits::input_parameter< NumericVector >::type cellIdVector(cellIdVectorSEXP);
+    Rcpp::traits::input_parameter< bool >::type naRm(naRmSEXP);
+    rcpp_result_gen = Rcpp::wrap(cpp_s2_cell_range(cellIdVector, naRm));
+    return rcpp_result_gen;
+END_RCPP
+}
+// cpp_s2_cell_unique
+NumericVector cpp_s2_cell_unique(NumericVector cellIdVector);
+RcppExport SEXP _s2_cpp_s2_cell_unique(SEXP cellIdVectorSEXP) {
+BEGIN_RCPP
+    Rcpp::RObject rcpp_result_gen;
+    Rcpp::RNGScope rcpp_rngScope_gen;
+    Rcpp::traits::input_parameter< NumericVector >::type cellIdVector(cellIdVectorSEXP);
+    rcpp_result_gen = Rcpp::wrap(cpp_s2_cell_unique(cellIdVector));
+    return rcpp_result_gen;
+END_RCPP
+}
+// cpp_s2_cell_to_string
+CharacterVector cpp_s2_cell_to_string(NumericVector cellIdVector);
+RcppExport SEXP _s2_cpp_s2_cell_to_string(SEXP cellIdVectorSEXP) {
+BEGIN_RCPP
+    Rcpp::RObject rcpp_result_gen;
+    Rcpp::RNGScope rcpp_rngScope_gen;
+    Rcpp::traits::input_parameter< NumericVector >::type cellIdVector(cellIdVectorSEXP);
+    rcpp_result_gen = Rcpp::wrap(cpp_s2_cell_to_string(cellIdVector));
+    return rcpp_result_gen;
+END_RCPP
+}
+// cpp_s2_cell_debug_string
+CharacterVector cpp_s2_cell_debug_string(NumericVector cellIdVector);
+RcppExport SEXP _s2_cpp_s2_cell_debug_string(SEXP cellIdVectorSEXP) {
+BEGIN_RCPP
+    Rcpp::RObject rcpp_result_gen;
+    Rcpp::RNGScope rcpp_rngScope_gen;
+    Rcpp::traits::input_parameter< NumericVector >::type cellIdVector(cellIdVectorSEXP);
+    rcpp_result_gen = Rcpp::wrap(cpp_s2_cell_debug_string(cellIdVector));
+    return rcpp_result_gen;
+END_RCPP
+}
+// cpp_s2_cell_is_valid
+LogicalVector cpp_s2_cell_is_valid(NumericVector cellIdVector);
+RcppExport SEXP _s2_cpp_s2_cell_is_valid(SEXP cellIdVectorSEXP) {
+BEGIN_RCPP
+    Rcpp::RObject rcpp_result_gen;
+    Rcpp::RNGScope rcpp_rngScope_gen;
+    Rcpp::traits::input_parameter< NumericVector >::type cellIdVector(cellIdVectorSEXP);
+    rcpp_result_gen = Rcpp::wrap(cpp_s2_cell_is_valid(cellIdVector));
+    return rcpp_result_gen;
+END_RCPP
+}
+// cpp_s2_cell_center
+List cpp_s2_cell_center(NumericVector cellIdVector);
+RcppExport SEXP _s2_cpp_s2_cell_center(SEXP cellIdVectorSEXP) {
+BEGIN_RCPP
+    Rcpp::RObject rcpp_result_gen;
+    Rcpp::RNGScope rcpp_rngScope_gen;
+    Rcpp::traits::input_parameter< NumericVector >::type cellIdVector(cellIdVectorSEXP);
+    rcpp_result_gen = Rcpp::wrap(cpp_s2_cell_center(cellIdVector));
+    return rcpp_result_gen;
+END_RCPP
+}
+// cpp_s2_cell_polygon
+List cpp_s2_cell_polygon(NumericVector cellIdVector);
+RcppExport SEXP _s2_cpp_s2_cell_polygon(SEXP cellIdVectorSEXP) {
+BEGIN_RCPP
+    Rcpp::RObject rcpp_result_gen;
+    Rcpp::RNGScope rcpp_rngScope_gen;
+    Rcpp::traits::input_parameter< NumericVector >::type cellIdVector(cellIdVectorSEXP);
+    rcpp_result_gen = Rcpp::wrap(cpp_s2_cell_polygon(cellIdVector));
+    return rcpp_result_gen;
+END_RCPP
+}
+// cpp_s2_cell_vertex
+List cpp_s2_cell_vertex(NumericVector cellIdVector, IntegerVector k);
+RcppExport SEXP _s2_cpp_s2_cell_vertex(SEXP cellIdVectorSEXP, SEXP kSEXP) {
+BEGIN_RCPP
+    Rcpp::RObject rcpp_result_gen;
+    Rcpp::RNGScope rcpp_rngScope_gen;
+    Rcpp::traits::input_parameter< NumericVector >::type cellIdVector(cellIdVectorSEXP);
+    Rcpp::traits::input_parameter< IntegerVector >::type k(kSEXP);
+    rcpp_result_gen = Rcpp::wrap(cpp_s2_cell_vertex(cellIdVector, k));
+    return rcpp_result_gen;
+END_RCPP
+}
+// cpp_s2_cell_level
+IntegerVector cpp_s2_cell_level(NumericVector cellIdVector);
+RcppExport SEXP _s2_cpp_s2_cell_level(SEXP cellIdVectorSEXP) {
+BEGIN_RCPP
+    Rcpp::RObject rcpp_result_gen;
+    Rcpp::RNGScope rcpp_rngScope_gen;
+    Rcpp::traits::input_parameter< NumericVector >::type cellIdVector(cellIdVectorSEXP);
+    rcpp_result_gen = Rcpp::wrap(cpp_s2_cell_level(cellIdVector));
+    return rcpp_result_gen;
+END_RCPP
+}
+// cpp_s2_cell_area
+NumericVector cpp_s2_cell_area(NumericVector cellIdVector);
+RcppExport SEXP _s2_cpp_s2_cell_area(SEXP cellIdVectorSEXP) {
+BEGIN_RCPP
+    Rcpp::RObject rcpp_result_gen;
+    Rcpp::RNGScope rcpp_rngScope_gen;
+    Rcpp::traits::input_parameter< NumericVector >::type cellIdVector(cellIdVectorSEXP);
+    rcpp_result_gen = Rcpp::wrap(cpp_s2_cell_area(cellIdVector));
+    return rcpp_result_gen;
+END_RCPP
+}
+// cpp_s2_cell_area_approx
+NumericVector cpp_s2_cell_area_approx(NumericVector cellIdVector);
+RcppExport SEXP _s2_cpp_s2_cell_area_approx(SEXP cellIdVectorSEXP) {
+BEGIN_RCPP
+    Rcpp::RObject rcpp_result_gen;
+    Rcpp::RNGScope rcpp_rngScope_gen;
+    Rcpp::traits::input_parameter< NumericVector >::type cellIdVector(cellIdVectorSEXP);
+    rcpp_result_gen = Rcpp::wrap(cpp_s2_cell_area_approx(cellIdVector));
+    return rcpp_result_gen;
+END_RCPP
+}
+// cpp_s2_cell_parent
+NumericVector cpp_s2_cell_parent(NumericVector cellIdVector, IntegerVector level);
+RcppExport SEXP _s2_cpp_s2_cell_parent(SEXP cellIdVectorSEXP, SEXP levelSEXP) {
+BEGIN_RCPP
+    Rcpp::RObject rcpp_result_gen;
+    Rcpp::RNGScope rcpp_rngScope_gen;
+    Rcpp::traits::input_parameter< NumericVector >::type cellIdVector(cellIdVectorSEXP);
+    Rcpp::traits::input_parameter< IntegerVector >::type level(levelSEXP);
+    rcpp_result_gen = Rcpp::wrap(cpp_s2_cell_parent(cellIdVector, level));
+    return rcpp_result_gen;
+END_RCPP
+}
+// cpp_s2_cell_child
+NumericVector cpp_s2_cell_child(NumericVector cellIdVector, IntegerVector k);
+RcppExport SEXP _s2_cpp_s2_cell_child(SEXP cellIdVectorSEXP, SEXP kSEXP) {
+BEGIN_RCPP
+    Rcpp::RObject rcpp_result_gen;
+    Rcpp::RNGScope rcpp_rngScope_gen;
+    Rcpp::traits::input_parameter< NumericVector >::type cellIdVector(cellIdVectorSEXP);
+    Rcpp::traits::input_parameter< IntegerVector >::type k(kSEXP);
+    rcpp_result_gen = Rcpp::wrap(cpp_s2_cell_child(cellIdVector, k));
+    return rcpp_result_gen;
+END_RCPP
+}
+// cpp_s2_cell_edge_neighbour
+NumericVector cpp_s2_cell_edge_neighbour(NumericVector cellIdVector, IntegerVector k);
+RcppExport SEXP _s2_cpp_s2_cell_edge_neighbour(SEXP cellIdVectorSEXP, SEXP kSEXP) {
+BEGIN_RCPP
+    Rcpp::RObject rcpp_result_gen;
+    Rcpp::RNGScope rcpp_rngScope_gen;
+    Rcpp::traits::input_parameter< NumericVector >::type cellIdVector(cellIdVectorSEXP);
+    Rcpp::traits::input_parameter< IntegerVector >::type k(kSEXP);
+    rcpp_result_gen = Rcpp::wrap(cpp_s2_cell_edge_neighbour(cellIdVector, k));
+    return rcpp_result_gen;
+END_RCPP
+}
+// cpp_s2_cell_cummax
+NumericVector cpp_s2_cell_cummax(NumericVector cellIdVector);
+RcppExport SEXP _s2_cpp_s2_cell_cummax(SEXP cellIdVectorSEXP) {
+BEGIN_RCPP
+    Rcpp::RObject rcpp_result_gen;
+    Rcpp::RNGScope rcpp_rngScope_gen;
+    Rcpp::traits::input_parameter< NumericVector >::type cellIdVector(cellIdVectorSEXP);
+    rcpp_result_gen = Rcpp::wrap(cpp_s2_cell_cummax(cellIdVector));
+    return rcpp_result_gen;
+END_RCPP
+}
+// cpp_s2_cell_cummin
+NumericVector cpp_s2_cell_cummin(NumericVector cellIdVector);
+RcppExport SEXP _s2_cpp_s2_cell_cummin(SEXP cellIdVectorSEXP) {
+BEGIN_RCPP
+    Rcpp::RObject rcpp_result_gen;
+    Rcpp::RNGScope rcpp_rngScope_gen;
+    Rcpp::traits::input_parameter< NumericVector >::type cellIdVector(cellIdVectorSEXP);
+    rcpp_result_gen = Rcpp::wrap(cpp_s2_cell_cummin(cellIdVector));
+    return rcpp_result_gen;
+END_RCPP
+}
+// cpp_s2_cell_eq
+LogicalVector cpp_s2_cell_eq(NumericVector cellIdVector1, NumericVector cellIdVector2);
+RcppExport SEXP _s2_cpp_s2_cell_eq(SEXP cellIdVector1SEXP, SEXP cellIdVector2SEXP) {
+BEGIN_RCPP
+    Rcpp::RObject rcpp_result_gen;
+    Rcpp::RNGScope rcpp_rngScope_gen;
+    Rcpp::traits::input_parameter< NumericVector >::type cellIdVector1(cellIdVector1SEXP);
+    Rcpp::traits::input_parameter< NumericVector >::type cellIdVector2(cellIdVector2SEXP);
+    rcpp_result_gen = Rcpp::wrap(cpp_s2_cell_eq(cellIdVector1, cellIdVector2));
+    return rcpp_result_gen;
+END_RCPP
+}
+// cpp_s2_cell_neq
+LogicalVector cpp_s2_cell_neq(NumericVector cellIdVector1, NumericVector cellIdVector2);
+RcppExport SEXP _s2_cpp_s2_cell_neq(SEXP cellIdVector1SEXP, SEXP cellIdVector2SEXP) {
+BEGIN_RCPP
+    Rcpp::RObject rcpp_result_gen;
+    Rcpp::RNGScope rcpp_rngScope_gen;
+    Rcpp::traits::input_parameter< NumericVector >::type cellIdVector1(cellIdVector1SEXP);
+    Rcpp::traits::input_parameter< NumericVector >::type cellIdVector2(cellIdVector2SEXP);
+    rcpp_result_gen = Rcpp::wrap(cpp_s2_cell_neq(cellIdVector1, cellIdVector2));
+    return rcpp_result_gen;
+END_RCPP
+}
+// cpp_s2_cell_lt
+LogicalVector cpp_s2_cell_lt(NumericVector cellIdVector1, NumericVector cellIdVector2);
+RcppExport SEXP _s2_cpp_s2_cell_lt(SEXP cellIdVector1SEXP, SEXP cellIdVector2SEXP) {
+BEGIN_RCPP
+    Rcpp::RObject rcpp_result_gen;
+    Rcpp::RNGScope rcpp_rngScope_gen;
+    Rcpp::traits::input_parameter< NumericVector >::type cellIdVector1(cellIdVector1SEXP);
+    Rcpp::traits::input_parameter< NumericVector >::type cellIdVector2(cellIdVector2SEXP);
+    rcpp_result_gen = Rcpp::wrap(cpp_s2_cell_lt(cellIdVector1, cellIdVector2));
+    return rcpp_result_gen;
+END_RCPP
+}
+// cpp_s2_cell_lte
+LogicalVector cpp_s2_cell_lte(NumericVector cellIdVector1, NumericVector cellIdVector2);
+RcppExport SEXP _s2_cpp_s2_cell_lte(SEXP cellIdVector1SEXP, SEXP cellIdVector2SEXP) {
+BEGIN_RCPP
+    Rcpp::RObject rcpp_result_gen;
+    Rcpp::RNGScope rcpp_rngScope_gen;
+    Rcpp::traits::input_parameter< NumericVector >::type cellIdVector1(cellIdVector1SEXP);
+    Rcpp::traits::input_parameter< NumericVector >::type cellIdVector2(cellIdVector2SEXP);
+    rcpp_result_gen = Rcpp::wrap(cpp_s2_cell_lte(cellIdVector1, cellIdVector2));
+    return rcpp_result_gen;
+END_RCPP
+}
+// cpp_s2_cell_gte
+LogicalVector cpp_s2_cell_gte(NumericVector cellIdVector1, NumericVector cellIdVector2);
+RcppExport SEXP _s2_cpp_s2_cell_gte(SEXP cellIdVector1SEXP, SEXP cellIdVector2SEXP) {
+BEGIN_RCPP
+    Rcpp::RObject rcpp_result_gen;
+    Rcpp::RNGScope rcpp_rngScope_gen;
+    Rcpp::traits::input_parameter< NumericVector >::type cellIdVector1(cellIdVector1SEXP);
+    Rcpp::traits::input_parameter< NumericVector >::type cellIdVector2(cellIdVector2SEXP);
+    rcpp_result_gen = Rcpp::wrap(cpp_s2_cell_gte(cellIdVector1, cellIdVector2));
+    return rcpp_result_gen;
+END_RCPP
+}
+// cpp_s2_cell_gt
+LogicalVector cpp_s2_cell_gt(NumericVector cellIdVector1, NumericVector cellIdVector2);
+RcppExport SEXP _s2_cpp_s2_cell_gt(SEXP cellIdVector1SEXP, SEXP cellIdVector2SEXP) {
+BEGIN_RCPP
+    Rcpp::RObject rcpp_result_gen;
+    Rcpp::RNGScope rcpp_rngScope_gen;
+    Rcpp::traits::input_parameter< NumericVector >::type cellIdVector1(cellIdVector1SEXP);
+    Rcpp::traits::input_parameter< NumericVector >::type cellIdVector2(cellIdVector2SEXP);
+    rcpp_result_gen = Rcpp::wrap(cpp_s2_cell_gt(cellIdVector1, cellIdVector2));
+    return rcpp_result_gen;
+END_RCPP
+}
+// cpp_s2_cell_contains
+LogicalVector cpp_s2_cell_contains(NumericVector cellIdVector1, NumericVector cellIdVector2);
+RcppExport SEXP _s2_cpp_s2_cell_contains(SEXP cellIdVector1SEXP, SEXP cellIdVector2SEXP) {
+BEGIN_RCPP
+    Rcpp::RObject rcpp_result_gen;
+    Rcpp::RNGScope rcpp_rngScope_gen;
+    Rcpp::traits::input_parameter< NumericVector >::type cellIdVector1(cellIdVector1SEXP);
+    Rcpp::traits::input_parameter< NumericVector >::type cellIdVector2(cellIdVector2SEXP);
+    rcpp_result_gen = Rcpp::wrap(cpp_s2_cell_contains(cellIdVector1, cellIdVector2));
+    return rcpp_result_gen;
+END_RCPP
+}
+// cpp_s2_cell_may_intersect
+LogicalVector cpp_s2_cell_may_intersect(NumericVector cellIdVector1, NumericVector cellIdVector2);
+RcppExport SEXP _s2_cpp_s2_cell_may_intersect(SEXP cellIdVector1SEXP, SEXP cellIdVector2SEXP) {
+BEGIN_RCPP
+    Rcpp::RObject rcpp_result_gen;
+    Rcpp::RNGScope rcpp_rngScope_gen;
+    Rcpp::traits::input_parameter< NumericVector >::type cellIdVector1(cellIdVector1SEXP);
+    Rcpp::traits::input_parameter< NumericVector >::type cellIdVector2(cellIdVector2SEXP);
+    rcpp_result_gen = Rcpp::wrap(cpp_s2_cell_may_intersect(cellIdVector1, cellIdVector2));
+    return rcpp_result_gen;
+END_RCPP
+}
+// cpp_s2_cell_distance
+NumericVector cpp_s2_cell_distance(NumericVector cellIdVector1, NumericVector cellIdVector2);
+RcppExport SEXP _s2_cpp_s2_cell_distance(SEXP cellIdVector1SEXP, SEXP cellIdVector2SEXP) {
+BEGIN_RCPP
+    Rcpp::RObject rcpp_result_gen;
+    Rcpp::RNGScope rcpp_rngScope_gen;
+    Rcpp::traits::input_parameter< NumericVector >::type cellIdVector1(cellIdVector1SEXP);
+    Rcpp::traits::input_parameter< NumericVector >::type cellIdVector2(cellIdVector2SEXP);
+    rcpp_result_gen = Rcpp::wrap(cpp_s2_cell_distance(cellIdVector1, cellIdVector2));
+    return rcpp_result_gen;
+END_RCPP
+}
+// cpp_s2_cell_max_distance
+NumericVector cpp_s2_cell_max_distance(NumericVector cellIdVector1, NumericVector cellIdVector2);
+RcppExport SEXP _s2_cpp_s2_cell_max_distance(SEXP cellIdVector1SEXP, SEXP cellIdVector2SEXP) {
+BEGIN_RCPP
+    Rcpp::RObject rcpp_result_gen;
+    Rcpp::RNGScope rcpp_rngScope_gen;
+    Rcpp::traits::input_parameter< NumericVector >::type cellIdVector1(cellIdVector1SEXP);
+    Rcpp::traits::input_parameter< NumericVector >::type cellIdVector2(cellIdVector2SEXP);
+    rcpp_result_gen = Rcpp::wrap(cpp_s2_cell_max_distance(cellIdVector1, cellIdVector2));
+    return rcpp_result_gen;
+END_RCPP
+}
+// cpp_s2_geog_point
+List cpp_s2_geog_point(NumericVector x, NumericVector y);
+RcppExport SEXP _s2_cpp_s2_geog_point(SEXP xSEXP, SEXP ySEXP) {
+BEGIN_RCPP
+    Rcpp::RObject rcpp_result_gen;
+    Rcpp::RNGScope rcpp_rngScope_gen;
+    Rcpp::traits::input_parameter< NumericVector >::type x(xSEXP);
+    Rcpp::traits::input_parameter< NumericVector >::type y(ySEXP);
+    rcpp_result_gen = Rcpp::wrap(cpp_s2_geog_point(x, y));
+    return rcpp_result_gen;
+END_RCPP
+}
+// cpp_s2_make_line
+List cpp_s2_make_line(NumericVector x, NumericVector y, IntegerVector featureId);
+RcppExport SEXP _s2_cpp_s2_make_line(SEXP xSEXP, SEXP ySEXP, SEXP featureIdSEXP) {
+BEGIN_RCPP
+    Rcpp::RObject rcpp_result_gen;
+    Rcpp::RNGScope rcpp_rngScope_gen;
+    Rcpp::traits::input_parameter< NumericVector >::type x(xSEXP);
+    Rcpp::traits::input_parameter< NumericVector >::type y(ySEXP);
+    Rcpp::traits::input_parameter< IntegerVector >::type featureId(featureIdSEXP);
+    rcpp_result_gen = Rcpp::wrap(cpp_s2_make_line(x, y, featureId));
+    return rcpp_result_gen;
+END_RCPP
+}
+// cpp_s2_make_polygon
+List cpp_s2_make_polygon(NumericVector x, NumericVector y, IntegerVector featureId, IntegerVector ringId, bool oriented, bool check);
+RcppExport SEXP _s2_cpp_s2_make_polygon(SEXP xSEXP, SEXP ySEXP, SEXP featureIdSEXP, SEXP ringIdSEXP, SEXP orientedSEXP, SEXP checkSEXP) {
+BEGIN_RCPP
+    Rcpp::RObject rcpp_result_gen;
+    Rcpp::RNGScope rcpp_rngScope_gen;
+    Rcpp::traits::input_parameter< NumericVector >::type x(xSEXP);
+    Rcpp::traits::input_parameter< NumericVector >::type y(ySEXP);
+    Rcpp::traits::input_parameter< IntegerVector >::type featureId(featureIdSEXP);
+    Rcpp::traits::input_parameter< IntegerVector >::type ringId(ringIdSEXP);
+    Rcpp::traits::input_parameter< bool >::type oriented(orientedSEXP);
+    Rcpp::traits::input_parameter< bool >::type check(checkSEXP);
+    rcpp_result_gen = Rcpp::wrap(cpp_s2_make_polygon(x, y, featureId, ringId, oriented, check));
+    return rcpp_result_gen;
+END_RCPP
+}
+// s2_geography_from_wkb
+List s2_geography_from_wkb(List wkb, bool oriented, bool check);
+RcppExport SEXP _s2_s2_geography_from_wkb(SEXP wkbSEXP, SEXP orientedSEXP, SEXP checkSEXP) {
+BEGIN_RCPP
+    Rcpp::RObject rcpp_result_gen;
+    Rcpp::RNGScope rcpp_rngScope_gen;
+    Rcpp::traits::input_parameter< List >::type wkb(wkbSEXP);
+    Rcpp::traits::input_parameter< bool >::type oriented(orientedSEXP);
+    Rcpp::traits::input_parameter< bool >::type check(checkSEXP);
+    rcpp_result_gen = Rcpp::wrap(s2_geography_from_wkb(wkb, oriented, check));
+    return rcpp_result_gen;
+END_RCPP
+}
+// s2_geography_from_wkt
+List s2_geography_from_wkt(CharacterVector wkt, bool oriented, bool check);
+RcppExport SEXP _s2_s2_geography_from_wkt(SEXP wktSEXP, SEXP orientedSEXP, SEXP checkSEXP) {
+BEGIN_RCPP
+    Rcpp::RObject rcpp_result_gen;
+    Rcpp::RNGScope rcpp_rngScope_gen;
+    Rcpp::traits::input_parameter< CharacterVector >::type wkt(wktSEXP);
+    Rcpp::traits::input_parameter< bool >::type oriented(orientedSEXP);
+    Rcpp::traits::input_parameter< bool >::type check(checkSEXP);
+    rcpp_result_gen = Rcpp::wrap(s2_geography_from_wkt(wkt, oriented, check));
+    return rcpp_result_gen;
+END_RCPP
+}
+// s2_geography_full
+List s2_geography_full(LogicalVector x);
+RcppExport SEXP _s2_s2_geography_full(SEXP xSEXP) {
+BEGIN_RCPP
+    Rcpp::RObject rcpp_result_gen;
+    Rcpp::RNGScope rcpp_rngScope_gen;
+    Rcpp::traits::input_parameter< LogicalVector >::type x(xSEXP);
+    rcpp_result_gen = Rcpp::wrap(s2_geography_full(x));
+    return rcpp_result_gen;
+END_RCPP
+}
+// s2_geography_to_wkt
+CharacterVector s2_geography_to_wkt(List s2_geography, int precision, bool trim);
+RcppExport SEXP _s2_s2_geography_to_wkt(SEXP s2_geographySEXP, SEXP precisionSEXP, SEXP trimSEXP) {
+BEGIN_RCPP
+    Rcpp::RObject rcpp_result_gen;
+    Rcpp::RNGScope rcpp_rngScope_gen;
+    Rcpp::traits::input_parameter< List >::type s2_geography(s2_geographySEXP);
+    Rcpp::traits::input_parameter< int >::type precision(precisionSEXP);
+    Rcpp::traits::input_parameter< bool >::type trim(trimSEXP);
+    rcpp_result_gen = Rcpp::wrap(s2_geography_to_wkt(s2_geography, precision, trim));
+    return rcpp_result_gen;
+END_RCPP
+}
+// s2_geography_to_wkb
+List s2_geography_to_wkb(List s2_geography, int endian);
+RcppExport SEXP _s2_s2_geography_to_wkb(SEXP s2_geographySEXP, SEXP endianSEXP) {
+BEGIN_RCPP
+    Rcpp::RObject rcpp_result_gen;
+    Rcpp::RNGScope rcpp_rngScope_gen;
+    Rcpp::traits::input_parameter< List >::type s2_geography(s2_geographySEXP);
+    Rcpp::traits::input_parameter< int >::type endian(endianSEXP);
+    rcpp_result_gen = Rcpp::wrap(s2_geography_to_wkb(s2_geography, endian));
+    return rcpp_result_gen;
+END_RCPP
+}
+// s2_geography_format
+CharacterVector s2_geography_format(List s2_geography, int maxCoords, int precision, bool trim);
+RcppExport SEXP _s2_s2_geography_format(SEXP s2_geographySEXP, SEXP maxCoordsSEXP, SEXP precisionSEXP, SEXP trimSEXP) {
+BEGIN_RCPP
+    Rcpp::RObject rcpp_result_gen;
+    Rcpp::RNGScope rcpp_rngScope_gen;
+    Rcpp::traits::input_parameter< List >::type s2_geography(s2_geographySEXP);
+    Rcpp::traits::input_parameter< int >::type maxCoords(maxCoordsSEXP);
+    Rcpp::traits::input_parameter< int >::type precision(precisionSEXP);
+    Rcpp::traits::input_parameter< bool >::type trim(trimSEXP);
+    rcpp_result_gen = Rcpp::wrap(s2_geography_format(s2_geography, maxCoords, precision, trim));
+    return rcpp_result_gen;
+END_RCPP
+}
+// s2_lnglat_from_numeric
+List s2_lnglat_from_numeric(NumericVector lng, NumericVector lat);
+RcppExport SEXP _s2_s2_lnglat_from_numeric(SEXP lngSEXP, SEXP latSEXP) {
+BEGIN_RCPP
+    Rcpp::RObject rcpp_result_gen;
+    Rcpp::RNGScope rcpp_rngScope_gen;
+    Rcpp::traits::input_parameter< NumericVector >::type lng(lngSEXP);
+    Rcpp::traits::input_parameter< NumericVector >::type lat(latSEXP);
+    rcpp_result_gen = Rcpp::wrap(s2_lnglat_from_numeric(lng, lat));
+    return rcpp_result_gen;
+END_RCPP
+}
+// s2_lnglat_from_s2_point
+List s2_lnglat_from_s2_point(List s2_point);
+RcppExport SEXP _s2_s2_lnglat_from_s2_point(SEXP s2_pointSEXP) {
+BEGIN_RCPP
+    Rcpp::RObject rcpp_result_gen;
+    Rcpp::RNGScope rcpp_rngScope_gen;
+    Rcpp::traits::input_parameter< List >::type s2_point(s2_pointSEXP);
+    rcpp_result_gen = Rcpp::wrap(s2_lnglat_from_s2_point(s2_point));
+    return rcpp_result_gen;
+END_RCPP
+}
+// data_frame_from_s2_lnglat
+List data_frame_from_s2_lnglat(List xptr);
+RcppExport SEXP _s2_data_frame_from_s2_lnglat(SEXP xptrSEXP) {
+BEGIN_RCPP
+    Rcpp::RObject rcpp_result_gen;
+    Rcpp::RNGScope rcpp_rngScope_gen;
+    Rcpp::traits::input_parameter< List >::type xptr(xptrSEXP);
+    rcpp_result_gen = Rcpp::wrap(data_frame_from_s2_lnglat(xptr));
+    return rcpp_result_gen;
+END_RCPP
+}
+// cpp_s2_closest_feature
+IntegerVector cpp_s2_closest_feature(List geog1, List geog2);
+RcppExport SEXP _s2_cpp_s2_closest_feature(SEXP geog1SEXP, SEXP geog2SEXP) {
+BEGIN_RCPP
+    Rcpp::RObject rcpp_result_gen;
+    Rcpp::RNGScope rcpp_rngScope_gen;
+    Rcpp::traits::input_parameter< List >::type geog1(geog1SEXP);
+    Rcpp::traits::input_parameter< List >::type geog2(geog2SEXP);
+    rcpp_result_gen = Rcpp::wrap(cpp_s2_closest_feature(geog1, geog2));
+    return rcpp_result_gen;
+END_RCPP
+}
+// cpp_s2_farthest_feature
+IntegerVector cpp_s2_farthest_feature(List geog1, List geog2);
+RcppExport SEXP _s2_cpp_s2_farthest_feature(SEXP geog1SEXP, SEXP geog2SEXP) {
+BEGIN_RCPP
+    Rcpp::RObject rcpp_result_gen;
+    Rcpp::RNGScope rcpp_rngScope_gen;
+    Rcpp::traits::input_parameter< List >::type geog1(geog1SEXP);
+    Rcpp::traits::input_parameter< List >::type geog2(geog2SEXP);
+    rcpp_result_gen = Rcpp::wrap(cpp_s2_farthest_feature(geog1, geog2));
+    return rcpp_result_gen;
+END_RCPP
+}
+// cpp_s2_closest_edges
+List cpp_s2_closest_edges(List geog1, List geog2, int n, double min_distance);
+RcppExport SEXP _s2_cpp_s2_closest_edges(SEXP geog1SEXP, SEXP geog2SEXP, SEXP nSEXP, SEXP min_distanceSEXP) {
+BEGIN_RCPP
+    Rcpp::RObject rcpp_result_gen;
+    Rcpp::RNGScope rcpp_rngScope_gen;
+    Rcpp::traits::input_parameter< List >::type geog1(geog1SEXP);
+    Rcpp::traits::input_parameter< List >::type geog2(geog2SEXP);
+    Rcpp::traits::input_parameter< int >::type n(nSEXP);
+    Rcpp::traits::input_parameter< double >::type min_distance(min_distanceSEXP);
+    rcpp_result_gen = Rcpp::wrap(cpp_s2_closest_edges(geog1, geog2, n, min_distance));
+    return rcpp_result_gen;
+END_RCPP
+}
+// cpp_s2_may_intersect_matrix
+List cpp_s2_may_intersect_matrix(List geog1, List geog2, int maxEdgesPerCell, int maxFeatureCells, List s2options);
+RcppExport SEXP _s2_cpp_s2_may_intersect_matrix(SEXP geog1SEXP, SEXP geog2SEXP, SEXP maxEdgesPerCellSEXP, SEXP maxFeatureCellsSEXP, SEXP s2optionsSEXP) {
+BEGIN_RCPP
+    Rcpp::RObject rcpp_result_gen;
+    Rcpp::RNGScope rcpp_rngScope_gen;
+    Rcpp::traits::input_parameter< List >::type geog1(geog1SEXP);
+    Rcpp::traits::input_parameter< List >::type geog2(geog2SEXP);
+    Rcpp::traits::input_parameter< int >::type maxEdgesPerCell(maxEdgesPerCellSEXP);
+    Rcpp::traits::input_parameter< int >::type maxFeatureCells(maxFeatureCellsSEXP);
+    Rcpp::traits::input_parameter< List >::type s2options(s2optionsSEXP);
+    rcpp_result_gen = Rcpp::wrap(cpp_s2_may_intersect_matrix(geog1, geog2, maxEdgesPerCell, maxFeatureCells, s2options));
+    return rcpp_result_gen;
+END_RCPP
+}
+// cpp_s2_contains_matrix
+List cpp_s2_contains_matrix(List geog1, List geog2, List s2options);
+RcppExport SEXP _s2_cpp_s2_contains_matrix(SEXP geog1SEXP, SEXP geog2SEXP, SEXP s2optionsSEXP) {
+BEGIN_RCPP
+    Rcpp::RObject rcpp_result_gen;
+    Rcpp::RNGScope rcpp_rngScope_gen;
+    Rcpp::traits::input_parameter< List >::type geog1(geog1SEXP);
+    Rcpp::traits::input_parameter< List >::type geog2(geog2SEXP);
+    Rcpp::traits::input_parameter< List >::type s2options(s2optionsSEXP);
+    rcpp_result_gen = Rcpp::wrap(cpp_s2_contains_matrix(geog1, geog2, s2options));
+    return rcpp_result_gen;
+END_RCPP
+}
+// cpp_s2_within_matrix
+List cpp_s2_within_matrix(List geog1, List geog2, List s2options);
+RcppExport SEXP _s2_cpp_s2_within_matrix(SEXP geog1SEXP, SEXP geog2SEXP, SEXP s2optionsSEXP) {
+BEGIN_RCPP
+    Rcpp::RObject rcpp_result_gen;
+    Rcpp::RNGScope rcpp_rngScope_gen;
+    Rcpp::traits::input_parameter< List >::type geog1(geog1SEXP);
+    Rcpp::traits::input_parameter< List >::type geog2(geog2SEXP);
+    Rcpp::traits::input_parameter< List >::type s2options(s2optionsSEXP);
+    rcpp_result_gen = Rcpp::wrap(cpp_s2_within_matrix(geog1, geog2, s2options));
+    return rcpp_result_gen;
+END_RCPP
+}
+// cpp_s2_intersects_matrix
+List cpp_s2_intersects_matrix(List geog1, List geog2, List s2options);
+RcppExport SEXP _s2_cpp_s2_intersects_matrix(SEXP geog1SEXP, SEXP geog2SEXP, SEXP s2optionsSEXP) {
+BEGIN_RCPP
+    Rcpp::RObject rcpp_result_gen;
+    Rcpp::RNGScope rcpp_rngScope_gen;
+    Rcpp::traits::input_parameter< List >::type geog1(geog1SEXP);
+    Rcpp::traits::input_parameter< List >::type geog2(geog2SEXP);
+    Rcpp::traits::input_parameter< List >::type s2options(s2optionsSEXP);
+    rcpp_result_gen = Rcpp::wrap(cpp_s2_intersects_matrix(geog1, geog2, s2options));
+    return rcpp_result_gen;
+END_RCPP
+}
+// cpp_s2_equals_matrix
+List cpp_s2_equals_matrix(List geog1, List geog2, List s2options);
+RcppExport SEXP _s2_cpp_s2_equals_matrix(SEXP geog1SEXP, SEXP geog2SEXP, SEXP s2optionsSEXP) {
+BEGIN_RCPP
+    Rcpp::RObject rcpp_result_gen;
+    Rcpp::RNGScope rcpp_rngScope_gen;
+    Rcpp::traits::input_parameter< List >::type geog1(geog1SEXP);
+    Rcpp::traits::input_parameter< List >::type geog2(geog2SEXP);
+    Rcpp::traits::input_parameter< List >::type s2options(s2optionsSEXP);
+    rcpp_result_gen = Rcpp::wrap(cpp_s2_equals_matrix(geog1, geog2, s2options));
+    return rcpp_result_gen;
+END_RCPP
+}
+// cpp_s2_touches_matrix
+List cpp_s2_touches_matrix(List geog1, List geog2, List s2options);
+RcppExport SEXP _s2_cpp_s2_touches_matrix(SEXP geog1SEXP, SEXP geog2SEXP, SEXP s2optionsSEXP) {
+BEGIN_RCPP
+    Rcpp::RObject rcpp_result_gen;
+    Rcpp::RNGScope rcpp_rngScope_gen;
+    Rcpp::traits::input_parameter< List >::type geog1(geog1SEXP);
+    Rcpp::traits::input_parameter< List >::type geog2(geog2SEXP);
+    Rcpp::traits::input_parameter< List >::type s2options(s2optionsSEXP);
+    rcpp_result_gen = Rcpp::wrap(cpp_s2_touches_matrix(geog1, geog2, s2options));
+    return rcpp_result_gen;
+END_RCPP
+}
+// cpp_s2_dwithin_matrix
+List cpp_s2_dwithin_matrix(List geog1, List geog2, double distance);
+RcppExport SEXP _s2_cpp_s2_dwithin_matrix(SEXP geog1SEXP, SEXP geog2SEXP, SEXP distanceSEXP) {
+BEGIN_RCPP
+    Rcpp::RObject rcpp_result_gen;
+    Rcpp::RNGScope rcpp_rngScope_gen;
+    Rcpp::traits::input_parameter< List >::type geog1(geog1SEXP);
+    Rcpp::traits::input_parameter< List >::type geog2(geog2SEXP);
+    Rcpp::traits::input_parameter< double >::type distance(distanceSEXP);
+    rcpp_result_gen = Rcpp::wrap(cpp_s2_dwithin_matrix(geog1, geog2, distance));
+    return rcpp_result_gen;
+END_RCPP
+}
+// cpp_s2_distance_matrix
+NumericMatrix cpp_s2_distance_matrix(List geog1, List geog2);
+RcppExport SEXP _s2_cpp_s2_distance_matrix(SEXP geog1SEXP, SEXP geog2SEXP) {
+BEGIN_RCPP
+    Rcpp::RObject rcpp_result_gen;
+    Rcpp::RNGScope rcpp_rngScope_gen;
+    Rcpp::traits::input_parameter< List >::type geog1(geog1SEXP);
+    Rcpp::traits::input_parameter< List >::type geog2(geog2SEXP);
+    rcpp_result_gen = Rcpp::wrap(cpp_s2_distance_matrix(geog1, geog2));
+    return rcpp_result_gen;
+END_RCPP
+}
+// cpp_s2_max_distance_matrix
+NumericMatrix cpp_s2_max_distance_matrix(List geog1, List geog2);
+RcppExport SEXP _s2_cpp_s2_max_distance_matrix(SEXP geog1SEXP, SEXP geog2SEXP) {
+BEGIN_RCPP
+    Rcpp::RObject rcpp_result_gen;
+    Rcpp::RNGScope rcpp_rngScope_gen;
+    Rcpp::traits::input_parameter< List >::type geog1(geog1SEXP);
+    Rcpp::traits::input_parameter< List >::type geog2(geog2SEXP);
+    rcpp_result_gen = Rcpp::wrap(cpp_s2_max_distance_matrix(geog1, geog2));
+    return rcpp_result_gen;
+END_RCPP
+}
+// cpp_s2_contains_matrix_brute_force
+List cpp_s2_contains_matrix_brute_force(List geog1, List geog2, List s2options);
+RcppExport SEXP _s2_cpp_s2_contains_matrix_brute_force(SEXP geog1SEXP, SEXP geog2SEXP, SEXP s2optionsSEXP) {
+BEGIN_RCPP
+    Rcpp::RObject rcpp_result_gen;
+    Rcpp::RNGScope rcpp_rngScope_gen;
+    Rcpp::traits::input_parameter< List >::type geog1(geog1SEXP);
+    Rcpp::traits::input_parameter< List >::type geog2(geog2SEXP);
+    Rcpp::traits::input_parameter< List >::type s2options(s2optionsSEXP);
+    rcpp_result_gen = Rcpp::wrap(cpp_s2_contains_matrix_brute_force(geog1, geog2, s2options));
+    return rcpp_result_gen;
+END_RCPP
+}
+// cpp_s2_within_matrix_brute_force
+List cpp_s2_within_matrix_brute_force(List geog1, List geog2, List s2options);
+RcppExport SEXP _s2_cpp_s2_within_matrix_brute_force(SEXP geog1SEXP, SEXP geog2SEXP, SEXP s2optionsSEXP) {
+BEGIN_RCPP
+    Rcpp::RObject rcpp_result_gen;
+    Rcpp::RNGScope rcpp_rngScope_gen;
+    Rcpp::traits::input_parameter< List >::type geog1(geog1SEXP);
+    Rcpp::traits::input_parameter< List >::type geog2(geog2SEXP);
+    Rcpp::traits::input_parameter< List >::type s2options(s2optionsSEXP);
+    rcpp_result_gen = Rcpp::wrap(cpp_s2_within_matrix_brute_force(geog1, geog2, s2options));
+    return rcpp_result_gen;
+END_RCPP
+}
+// cpp_s2_intersects_matrix_brute_force
+List cpp_s2_intersects_matrix_brute_force(List geog1, List geog2, List s2options);
+RcppExport SEXP _s2_cpp_s2_intersects_matrix_brute_force(SEXP geog1SEXP, SEXP geog2SEXP, SEXP s2optionsSEXP) {
+BEGIN_RCPP
+    Rcpp::RObject rcpp_result_gen;
+    Rcpp::RNGScope rcpp_rngScope_gen;
+    Rcpp::traits::input_parameter< List >::type geog1(geog1SEXP);
+    Rcpp::traits::input_parameter< List >::type geog2(geog2SEXP);
+    Rcpp::traits::input_parameter< List >::type s2options(s2optionsSEXP);
+    rcpp_result_gen = Rcpp::wrap(cpp_s2_intersects_matrix_brute_force(geog1, geog2, s2options));
+    return rcpp_result_gen;
+END_RCPP
+}
+// cpp_s2_disjoint_matrix_brute_force
+List cpp_s2_disjoint_matrix_brute_force(List geog1, List geog2, List s2options);
+RcppExport SEXP _s2_cpp_s2_disjoint_matrix_brute_force(SEXP geog1SEXP, SEXP geog2SEXP, SEXP s2optionsSEXP) {
+BEGIN_RCPP
+    Rcpp::RObject rcpp_result_gen;
+    Rcpp::RNGScope rcpp_rngScope_gen;
+    Rcpp::traits::input_parameter< List >::type geog1(geog1SEXP);
+    Rcpp::traits::input_parameter< List >::type geog2(geog2SEXP);
+    Rcpp::traits::input_parameter< List >::type s2options(s2optionsSEXP);
+    rcpp_result_gen = Rcpp::wrap(cpp_s2_disjoint_matrix_brute_force(geog1, geog2, s2options));
+    return rcpp_result_gen;
+END_RCPP
+}
+// cpp_s2_equals_matrix_brute_force
+List cpp_s2_equals_matrix_brute_force(List geog1, List geog2, List s2options);
+RcppExport SEXP _s2_cpp_s2_equals_matrix_brute_force(SEXP geog1SEXP, SEXP geog2SEXP, SEXP s2optionsSEXP) {
+BEGIN_RCPP
+    Rcpp::RObject rcpp_result_gen;
+    Rcpp::RNGScope rcpp_rngScope_gen;
+    Rcpp::traits::input_parameter< List >::type geog1(geog1SEXP);
+    Rcpp::traits::input_parameter< List >::type geog2(geog2SEXP);
+    Rcpp::traits::input_parameter< List >::type s2options(s2optionsSEXP);
+    rcpp_result_gen = Rcpp::wrap(cpp_s2_equals_matrix_brute_force(geog1, geog2, s2options));
+    return rcpp_result_gen;
+END_RCPP
+}
+// s2_point_from_numeric
+List s2_point_from_numeric(NumericVector x, NumericVector y, NumericVector z);
+RcppExport SEXP _s2_s2_point_from_numeric(SEXP xSEXP, SEXP ySEXP, SEXP zSEXP) {
+BEGIN_RCPP
+    Rcpp::RObject rcpp_result_gen;
+    Rcpp::RNGScope rcpp_rngScope_gen;
+    Rcpp::traits::input_parameter< NumericVector >::type x(xSEXP);
+    Rcpp::traits::input_parameter< NumericVector >::type y(ySEXP);
+    Rcpp::traits::input_parameter< NumericVector >::type z(zSEXP);
+    rcpp_result_gen = Rcpp::wrap(s2_point_from_numeric(x, y, z));
+    return rcpp_result_gen;
+END_RCPP
+}
+// s2_point_from_s2_lnglat
+List s2_point_from_s2_lnglat(List s2_lnglat);
+RcppExport SEXP _s2_s2_point_from_s2_lnglat(SEXP s2_lnglatSEXP) {
+BEGIN_RCPP
+    Rcpp::RObject rcpp_result_gen;
+    Rcpp::RNGScope rcpp_rngScope_gen;
+    Rcpp::traits::input_parameter< List >::type s2_lnglat(s2_lnglatSEXP);
+    rcpp_result_gen = Rcpp::wrap(s2_point_from_s2_lnglat(s2_lnglat));
+    return rcpp_result_gen;
+END_RCPP
+}
+// data_frame_from_s2_point
+List data_frame_from_s2_point(List s2_point);
+RcppExport SEXP _s2_data_frame_from_s2_point(SEXP s2_pointSEXP) {
+BEGIN_RCPP
+    Rcpp::RObject rcpp_result_gen;
+    Rcpp::RNGScope rcpp_rngScope_gen;
+    Rcpp::traits::input_parameter< List >::type s2_point(s2_pointSEXP);
+    rcpp_result_gen = Rcpp::wrap(data_frame_from_s2_point(s2_point));
+    return rcpp_result_gen;
+END_RCPP
+}
+// cpp_s2_intersects
+LogicalVector cpp_s2_intersects(List geog1, List geog2, List s2options);
+RcppExport SEXP _s2_cpp_s2_intersects(SEXP geog1SEXP, SEXP geog2SEXP, SEXP s2optionsSEXP) {
+BEGIN_RCPP
+    Rcpp::RObject rcpp_result_gen;
+    Rcpp::RNGScope rcpp_rngScope_gen;
+    Rcpp::traits::input_parameter< List >::type geog1(geog1SEXP);
+    Rcpp::traits::input_parameter< List >::type geog2(geog2SEXP);
+    Rcpp::traits::input_parameter< List >::type s2options(s2optionsSEXP);
+    rcpp_result_gen = Rcpp::wrap(cpp_s2_intersects(geog1, geog2, s2options));
+    return rcpp_result_gen;
+END_RCPP
+}
+// cpp_s2_equals
+LogicalVector cpp_s2_equals(List geog1, List geog2, List s2options);
+RcppExport SEXP _s2_cpp_s2_equals(SEXP geog1SEXP, SEXP geog2SEXP, SEXP s2optionsSEXP) {
+BEGIN_RCPP
+    Rcpp::RObject rcpp_result_gen;
+    Rcpp::RNGScope rcpp_rngScope_gen;
+    Rcpp::traits::input_parameter< List >::type geog1(geog1SEXP);
+    Rcpp::traits::input_parameter< List >::type geog2(geog2SEXP);
+    Rcpp::traits::input_parameter< List >::type s2options(s2optionsSEXP);
+    rcpp_result_gen = Rcpp::wrap(cpp_s2_equals(geog1, geog2, s2options));
+    return rcpp_result_gen;
+END_RCPP
+}
+// cpp_s2_contains
+LogicalVector cpp_s2_contains(List geog1, List geog2, List s2options);
+RcppExport SEXP _s2_cpp_s2_contains(SEXP geog1SEXP, SEXP geog2SEXP, SEXP s2optionsSEXP) {
+BEGIN_RCPP
+    Rcpp::RObject rcpp_result_gen;
+    Rcpp::RNGScope rcpp_rngScope_gen;
+    Rcpp::traits::input_parameter< List >::type geog1(geog1SEXP);
+    Rcpp::traits::input_parameter< List >::type geog2(geog2SEXP);
+    Rcpp::traits::input_parameter< List >::type s2options(s2optionsSEXP);
+    rcpp_result_gen = Rcpp::wrap(cpp_s2_contains(geog1, geog2, s2options));
+    return rcpp_result_gen;
+END_RCPP
+}
+// cpp_s2_touches
+LogicalVector cpp_s2_touches(List geog1, List geog2, List s2options);
+RcppExport SEXP _s2_cpp_s2_touches(SEXP geog1SEXP, SEXP geog2SEXP, SEXP s2optionsSEXP) {
+BEGIN_RCPP
+    Rcpp::RObject rcpp_result_gen;
+    Rcpp::RNGScope rcpp_rngScope_gen;
+    Rcpp::traits::input_parameter< List >::type geog1(geog1SEXP);
+    Rcpp::traits::input_parameter< List >::type geog2(geog2SEXP);
+    Rcpp::traits::input_parameter< List >::type s2options(s2optionsSEXP);
+    rcpp_result_gen = Rcpp::wrap(cpp_s2_touches(geog1, geog2, s2options));
+    return rcpp_result_gen;
+END_RCPP
+}
+// cpp_s2_dwithin
+LogicalVector cpp_s2_dwithin(List geog1, List geog2, NumericVector distance);
+RcppExport SEXP _s2_cpp_s2_dwithin(SEXP geog1SEXP, SEXP geog2SEXP, SEXP distanceSEXP) {
+BEGIN_RCPP
+    Rcpp::RObject rcpp_result_gen;
+    Rcpp::RNGScope rcpp_rngScope_gen;
+    Rcpp::traits::input_parameter< List >::type geog1(geog1SEXP);
+    Rcpp::traits::input_parameter< List >::type geog2(geog2SEXP);
+    Rcpp::traits::input_parameter< NumericVector >::type distance(distanceSEXP);
+    rcpp_result_gen = Rcpp::wrap(cpp_s2_dwithin(geog1, geog2, distance));
+    return rcpp_result_gen;
+END_RCPP
+}
+// cpp_s2_intersects_box
+LogicalVector cpp_s2_intersects_box(List geog, NumericVector lng1, NumericVector lat1, NumericVector lng2, NumericVector lat2, IntegerVector detail, List s2options);
+RcppExport SEXP _s2_cpp_s2_intersects_box(SEXP geogSEXP, SEXP lng1SEXP, SEXP lat1SEXP, SEXP lng2SEXP, SEXP lat2SEXP, SEXP detailSEXP, SEXP s2optionsSEXP) {
+BEGIN_RCPP
+    Rcpp::RObject rcpp_result_gen;
+    Rcpp::RNGScope rcpp_rngScope_gen;
+    Rcpp::traits::input_parameter< List >::type geog(geogSEXP);
+    Rcpp::traits::input_parameter< NumericVector >::type lng1(lng1SEXP);
+    Rcpp::traits::input_parameter< NumericVector >::type lat1(lat1SEXP);
+    Rcpp::traits::input_parameter< NumericVector >::type lng2(lng2SEXP);
+    Rcpp::traits::input_parameter< NumericVector >::type lat2(lat2SEXP);
+    Rcpp::traits::input_parameter< IntegerVector >::type detail(detailSEXP);
+    Rcpp::traits::input_parameter< List >::type s2options(s2optionsSEXP);
+    rcpp_result_gen = Rcpp::wrap(cpp_s2_intersects_box(geog, lng1, lat1, lng2, lat2, detail, s2options));
+    return rcpp_result_gen;
+END_RCPP
+}
+// cpp_s2_intersection
+List cpp_s2_intersection(List geog1, List geog2, List s2options);
+RcppExport SEXP _s2_cpp_s2_intersection(SEXP geog1SEXP, SEXP geog2SEXP, SEXP s2optionsSEXP) {
+BEGIN_RCPP
+    Rcpp::RObject rcpp_result_gen;
+    Rcpp::RNGScope rcpp_rngScope_gen;
+    Rcpp::traits::input_parameter< List >::type geog1(geog1SEXP);
+    Rcpp::traits::input_parameter< List >::type geog2(geog2SEXP);
+    Rcpp::traits::input_parameter< List >::type s2options(s2optionsSEXP);
+    rcpp_result_gen = Rcpp::wrap(cpp_s2_intersection(geog1, geog2, s2options));
+    return rcpp_result_gen;
+END_RCPP
+}
+// cpp_s2_union
+List cpp_s2_union(List geog1, List geog2, List s2options);
+RcppExport SEXP _s2_cpp_s2_union(SEXP geog1SEXP, SEXP geog2SEXP, SEXP s2optionsSEXP) {
+BEGIN_RCPP
+    Rcpp::RObject rcpp_result_gen;
+    Rcpp::RNGScope rcpp_rngScope_gen;
+    Rcpp::traits::input_parameter< List >::type geog1(geog1SEXP);
+    Rcpp::traits::input_parameter< List >::type geog2(geog2SEXP);
+    Rcpp::traits::input_parameter< List >::type s2options(s2optionsSEXP);
+    rcpp_result_gen = Rcpp::wrap(cpp_s2_union(geog1, geog2, s2options));
+    return rcpp_result_gen;
+END_RCPP
+}
+// cpp_s2_difference
+List cpp_s2_difference(List geog1, List geog2, List s2options);
+RcppExport SEXP _s2_cpp_s2_difference(SEXP geog1SEXP, SEXP geog2SEXP, SEXP s2optionsSEXP) {
+BEGIN_RCPP
+    Rcpp::RObject rcpp_result_gen;
+    Rcpp::RNGScope rcpp_rngScope_gen;
+    Rcpp::traits::input_parameter< List >::type geog1(geog1SEXP);
+    Rcpp::traits::input_parameter< List >::type geog2(geog2SEXP);
+    Rcpp::traits::input_parameter< List >::type s2options(s2optionsSEXP);
+    rcpp_result_gen = Rcpp::wrap(cpp_s2_difference(geog1, geog2, s2options));
+    return rcpp_result_gen;
+END_RCPP
+}
+// cpp_s2_sym_difference
+List cpp_s2_sym_difference(List geog1, List geog2, List s2options);
+RcppExport SEXP _s2_cpp_s2_sym_difference(SEXP geog1SEXP, SEXP geog2SEXP, SEXP s2optionsSEXP) {
+BEGIN_RCPP
+    Rcpp::RObject rcpp_result_gen;
+    Rcpp::RNGScope rcpp_rngScope_gen;
+    Rcpp::traits::input_parameter< List >::type geog1(geog1SEXP);
+    Rcpp::traits::input_parameter< List >::type geog2(geog2SEXP);
+    Rcpp::traits::input_parameter< List >::type s2options(s2optionsSEXP);
+    rcpp_result_gen = Rcpp::wrap(cpp_s2_sym_difference(geog1, geog2, s2options));
+    return rcpp_result_gen;
+END_RCPP
+}
+// cpp_s2_coverage_union_agg
+List cpp_s2_coverage_union_agg(List geog, List s2options, bool naRm);
+RcppExport SEXP _s2_cpp_s2_coverage_union_agg(SEXP geogSEXP, SEXP s2optionsSEXP, SEXP naRmSEXP) {
+BEGIN_RCPP
+    Rcpp::RObject rcpp_result_gen;
+    Rcpp::RNGScope rcpp_rngScope_gen;
+    Rcpp::traits::input_parameter< List >::type geog(geogSEXP);
+    Rcpp::traits::input_parameter< List >::type s2options(s2optionsSEXP);
+    Rcpp::traits::input_parameter< bool >::type naRm(naRmSEXP);
+    rcpp_result_gen = Rcpp::wrap(cpp_s2_coverage_union_agg(geog, s2options, naRm));
+    return rcpp_result_gen;
+END_RCPP
+}
+// cpp_s2_union_agg
+List cpp_s2_union_agg(List geog, List s2options, bool naRm);
+RcppExport SEXP _s2_cpp_s2_union_agg(SEXP geogSEXP, SEXP s2optionsSEXP, SEXP naRmSEXP) {
+BEGIN_RCPP
+    Rcpp::RObject rcpp_result_gen;
+    Rcpp::RNGScope rcpp_rngScope_gen;
+    Rcpp::traits::input_parameter< List >::type geog(geogSEXP);
+    Rcpp::traits::input_parameter< List >::type s2options(s2optionsSEXP);
+    Rcpp::traits::input_parameter< bool >::type naRm(naRmSEXP);
+    rcpp_result_gen = Rcpp::wrap(cpp_s2_union_agg(geog, s2options, naRm));
+    return rcpp_result_gen;
+END_RCPP
+}
+// cpp_s2_centroid_agg
+List cpp_s2_centroid_agg(List geog, bool naRm);
+RcppExport SEXP _s2_cpp_s2_centroid_agg(SEXP geogSEXP, SEXP naRmSEXP) {
+BEGIN_RCPP
+    Rcpp::RObject rcpp_result_gen;
+    Rcpp::RNGScope rcpp_rngScope_gen;
+    Rcpp::traits::input_parameter< List >::type geog(geogSEXP);
+    Rcpp::traits::input_parameter< bool >::type naRm(naRmSEXP);
+    rcpp_result_gen = Rcpp::wrap(cpp_s2_centroid_agg(geog, naRm));
+    return rcpp_result_gen;
+END_RCPP
+}
+// cpp_s2_rebuild_agg
+List cpp_s2_rebuild_agg(List geog, List s2options, bool naRm);
+RcppExport SEXP _s2_cpp_s2_rebuild_agg(SEXP geogSEXP, SEXP s2optionsSEXP, SEXP naRmSEXP) {
+BEGIN_RCPP
+    Rcpp::RObject rcpp_result_gen;
+    Rcpp::RNGScope rcpp_rngScope_gen;
+    Rcpp::traits::input_parameter< List >::type geog(geogSEXP);
+    Rcpp::traits::input_parameter< List >::type s2options(s2optionsSEXP);
+    Rcpp::traits::input_parameter< bool >::type naRm(naRmSEXP);
+    rcpp_result_gen = Rcpp::wrap(cpp_s2_rebuild_agg(geog, s2options, naRm));
+    return rcpp_result_gen;
+END_RCPP
+}
+// cpp_s2_closest_point
+List cpp_s2_closest_point(List geog1, List geog2);
+RcppExport SEXP _s2_cpp_s2_closest_point(SEXP geog1SEXP, SEXP geog2SEXP) {
+BEGIN_RCPP
+    Rcpp::RObject rcpp_result_gen;
+    Rcpp::RNGScope rcpp_rngScope_gen;
+    Rcpp::traits::input_parameter< List >::type geog1(geog1SEXP);
+    Rcpp::traits::input_parameter< List >::type geog2(geog2SEXP);
+    rcpp_result_gen = Rcpp::wrap(cpp_s2_closest_point(geog1, geog2));
+    return rcpp_result_gen;
+END_RCPP
+}
+// cpp_s2_minimum_clearance_line_between
+List cpp_s2_minimum_clearance_line_between(List geog1, List geog2);
+RcppExport SEXP _s2_cpp_s2_minimum_clearance_line_between(SEXP geog1SEXP, SEXP geog2SEXP) {
+BEGIN_RCPP
+    Rcpp::RObject rcpp_result_gen;
+    Rcpp::RNGScope rcpp_rngScope_gen;
+    Rcpp::traits::input_parameter< List >::type geog1(geog1SEXP);
+    Rcpp::traits::input_parameter< List >::type geog2(geog2SEXP);
+    rcpp_result_gen = Rcpp::wrap(cpp_s2_minimum_clearance_line_between(geog1, geog2));
+    return rcpp_result_gen;
+END_RCPP
+}
+// cpp_s2_centroid
+List cpp_s2_centroid(List geog);
+RcppExport SEXP _s2_cpp_s2_centroid(SEXP geogSEXP) {
+BEGIN_RCPP
+    Rcpp::RObject rcpp_result_gen;
+    Rcpp::RNGScope rcpp_rngScope_gen;
+    Rcpp::traits::input_parameter< List >::type geog(geogSEXP);
+    rcpp_result_gen = Rcpp::wrap(cpp_s2_centroid(geog));
+    return rcpp_result_gen;
+END_RCPP
+}
+// cpp_s2_boundary
+List cpp_s2_boundary(List geog);
+RcppExport SEXP _s2_cpp_s2_boundary(SEXP geogSEXP) {
+BEGIN_RCPP
+    Rcpp::RObject rcpp_result_gen;
+    Rcpp::RNGScope rcpp_rngScope_gen;
+    Rcpp::traits::input_parameter< List >::type geog(geogSEXP);
+    rcpp_result_gen = Rcpp::wrap(cpp_s2_boundary(geog));
+    return rcpp_result_gen;
+END_RCPP
+}
+// cpp_s2_rebuild
+List cpp_s2_rebuild(List geog, List s2options);
+RcppExport SEXP _s2_cpp_s2_rebuild(SEXP geogSEXP, SEXP s2optionsSEXP) {
+BEGIN_RCPP
+    Rcpp::RObject rcpp_result_gen;
+    Rcpp::RNGScope rcpp_rngScope_gen;
+    Rcpp::traits::input_parameter< List >::type geog(geogSEXP);
+    Rcpp::traits::input_parameter< List >::type s2options(s2optionsSEXP);
+    rcpp_result_gen = Rcpp::wrap(cpp_s2_rebuild(geog, s2options));
+    return rcpp_result_gen;
+END_RCPP
+}
+// cpp_s2_unary_union
+List cpp_s2_unary_union(List geog, List s2options);
+RcppExport SEXP _s2_cpp_s2_unary_union(SEXP geogSEXP, SEXP s2optionsSEXP) {
+BEGIN_RCPP
+    Rcpp::RObject rcpp_result_gen;
+    Rcpp::RNGScope rcpp_rngScope_gen;
+    Rcpp::traits::input_parameter< List >::type geog(geogSEXP);
+    Rcpp::traits::input_parameter< List >::type s2options(s2optionsSEXP);
+    rcpp_result_gen = Rcpp::wrap(cpp_s2_unary_union(geog, s2options));
+    return rcpp_result_gen;
+END_RCPP
+}
+// cpp_s2_interpolate_normalized
+List cpp_s2_interpolate_normalized(List geog, NumericVector distanceNormalized);
+RcppExport SEXP _s2_cpp_s2_interpolate_normalized(SEXP geogSEXP, SEXP distanceNormalizedSEXP) {
+BEGIN_RCPP
+    Rcpp::RObject rcpp_result_gen;
+    Rcpp::RNGScope rcpp_rngScope_gen;
+    Rcpp::traits::input_parameter< List >::type geog(geogSEXP);
+    Rcpp::traits::input_parameter< NumericVector >::type distanceNormalized(distanceNormalizedSEXP);
+    rcpp_result_gen = Rcpp::wrap(cpp_s2_interpolate_normalized(geog, distanceNormalized));
+    return rcpp_result_gen;
+END_RCPP
+}
+// cpp_s2_buffer_cells
+List cpp_s2_buffer_cells(List geog, NumericVector distance, int maxCells, int minLevel);
+RcppExport SEXP _s2_cpp_s2_buffer_cells(SEXP geogSEXP, SEXP distanceSEXP, SEXP maxCellsSEXP, SEXP minLevelSEXP) {
+BEGIN_RCPP
+    Rcpp::RObject rcpp_result_gen;
+    Rcpp::RNGScope rcpp_rngScope_gen;
+    Rcpp::traits::input_parameter< List >::type geog(geogSEXP);
+    Rcpp::traits::input_parameter< NumericVector >::type distance(distanceSEXP);
+    Rcpp::traits::input_parameter< int >::type maxCells(maxCellsSEXP);
+    Rcpp::traits::input_parameter< int >::type minLevel(minLevelSEXP);
+    rcpp_result_gen = Rcpp::wrap(cpp_s2_buffer_cells(geog, distance, maxCells, minLevel));
+    return rcpp_result_gen;
+END_RCPP
+}
+// s2_xptr_test
+List s2_xptr_test(R_xlen_t size);
+RcppExport SEXP _s2_s2_xptr_test(SEXP sizeSEXP) {
+BEGIN_RCPP
+    Rcpp::RObject rcpp_result_gen;
+    Rcpp::RNGScope rcpp_rngScope_gen;
+    Rcpp::traits::input_parameter< R_xlen_t >::type size(sizeSEXP);
+    rcpp_result_gen = Rcpp::wrap(s2_xptr_test(size));
+    return rcpp_result_gen;
+END_RCPP
+}
+// s2_xptr_test_op
+void s2_xptr_test_op(List s2_xptr_test);
+RcppExport SEXP _s2_s2_xptr_test_op(SEXP s2_xptr_testSEXP) {
+BEGIN_RCPP
+    Rcpp::RNGScope rcpp_rngScope_gen;
+    Rcpp::traits::input_parameter< List >::type s2_xptr_test(s2_xptr_testSEXP);
+    s2_xptr_test_op(s2_xptr_test);
+    return R_NilValue;
+END_RCPP
+}
+
+RcppExport SEXP c_s2_coord_filter_new(SEXP, SEXP, SEXP, SEXP);
+RcppExport SEXP c_s2_projection_mercator();
+RcppExport SEXP c_s2_projection_plate_carree();
+
+static const R_CallMethodDef CallEntries[] = {
+    {"_s2_cpp_s2_init", (DL_FUNC) &_s2_cpp_s2_init, 0},
+    {"_s2_cpp_s2_is_collection", (DL_FUNC) &_s2_cpp_s2_is_collection, 1},
+    {"_s2_cpp_s2_is_valid", (DL_FUNC) &_s2_cpp_s2_is_valid, 1},
+    {"_s2_cpp_s2_is_valid_reason", (DL_FUNC) &_s2_cpp_s2_is_valid_reason, 1},
+    {"_s2_cpp_s2_dimension", (DL_FUNC) &_s2_cpp_s2_dimension, 1},
+    {"_s2_cpp_s2_num_points", (DL_FUNC) &_s2_cpp_s2_num_points, 1},
+    {"_s2_cpp_s2_is_empty", (DL_FUNC) &_s2_cpp_s2_is_empty, 1},
+    {"_s2_cpp_s2_area", (DL_FUNC) &_s2_cpp_s2_area, 1},
+    {"_s2_cpp_s2_length", (DL_FUNC) &_s2_cpp_s2_length, 1},
+    {"_s2_cpp_s2_perimeter", (DL_FUNC) &_s2_cpp_s2_perimeter, 1},
+    {"_s2_cpp_s2_x", (DL_FUNC) &_s2_cpp_s2_x, 1},
+    {"_s2_cpp_s2_y", (DL_FUNC) &_s2_cpp_s2_y, 1},
+    {"_s2_cpp_s2_project_normalized", (DL_FUNC) &_s2_cpp_s2_project_normalized, 2},
+    {"_s2_cpp_s2_distance", (DL_FUNC) &_s2_cpp_s2_distance, 2},
+    {"_s2_cpp_s2_max_distance", (DL_FUNC) &_s2_cpp_s2_max_distance, 2},
+    {"_s2_cpp_s2_bounds_cap", (DL_FUNC) &_s2_cpp_s2_bounds_cap, 1},
+    {"_s2_cpp_s2_bounds_rect", (DL_FUNC) &_s2_cpp_s2_bounds_rect, 1},
+    {"_s2_cpp_s2_cell_sentinel", (DL_FUNC) &_s2_cpp_s2_cell_sentinel, 0},
+    {"_s2_cpp_s2_cell_from_string", (DL_FUNC) &_s2_cpp_s2_cell_from_string, 1},
+    {"_s2_cpp_s2_cell_from_lnglat", (DL_FUNC) &_s2_cpp_s2_cell_from_lnglat, 1},
+    {"_s2_cpp_s2_cell_to_lnglat", (DL_FUNC) &_s2_cpp_s2_cell_to_lnglat, 1},
+    {"_s2_cpp_s2_cell_is_na", (DL_FUNC) &_s2_cpp_s2_cell_is_na, 1},
+    {"_s2_cpp_s2_cell_sort", (DL_FUNC) &_s2_cpp_s2_cell_sort, 2},
+    {"_s2_cpp_s2_cell_range", (DL_FUNC) &_s2_cpp_s2_cell_range, 2},
+    {"_s2_cpp_s2_cell_unique", (DL_FUNC) &_s2_cpp_s2_cell_unique, 1},
+    {"_s2_cpp_s2_cell_to_string", (DL_FUNC) &_s2_cpp_s2_cell_to_string, 1},
+    {"_s2_cpp_s2_cell_debug_string", (DL_FUNC) &_s2_cpp_s2_cell_debug_string, 1},
+    {"_s2_cpp_s2_cell_is_valid", (DL_FUNC) &_s2_cpp_s2_cell_is_valid, 1},
+    {"_s2_cpp_s2_cell_center", (DL_FUNC) &_s2_cpp_s2_cell_center, 1},
+    {"_s2_cpp_s2_cell_polygon", (DL_FUNC) &_s2_cpp_s2_cell_polygon, 1},
+    {"_s2_cpp_s2_cell_vertex", (DL_FUNC) &_s2_cpp_s2_cell_vertex, 2},
+    {"_s2_cpp_s2_cell_level", (DL_FUNC) &_s2_cpp_s2_cell_level, 1},
+    {"_s2_cpp_s2_cell_area", (DL_FUNC) &_s2_cpp_s2_cell_area, 1},
+    {"_s2_cpp_s2_cell_area_approx", (DL_FUNC) &_s2_cpp_s2_cell_area_approx, 1},
+    {"_s2_cpp_s2_cell_parent", (DL_FUNC) &_s2_cpp_s2_cell_parent, 2},
+    {"_s2_cpp_s2_cell_child", (DL_FUNC) &_s2_cpp_s2_cell_child, 2},
+    {"_s2_cpp_s2_cell_edge_neighbour", (DL_FUNC) &_s2_cpp_s2_cell_edge_neighbour, 2},
+    {"_s2_cpp_s2_cell_cummax", (DL_FUNC) &_s2_cpp_s2_cell_cummax, 1},
+    {"_s2_cpp_s2_cell_cummin", (DL_FUNC) &_s2_cpp_s2_cell_cummin, 1},
+    {"_s2_cpp_s2_cell_eq", (DL_FUNC) &_s2_cpp_s2_cell_eq, 2},
+    {"_s2_cpp_s2_cell_neq", (DL_FUNC) &_s2_cpp_s2_cell_neq, 2},
+    {"_s2_cpp_s2_cell_lt", (DL_FUNC) &_s2_cpp_s2_cell_lt, 2},
+    {"_s2_cpp_s2_cell_lte", (DL_FUNC) &_s2_cpp_s2_cell_lte, 2},
+    {"_s2_cpp_s2_cell_gte", (DL_FUNC) &_s2_cpp_s2_cell_gte, 2},
+    {"_s2_cpp_s2_cell_gt", (DL_FUNC) &_s2_cpp_s2_cell_gt, 2},
+    {"_s2_cpp_s2_cell_contains", (DL_FUNC) &_s2_cpp_s2_cell_contains, 2},
+    {"_s2_cpp_s2_cell_may_intersect", (DL_FUNC) &_s2_cpp_s2_cell_may_intersect, 2},
+    {"_s2_cpp_s2_cell_distance", (DL_FUNC) &_s2_cpp_s2_cell_distance, 2},
+    {"_s2_cpp_s2_cell_max_distance", (DL_FUNC) &_s2_cpp_s2_cell_max_distance, 2},
+    {"_s2_cpp_s2_geog_point", (DL_FUNC) &_s2_cpp_s2_geog_point, 2},
+    {"_s2_cpp_s2_make_line", (DL_FUNC) &_s2_cpp_s2_make_line, 3},
+    {"_s2_cpp_s2_make_polygon", (DL_FUNC) &_s2_cpp_s2_make_polygon, 6},
+    {"_s2_s2_geography_from_wkb", (DL_FUNC) &_s2_s2_geography_from_wkb, 3},
+    {"_s2_s2_geography_from_wkt", (DL_FUNC) &_s2_s2_geography_from_wkt, 3},
+    {"_s2_s2_geography_full", (DL_FUNC) &_s2_s2_geography_full, 1},
+    {"_s2_s2_geography_to_wkt", (DL_FUNC) &_s2_s2_geography_to_wkt, 3},
+    {"_s2_s2_geography_to_wkb", (DL_FUNC) &_s2_s2_geography_to_wkb, 2},
+    {"_s2_s2_geography_format", (DL_FUNC) &_s2_s2_geography_format, 4},
+    {"_s2_s2_lnglat_from_numeric", (DL_FUNC) &_s2_s2_lnglat_from_numeric, 2},
+    {"_s2_s2_lnglat_from_s2_point", (DL_FUNC) &_s2_s2_lnglat_from_s2_point, 1},
+    {"_s2_data_frame_from_s2_lnglat", (DL_FUNC) &_s2_data_frame_from_s2_lnglat, 1},
+    {"_s2_cpp_s2_closest_feature", (DL_FUNC) &_s2_cpp_s2_closest_feature, 2},
+    {"_s2_cpp_s2_farthest_feature", (DL_FUNC) &_s2_cpp_s2_farthest_feature, 2},
+    {"_s2_cpp_s2_closest_edges", (DL_FUNC) &_s2_cpp_s2_closest_edges, 4},
+    {"_s2_cpp_s2_may_intersect_matrix", (DL_FUNC) &_s2_cpp_s2_may_intersect_matrix, 5},
+    {"_s2_cpp_s2_contains_matrix", (DL_FUNC) &_s2_cpp_s2_contains_matrix, 3},
+    {"_s2_cpp_s2_within_matrix", (DL_FUNC) &_s2_cpp_s2_within_matrix, 3},
+    {"_s2_cpp_s2_intersects_matrix", (DL_FUNC) &_s2_cpp_s2_intersects_matrix, 3},
+    {"_s2_cpp_s2_equals_matrix", (DL_FUNC) &_s2_cpp_s2_equals_matrix, 3},
+    {"_s2_cpp_s2_touches_matrix", (DL_FUNC) &_s2_cpp_s2_touches_matrix, 3},
+    {"_s2_cpp_s2_dwithin_matrix", (DL_FUNC) &_s2_cpp_s2_dwithin_matrix, 3},
+    {"_s2_cpp_s2_distance_matrix", (DL_FUNC) &_s2_cpp_s2_distance_matrix, 2},
+    {"_s2_cpp_s2_max_distance_matrix", (DL_FUNC) &_s2_cpp_s2_max_distance_matrix, 2},
+    {"_s2_cpp_s2_contains_matrix_brute_force", (DL_FUNC) &_s2_cpp_s2_contains_matrix_brute_force, 3},
+    {"_s2_cpp_s2_within_matrix_brute_force", (DL_FUNC) &_s2_cpp_s2_within_matrix_brute_force, 3},
+    {"_s2_cpp_s2_intersects_matrix_brute_force", (DL_FUNC) &_s2_cpp_s2_intersects_matrix_brute_force, 3},
+    {"_s2_cpp_s2_disjoint_matrix_brute_force", (DL_FUNC) &_s2_cpp_s2_disjoint_matrix_brute_force, 3},
+    {"_s2_cpp_s2_equals_matrix_brute_force", (DL_FUNC) &_s2_cpp_s2_equals_matrix_brute_force, 3},
+    {"_s2_s2_point_from_numeric", (DL_FUNC) &_s2_s2_point_from_numeric, 3},
+    {"_s2_s2_point_from_s2_lnglat", (DL_FUNC) &_s2_s2_point_from_s2_lnglat, 1},
+    {"_s2_data_frame_from_s2_point", (DL_FUNC) &_s2_data_frame_from_s2_point, 1},
+    {"_s2_cpp_s2_intersects", (DL_FUNC) &_s2_cpp_s2_intersects, 3},
+    {"_s2_cpp_s2_equals", (DL_FUNC) &_s2_cpp_s2_equals, 3},
+    {"_s2_cpp_s2_contains", (DL_FUNC) &_s2_cpp_s2_contains, 3},
+    {"_s2_cpp_s2_touches", (DL_FUNC) &_s2_cpp_s2_touches, 3},
+    {"_s2_cpp_s2_dwithin", (DL_FUNC) &_s2_cpp_s2_dwithin, 3},
+    {"_s2_cpp_s2_intersects_box", (DL_FUNC) &_s2_cpp_s2_intersects_box, 7},
+    {"_s2_cpp_s2_intersection", (DL_FUNC) &_s2_cpp_s2_intersection, 3},
+    {"_s2_cpp_s2_union", (DL_FUNC) &_s2_cpp_s2_union, 3},
+    {"_s2_cpp_s2_difference", (DL_FUNC) &_s2_cpp_s2_difference, 3},
+    {"_s2_cpp_s2_sym_difference", (DL_FUNC) &_s2_cpp_s2_sym_difference, 3},
+    {"_s2_cpp_s2_coverage_union_agg", (DL_FUNC) &_s2_cpp_s2_coverage_union_agg, 3},
+    {"_s2_cpp_s2_union_agg", (DL_FUNC) &_s2_cpp_s2_union_agg, 3},
+    {"_s2_cpp_s2_centroid_agg", (DL_FUNC) &_s2_cpp_s2_centroid_agg, 2},
+    {"_s2_cpp_s2_rebuild_agg", (DL_FUNC) &_s2_cpp_s2_rebuild_agg, 3},
+    {"_s2_cpp_s2_closest_point", (DL_FUNC) &_s2_cpp_s2_closest_point, 2},
+    {"_s2_cpp_s2_minimum_clearance_line_between", (DL_FUNC) &_s2_cpp_s2_minimum_clearance_line_between, 2},
+    {"_s2_cpp_s2_centroid", (DL_FUNC) &_s2_cpp_s2_centroid, 1},
+    {"_s2_cpp_s2_boundary", (DL_FUNC) &_s2_cpp_s2_boundary, 1},
+    {"_s2_cpp_s2_rebuild", (DL_FUNC) &_s2_cpp_s2_rebuild, 2},
+    {"_s2_cpp_s2_unary_union", (DL_FUNC) &_s2_cpp_s2_unary_union, 2},
+    {"_s2_cpp_s2_interpolate_normalized", (DL_FUNC) &_s2_cpp_s2_interpolate_normalized, 2},
+    {"_s2_cpp_s2_buffer_cells", (DL_FUNC) &_s2_cpp_s2_buffer_cells, 4},
+    {"_s2_s2_xptr_test", (DL_FUNC) &_s2_s2_xptr_test, 1},
+    {"_s2_s2_xptr_test_op", (DL_FUNC) &_s2_s2_xptr_test_op, 1},
+    {"c_s2_coord_filter_new",        (DL_FUNC) &c_s2_coord_filter_new,        4},
+    {"c_s2_projection_mercator",     (DL_FUNC) &c_s2_projection_mercator,     0},
+    {"c_s2_projection_plate_carree", (DL_FUNC) &c_s2_projection_plate_carree, 0},
+    {NULL, NULL, 0}
+};
+
+RcppExport void R_init_s2(DllInfo *dll) {
+    R_registerRoutines(dll, NULL, CallEntries, NULL, NULL);
+    R_useDynamicSymbols(dll, FALSE);
+}
diff --git a/src/absl/algorithm/algorithm.h b/src/absl/algorithm/algorithm.h
new file mode 100644 (file)
index 0000000..e9b4733
--- /dev/null
@@ -0,0 +1,159 @@
+// Copyright 2017 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// -----------------------------------------------------------------------------
+// File: algorithm.h
+// -----------------------------------------------------------------------------
+//
+// This header file contains Google extensions to the standard <algorithm> C++
+// header.
+
+#ifndef ABSL_ALGORITHM_ALGORITHM_H_
+#define ABSL_ALGORITHM_ALGORITHM_H_
+
+#include <algorithm>
+#include <iterator>
+#include <type_traits>
+
+#include "absl/base/config.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+
+namespace algorithm_internal {
+
+// Performs comparisons with operator==, similar to C++14's `std::equal_to<>`.
+struct EqualTo {
+  template <typename T, typename U>
+  bool operator()(const T& a, const U& b) const {
+    return a == b;
+  }
+};
+
+template <typename InputIter1, typename InputIter2, typename Pred>
+bool EqualImpl(InputIter1 first1, InputIter1 last1, InputIter2 first2,
+               InputIter2 last2, Pred pred, std::input_iterator_tag,
+               std::input_iterator_tag) {
+  while (true) {
+    if (first1 == last1) return first2 == last2;
+    if (first2 == last2) return false;
+    if (!pred(*first1, *first2)) return false;
+    ++first1;
+    ++first2;
+  }
+}
+
+template <typename InputIter1, typename InputIter2, typename Pred>
+bool EqualImpl(InputIter1 first1, InputIter1 last1, InputIter2 first2,
+               InputIter2 last2, Pred&& pred, std::random_access_iterator_tag,
+               std::random_access_iterator_tag) {
+  return (last1 - first1 == last2 - first2) &&
+         std::equal(first1, last1, first2, std::forward<Pred>(pred));
+}
+
+// When we are using our own internal predicate that just applies operator==, we
+// forward to the non-predicate form of std::equal. This enables an optimization
+// in libstdc++ that can result in std::memcmp being used for integer types.
+template <typename InputIter1, typename InputIter2>
+bool EqualImpl(InputIter1 first1, InputIter1 last1, InputIter2 first2,
+               InputIter2 last2, algorithm_internal::EqualTo /* unused */,
+               std::random_access_iterator_tag,
+               std::random_access_iterator_tag) {
+  return (last1 - first1 == last2 - first2) &&
+         std::equal(first1, last1, first2);
+}
+
+template <typename It>
+It RotateImpl(It first, It middle, It last, std::true_type) {
+  return std::rotate(first, middle, last);
+}
+
+template <typename It>
+It RotateImpl(It first, It middle, It last, std::false_type) {
+  std::rotate(first, middle, last);
+  return std::next(first, std::distance(middle, last));
+}
+
+}  // namespace algorithm_internal
+
+// equal()
+//
+// Compares the equality of two ranges specified by pairs of iterators, using
+// the given predicate, returning true iff for each corresponding iterator i1
+// and i2 in the first and second range respectively, pred(*i1, *i2) == true
+//
+// This comparison takes at most min(`last1` - `first1`, `last2` - `first2`)
+// invocations of the predicate. Additionally, if InputIter1 and InputIter2 are
+// both random-access iterators, and `last1` - `first1` != `last2` - `first2`,
+// then the predicate is never invoked and the function returns false.
+//
+// This is a C++11-compatible implementation of C++14 `std::equal`.  See
+// https://en.cppreference.com/w/cpp/algorithm/equal for more information.
+template <typename InputIter1, typename InputIter2, typename Pred>
+bool equal(InputIter1 first1, InputIter1 last1, InputIter2 first2,
+           InputIter2 last2, Pred&& pred) {
+  return algorithm_internal::EqualImpl(
+      first1, last1, first2, last2, std::forward<Pred>(pred),
+      typename std::iterator_traits<InputIter1>::iterator_category{},
+      typename std::iterator_traits<InputIter2>::iterator_category{});
+}
+
+// Overload of equal() that performs comparison of two ranges specified by pairs
+// of iterators using operator==.
+template <typename InputIter1, typename InputIter2>
+bool equal(InputIter1 first1, InputIter1 last1, InputIter2 first2,
+           InputIter2 last2) {
+  return absl::equal(first1, last1, first2, last2,
+                     algorithm_internal::EqualTo{});
+}
+
+// linear_search()
+//
+// Performs a linear search for `value` using the iterator `first` up to
+// but not including `last`, returning true if [`first`, `last`) contains an
+// element equal to `value`.
+//
+// A linear search is of O(n) complexity which is guaranteed to make at most
+// n = (`last` - `first`) comparisons. A linear search over short containers
+// may be faster than a binary search, even when the container is sorted.
+template <typename InputIterator, typename EqualityComparable>
+bool linear_search(InputIterator first, InputIterator last,
+                   const EqualityComparable& value) {
+  return std::find(first, last, value) != last;
+}
+
+// rotate()
+//
+// Performs a left rotation on a range of elements (`first`, `last`) such that
+// `middle` is now the first element. `rotate()` returns an iterator pointing to
+// the first element before rotation. This function is exactly the same as
+// `std::rotate`, but fixes a bug in gcc
+// <= 4.9 where `std::rotate` returns `void` instead of an iterator.
+//
+// The complexity of this algorithm is the same as that of `std::rotate`, but if
+// `ForwardIterator` is not a random-access iterator, then `absl::rotate`
+// performs an additional pass over the range to construct the return value.
+template <typename ForwardIterator>
+ForwardIterator rotate(ForwardIterator first, ForwardIterator middle,
+                       ForwardIterator last) {
+  return algorithm_internal::RotateImpl(
+      first, middle, last,
+      std::is_same<decltype(std::rotate(first, middle, last)),
+                   ForwardIterator>());
+}
+
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#endif  // ABSL_ALGORITHM_ALGORITHM_H_
diff --git a/src/absl/algorithm/container.h b/src/absl/algorithm/container.h
new file mode 100644 (file)
index 0000000..6398438
--- /dev/null
@@ -0,0 +1,1764 @@
+// Copyright 2017 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// -----------------------------------------------------------------------------
+// File: container.h
+// -----------------------------------------------------------------------------
+//
+// This header file provides Container-based versions of algorithmic functions
+// within the C++ standard library. The following standard library sets of
+// functions are covered within this file:
+//
+//   * Algorithmic <iterator> functions
+//   * Algorithmic <numeric> functions
+//   * <algorithm> functions
+//
+// The standard library functions operate on iterator ranges; the functions
+// within this API operate on containers, though many return iterator ranges.
+//
+// All functions within this API are named with a `c_` prefix. Calls such as
+// `absl::c_xx(container, ...) are equivalent to std:: functions such as
+// `std::xx(std::begin(cont), std::end(cont), ...)`. Functions that act on
+// iterators but not conceptually on iterator ranges (e.g. `std::iter_swap`)
+// have no equivalent here.
+//
+// For template parameter and variable naming, `C` indicates the container type
+// to which the function is applied, `Pred` indicates the predicate object type
+// to be used by the function and `T` indicates the applicable element type.
+
+#ifndef ABSL_ALGORITHM_CONTAINER_H_
+#define ABSL_ALGORITHM_CONTAINER_H_
+
+#include <algorithm>
+#include <cassert>
+#include <iterator>
+#include <numeric>
+#include <type_traits>
+#include <unordered_map>
+#include <unordered_set>
+#include <utility>
+#include <vector>
+
+#include "absl/algorithm/algorithm.h"
+#include "absl/base/macros.h"
+#include "absl/meta/type_traits.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace container_algorithm_internal {
+
+// NOTE: it is important to defer to ADL lookup for building with C++ modules,
+// especially for headers like <valarray> which are not visible from this file
+// but specialize std::begin and std::end.
+using std::begin;
+using std::end;
+
+// The type of the iterator given by begin(c) (possibly std::begin(c)).
+// ContainerIter<const vector<T>> gives vector<T>::const_iterator,
+// while ContainerIter<vector<T>> gives vector<T>::iterator.
+template <typename C>
+using ContainerIter = decltype(begin(std::declval<C&>()));
+
+// An MSVC bug involving template parameter substitution requires us to use
+// decltype() here instead of just std::pair.
+template <typename C1, typename C2>
+using ContainerIterPairType =
+    decltype(std::make_pair(ContainerIter<C1>(), ContainerIter<C2>()));
+
+template <typename C>
+using ContainerDifferenceType =
+    decltype(std::distance(std::declval<ContainerIter<C>>(),
+                           std::declval<ContainerIter<C>>()));
+
+template <typename C>
+using ContainerPointerType =
+    typename std::iterator_traits<ContainerIter<C>>::pointer;
+
+// container_algorithm_internal::c_begin and
+// container_algorithm_internal::c_end are abbreviations for proper ADL
+// lookup of std::begin and std::end, i.e.
+//   using std::begin;
+//   using std::end;
+//   std::foo(begin(c), end(c));
+// becomes
+//   std::foo(container_algorithm_internal::begin(c),
+//            container_algorithm_internal::end(c));
+// These are meant for internal use only.
+
+template <typename C>
+ContainerIter<C> c_begin(C& c) { return begin(c); }
+
+template <typename C>
+ContainerIter<C> c_end(C& c) { return end(c); }
+
+template <typename T>
+struct IsUnorderedContainer : std::false_type {};
+
+template <class Key, class T, class Hash, class KeyEqual, class Allocator>
+struct IsUnorderedContainer<
+    std::unordered_map<Key, T, Hash, KeyEqual, Allocator>> : std::true_type {};
+
+template <class Key, class Hash, class KeyEqual, class Allocator>
+struct IsUnorderedContainer<std::unordered_set<Key, Hash, KeyEqual, Allocator>>
+    : std::true_type {};
+
+// container_algorithm_internal::c_size. It is meant for internal use only.
+
+template <class C>
+auto c_size(C& c) -> decltype(c.size()) {
+  return c.size();
+}
+
+template <class T, std::size_t N>
+constexpr std::size_t c_size(T (&)[N]) {
+  return N;
+}
+
+}  // namespace container_algorithm_internal
+
+// PUBLIC API
+
+//------------------------------------------------------------------------------
+// Abseil algorithm.h functions
+//------------------------------------------------------------------------------
+
+// c_linear_search()
+//
+// Container-based version of absl::linear_search() for performing a linear
+// search within a container.
+template <typename C, typename EqualityComparable>
+bool c_linear_search(const C& c, EqualityComparable&& value) {
+  return linear_search(container_algorithm_internal::c_begin(c),
+                       container_algorithm_internal::c_end(c),
+                       std::forward<EqualityComparable>(value));
+}
+
+//------------------------------------------------------------------------------
+// <iterator> algorithms
+//------------------------------------------------------------------------------
+
+// c_distance()
+//
+// Container-based version of the <iterator> `std::distance()` function to
+// return the number of elements within a container.
+template <typename C>
+container_algorithm_internal::ContainerDifferenceType<const C> c_distance(
+    const C& c) {
+  return std::distance(container_algorithm_internal::c_begin(c),
+                       container_algorithm_internal::c_end(c));
+}
+
+//------------------------------------------------------------------------------
+// <algorithm> Non-modifying sequence operations
+//------------------------------------------------------------------------------
+
+// c_all_of()
+//
+// Container-based version of the <algorithm> `std::all_of()` function to
+// test a condition on all elements within a container.
+template <typename C, typename Pred>
+bool c_all_of(const C& c, Pred&& pred) {
+  return std::all_of(container_algorithm_internal::c_begin(c),
+                     container_algorithm_internal::c_end(c),
+                     std::forward<Pred>(pred));
+}
+
+// c_any_of()
+//
+// Container-based version of the <algorithm> `std::any_of()` function to
+// test if any element in a container fulfills a condition.
+template <typename C, typename Pred>
+bool c_any_of(const C& c, Pred&& pred) {
+  return std::any_of(container_algorithm_internal::c_begin(c),
+                     container_algorithm_internal::c_end(c),
+                     std::forward<Pred>(pred));
+}
+
+// c_none_of()
+//
+// Container-based version of the <algorithm> `std::none_of()` function to
+// test if no elements in a container fulfill a condition.
+template <typename C, typename Pred>
+bool c_none_of(const C& c, Pred&& pred) {
+  return std::none_of(container_algorithm_internal::c_begin(c),
+                      container_algorithm_internal::c_end(c),
+                      std::forward<Pred>(pred));
+}
+
+// c_for_each()
+//
+// Container-based version of the <algorithm> `std::for_each()` function to
+// apply a function to a container's elements.
+template <typename C, typename Function>
+decay_t<Function> c_for_each(C&& c, Function&& f) {
+  return std::for_each(container_algorithm_internal::c_begin(c),
+                       container_algorithm_internal::c_end(c),
+                       std::forward<Function>(f));
+}
+
+// c_find()
+//
+// Container-based version of the <algorithm> `std::find()` function to find
+// the first element containing the passed value within a container value.
+template <typename C, typename T>
+container_algorithm_internal::ContainerIter<C> c_find(C& c, T&& value) {
+  return std::find(container_algorithm_internal::c_begin(c),
+                   container_algorithm_internal::c_end(c),
+                   std::forward<T>(value));
+}
+
+// c_find_if()
+//
+// Container-based version of the <algorithm> `std::find_if()` function to find
+// the first element in a container matching the given condition.
+template <typename C, typename Pred>
+container_algorithm_internal::ContainerIter<C> c_find_if(C& c, Pred&& pred) {
+  return std::find_if(container_algorithm_internal::c_begin(c),
+                      container_algorithm_internal::c_end(c),
+                      std::forward<Pred>(pred));
+}
+
+// c_find_if_not()
+//
+// Container-based version of the <algorithm> `std::find_if_not()` function to
+// find the first element in a container not matching the given condition.
+template <typename C, typename Pred>
+container_algorithm_internal::ContainerIter<C> c_find_if_not(C& c,
+                                                             Pred&& pred) {
+  return std::find_if_not(container_algorithm_internal::c_begin(c),
+                          container_algorithm_internal::c_end(c),
+                          std::forward<Pred>(pred));
+}
+
+// c_find_end()
+//
+// Container-based version of the <algorithm> `std::find_end()` function to
+// find the last subsequence within a container.
+template <typename Sequence1, typename Sequence2>
+container_algorithm_internal::ContainerIter<Sequence1> c_find_end(
+    Sequence1& sequence, Sequence2& subsequence) {
+  return std::find_end(container_algorithm_internal::c_begin(sequence),
+                       container_algorithm_internal::c_end(sequence),
+                       container_algorithm_internal::c_begin(subsequence),
+                       container_algorithm_internal::c_end(subsequence));
+}
+
+// Overload of c_find_end() for using a predicate evaluation other than `==` as
+// the function's test condition.
+template <typename Sequence1, typename Sequence2, typename BinaryPredicate>
+container_algorithm_internal::ContainerIter<Sequence1> c_find_end(
+    Sequence1& sequence, Sequence2& subsequence, BinaryPredicate&& pred) {
+  return std::find_end(container_algorithm_internal::c_begin(sequence),
+                       container_algorithm_internal::c_end(sequence),
+                       container_algorithm_internal::c_begin(subsequence),
+                       container_algorithm_internal::c_end(subsequence),
+                       std::forward<BinaryPredicate>(pred));
+}
+
+// c_find_first_of()
+//
+// Container-based version of the <algorithm> `std::find_first_of()` function to
+// find the first element within the container that is also within the options
+// container.
+template <typename C1, typename C2>
+container_algorithm_internal::ContainerIter<C1> c_find_first_of(C1& container,
+                                                                C2& options) {
+  return std::find_first_of(container_algorithm_internal::c_begin(container),
+                            container_algorithm_internal::c_end(container),
+                            container_algorithm_internal::c_begin(options),
+                            container_algorithm_internal::c_end(options));
+}
+
+// Overload of c_find_first_of() for using a predicate evaluation other than
+// `==` as the function's test condition.
+template <typename C1, typename C2, typename BinaryPredicate>
+container_algorithm_internal::ContainerIter<C1> c_find_first_of(
+    C1& container, C2& options, BinaryPredicate&& pred) {
+  return std::find_first_of(container_algorithm_internal::c_begin(container),
+                            container_algorithm_internal::c_end(container),
+                            container_algorithm_internal::c_begin(options),
+                            container_algorithm_internal::c_end(options),
+                            std::forward<BinaryPredicate>(pred));
+}
+
+// c_adjacent_find()
+//
+// Container-based version of the <algorithm> `std::adjacent_find()` function to
+// find equal adjacent elements within a container.
+template <typename Sequence>
+container_algorithm_internal::ContainerIter<Sequence> c_adjacent_find(
+    Sequence& sequence) {
+  return std::adjacent_find(container_algorithm_internal::c_begin(sequence),
+                            container_algorithm_internal::c_end(sequence));
+}
+
+// Overload of c_adjacent_find() for using a predicate evaluation other than
+// `==` as the function's test condition.
+template <typename Sequence, typename BinaryPredicate>
+container_algorithm_internal::ContainerIter<Sequence> c_adjacent_find(
+    Sequence& sequence, BinaryPredicate&& pred) {
+  return std::adjacent_find(container_algorithm_internal::c_begin(sequence),
+                            container_algorithm_internal::c_end(sequence),
+                            std::forward<BinaryPredicate>(pred));
+}
+
+// c_count()
+//
+// Container-based version of the <algorithm> `std::count()` function to count
+// values that match within a container.
+template <typename C, typename T>
+container_algorithm_internal::ContainerDifferenceType<const C> c_count(
+    const C& c, T&& value) {
+  return std::count(container_algorithm_internal::c_begin(c),
+                    container_algorithm_internal::c_end(c),
+                    std::forward<T>(value));
+}
+
+// c_count_if()
+//
+// Container-based version of the <algorithm> `std::count_if()` function to
+// count values matching a condition within a container.
+template <typename C, typename Pred>
+container_algorithm_internal::ContainerDifferenceType<const C> c_count_if(
+    const C& c, Pred&& pred) {
+  return std::count_if(container_algorithm_internal::c_begin(c),
+                       container_algorithm_internal::c_end(c),
+                       std::forward<Pred>(pred));
+}
+
+// c_mismatch()
+//
+// Container-based version of the <algorithm> `std::mismatch()` function to
+// return the first element where two ordered containers differ. Applies `==` to
+// the first N elements of `c1` and `c2`, where N = min(size(c1), size(c2)).
+template <typename C1, typename C2>
+container_algorithm_internal::ContainerIterPairType<C1, C2>
+c_mismatch(C1& c1, C2& c2) {
+  auto first1 = container_algorithm_internal::c_begin(c1);
+  auto last1 = container_algorithm_internal::c_end(c1);
+  auto first2 = container_algorithm_internal::c_begin(c2);
+  auto last2 = container_algorithm_internal::c_end(c2);
+
+  for (; first1 != last1 && first2 != last2; ++first1, (void)++first2) {
+    // Negates equality because Cpp17EqualityComparable doesn't require clients
+    // to overload both `operator==` and `operator!=`.
+    if (!(*first1 == *first2)) {
+      break;
+    }
+  }
+
+  return std::make_pair(first1, first2);
+}
+
+// Overload of c_mismatch() for using a predicate evaluation other than `==` as
+// the function's test condition. Applies `pred`to the first N elements of `c1`
+// and `c2`, where N = min(size(c1), size(c2)).
+template <typename C1, typename C2, typename BinaryPredicate>
+container_algorithm_internal::ContainerIterPairType<C1, C2>
+c_mismatch(C1& c1, C2& c2, BinaryPredicate pred) {
+  auto first1 = container_algorithm_internal::c_begin(c1);
+  auto last1 = container_algorithm_internal::c_end(c1);
+  auto first2 = container_algorithm_internal::c_begin(c2);
+  auto last2 = container_algorithm_internal::c_end(c2);
+
+  for (; first1 != last1 && first2 != last2; ++first1, (void)++first2) {
+    if (!pred(*first1, *first2)) {
+      break;
+    }
+  }
+
+  return std::make_pair(first1, first2);
+}
+
+// c_equal()
+//
+// Container-based version of the <algorithm> `std::equal()` function to
+// test whether two containers are equal.
+//
+// NOTE: the semantics of c_equal() are slightly different than those of
+// equal(): while the latter iterates over the second container only up to the
+// size of the first container, c_equal() also checks whether the container
+// sizes are equal.  This better matches expectations about c_equal() based on
+// its signature.
+//
+// Example:
+//   vector v1 = <1, 2, 3>;
+//   vector v2 = <1, 2, 3, 4>;
+//   equal(std::begin(v1), std::end(v1), std::begin(v2)) returns true
+//   c_equal(v1, v2) returns false
+
+template <typename C1, typename C2>
+bool c_equal(const C1& c1, const C2& c2) {
+  return ((container_algorithm_internal::c_size(c1) ==
+           container_algorithm_internal::c_size(c2)) &&
+          std::equal(container_algorithm_internal::c_begin(c1),
+                     container_algorithm_internal::c_end(c1),
+                     container_algorithm_internal::c_begin(c2)));
+}
+
+// Overload of c_equal() for using a predicate evaluation other than `==` as
+// the function's test condition.
+template <typename C1, typename C2, typename BinaryPredicate>
+bool c_equal(const C1& c1, const C2& c2, BinaryPredicate&& pred) {
+  return ((container_algorithm_internal::c_size(c1) ==
+           container_algorithm_internal::c_size(c2)) &&
+          std::equal(container_algorithm_internal::c_begin(c1),
+                     container_algorithm_internal::c_end(c1),
+                     container_algorithm_internal::c_begin(c2),
+                     std::forward<BinaryPredicate>(pred)));
+}
+
+// c_is_permutation()
+//
+// Container-based version of the <algorithm> `std::is_permutation()` function
+// to test whether a container is a permutation of another.
+template <typename C1, typename C2>
+bool c_is_permutation(const C1& c1, const C2& c2) {
+  using std::begin;
+  using std::end;
+  return c1.size() == c2.size() &&
+         std::is_permutation(begin(c1), end(c1), begin(c2));
+}
+
+// Overload of c_is_permutation() for using a predicate evaluation other than
+// `==` as the function's test condition.
+template <typename C1, typename C2, typename BinaryPredicate>
+bool c_is_permutation(const C1& c1, const C2& c2, BinaryPredicate&& pred) {
+  using std::begin;
+  using std::end;
+  return c1.size() == c2.size() &&
+         std::is_permutation(begin(c1), end(c1), begin(c2),
+                             std::forward<BinaryPredicate>(pred));
+}
+
+// c_search()
+//
+// Container-based version of the <algorithm> `std::search()` function to search
+// a container for a subsequence.
+template <typename Sequence1, typename Sequence2>
+container_algorithm_internal::ContainerIter<Sequence1> c_search(
+    Sequence1& sequence, Sequence2& subsequence) {
+  return std::search(container_algorithm_internal::c_begin(sequence),
+                     container_algorithm_internal::c_end(sequence),
+                     container_algorithm_internal::c_begin(subsequence),
+                     container_algorithm_internal::c_end(subsequence));
+}
+
+// Overload of c_search() for using a predicate evaluation other than
+// `==` as the function's test condition.
+template <typename Sequence1, typename Sequence2, typename BinaryPredicate>
+container_algorithm_internal::ContainerIter<Sequence1> c_search(
+    Sequence1& sequence, Sequence2& subsequence, BinaryPredicate&& pred) {
+  return std::search(container_algorithm_internal::c_begin(sequence),
+                     container_algorithm_internal::c_end(sequence),
+                     container_algorithm_internal::c_begin(subsequence),
+                     container_algorithm_internal::c_end(subsequence),
+                     std::forward<BinaryPredicate>(pred));
+}
+
+// c_search_n()
+//
+// Container-based version of the <algorithm> `std::search_n()` function to
+// search a container for the first sequence of N elements.
+template <typename Sequence, typename Size, typename T>
+container_algorithm_internal::ContainerIter<Sequence> c_search_n(
+    Sequence& sequence, Size count, T&& value) {
+  return std::search_n(container_algorithm_internal::c_begin(sequence),
+                       container_algorithm_internal::c_end(sequence), count,
+                       std::forward<T>(value));
+}
+
+// Overload of c_search_n() for using a predicate evaluation other than
+// `==` as the function's test condition.
+template <typename Sequence, typename Size, typename T,
+          typename BinaryPredicate>
+container_algorithm_internal::ContainerIter<Sequence> c_search_n(
+    Sequence& sequence, Size count, T&& value, BinaryPredicate&& pred) {
+  return std::search_n(container_algorithm_internal::c_begin(sequence),
+                       container_algorithm_internal::c_end(sequence), count,
+                       std::forward<T>(value),
+                       std::forward<BinaryPredicate>(pred));
+}
+
+//------------------------------------------------------------------------------
+// <algorithm> Modifying sequence operations
+//------------------------------------------------------------------------------
+
+// c_copy()
+//
+// Container-based version of the <algorithm> `std::copy()` function to copy a
+// container's elements into an iterator.
+template <typename InputSequence, typename OutputIterator>
+OutputIterator c_copy(const InputSequence& input, OutputIterator output) {
+  return std::copy(container_algorithm_internal::c_begin(input),
+                   container_algorithm_internal::c_end(input), output);
+}
+
+// c_copy_n()
+//
+// Container-based version of the <algorithm> `std::copy_n()` function to copy a
+// container's first N elements into an iterator.
+template <typename C, typename Size, typename OutputIterator>
+OutputIterator c_copy_n(const C& input, Size n, OutputIterator output) {
+  return std::copy_n(container_algorithm_internal::c_begin(input), n, output);
+}
+
+// c_copy_if()
+//
+// Container-based version of the <algorithm> `std::copy_if()` function to copy
+// a container's elements satisfying some condition into an iterator.
+template <typename InputSequence, typename OutputIterator, typename Pred>
+OutputIterator c_copy_if(const InputSequence& input, OutputIterator output,
+                         Pred&& pred) {
+  return std::copy_if(container_algorithm_internal::c_begin(input),
+                      container_algorithm_internal::c_end(input), output,
+                      std::forward<Pred>(pred));
+}
+
+// c_copy_backward()
+//
+// Container-based version of the <algorithm> `std::copy_backward()` function to
+// copy a container's elements in reverse order into an iterator.
+template <typename C, typename BidirectionalIterator>
+BidirectionalIterator c_copy_backward(const C& src,
+                                      BidirectionalIterator dest) {
+  return std::copy_backward(container_algorithm_internal::c_begin(src),
+                            container_algorithm_internal::c_end(src), dest);
+}
+
+// c_move()
+//
+// Container-based version of the <algorithm> `std::move()` function to move
+// a container's elements into an iterator.
+template <typename C, typename OutputIterator>
+OutputIterator c_move(C&& src, OutputIterator dest) {
+  return std::move(container_algorithm_internal::c_begin(src),
+                   container_algorithm_internal::c_end(src), dest);
+}
+
+// c_move_backward()
+//
+// Container-based version of the <algorithm> `std::move_backward()` function to
+// move a container's elements into an iterator in reverse order.
+template <typename C, typename BidirectionalIterator>
+BidirectionalIterator c_move_backward(C&& src, BidirectionalIterator dest) {
+  return std::move_backward(container_algorithm_internal::c_begin(src),
+                            container_algorithm_internal::c_end(src), dest);
+}
+
+// c_swap_ranges()
+//
+// Container-based version of the <algorithm> `std::swap_ranges()` function to
+// swap a container's elements with another container's elements. Swaps the
+// first N elements of `c1` and `c2`, where N = min(size(c1), size(c2)).
+template <typename C1, typename C2>
+container_algorithm_internal::ContainerIter<C2> c_swap_ranges(C1& c1, C2& c2) {
+  auto first1 = container_algorithm_internal::c_begin(c1);
+  auto last1 = container_algorithm_internal::c_end(c1);
+  auto first2 = container_algorithm_internal::c_begin(c2);
+  auto last2 = container_algorithm_internal::c_end(c2);
+
+  using std::swap;
+  for (; first1 != last1 && first2 != last2; ++first1, (void)++first2) {
+    swap(*first1, *first2);
+  }
+  return first2;
+}
+
+// c_transform()
+//
+// Container-based version of the <algorithm> `std::transform()` function to
+// transform a container's elements using the unary operation, storing the
+// result in an iterator pointing to the last transformed element in the output
+// range.
+template <typename InputSequence, typename OutputIterator, typename UnaryOp>
+OutputIterator c_transform(const InputSequence& input, OutputIterator output,
+                           UnaryOp&& unary_op) {
+  return std::transform(container_algorithm_internal::c_begin(input),
+                        container_algorithm_internal::c_end(input), output,
+                        std::forward<UnaryOp>(unary_op));
+}
+
+// Overload of c_transform() for performing a transformation using a binary
+// predicate. Applies `binary_op` to the first N elements of `c1` and `c2`,
+// where N = min(size(c1), size(c2)).
+template <typename InputSequence1, typename InputSequence2,
+          typename OutputIterator, typename BinaryOp>
+OutputIterator c_transform(const InputSequence1& input1,
+                           const InputSequence2& input2, OutputIterator output,
+                           BinaryOp&& binary_op) {
+  auto first1 = container_algorithm_internal::c_begin(input1);
+  auto last1 = container_algorithm_internal::c_end(input1);
+  auto first2 = container_algorithm_internal::c_begin(input2);
+  auto last2 = container_algorithm_internal::c_end(input2);
+  for (; first1 != last1 && first2 != last2;
+       ++first1, (void)++first2, ++output) {
+    *output = binary_op(*first1, *first2);
+  }
+
+  return output;
+}
+
+// c_replace()
+//
+// Container-based version of the <algorithm> `std::replace()` function to
+// replace a container's elements of some value with a new value. The container
+// is modified in place.
+template <typename Sequence, typename T>
+void c_replace(Sequence& sequence, const T& old_value, const T& new_value) {
+  std::replace(container_algorithm_internal::c_begin(sequence),
+               container_algorithm_internal::c_end(sequence), old_value,
+               new_value);
+}
+
+// c_replace_if()
+//
+// Container-based version of the <algorithm> `std::replace_if()` function to
+// replace a container's elements of some value with a new value based on some
+// condition. The container is modified in place.
+template <typename C, typename Pred, typename T>
+void c_replace_if(C& c, Pred&& pred, T&& new_value) {
+  std::replace_if(container_algorithm_internal::c_begin(c),
+                  container_algorithm_internal::c_end(c),
+                  std::forward<Pred>(pred), std::forward<T>(new_value));
+}
+
+// c_replace_copy()
+//
+// Container-based version of the <algorithm> `std::replace_copy()` function to
+// replace a container's elements of some value with a new value  and return the
+// results within an iterator.
+template <typename C, typename OutputIterator, typename T>
+OutputIterator c_replace_copy(const C& c, OutputIterator result, T&& old_value,
+                              T&& new_value) {
+  return std::replace_copy(container_algorithm_internal::c_begin(c),
+                           container_algorithm_internal::c_end(c), result,
+                           std::forward<T>(old_value),
+                           std::forward<T>(new_value));
+}
+
+// c_replace_copy_if()
+//
+// Container-based version of the <algorithm> `std::replace_copy_if()` function
+// to replace a container's elements of some value with a new value based on
+// some condition, and return the results within an iterator.
+template <typename C, typename OutputIterator, typename Pred, typename T>
+OutputIterator c_replace_copy_if(const C& c, OutputIterator result, Pred&& pred,
+                                 T&& new_value) {
+  return std::replace_copy_if(container_algorithm_internal::c_begin(c),
+                              container_algorithm_internal::c_end(c), result,
+                              std::forward<Pred>(pred),
+                              std::forward<T>(new_value));
+}
+
+// c_fill()
+//
+// Container-based version of the <algorithm> `std::fill()` function to fill a
+// container with some value.
+template <typename C, typename T>
+void c_fill(C& c, T&& value) {
+  std::fill(container_algorithm_internal::c_begin(c),
+            container_algorithm_internal::c_end(c), std::forward<T>(value));
+}
+
+// c_fill_n()
+//
+// Container-based version of the <algorithm> `std::fill_n()` function to fill
+// the first N elements in a container with some value.
+template <typename C, typename Size, typename T>
+void c_fill_n(C& c, Size n, T&& value) {
+  std::fill_n(container_algorithm_internal::c_begin(c), n,
+              std::forward<T>(value));
+}
+
+// c_generate()
+//
+// Container-based version of the <algorithm> `std::generate()` function to
+// assign a container's elements to the values provided by the given generator.
+template <typename C, typename Generator>
+void c_generate(C& c, Generator&& gen) {
+  std::generate(container_algorithm_internal::c_begin(c),
+                container_algorithm_internal::c_end(c),
+                std::forward<Generator>(gen));
+}
+
+// c_generate_n()
+//
+// Container-based version of the <algorithm> `std::generate_n()` function to
+// assign a container's first N elements to the values provided by the given
+// generator.
+template <typename C, typename Size, typename Generator>
+container_algorithm_internal::ContainerIter<C> c_generate_n(C& c, Size n,
+                                                            Generator&& gen) {
+  return std::generate_n(container_algorithm_internal::c_begin(c), n,
+                         std::forward<Generator>(gen));
+}
+
+// Note: `c_xx()` <algorithm> container versions for `remove()`, `remove_if()`,
+// and `unique()` are omitted, because it's not clear whether or not such
+// functions should call erase on their supplied sequences afterwards. Either
+// behavior would be surprising for a different set of users.
+
+// c_remove_copy()
+//
+// Container-based version of the <algorithm> `std::remove_copy()` function to
+// copy a container's elements while removing any elements matching the given
+// `value`.
+template <typename C, typename OutputIterator, typename T>
+OutputIterator c_remove_copy(const C& c, OutputIterator result, T&& value) {
+  return std::remove_copy(container_algorithm_internal::c_begin(c),
+                          container_algorithm_internal::c_end(c), result,
+                          std::forward<T>(value));
+}
+
+// c_remove_copy_if()
+//
+// Container-based version of the <algorithm> `std::remove_copy_if()` function
+// to copy a container's elements while removing any elements matching the given
+// condition.
+template <typename C, typename OutputIterator, typename Pred>
+OutputIterator c_remove_copy_if(const C& c, OutputIterator result,
+                                Pred&& pred) {
+  return std::remove_copy_if(container_algorithm_internal::c_begin(c),
+                             container_algorithm_internal::c_end(c), result,
+                             std::forward<Pred>(pred));
+}
+
+// c_unique_copy()
+//
+// Container-based version of the <algorithm> `std::unique_copy()` function to
+// copy a container's elements while removing any elements containing duplicate
+// values.
+template <typename C, typename OutputIterator>
+OutputIterator c_unique_copy(const C& c, OutputIterator result) {
+  return std::unique_copy(container_algorithm_internal::c_begin(c),
+                          container_algorithm_internal::c_end(c), result);
+}
+
+// Overload of c_unique_copy() for using a predicate evaluation other than
+// `==` for comparing uniqueness of the element values.
+template <typename C, typename OutputIterator, typename BinaryPredicate>
+OutputIterator c_unique_copy(const C& c, OutputIterator result,
+                             BinaryPredicate&& pred) {
+  return std::unique_copy(container_algorithm_internal::c_begin(c),
+                          container_algorithm_internal::c_end(c), result,
+                          std::forward<BinaryPredicate>(pred));
+}
+
+// c_reverse()
+//
+// Container-based version of the <algorithm> `std::reverse()` function to
+// reverse a container's elements.
+template <typename Sequence>
+void c_reverse(Sequence& sequence) {
+  std::reverse(container_algorithm_internal::c_begin(sequence),
+               container_algorithm_internal::c_end(sequence));
+}
+
+// c_reverse_copy()
+//
+// Container-based version of the <algorithm> `std::reverse()` function to
+// reverse a container's elements and write them to an iterator range.
+template <typename C, typename OutputIterator>
+OutputIterator c_reverse_copy(const C& sequence, OutputIterator result) {
+  return std::reverse_copy(container_algorithm_internal::c_begin(sequence),
+                           container_algorithm_internal::c_end(sequence),
+                           result);
+}
+
+// c_rotate()
+//
+// Container-based version of the <algorithm> `std::rotate()` function to
+// shift a container's elements leftward such that the `middle` element becomes
+// the first element in the container.
+template <typename C,
+          typename Iterator = container_algorithm_internal::ContainerIter<C>>
+Iterator c_rotate(C& sequence, Iterator middle) {
+  return absl::rotate(container_algorithm_internal::c_begin(sequence), middle,
+                      container_algorithm_internal::c_end(sequence));
+}
+
+// c_rotate_copy()
+//
+// Container-based version of the <algorithm> `std::rotate_copy()` function to
+// shift a container's elements leftward such that the `middle` element becomes
+// the first element in a new iterator range.
+template <typename C, typename OutputIterator>
+OutputIterator c_rotate_copy(
+    const C& sequence,
+    container_algorithm_internal::ContainerIter<const C> middle,
+    OutputIterator result) {
+  return std::rotate_copy(container_algorithm_internal::c_begin(sequence),
+                          middle, container_algorithm_internal::c_end(sequence),
+                          result);
+}
+
+// c_shuffle()
+//
+// Container-based version of the <algorithm> `std::shuffle()` function to
+// randomly shuffle elements within the container using a `gen()` uniform random
+// number generator.
+template <typename RandomAccessContainer, typename UniformRandomBitGenerator>
+void c_shuffle(RandomAccessContainer& c, UniformRandomBitGenerator&& gen) {
+  std::shuffle(container_algorithm_internal::c_begin(c),
+               container_algorithm_internal::c_end(c),
+               std::forward<UniformRandomBitGenerator>(gen));
+}
+
+//------------------------------------------------------------------------------
+// <algorithm> Partition functions
+//------------------------------------------------------------------------------
+
+// c_is_partitioned()
+//
+// Container-based version of the <algorithm> `std::is_partitioned()` function
+// to test whether all elements in the container for which `pred` returns `true`
+// precede those for which `pred` is `false`.
+template <typename C, typename Pred>
+bool c_is_partitioned(const C& c, Pred&& pred) {
+  return std::is_partitioned(container_algorithm_internal::c_begin(c),
+                             container_algorithm_internal::c_end(c),
+                             std::forward<Pred>(pred));
+}
+
+// c_partition()
+//
+// Container-based version of the <algorithm> `std::partition()` function
+// to rearrange all elements in a container in such a way that all elements for
+// which `pred` returns `true` precede all those for which it returns `false`,
+// returning an iterator to the first element of the second group.
+template <typename C, typename Pred>
+container_algorithm_internal::ContainerIter<C> c_partition(C& c, Pred&& pred) {
+  return std::partition(container_algorithm_internal::c_begin(c),
+                        container_algorithm_internal::c_end(c),
+                        std::forward<Pred>(pred));
+}
+
+// c_stable_partition()
+//
+// Container-based version of the <algorithm> `std::stable_partition()` function
+// to rearrange all elements in a container in such a way that all elements for
+// which `pred` returns `true` precede all those for which it returns `false`,
+// preserving the relative ordering between the two groups. The function returns
+// an iterator to the first element of the second group.
+template <typename C, typename Pred>
+container_algorithm_internal::ContainerIter<C> c_stable_partition(C& c,
+                                                                  Pred&& pred) {
+  return std::stable_partition(container_algorithm_internal::c_begin(c),
+                               container_algorithm_internal::c_end(c),
+                               std::forward<Pred>(pred));
+}
+
+// c_partition_copy()
+//
+// Container-based version of the <algorithm> `std::partition_copy()` function
+// to partition a container's elements and return them into two iterators: one
+// for which `pred` returns `true`, and one for which `pred` returns `false.`
+
+template <typename C, typename OutputIterator1, typename OutputIterator2,
+          typename Pred>
+std::pair<OutputIterator1, OutputIterator2> c_partition_copy(
+    const C& c, OutputIterator1 out_true, OutputIterator2 out_false,
+    Pred&& pred) {
+  return std::partition_copy(container_algorithm_internal::c_begin(c),
+                             container_algorithm_internal::c_end(c), out_true,
+                             out_false, std::forward<Pred>(pred));
+}
+
+// c_partition_point()
+//
+// Container-based version of the <algorithm> `std::partition_point()` function
+// to return the first element of an already partitioned container for which
+// the given `pred` is not `true`.
+template <typename C, typename Pred>
+container_algorithm_internal::ContainerIter<C> c_partition_point(C& c,
+                                                                 Pred&& pred) {
+  return std::partition_point(container_algorithm_internal::c_begin(c),
+                              container_algorithm_internal::c_end(c),
+                              std::forward<Pred>(pred));
+}
+
+//------------------------------------------------------------------------------
+// <algorithm> Sorting functions
+//------------------------------------------------------------------------------
+
+// c_sort()
+//
+// Container-based version of the <algorithm> `std::sort()` function
+// to sort elements in ascending order of their values.
+template <typename C>
+void c_sort(C& c) {
+  std::sort(container_algorithm_internal::c_begin(c),
+            container_algorithm_internal::c_end(c));
+}
+
+// Overload of c_sort() for performing a `comp` comparison other than the
+// default `operator<`.
+template <typename C, typename Compare>
+void c_sort(C& c, Compare&& comp) {
+  std::sort(container_algorithm_internal::c_begin(c),
+            container_algorithm_internal::c_end(c),
+            std::forward<Compare>(comp));
+}
+
+// c_stable_sort()
+//
+// Container-based version of the <algorithm> `std::stable_sort()` function
+// to sort elements in ascending order of their values, preserving the order
+// of equivalents.
+template <typename C>
+void c_stable_sort(C& c) {
+  std::stable_sort(container_algorithm_internal::c_begin(c),
+                   container_algorithm_internal::c_end(c));
+}
+
+// Overload of c_stable_sort() for performing a `comp` comparison other than the
+// default `operator<`.
+template <typename C, typename Compare>
+void c_stable_sort(C& c, Compare&& comp) {
+  std::stable_sort(container_algorithm_internal::c_begin(c),
+                   container_algorithm_internal::c_end(c),
+                   std::forward<Compare>(comp));
+}
+
+// c_is_sorted()
+//
+// Container-based version of the <algorithm> `std::is_sorted()` function
+// to evaluate whether the given container is sorted in ascending order.
+template <typename C>
+bool c_is_sorted(const C& c) {
+  return std::is_sorted(container_algorithm_internal::c_begin(c),
+                        container_algorithm_internal::c_end(c));
+}
+
+// c_is_sorted() overload for performing a `comp` comparison other than the
+// default `operator<`.
+template <typename C, typename Compare>
+bool c_is_sorted(const C& c, Compare&& comp) {
+  return std::is_sorted(container_algorithm_internal::c_begin(c),
+                        container_algorithm_internal::c_end(c),
+                        std::forward<Compare>(comp));
+}
+
+// c_partial_sort()
+//
+// Container-based version of the <algorithm> `std::partial_sort()` function
+// to rearrange elements within a container such that elements before `middle`
+// are sorted in ascending order.
+template <typename RandomAccessContainer>
+void c_partial_sort(
+    RandomAccessContainer& sequence,
+    container_algorithm_internal::ContainerIter<RandomAccessContainer> middle) {
+  std::partial_sort(container_algorithm_internal::c_begin(sequence), middle,
+                    container_algorithm_internal::c_end(sequence));
+}
+
+// Overload of c_partial_sort() for performing a `comp` comparison other than
+// the default `operator<`.
+template <typename RandomAccessContainer, typename Compare>
+void c_partial_sort(
+    RandomAccessContainer& sequence,
+    container_algorithm_internal::ContainerIter<RandomAccessContainer> middle,
+    Compare&& comp) {
+  std::partial_sort(container_algorithm_internal::c_begin(sequence), middle,
+                    container_algorithm_internal::c_end(sequence),
+                    std::forward<Compare>(comp));
+}
+
+// c_partial_sort_copy()
+//
+// Container-based version of the <algorithm> `std::partial_sort_copy()`
+// function to sort the elements in the given range `result` within the larger
+// `sequence` in ascending order (and using `result` as the output parameter).
+// At most min(result.last - result.first, sequence.last - sequence.first)
+// elements from the sequence will be stored in the result.
+template <typename C, typename RandomAccessContainer>
+container_algorithm_internal::ContainerIter<RandomAccessContainer>
+c_partial_sort_copy(const C& sequence, RandomAccessContainer& result) {
+  return std::partial_sort_copy(container_algorithm_internal::c_begin(sequence),
+                                container_algorithm_internal::c_end(sequence),
+                                container_algorithm_internal::c_begin(result),
+                                container_algorithm_internal::c_end(result));
+}
+
+// Overload of c_partial_sort_copy() for performing a `comp` comparison other
+// than the default `operator<`.
+template <typename C, typename RandomAccessContainer, typename Compare>
+container_algorithm_internal::ContainerIter<RandomAccessContainer>
+c_partial_sort_copy(const C& sequence, RandomAccessContainer& result,
+                    Compare&& comp) {
+  return std::partial_sort_copy(container_algorithm_internal::c_begin(sequence),
+                                container_algorithm_internal::c_end(sequence),
+                                container_algorithm_internal::c_begin(result),
+                                container_algorithm_internal::c_end(result),
+                                std::forward<Compare>(comp));
+}
+
+// c_is_sorted_until()
+//
+// Container-based version of the <algorithm> `std::is_sorted_until()` function
+// to return the first element within a container that is not sorted in
+// ascending order as an iterator.
+template <typename C>
+container_algorithm_internal::ContainerIter<C> c_is_sorted_until(C& c) {
+  return std::is_sorted_until(container_algorithm_internal::c_begin(c),
+                              container_algorithm_internal::c_end(c));
+}
+
+// Overload of c_is_sorted_until() for performing a `comp` comparison other than
+// the default `operator<`.
+template <typename C, typename Compare>
+container_algorithm_internal::ContainerIter<C> c_is_sorted_until(
+    C& c, Compare&& comp) {
+  return std::is_sorted_until(container_algorithm_internal::c_begin(c),
+                              container_algorithm_internal::c_end(c),
+                              std::forward<Compare>(comp));
+}
+
+// c_nth_element()
+//
+// Container-based version of the <algorithm> `std::nth_element()` function
+// to rearrange the elements within a container such that the `nth` element
+// would be in that position in an ordered sequence; other elements may be in
+// any order, except that all preceding `nth` will be less than that element,
+// and all following `nth` will be greater than that element.
+template <typename RandomAccessContainer>
+void c_nth_element(
+    RandomAccessContainer& sequence,
+    container_algorithm_internal::ContainerIter<RandomAccessContainer> nth) {
+  std::nth_element(container_algorithm_internal::c_begin(sequence), nth,
+                   container_algorithm_internal::c_end(sequence));
+}
+
+// Overload of c_nth_element() for performing a `comp` comparison other than
+// the default `operator<`.
+template <typename RandomAccessContainer, typename Compare>
+void c_nth_element(
+    RandomAccessContainer& sequence,
+    container_algorithm_internal::ContainerIter<RandomAccessContainer> nth,
+    Compare&& comp) {
+  std::nth_element(container_algorithm_internal::c_begin(sequence), nth,
+                   container_algorithm_internal::c_end(sequence),
+                   std::forward<Compare>(comp));
+}
+
+//------------------------------------------------------------------------------
+// <algorithm> Binary Search
+//------------------------------------------------------------------------------
+
+// c_lower_bound()
+//
+// Container-based version of the <algorithm> `std::lower_bound()` function
+// to return an iterator pointing to the first element in a sorted container
+// which does not compare less than `value`.
+template <typename Sequence, typename T>
+container_algorithm_internal::ContainerIter<Sequence> c_lower_bound(
+    Sequence& sequence, T&& value) {
+  return std::lower_bound(container_algorithm_internal::c_begin(sequence),
+                          container_algorithm_internal::c_end(sequence),
+                          std::forward<T>(value));
+}
+
+// Overload of c_lower_bound() for performing a `comp` comparison other than
+// the default `operator<`.
+template <typename Sequence, typename T, typename Compare>
+container_algorithm_internal::ContainerIter<Sequence> c_lower_bound(
+    Sequence& sequence, T&& value, Compare&& comp) {
+  return std::lower_bound(container_algorithm_internal::c_begin(sequence),
+                          container_algorithm_internal::c_end(sequence),
+                          std::forward<T>(value), std::forward<Compare>(comp));
+}
+
+// c_upper_bound()
+//
+// Container-based version of the <algorithm> `std::upper_bound()` function
+// to return an iterator pointing to the first element in a sorted container
+// which is greater than `value`.
+template <typename Sequence, typename T>
+container_algorithm_internal::ContainerIter<Sequence> c_upper_bound(
+    Sequence& sequence, T&& value) {
+  return std::upper_bound(container_algorithm_internal::c_begin(sequence),
+                          container_algorithm_internal::c_end(sequence),
+                          std::forward<T>(value));
+}
+
+// Overload of c_upper_bound() for performing a `comp` comparison other than
+// the default `operator<`.
+template <typename Sequence, typename T, typename Compare>
+container_algorithm_internal::ContainerIter<Sequence> c_upper_bound(
+    Sequence& sequence, T&& value, Compare&& comp) {
+  return std::upper_bound(container_algorithm_internal::c_begin(sequence),
+                          container_algorithm_internal::c_end(sequence),
+                          std::forward<T>(value), std::forward<Compare>(comp));
+}
+
+// c_equal_range()
+//
+// Container-based version of the <algorithm> `std::equal_range()` function
+// to return an iterator pair pointing to the first and last elements in a
+// sorted container which compare equal to `value`.
+template <typename Sequence, typename T>
+container_algorithm_internal::ContainerIterPairType<Sequence, Sequence>
+c_equal_range(Sequence& sequence, T&& value) {
+  return std::equal_range(container_algorithm_internal::c_begin(sequence),
+                          container_algorithm_internal::c_end(sequence),
+                          std::forward<T>(value));
+}
+
+// Overload of c_equal_range() for performing a `comp` comparison other than
+// the default `operator<`.
+template <typename Sequence, typename T, typename Compare>
+container_algorithm_internal::ContainerIterPairType<Sequence, Sequence>
+c_equal_range(Sequence& sequence, T&& value, Compare&& comp) {
+  return std::equal_range(container_algorithm_internal::c_begin(sequence),
+                          container_algorithm_internal::c_end(sequence),
+                          std::forward<T>(value), std::forward<Compare>(comp));
+}
+
+// c_binary_search()
+//
+// Container-based version of the <algorithm> `std::binary_search()` function
+// to test if any element in the sorted container contains a value equivalent to
+// 'value'.
+template <typename Sequence, typename T>
+bool c_binary_search(Sequence&& sequence, T&& value) {
+  return std::binary_search(container_algorithm_internal::c_begin(sequence),
+                            container_algorithm_internal::c_end(sequence),
+                            std::forward<T>(value));
+}
+
+// Overload of c_binary_search() for performing a `comp` comparison other than
+// the default `operator<`.
+template <typename Sequence, typename T, typename Compare>
+bool c_binary_search(Sequence&& sequence, T&& value, Compare&& comp) {
+  return std::binary_search(container_algorithm_internal::c_begin(sequence),
+                            container_algorithm_internal::c_end(sequence),
+                            std::forward<T>(value),
+                            std::forward<Compare>(comp));
+}
+
+//------------------------------------------------------------------------------
+// <algorithm> Merge functions
+//------------------------------------------------------------------------------
+
+// c_merge()
+//
+// Container-based version of the <algorithm> `std::merge()` function
+// to merge two sorted containers into a single sorted iterator.
+template <typename C1, typename C2, typename OutputIterator>
+OutputIterator c_merge(const C1& c1, const C2& c2, OutputIterator result) {
+  return std::merge(container_algorithm_internal::c_begin(c1),
+                    container_algorithm_internal::c_end(c1),
+                    container_algorithm_internal::c_begin(c2),
+                    container_algorithm_internal::c_end(c2), result);
+}
+
+// Overload of c_merge() for performing a `comp` comparison other than
+// the default `operator<`.
+template <typename C1, typename C2, typename OutputIterator, typename Compare>
+OutputIterator c_merge(const C1& c1, const C2& c2, OutputIterator result,
+                       Compare&& comp) {
+  return std::merge(container_algorithm_internal::c_begin(c1),
+                    container_algorithm_internal::c_end(c1),
+                    container_algorithm_internal::c_begin(c2),
+                    container_algorithm_internal::c_end(c2), result,
+                    std::forward<Compare>(comp));
+}
+
+// c_inplace_merge()
+//
+// Container-based version of the <algorithm> `std::inplace_merge()` function
+// to merge a supplied iterator `middle` into a container.
+template <typename C>
+void c_inplace_merge(C& c,
+                     container_algorithm_internal::ContainerIter<C> middle) {
+  std::inplace_merge(container_algorithm_internal::c_begin(c), middle,
+                     container_algorithm_internal::c_end(c));
+}
+
+// Overload of c_inplace_merge() for performing a merge using a `comp` other
+// than `operator<`.
+template <typename C, typename Compare>
+void c_inplace_merge(C& c,
+                     container_algorithm_internal::ContainerIter<C> middle,
+                     Compare&& comp) {
+  std::inplace_merge(container_algorithm_internal::c_begin(c), middle,
+                     container_algorithm_internal::c_end(c),
+                     std::forward<Compare>(comp));
+}
+
+// c_includes()
+//
+// Container-based version of the <algorithm> `std::includes()` function
+// to test whether a sorted container `c1` entirely contains another sorted
+// container `c2`.
+template <typename C1, typename C2>
+bool c_includes(const C1& c1, const C2& c2) {
+  return std::includes(container_algorithm_internal::c_begin(c1),
+                       container_algorithm_internal::c_end(c1),
+                       container_algorithm_internal::c_begin(c2),
+                       container_algorithm_internal::c_end(c2));
+}
+
+// Overload of c_includes() for performing a merge using a `comp` other than
+// `operator<`.
+template <typename C1, typename C2, typename Compare>
+bool c_includes(const C1& c1, const C2& c2, Compare&& comp) {
+  return std::includes(container_algorithm_internal::c_begin(c1),
+                       container_algorithm_internal::c_end(c1),
+                       container_algorithm_internal::c_begin(c2),
+                       container_algorithm_internal::c_end(c2),
+                       std::forward<Compare>(comp));
+}
+
+// c_set_union()
+//
+// Container-based version of the <algorithm> `std::set_union()` function
+// to return an iterator containing the union of two containers; duplicate
+// values are not copied into the output.
+template <typename C1, typename C2, typename OutputIterator,
+          typename = typename std::enable_if<
+              !container_algorithm_internal::IsUnorderedContainer<C1>::value,
+              void>::type,
+          typename = typename std::enable_if<
+              !container_algorithm_internal::IsUnorderedContainer<C2>::value,
+              void>::type>
+OutputIterator c_set_union(const C1& c1, const C2& c2, OutputIterator output) {
+  return std::set_union(container_algorithm_internal::c_begin(c1),
+                        container_algorithm_internal::c_end(c1),
+                        container_algorithm_internal::c_begin(c2),
+                        container_algorithm_internal::c_end(c2), output);
+}
+
+// Overload of c_set_union() for performing a merge using a `comp` other than
+// `operator<`.
+template <typename C1, typename C2, typename OutputIterator, typename Compare,
+          typename = typename std::enable_if<
+              !container_algorithm_internal::IsUnorderedContainer<C1>::value,
+              void>::type,
+          typename = typename std::enable_if<
+              !container_algorithm_internal::IsUnorderedContainer<C2>::value,
+              void>::type>
+OutputIterator c_set_union(const C1& c1, const C2& c2, OutputIterator output,
+                           Compare&& comp) {
+  return std::set_union(container_algorithm_internal::c_begin(c1),
+                        container_algorithm_internal::c_end(c1),
+                        container_algorithm_internal::c_begin(c2),
+                        container_algorithm_internal::c_end(c2), output,
+                        std::forward<Compare>(comp));
+}
+
+// c_set_intersection()
+//
+// Container-based version of the <algorithm> `std::set_intersection()` function
+// to return an iterator containing the intersection of two containers.
+template <typename C1, typename C2, typename OutputIterator,
+          typename = typename std::enable_if<
+              !container_algorithm_internal::IsUnorderedContainer<C1>::value,
+              void>::type,
+          typename = typename std::enable_if<
+              !container_algorithm_internal::IsUnorderedContainer<C2>::value,
+              void>::type>
+OutputIterator c_set_intersection(const C1& c1, const C2& c2,
+                                  OutputIterator output) {
+  return std::set_intersection(container_algorithm_internal::c_begin(c1),
+                               container_algorithm_internal::c_end(c1),
+                               container_algorithm_internal::c_begin(c2),
+                               container_algorithm_internal::c_end(c2), output);
+}
+
+// Overload of c_set_intersection() for performing a merge using a `comp` other
+// than `operator<`.
+template <typename C1, typename C2, typename OutputIterator, typename Compare,
+          typename = typename std::enable_if<
+              !container_algorithm_internal::IsUnorderedContainer<C1>::value,
+              void>::type,
+          typename = typename std::enable_if<
+              !container_algorithm_internal::IsUnorderedContainer<C2>::value,
+              void>::type>
+OutputIterator c_set_intersection(const C1& c1, const C2& c2,
+                                  OutputIterator output, Compare&& comp) {
+  return std::set_intersection(container_algorithm_internal::c_begin(c1),
+                               container_algorithm_internal::c_end(c1),
+                               container_algorithm_internal::c_begin(c2),
+                               container_algorithm_internal::c_end(c2), output,
+                               std::forward<Compare>(comp));
+}
+
+// c_set_difference()
+//
+// Container-based version of the <algorithm> `std::set_difference()` function
+// to return an iterator containing elements present in the first container but
+// not in the second.
+template <typename C1, typename C2, typename OutputIterator,
+          typename = typename std::enable_if<
+              !container_algorithm_internal::IsUnorderedContainer<C1>::value,
+              void>::type,
+          typename = typename std::enable_if<
+              !container_algorithm_internal::IsUnorderedContainer<C2>::value,
+              void>::type>
+OutputIterator c_set_difference(const C1& c1, const C2& c2,
+                                OutputIterator output) {
+  return std::set_difference(container_algorithm_internal::c_begin(c1),
+                             container_algorithm_internal::c_end(c1),
+                             container_algorithm_internal::c_begin(c2),
+                             container_algorithm_internal::c_end(c2), output);
+}
+
+// Overload of c_set_difference() for performing a merge using a `comp` other
+// than `operator<`.
+template <typename C1, typename C2, typename OutputIterator, typename Compare,
+          typename = typename std::enable_if<
+              !container_algorithm_internal::IsUnorderedContainer<C1>::value,
+              void>::type,
+          typename = typename std::enable_if<
+              !container_algorithm_internal::IsUnorderedContainer<C2>::value,
+              void>::type>
+OutputIterator c_set_difference(const C1& c1, const C2& c2,
+                                OutputIterator output, Compare&& comp) {
+  return std::set_difference(container_algorithm_internal::c_begin(c1),
+                             container_algorithm_internal::c_end(c1),
+                             container_algorithm_internal::c_begin(c2),
+                             container_algorithm_internal::c_end(c2), output,
+                             std::forward<Compare>(comp));
+}
+
+// c_set_symmetric_difference()
+//
+// Container-based version of the <algorithm> `std::set_symmetric_difference()`
+// function to return an iterator containing elements present in either one
+// container or the other, but not both.
+template <typename C1, typename C2, typename OutputIterator,
+          typename = typename std::enable_if<
+              !container_algorithm_internal::IsUnorderedContainer<C1>::value,
+              void>::type,
+          typename = typename std::enable_if<
+              !container_algorithm_internal::IsUnorderedContainer<C2>::value,
+              void>::type>
+OutputIterator c_set_symmetric_difference(const C1& c1, const C2& c2,
+                                          OutputIterator output) {
+  return std::set_symmetric_difference(
+      container_algorithm_internal::c_begin(c1),
+      container_algorithm_internal::c_end(c1),
+      container_algorithm_internal::c_begin(c2),
+      container_algorithm_internal::c_end(c2), output);
+}
+
+// Overload of c_set_symmetric_difference() for performing a merge using a
+// `comp` other than `operator<`.
+template <typename C1, typename C2, typename OutputIterator, typename Compare,
+          typename = typename std::enable_if<
+              !container_algorithm_internal::IsUnorderedContainer<C1>::value,
+              void>::type,
+          typename = typename std::enable_if<
+              !container_algorithm_internal::IsUnorderedContainer<C2>::value,
+              void>::type>
+OutputIterator c_set_symmetric_difference(const C1& c1, const C2& c2,
+                                          OutputIterator output,
+                                          Compare&& comp) {
+  return std::set_symmetric_difference(
+      container_algorithm_internal::c_begin(c1),
+      container_algorithm_internal::c_end(c1),
+      container_algorithm_internal::c_begin(c2),
+      container_algorithm_internal::c_end(c2), output,
+      std::forward<Compare>(comp));
+}
+
+//------------------------------------------------------------------------------
+// <algorithm> Heap functions
+//------------------------------------------------------------------------------
+
+// c_push_heap()
+//
+// Container-based version of the <algorithm> `std::push_heap()` function
+// to push a value onto a container heap.
+template <typename RandomAccessContainer>
+void c_push_heap(RandomAccessContainer& sequence) {
+  std::push_heap(container_algorithm_internal::c_begin(sequence),
+                 container_algorithm_internal::c_end(sequence));
+}
+
+// Overload of c_push_heap() for performing a push operation on a heap using a
+// `comp` other than `operator<`.
+template <typename RandomAccessContainer, typename Compare>
+void c_push_heap(RandomAccessContainer& sequence, Compare&& comp) {
+  std::push_heap(container_algorithm_internal::c_begin(sequence),
+                 container_algorithm_internal::c_end(sequence),
+                 std::forward<Compare>(comp));
+}
+
+// c_pop_heap()
+//
+// Container-based version of the <algorithm> `std::pop_heap()` function
+// to pop a value from a heap container.
+template <typename RandomAccessContainer>
+void c_pop_heap(RandomAccessContainer& sequence) {
+  std::pop_heap(container_algorithm_internal::c_begin(sequence),
+                container_algorithm_internal::c_end(sequence));
+}
+
+// Overload of c_pop_heap() for performing a pop operation on a heap using a
+// `comp` other than `operator<`.
+template <typename RandomAccessContainer, typename Compare>
+void c_pop_heap(RandomAccessContainer& sequence, Compare&& comp) {
+  std::pop_heap(container_algorithm_internal::c_begin(sequence),
+                container_algorithm_internal::c_end(sequence),
+                std::forward<Compare>(comp));
+}
+
+// c_make_heap()
+//
+// Container-based version of the <algorithm> `std::make_heap()` function
+// to make a container a heap.
+template <typename RandomAccessContainer>
+void c_make_heap(RandomAccessContainer& sequence) {
+  std::make_heap(container_algorithm_internal::c_begin(sequence),
+                 container_algorithm_internal::c_end(sequence));
+}
+
+// Overload of c_make_heap() for performing heap comparisons using a
+// `comp` other than `operator<`
+template <typename RandomAccessContainer, typename Compare>
+void c_make_heap(RandomAccessContainer& sequence, Compare&& comp) {
+  std::make_heap(container_algorithm_internal::c_begin(sequence),
+                 container_algorithm_internal::c_end(sequence),
+                 std::forward<Compare>(comp));
+}
+
+// c_sort_heap()
+//
+// Container-based version of the <algorithm> `std::sort_heap()` function
+// to sort a heap into ascending order (after which it is no longer a heap).
+template <typename RandomAccessContainer>
+void c_sort_heap(RandomAccessContainer& sequence) {
+  std::sort_heap(container_algorithm_internal::c_begin(sequence),
+                 container_algorithm_internal::c_end(sequence));
+}
+
+// Overload of c_sort_heap() for performing heap comparisons using a
+// `comp` other than `operator<`
+template <typename RandomAccessContainer, typename Compare>
+void c_sort_heap(RandomAccessContainer& sequence, Compare&& comp) {
+  std::sort_heap(container_algorithm_internal::c_begin(sequence),
+                 container_algorithm_internal::c_end(sequence),
+                 std::forward<Compare>(comp));
+}
+
+// c_is_heap()
+//
+// Container-based version of the <algorithm> `std::is_heap()` function
+// to check whether the given container is a heap.
+template <typename RandomAccessContainer>
+bool c_is_heap(const RandomAccessContainer& sequence) {
+  return std::is_heap(container_algorithm_internal::c_begin(sequence),
+                      container_algorithm_internal::c_end(sequence));
+}
+
+// Overload of c_is_heap() for performing heap comparisons using a
+// `comp` other than `operator<`
+template <typename RandomAccessContainer, typename Compare>
+bool c_is_heap(const RandomAccessContainer& sequence, Compare&& comp) {
+  return std::is_heap(container_algorithm_internal::c_begin(sequence),
+                      container_algorithm_internal::c_end(sequence),
+                      std::forward<Compare>(comp));
+}
+
+// c_is_heap_until()
+//
+// Container-based version of the <algorithm> `std::is_heap_until()` function
+// to find the first element in a given container which is not in heap order.
+template <typename RandomAccessContainer>
+container_algorithm_internal::ContainerIter<RandomAccessContainer>
+c_is_heap_until(RandomAccessContainer& sequence) {
+  return std::is_heap_until(container_algorithm_internal::c_begin(sequence),
+                            container_algorithm_internal::c_end(sequence));
+}
+
+// Overload of c_is_heap_until() for performing heap comparisons using a
+// `comp` other than `operator<`
+template <typename RandomAccessContainer, typename Compare>
+container_algorithm_internal::ContainerIter<RandomAccessContainer>
+c_is_heap_until(RandomAccessContainer& sequence, Compare&& comp) {
+  return std::is_heap_until(container_algorithm_internal::c_begin(sequence),
+                            container_algorithm_internal::c_end(sequence),
+                            std::forward<Compare>(comp));
+}
+
+//------------------------------------------------------------------------------
+//  <algorithm> Min/max
+//------------------------------------------------------------------------------
+
+// c_min_element()
+//
+// Container-based version of the <algorithm> `std::min_element()` function
+// to return an iterator pointing to the element with the smallest value, using
+// `operator<` to make the comparisons.
+template <typename Sequence>
+container_algorithm_internal::ContainerIter<Sequence> c_min_element(
+    Sequence& sequence) {
+  return std::min_element(container_algorithm_internal::c_begin(sequence),
+                          container_algorithm_internal::c_end(sequence));
+}
+
+// Overload of c_min_element() for performing a `comp` comparison other than
+// `operator<`.
+template <typename Sequence, typename Compare>
+container_algorithm_internal::ContainerIter<Sequence> c_min_element(
+    Sequence& sequence, Compare&& comp) {
+  return std::min_element(container_algorithm_internal::c_begin(sequence),
+                          container_algorithm_internal::c_end(sequence),
+                          std::forward<Compare>(comp));
+}
+
+// c_max_element()
+//
+// Container-based version of the <algorithm> `std::max_element()` function
+// to return an iterator pointing to the element with the largest value, using
+// `operator<` to make the comparisons.
+template <typename Sequence>
+container_algorithm_internal::ContainerIter<Sequence> c_max_element(
+    Sequence& sequence) {
+  return std::max_element(container_algorithm_internal::c_begin(sequence),
+                          container_algorithm_internal::c_end(sequence));
+}
+
+// Overload of c_max_element() for performing a `comp` comparison other than
+// `operator<`.
+template <typename Sequence, typename Compare>
+container_algorithm_internal::ContainerIter<Sequence> c_max_element(
+    Sequence& sequence, Compare&& comp) {
+  return std::max_element(container_algorithm_internal::c_begin(sequence),
+                          container_algorithm_internal::c_end(sequence),
+                          std::forward<Compare>(comp));
+}
+
+// c_minmax_element()
+//
+// Container-based version of the <algorithm> `std::minmax_element()` function
+// to return a pair of iterators pointing to the elements containing the
+// smallest and largest values, respectively, using `operator<` to make the
+// comparisons.
+template <typename C>
+container_algorithm_internal::ContainerIterPairType<C, C>
+c_minmax_element(C& c) {
+  return std::minmax_element(container_algorithm_internal::c_begin(c),
+                             container_algorithm_internal::c_end(c));
+}
+
+// Overload of c_minmax_element() for performing `comp` comparisons other than
+// `operator<`.
+template <typename C, typename Compare>
+container_algorithm_internal::ContainerIterPairType<C, C>
+c_minmax_element(C& c, Compare&& comp) {
+  return std::minmax_element(container_algorithm_internal::c_begin(c),
+                             container_algorithm_internal::c_end(c),
+                             std::forward<Compare>(comp));
+}
+
+//------------------------------------------------------------------------------
+//  <algorithm> Lexicographical Comparisons
+//------------------------------------------------------------------------------
+
+// c_lexicographical_compare()
+//
+// Container-based version of the <algorithm> `std::lexicographical_compare()`
+// function to lexicographically compare (e.g. sort words alphabetically) two
+// container sequences. The comparison is performed using `operator<`. Note
+// that capital letters ("A-Z") have ASCII values less than lowercase letters
+// ("a-z").
+template <typename Sequence1, typename Sequence2>
+bool c_lexicographical_compare(Sequence1&& sequence1, Sequence2&& sequence2) {
+  return std::lexicographical_compare(
+      container_algorithm_internal::c_begin(sequence1),
+      container_algorithm_internal::c_end(sequence1),
+      container_algorithm_internal::c_begin(sequence2),
+      container_algorithm_internal::c_end(sequence2));
+}
+
+// Overload of c_lexicographical_compare() for performing a lexicographical
+// comparison using a `comp` operator instead of `operator<`.
+template <typename Sequence1, typename Sequence2, typename Compare>
+bool c_lexicographical_compare(Sequence1&& sequence1, Sequence2&& sequence2,
+                               Compare&& comp) {
+  return std::lexicographical_compare(
+      container_algorithm_internal::c_begin(sequence1),
+      container_algorithm_internal::c_end(sequence1),
+      container_algorithm_internal::c_begin(sequence2),
+      container_algorithm_internal::c_end(sequence2),
+      std::forward<Compare>(comp));
+}
+
+// c_next_permutation()
+//
+// Container-based version of the <algorithm> `std::next_permutation()` function
+// to rearrange a container's elements into the next lexicographically greater
+// permutation.
+template <typename C>
+bool c_next_permutation(C& c) {
+  return std::next_permutation(container_algorithm_internal::c_begin(c),
+                               container_algorithm_internal::c_end(c));
+}
+
+// Overload of c_next_permutation() for performing a lexicographical
+// comparison using a `comp` operator instead of `operator<`.
+template <typename C, typename Compare>
+bool c_next_permutation(C& c, Compare&& comp) {
+  return std::next_permutation(container_algorithm_internal::c_begin(c),
+                               container_algorithm_internal::c_end(c),
+                               std::forward<Compare>(comp));
+}
+
+// c_prev_permutation()
+//
+// Container-based version of the <algorithm> `std::prev_permutation()` function
+// to rearrange a container's elements into the next lexicographically lesser
+// permutation.
+template <typename C>
+bool c_prev_permutation(C& c) {
+  return std::prev_permutation(container_algorithm_internal::c_begin(c),
+                               container_algorithm_internal::c_end(c));
+}
+
+// Overload of c_prev_permutation() for performing a lexicographical
+// comparison using a `comp` operator instead of `operator<`.
+template <typename C, typename Compare>
+bool c_prev_permutation(C& c, Compare&& comp) {
+  return std::prev_permutation(container_algorithm_internal::c_begin(c),
+                               container_algorithm_internal::c_end(c),
+                               std::forward<Compare>(comp));
+}
+
+//------------------------------------------------------------------------------
+// <numeric> algorithms
+//------------------------------------------------------------------------------
+
+// c_iota()
+//
+// Container-based version of the <algorithm> `std::iota()` function
+// to compute successive values of `value`, as if incremented with `++value`
+// after each element is written. and write them to the container.
+template <typename Sequence, typename T>
+void c_iota(Sequence& sequence, T&& value) {
+  std::iota(container_algorithm_internal::c_begin(sequence),
+            container_algorithm_internal::c_end(sequence),
+            std::forward<T>(value));
+}
+// c_accumulate()
+//
+// Container-based version of the <algorithm> `std::accumulate()` function
+// to accumulate the element values of a container to `init` and return that
+// accumulation by value.
+//
+// Note: Due to a language technicality this function has return type
+// absl::decay_t<T>. As a user of this function you can casually read
+// this as "returns T by value" and assume it does the right thing.
+template <typename Sequence, typename T>
+decay_t<T> c_accumulate(const Sequence& sequence, T&& init) {
+  return std::accumulate(container_algorithm_internal::c_begin(sequence),
+                         container_algorithm_internal::c_end(sequence),
+                         std::forward<T>(init));
+}
+
+// Overload of c_accumulate() for using a binary operations other than
+// addition for computing the accumulation.
+template <typename Sequence, typename T, typename BinaryOp>
+decay_t<T> c_accumulate(const Sequence& sequence, T&& init,
+                        BinaryOp&& binary_op) {
+  return std::accumulate(container_algorithm_internal::c_begin(sequence),
+                         container_algorithm_internal::c_end(sequence),
+                         std::forward<T>(init),
+                         std::forward<BinaryOp>(binary_op));
+}
+
+// c_inner_product()
+//
+// Container-based version of the <algorithm> `std::inner_product()` function
+// to compute the cumulative inner product of container element pairs.
+//
+// Note: Due to a language technicality this function has return type
+// absl::decay_t<T>. As a user of this function you can casually read
+// this as "returns T by value" and assume it does the right thing.
+template <typename Sequence1, typename Sequence2, typename T>
+decay_t<T> c_inner_product(const Sequence1& factors1, const Sequence2& factors2,
+                           T&& sum) {
+  return std::inner_product(container_algorithm_internal::c_begin(factors1),
+                            container_algorithm_internal::c_end(factors1),
+                            container_algorithm_internal::c_begin(factors2),
+                            std::forward<T>(sum));
+}
+
+// Overload of c_inner_product() for using binary operations other than
+// `operator+` (for computing the accumulation) and `operator*` (for computing
+// the product between the two container's element pair).
+template <typename Sequence1, typename Sequence2, typename T,
+          typename BinaryOp1, typename BinaryOp2>
+decay_t<T> c_inner_product(const Sequence1& factors1, const Sequence2& factors2,
+                           T&& sum, BinaryOp1&& op1, BinaryOp2&& op2) {
+  return std::inner_product(container_algorithm_internal::c_begin(factors1),
+                            container_algorithm_internal::c_end(factors1),
+                            container_algorithm_internal::c_begin(factors2),
+                            std::forward<T>(sum), std::forward<BinaryOp1>(op1),
+                            std::forward<BinaryOp2>(op2));
+}
+
+// c_adjacent_difference()
+//
+// Container-based version of the <algorithm> `std::adjacent_difference()`
+// function to compute the difference between each element and the one preceding
+// it and write it to an iterator.
+template <typename InputSequence, typename OutputIt>
+OutputIt c_adjacent_difference(const InputSequence& input,
+                               OutputIt output_first) {
+  return std::adjacent_difference(container_algorithm_internal::c_begin(input),
+                                  container_algorithm_internal::c_end(input),
+                                  output_first);
+}
+
+// Overload of c_adjacent_difference() for using a binary operation other than
+// subtraction to compute the adjacent difference.
+template <typename InputSequence, typename OutputIt, typename BinaryOp>
+OutputIt c_adjacent_difference(const InputSequence& input,
+                               OutputIt output_first, BinaryOp&& op) {
+  return std::adjacent_difference(container_algorithm_internal::c_begin(input),
+                                  container_algorithm_internal::c_end(input),
+                                  output_first, std::forward<BinaryOp>(op));
+}
+
+// c_partial_sum()
+//
+// Container-based version of the <algorithm> `std::partial_sum()` function
+// to compute the partial sum of the elements in a sequence and write them
+// to an iterator. The partial sum is the sum of all element values so far in
+// the sequence.
+template <typename InputSequence, typename OutputIt>
+OutputIt c_partial_sum(const InputSequence& input, OutputIt output_first) {
+  return std::partial_sum(container_algorithm_internal::c_begin(input),
+                          container_algorithm_internal::c_end(input),
+                          output_first);
+}
+
+// Overload of c_partial_sum() for using a binary operation other than addition
+// to compute the "partial sum".
+template <typename InputSequence, typename OutputIt, typename BinaryOp>
+OutputIt c_partial_sum(const InputSequence& input, OutputIt output_first,
+                       BinaryOp&& op) {
+  return std::partial_sum(container_algorithm_internal::c_begin(input),
+                          container_algorithm_internal::c_end(input),
+                          output_first, std::forward<BinaryOp>(op));
+}
+
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#endif  // ABSL_ALGORITHM_CONTAINER_H_
diff --git a/src/absl/base/attributes.h b/src/absl/base/attributes.h
new file mode 100644 (file)
index 0000000..cf2cb55
--- /dev/null
@@ -0,0 +1,702 @@
+// Copyright 2017 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// This header file defines macros for declaring attributes for functions,
+// types, and variables.
+//
+// These macros are used within Abseil and allow the compiler to optimize, where
+// applicable, certain function calls.
+//
+// Most macros here are exposing GCC or Clang features, and are stubbed out for
+// other compilers.
+//
+// GCC attributes documentation:
+//   https://gcc.gnu.org/onlinedocs/gcc-4.7.0/gcc/Function-Attributes.html
+//   https://gcc.gnu.org/onlinedocs/gcc-4.7.0/gcc/Variable-Attributes.html
+//   https://gcc.gnu.org/onlinedocs/gcc-4.7.0/gcc/Type-Attributes.html
+//
+// Most attributes in this file are already supported by GCC 4.7. However, some
+// of them are not supported in older version of Clang. Thus, we check
+// `__has_attribute()` first. If the check fails, we check if we are on GCC and
+// assume the attribute exists on GCC (which is verified on GCC 4.7).
+
+#ifndef ABSL_BASE_ATTRIBUTES_H_
+#define ABSL_BASE_ATTRIBUTES_H_
+
+#include "absl/base/config.h"
+
+// ABSL_HAVE_ATTRIBUTE
+//
+// A function-like feature checking macro that is a wrapper around
+// `__has_attribute`, which is defined by GCC 5+ and Clang and evaluates to a
+// nonzero constant integer if the attribute is supported or 0 if not.
+//
+// It evaluates to zero if `__has_attribute` is not defined by the compiler.
+//
+// GCC: https://gcc.gnu.org/gcc-5/changes.html
+// Clang: https://clang.llvm.org/docs/LanguageExtensions.html
+#ifdef __has_attribute
+#define ABSL_HAVE_ATTRIBUTE(x) __has_attribute(x)
+#else
+#define ABSL_HAVE_ATTRIBUTE(x) 0
+#endif
+
+// ABSL_HAVE_CPP_ATTRIBUTE
+//
+// A function-like feature checking macro that accepts C++11 style attributes.
+// It's a wrapper around `__has_cpp_attribute`, defined by ISO C++ SD-6
+// (https://en.cppreference.com/w/cpp/experimental/feature_test). If we don't
+// find `__has_cpp_attribute`, will evaluate to 0.
+#if defined(__cplusplus) && defined(__has_cpp_attribute)
+// NOTE: requiring __cplusplus above should not be necessary, but
+// works around https://bugs.llvm.org/show_bug.cgi?id=23435.
+#define ABSL_HAVE_CPP_ATTRIBUTE(x) __has_cpp_attribute(x)
+#else
+#define ABSL_HAVE_CPP_ATTRIBUTE(x) 0
+#endif
+
+// -----------------------------------------------------------------------------
+// Function Attributes
+// -----------------------------------------------------------------------------
+//
+// GCC: https://gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html
+// Clang: https://clang.llvm.org/docs/AttributeReference.html
+
+// ABSL_PRINTF_ATTRIBUTE
+// ABSL_SCANF_ATTRIBUTE
+//
+// Tells the compiler to perform `printf` format string checking if the
+// compiler supports it; see the 'format' attribute in
+// <https://gcc.gnu.org/onlinedocs/gcc-4.7.0/gcc/Function-Attributes.html>.
+//
+// Note: As the GCC manual states, "[s]ince non-static C++ methods
+// have an implicit 'this' argument, the arguments of such methods
+// should be counted from two, not one."
+#if ABSL_HAVE_ATTRIBUTE(format) || (defined(__GNUC__) && !defined(__clang__))
+#define ABSL_PRINTF_ATTRIBUTE(string_index, first_to_check) \
+  __attribute__((__format__(__printf__, string_index, first_to_check)))
+#define ABSL_SCANF_ATTRIBUTE(string_index, first_to_check) \
+  __attribute__((__format__(__scanf__, string_index, first_to_check)))
+#else
+#define ABSL_PRINTF_ATTRIBUTE(string_index, first_to_check)
+#define ABSL_SCANF_ATTRIBUTE(string_index, first_to_check)
+#endif
+
+// ABSL_ATTRIBUTE_ALWAYS_INLINE
+// ABSL_ATTRIBUTE_NOINLINE
+//
+// Forces functions to either inline or not inline. Introduced in gcc 3.1.
+#if ABSL_HAVE_ATTRIBUTE(always_inline) || \
+    (defined(__GNUC__) && !defined(__clang__))
+#define ABSL_ATTRIBUTE_ALWAYS_INLINE __attribute__((always_inline))
+#define ABSL_HAVE_ATTRIBUTE_ALWAYS_INLINE 1
+#else
+#define ABSL_ATTRIBUTE_ALWAYS_INLINE
+#endif
+
+#if ABSL_HAVE_ATTRIBUTE(noinline) || (defined(__GNUC__) && !defined(__clang__))
+#define ABSL_ATTRIBUTE_NOINLINE __attribute__((noinline))
+#define ABSL_HAVE_ATTRIBUTE_NOINLINE 1
+#else
+#define ABSL_ATTRIBUTE_NOINLINE
+#endif
+
+// ABSL_ATTRIBUTE_NO_TAIL_CALL
+//
+// Prevents the compiler from optimizing away stack frames for functions which
+// end in a call to another function.
+#if ABSL_HAVE_ATTRIBUTE(disable_tail_calls)
+#define ABSL_HAVE_ATTRIBUTE_NO_TAIL_CALL 1
+#define ABSL_ATTRIBUTE_NO_TAIL_CALL __attribute__((disable_tail_calls))
+#elif defined(__GNUC__) && !defined(__clang__) && !defined(__e2k__)
+#define ABSL_HAVE_ATTRIBUTE_NO_TAIL_CALL 1
+#define ABSL_ATTRIBUTE_NO_TAIL_CALL \
+  __attribute__((optimize("no-optimize-sibling-calls")))
+#else
+#define ABSL_ATTRIBUTE_NO_TAIL_CALL
+#define ABSL_HAVE_ATTRIBUTE_NO_TAIL_CALL 0
+#endif
+
+// ABSL_ATTRIBUTE_WEAK
+//
+// Tags a function as weak for the purposes of compilation and linking.
+// Weak attributes currently do not work properly in LLVM's Windows backend,
+// so disable them there. See https://bugs.llvm.org/show_bug.cgi?id=37598
+// for further information.
+// The MinGW compiler doesn't complain about the weak attribute until the link
+// step, presumably because Windows doesn't use ELF binaries.
+#if (ABSL_HAVE_ATTRIBUTE(weak) ||                   \
+     (defined(__GNUC__) && !defined(__clang__))) && \
+    !(defined(__llvm__) && defined(_WIN32)) && !defined(__MINGW32__)
+#undef ABSL_ATTRIBUTE_WEAK
+#define ABSL_ATTRIBUTE_WEAK __attribute__((weak))
+#define ABSL_HAVE_ATTRIBUTE_WEAK 1
+#else
+#define ABSL_ATTRIBUTE_WEAK
+#define ABSL_HAVE_ATTRIBUTE_WEAK 0
+#endif
+
+// ABSL_ATTRIBUTE_NONNULL
+//
+// Tells the compiler either (a) that a particular function parameter
+// should be a non-null pointer, or (b) that all pointer arguments should
+// be non-null.
+//
+// Note: As the GCC manual states, "[s]ince non-static C++ methods
+// have an implicit 'this' argument, the arguments of such methods
+// should be counted from two, not one."
+//
+// Args are indexed starting at 1.
+//
+// For non-static class member functions, the implicit `this` argument
+// is arg 1, and the first explicit argument is arg 2. For static class member
+// functions, there is no implicit `this`, and the first explicit argument is
+// arg 1.
+//
+// Example:
+//
+//   /* arg_a cannot be null, but arg_b can */
+//   void Function(void* arg_a, void* arg_b) ABSL_ATTRIBUTE_NONNULL(1);
+//
+//   class C {
+//     /* arg_a cannot be null, but arg_b can */
+//     void Method(void* arg_a, void* arg_b) ABSL_ATTRIBUTE_NONNULL(2);
+//
+//     /* arg_a cannot be null, but arg_b can */
+//     static void StaticMethod(void* arg_a, void* arg_b)
+//     ABSL_ATTRIBUTE_NONNULL(1);
+//   };
+//
+// If no arguments are provided, then all pointer arguments should be non-null.
+//
+//  /* No pointer arguments may be null. */
+//  void Function(void* arg_a, void* arg_b, int arg_c) ABSL_ATTRIBUTE_NONNULL();
+//
+// NOTE: The GCC nonnull attribute actually accepts a list of arguments, but
+// ABSL_ATTRIBUTE_NONNULL does not.
+#if ABSL_HAVE_ATTRIBUTE(nonnull) || (defined(__GNUC__) && !defined(__clang__))
+#define ABSL_ATTRIBUTE_NONNULL(arg_index) __attribute__((nonnull(arg_index)))
+#else
+#define ABSL_ATTRIBUTE_NONNULL(...)
+#endif
+
+// ABSL_ATTRIBUTE_NORETURN
+//
+// Tells the compiler that a given function never returns.
+#if ABSL_HAVE_ATTRIBUTE(noreturn) || (defined(__GNUC__) && !defined(__clang__))
+#define ABSL_ATTRIBUTE_NORETURN __attribute__((noreturn))
+#elif defined(_MSC_VER)
+#define ABSL_ATTRIBUTE_NORETURN __declspec(noreturn)
+#else
+#define ABSL_ATTRIBUTE_NORETURN
+#endif
+
+// ABSL_ATTRIBUTE_NO_SANITIZE_ADDRESS
+//
+// Tells the AddressSanitizer (or other memory testing tools) to ignore a given
+// function. Useful for cases when a function reads random locations on stack,
+// calls _exit from a cloned subprocess, deliberately accesses buffer
+// out of bounds or does other scary things with memory.
+// NOTE: GCC supports AddressSanitizer(asan) since 4.8.
+// https://gcc.gnu.org/gcc-4.8/changes.html
+#if ABSL_HAVE_ATTRIBUTE(no_sanitize_address)
+#define ABSL_ATTRIBUTE_NO_SANITIZE_ADDRESS __attribute__((no_sanitize_address))
+#else
+#define ABSL_ATTRIBUTE_NO_SANITIZE_ADDRESS
+#endif
+
+// ABSL_ATTRIBUTE_NO_SANITIZE_MEMORY
+//
+// Tells the MemorySanitizer to relax the handling of a given function. All "Use
+// of uninitialized value" warnings from such functions will be suppressed, and
+// all values loaded from memory will be considered fully initialized.  This
+// attribute is similar to the ABSL_ATTRIBUTE_NO_SANITIZE_ADDRESS attribute
+// above, but deals with initialized-ness rather than addressability issues.
+// NOTE: MemorySanitizer(msan) is supported by Clang but not GCC.
+#if ABSL_HAVE_ATTRIBUTE(no_sanitize_memory)
+#define ABSL_ATTRIBUTE_NO_SANITIZE_MEMORY __attribute__((no_sanitize_memory))
+#else
+#define ABSL_ATTRIBUTE_NO_SANITIZE_MEMORY
+#endif
+
+// ABSL_ATTRIBUTE_NO_SANITIZE_THREAD
+//
+// Tells the ThreadSanitizer to not instrument a given function.
+// NOTE: GCC supports ThreadSanitizer(tsan) since 4.8.
+// https://gcc.gnu.org/gcc-4.8/changes.html
+#if ABSL_HAVE_ATTRIBUTE(no_sanitize_thread)
+#define ABSL_ATTRIBUTE_NO_SANITIZE_THREAD __attribute__((no_sanitize_thread))
+#else
+#define ABSL_ATTRIBUTE_NO_SANITIZE_THREAD
+#endif
+
+// ABSL_ATTRIBUTE_NO_SANITIZE_UNDEFINED
+//
+// Tells the UndefinedSanitizer to ignore a given function. Useful for cases
+// where certain behavior (eg. division by zero) is being used intentionally.
+// NOTE: GCC supports UndefinedBehaviorSanitizer(ubsan) since 4.9.
+// https://gcc.gnu.org/gcc-4.9/changes.html
+#if ABSL_HAVE_ATTRIBUTE(no_sanitize_undefined)
+#define ABSL_ATTRIBUTE_NO_SANITIZE_UNDEFINED \
+  __attribute__((no_sanitize_undefined))
+#elif ABSL_HAVE_ATTRIBUTE(no_sanitize)
+#define ABSL_ATTRIBUTE_NO_SANITIZE_UNDEFINED \
+  __attribute__((no_sanitize("undefined")))
+#else
+#define ABSL_ATTRIBUTE_NO_SANITIZE_UNDEFINED
+#endif
+
+// ABSL_ATTRIBUTE_NO_SANITIZE_CFI
+//
+// Tells the ControlFlowIntegrity sanitizer to not instrument a given function.
+// See https://clang.llvm.org/docs/ControlFlowIntegrity.html for details.
+#if ABSL_HAVE_ATTRIBUTE(no_sanitize)
+#define ABSL_ATTRIBUTE_NO_SANITIZE_CFI __attribute__((no_sanitize("cfi")))
+#else
+#define ABSL_ATTRIBUTE_NO_SANITIZE_CFI
+#endif
+
+// ABSL_ATTRIBUTE_NO_SANITIZE_SAFESTACK
+//
+// Tells the SafeStack to not instrument a given function.
+// See https://clang.llvm.org/docs/SafeStack.html for details.
+#if ABSL_HAVE_ATTRIBUTE(no_sanitize)
+#define ABSL_ATTRIBUTE_NO_SANITIZE_SAFESTACK \
+  __attribute__((no_sanitize("safe-stack")))
+#else
+#define ABSL_ATTRIBUTE_NO_SANITIZE_SAFESTACK
+#endif
+
+// ABSL_ATTRIBUTE_RETURNS_NONNULL
+//
+// Tells the compiler that a particular function never returns a null pointer.
+#if ABSL_HAVE_ATTRIBUTE(returns_nonnull) || \
+    (defined(__GNUC__) && \
+     (__GNUC__ > 5 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 9)) && \
+     !defined(__clang__))
+#define ABSL_ATTRIBUTE_RETURNS_NONNULL __attribute__((returns_nonnull))
+#else
+#define ABSL_ATTRIBUTE_RETURNS_NONNULL
+#endif
+
+// ABSL_HAVE_ATTRIBUTE_SECTION
+//
+// Indicates whether labeled sections are supported. Weak symbol support is
+// a prerequisite. Labeled sections are not supported on Darwin/iOS.
+#ifdef ABSL_HAVE_ATTRIBUTE_SECTION
+#error ABSL_HAVE_ATTRIBUTE_SECTION cannot be directly set
+#elif (ABSL_HAVE_ATTRIBUTE(section) ||                \
+       (defined(__GNUC__) && !defined(__clang__))) && \
+    !defined(__APPLE__) && ABSL_HAVE_ATTRIBUTE_WEAK
+#define ABSL_HAVE_ATTRIBUTE_SECTION 1
+
+// ABSL_ATTRIBUTE_SECTION
+//
+// Tells the compiler/linker to put a given function into a section and define
+// `__start_ ## name` and `__stop_ ## name` symbols to bracket the section.
+// This functionality is supported by GNU linker.  Any function annotated with
+// `ABSL_ATTRIBUTE_SECTION` must not be inlined, or it will be placed into
+// whatever section its caller is placed into.
+//
+#ifndef ABSL_ATTRIBUTE_SECTION
+#define ABSL_ATTRIBUTE_SECTION(name) \
+  __attribute__((section(#name))) __attribute__((noinline))
+#endif
+
+
+// ABSL_ATTRIBUTE_SECTION_VARIABLE
+//
+// Tells the compiler/linker to put a given variable into a section and define
+// `__start_ ## name` and `__stop_ ## name` symbols to bracket the section.
+// This functionality is supported by GNU linker.
+#ifndef ABSL_ATTRIBUTE_SECTION_VARIABLE
+#define ABSL_ATTRIBUTE_SECTION_VARIABLE(name) __attribute__((section(#name)))
+#endif
+
+// ABSL_DECLARE_ATTRIBUTE_SECTION_VARS
+//
+// A weak section declaration to be used as a global declaration
+// for ABSL_ATTRIBUTE_SECTION_START|STOP(name) to compile and link
+// even without functions with ABSL_ATTRIBUTE_SECTION(name).
+// ABSL_DEFINE_ATTRIBUTE_SECTION should be in the exactly one file; it's
+// a no-op on ELF but not on Mach-O.
+//
+#ifndef ABSL_DECLARE_ATTRIBUTE_SECTION_VARS
+#define ABSL_DECLARE_ATTRIBUTE_SECTION_VARS(name) \
+  extern char __start_##name[] ABSL_ATTRIBUTE_WEAK;    \
+  extern char __stop_##name[] ABSL_ATTRIBUTE_WEAK
+#endif
+#ifndef ABSL_DEFINE_ATTRIBUTE_SECTION_VARS
+#define ABSL_INIT_ATTRIBUTE_SECTION_VARS(name)
+#define ABSL_DEFINE_ATTRIBUTE_SECTION_VARS(name)
+#endif
+
+// ABSL_ATTRIBUTE_SECTION_START
+//
+// Returns `void*` pointers to start/end of a section of code with
+// functions having ABSL_ATTRIBUTE_SECTION(name).
+// Returns 0 if no such functions exist.
+// One must ABSL_DECLARE_ATTRIBUTE_SECTION_VARS(name) for this to compile and
+// link.
+//
+#define ABSL_ATTRIBUTE_SECTION_START(name) \
+  (reinterpret_cast<void *>(__start_##name))
+#define ABSL_ATTRIBUTE_SECTION_STOP(name) \
+  (reinterpret_cast<void *>(__stop_##name))
+
+#else  // !ABSL_HAVE_ATTRIBUTE_SECTION
+
+#define ABSL_HAVE_ATTRIBUTE_SECTION 0
+
+// provide dummy definitions
+#define ABSL_ATTRIBUTE_SECTION(name)
+#define ABSL_ATTRIBUTE_SECTION_VARIABLE(name)
+#define ABSL_INIT_ATTRIBUTE_SECTION_VARS(name)
+#define ABSL_DEFINE_ATTRIBUTE_SECTION_VARS(name)
+#define ABSL_DECLARE_ATTRIBUTE_SECTION_VARS(name)
+#define ABSL_ATTRIBUTE_SECTION_START(name) (reinterpret_cast<void *>(0))
+#define ABSL_ATTRIBUTE_SECTION_STOP(name) (reinterpret_cast<void *>(0))
+
+#endif  // ABSL_ATTRIBUTE_SECTION
+
+// ABSL_ATTRIBUTE_STACK_ALIGN_FOR_OLD_LIBC
+//
+// Support for aligning the stack on 32-bit x86.
+#if ABSL_HAVE_ATTRIBUTE(force_align_arg_pointer) || \
+    (defined(__GNUC__) && !defined(__clang__))
+#if defined(__i386__)
+#define ABSL_ATTRIBUTE_STACK_ALIGN_FOR_OLD_LIBC \
+  __attribute__((force_align_arg_pointer))
+#define ABSL_REQUIRE_STACK_ALIGN_TRAMPOLINE (0)
+#elif defined(__x86_64__)
+#define ABSL_REQUIRE_STACK_ALIGN_TRAMPOLINE (1)
+#define ABSL_ATTRIBUTE_STACK_ALIGN_FOR_OLD_LIBC
+#else  // !__i386__ && !__x86_64
+#define ABSL_REQUIRE_STACK_ALIGN_TRAMPOLINE (0)
+#define ABSL_ATTRIBUTE_STACK_ALIGN_FOR_OLD_LIBC
+#endif  // __i386__
+#else
+#define ABSL_ATTRIBUTE_STACK_ALIGN_FOR_OLD_LIBC
+#define ABSL_REQUIRE_STACK_ALIGN_TRAMPOLINE (0)
+#endif
+
+// ABSL_MUST_USE_RESULT
+//
+// Tells the compiler to warn about unused results.
+//
+// When annotating a function, it must appear as the first part of the
+// declaration or definition. The compiler will warn if the return value from
+// such a function is unused:
+//
+//   ABSL_MUST_USE_RESULT Sprocket* AllocateSprocket();
+//   AllocateSprocket();  // Triggers a warning.
+//
+// When annotating a class, it is equivalent to annotating every function which
+// returns an instance.
+//
+//   class ABSL_MUST_USE_RESULT Sprocket {};
+//   Sprocket();  // Triggers a warning.
+//
+//   Sprocket MakeSprocket();
+//   MakeSprocket();  // Triggers a warning.
+//
+// Note that references and pointers are not instances:
+//
+//   Sprocket* SprocketPointer();
+//   SprocketPointer();  // Does *not* trigger a warning.
+//
+// ABSL_MUST_USE_RESULT allows using cast-to-void to suppress the unused result
+// warning. For that, warn_unused_result is used only for clang but not for gcc.
+// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=66425
+//
+// Note: past advice was to place the macro after the argument list.
+#if ABSL_HAVE_ATTRIBUTE(nodiscard)
+#define ABSL_MUST_USE_RESULT [[nodiscard]]
+#elif defined(__clang__) && ABSL_HAVE_ATTRIBUTE(warn_unused_result)
+#define ABSL_MUST_USE_RESULT __attribute__((warn_unused_result))
+#else
+#define ABSL_MUST_USE_RESULT
+#endif
+
+// ABSL_ATTRIBUTE_HOT, ABSL_ATTRIBUTE_COLD
+//
+// Tells GCC that a function is hot or cold. GCC can use this information to
+// improve static analysis, i.e. a conditional branch to a cold function
+// is likely to be not-taken.
+// This annotation is used for function declarations.
+//
+// Example:
+//
+//   int foo() ABSL_ATTRIBUTE_HOT;
+#if ABSL_HAVE_ATTRIBUTE(hot) || (defined(__GNUC__) && !defined(__clang__))
+#define ABSL_ATTRIBUTE_HOT __attribute__((hot))
+#else
+#define ABSL_ATTRIBUTE_HOT
+#endif
+
+#if ABSL_HAVE_ATTRIBUTE(cold) || (defined(__GNUC__) && !defined(__clang__))
+#define ABSL_ATTRIBUTE_COLD __attribute__((cold))
+#else
+#define ABSL_ATTRIBUTE_COLD
+#endif
+
+// ABSL_XRAY_ALWAYS_INSTRUMENT, ABSL_XRAY_NEVER_INSTRUMENT, ABSL_XRAY_LOG_ARGS
+//
+// We define the ABSL_XRAY_ALWAYS_INSTRUMENT and ABSL_XRAY_NEVER_INSTRUMENT
+// macro used as an attribute to mark functions that must always or never be
+// instrumented by XRay. Currently, this is only supported in Clang/LLVM.
+//
+// For reference on the LLVM XRay instrumentation, see
+// http://llvm.org/docs/XRay.html.
+//
+// A function with the XRAY_ALWAYS_INSTRUMENT macro attribute in its declaration
+// will always get the XRay instrumentation sleds. These sleds may introduce
+// some binary size and runtime overhead and must be used sparingly.
+//
+// These attributes only take effect when the following conditions are met:
+//
+//   * The file/target is built in at least C++11 mode, with a Clang compiler
+//     that supports XRay attributes.
+//   * The file/target is built with the -fxray-instrument flag set for the
+//     Clang/LLVM compiler.
+//   * The function is defined in the translation unit (the compiler honors the
+//     attribute in either the definition or the declaration, and must match).
+//
+// There are cases when, even when building with XRay instrumentation, users
+// might want to control specifically which functions are instrumented for a
+// particular build using special-case lists provided to the compiler. These
+// special case lists are provided to Clang via the
+// -fxray-always-instrument=... and -fxray-never-instrument=... flags. The
+// attributes in source take precedence over these special-case lists.
+//
+// To disable the XRay attributes at build-time, users may define
+// ABSL_NO_XRAY_ATTRIBUTES. Do NOT define ABSL_NO_XRAY_ATTRIBUTES on specific
+// packages/targets, as this may lead to conflicting definitions of functions at
+// link-time.
+//
+// XRay isn't currently supported on Android:
+// https://github.com/android/ndk/issues/368
+#if ABSL_HAVE_CPP_ATTRIBUTE(clang::xray_always_instrument) && \
+    !defined(ABSL_NO_XRAY_ATTRIBUTES) && !defined(__ANDROID__)
+#define ABSL_XRAY_ALWAYS_INSTRUMENT [[clang::xray_always_instrument]]
+#define ABSL_XRAY_NEVER_INSTRUMENT [[clang::xray_never_instrument]]
+#if ABSL_HAVE_CPP_ATTRIBUTE(clang::xray_log_args)
+#define ABSL_XRAY_LOG_ARGS(N) \
+    [[clang::xray_always_instrument, clang::xray_log_args(N)]]
+#else
+#define ABSL_XRAY_LOG_ARGS(N) [[clang::xray_always_instrument]]
+#endif
+#else
+#define ABSL_XRAY_ALWAYS_INSTRUMENT
+#define ABSL_XRAY_NEVER_INSTRUMENT
+#define ABSL_XRAY_LOG_ARGS(N)
+#endif
+
+// ABSL_ATTRIBUTE_REINITIALIZES
+//
+// Indicates that a member function reinitializes the entire object to a known
+// state, independent of the previous state of the object.
+//
+// The clang-tidy check bugprone-use-after-move allows member functions marked
+// with this attribute to be called on objects that have been moved from;
+// without the attribute, this would result in a use-after-move warning.
+#if ABSL_HAVE_CPP_ATTRIBUTE(clang::reinitializes)
+#define ABSL_ATTRIBUTE_REINITIALIZES [[clang::reinitializes]]
+#else
+#define ABSL_ATTRIBUTE_REINITIALIZES
+#endif
+
+// -----------------------------------------------------------------------------
+// Variable Attributes
+// -----------------------------------------------------------------------------
+
+// ABSL_ATTRIBUTE_UNUSED
+//
+// Prevents the compiler from complaining about variables that appear unused.
+#if ABSL_HAVE_ATTRIBUTE(unused) || (defined(__GNUC__) && !defined(__clang__))
+#undef ABSL_ATTRIBUTE_UNUSED
+#define ABSL_ATTRIBUTE_UNUSED __attribute__((__unused__))
+#else
+#define ABSL_ATTRIBUTE_UNUSED
+#endif
+
+// ABSL_ATTRIBUTE_INITIAL_EXEC
+//
+// Tells the compiler to use "initial-exec" mode for a thread-local variable.
+// See http://people.redhat.com/drepper/tls.pdf for the gory details.
+#if ABSL_HAVE_ATTRIBUTE(tls_model) || (defined(__GNUC__) && !defined(__clang__))
+#define ABSL_ATTRIBUTE_INITIAL_EXEC __attribute__((tls_model("initial-exec")))
+#else
+#define ABSL_ATTRIBUTE_INITIAL_EXEC
+#endif
+
+// ABSL_ATTRIBUTE_PACKED
+//
+// Instructs the compiler not to use natural alignment for a tagged data
+// structure, but instead to reduce its alignment to 1. This attribute can
+// either be applied to members of a structure or to a structure in its
+// entirety. Applying this attribute (judiciously) to a structure in its
+// entirety to optimize the memory footprint of very commonly-used structs is
+// fine. Do not apply this attribute to a structure in its entirety if the
+// purpose is to control the offsets of the members in the structure. Instead,
+// apply this attribute only to structure members that need it.
+//
+// When applying ABSL_ATTRIBUTE_PACKED only to specific structure members the
+// natural alignment of structure members not annotated is preserved. Aligned
+// member accesses are faster than non-aligned member accesses even if the
+// targeted microprocessor supports non-aligned accesses.
+#if ABSL_HAVE_ATTRIBUTE(packed) || (defined(__GNUC__) && !defined(__clang__))
+#define ABSL_ATTRIBUTE_PACKED __attribute__((__packed__))
+#else
+#define ABSL_ATTRIBUTE_PACKED
+#endif
+
+// ABSL_ATTRIBUTE_FUNC_ALIGN
+//
+// Tells the compiler to align the function start at least to certain
+// alignment boundary
+#if ABSL_HAVE_ATTRIBUTE(aligned) || (defined(__GNUC__) && !defined(__clang__))
+#define ABSL_ATTRIBUTE_FUNC_ALIGN(bytes) __attribute__((aligned(bytes)))
+#else
+#define ABSL_ATTRIBUTE_FUNC_ALIGN(bytes)
+#endif
+
+// ABSL_FALLTHROUGH_INTENDED
+//
+// Annotates implicit fall-through between switch labels, allowing a case to
+// indicate intentional fallthrough and turn off warnings about any lack of a
+// `break` statement. The ABSL_FALLTHROUGH_INTENDED macro should be followed by
+// a semicolon and can be used in most places where `break` can, provided that
+// no statements exist between it and the next switch label.
+//
+// Example:
+//
+//  switch (x) {
+//    case 40:
+//    case 41:
+//      if (truth_is_out_there) {
+//        ++x;
+//        ABSL_FALLTHROUGH_INTENDED;  // Use instead of/along with annotations
+//                                    // in comments
+//      } else {
+//        return x;
+//      }
+//    case 42:
+//      ...
+//
+// Notes: when compiled with clang in C++11 mode, the ABSL_FALLTHROUGH_INTENDED
+// macro is expanded to the [[clang::fallthrough]] attribute, which is analysed
+// when  performing switch labels fall-through diagnostic
+// (`-Wimplicit-fallthrough`). See clang documentation on language extensions
+// for details:
+// https://clang.llvm.org/docs/AttributeReference.html#fallthrough-clang-fallthrough
+//
+// When used with unsupported compilers, the ABSL_FALLTHROUGH_INTENDED macro
+// has no effect on diagnostics. In any case this macro has no effect on runtime
+// behavior and performance of code.
+
+#ifdef ABSL_FALLTHROUGH_INTENDED
+#error "ABSL_FALLTHROUGH_INTENDED should not be defined."
+#endif
+
+// TODO(zhangxy): Use c++17 standard [[fallthrough]] macro, when supported.
+#if defined(__clang__) && defined(__has_warning)
+#if __has_feature(cxx_attributes) && __has_warning("-Wimplicit-fallthrough")
+#define ABSL_FALLTHROUGH_INTENDED [[clang::fallthrough]]
+#endif
+#elif defined(__GNUC__) && __GNUC__ >= 7
+#define ABSL_FALLTHROUGH_INTENDED [[gnu::fallthrough]]
+#endif
+
+#ifndef ABSL_FALLTHROUGH_INTENDED
+#define ABSL_FALLTHROUGH_INTENDED \
+  do {                            \
+  } while (0)
+#endif
+
+// ABSL_DEPRECATED()
+//
+// Marks a deprecated class, struct, enum, function, method and variable
+// declarations. The macro argument is used as a custom diagnostic message (e.g.
+// suggestion of a better alternative).
+//
+// Examples:
+//
+//   class ABSL_DEPRECATED("Use Bar instead") Foo {...};
+//
+//   ABSL_DEPRECATED("Use Baz() instead") void Bar() {...}
+//
+//   template <typename T>
+//   ABSL_DEPRECATED("Use DoThat() instead")
+//   void DoThis();
+//
+// Every usage of a deprecated entity will trigger a warning when compiled with
+// clang's `-Wdeprecated-declarations` option. This option is turned off by
+// default, but the warnings will be reported by clang-tidy.
+#if defined(__clang__) && defined(__cplusplus) && __cplusplus >= 201103L
+#define ABSL_DEPRECATED(message) __attribute__((deprecated(message)))
+#endif
+
+#ifndef ABSL_DEPRECATED
+#define ABSL_DEPRECATED(message)
+#endif
+
+// ABSL_CONST_INIT
+//
+// A variable declaration annotated with the `ABSL_CONST_INIT` attribute will
+// not compile (on supported platforms) unless the variable has a constant
+// initializer. This is useful for variables with static and thread storage
+// duration, because it guarantees that they will not suffer from the so-called
+// "static init order fiasco".  Prefer to put this attribute on the most visible
+// declaration of the variable, if there's more than one, because code that
+// accesses the variable can then use the attribute for optimization.
+//
+// Example:
+//
+//   class MyClass {
+//    public:
+//     ABSL_CONST_INIT static MyType my_var;
+//   };
+//
+//   MyType MyClass::my_var = MakeMyType(...);
+//
+// Note that this attribute is redundant if the variable is declared constexpr.
+#if ABSL_HAVE_CPP_ATTRIBUTE(clang::require_constant_initialization)
+#define ABSL_CONST_INIT [[clang::require_constant_initialization]]
+#else
+#define ABSL_CONST_INIT
+#endif  // ABSL_HAVE_CPP_ATTRIBUTE(clang::require_constant_initialization)
+
+// ABSL_ATTRIBUTE_PURE_FUNCTION
+//
+// ABSL_ATTRIBUTE_PURE_FUNCTION is used to annotate declarations of "pure"
+// functions. A function is pure if its return value is only a function of its
+// arguments. The pure attribute prohibits a function from modifying the state
+// of the program that is observable by means other than inspecting the
+// function's return value. Declaring such functions with the pure attribute
+// allows the compiler to avoid emitting some calls in repeated invocations of
+// the function with the same argument values.
+//
+// Example:
+//
+//  ABSL_ATTRIBUTE_PURE_FUNCTION int64_t ToInt64Milliseconds(Duration d);
+#if ABSL_HAVE_CPP_ATTRIBUTE(gnu::pure)
+#define ABSL_ATTRIBUTE_PURE_FUNCTION [[gnu::pure]]
+#elif ABSL_HAVE_ATTRIBUTE(pure)
+#define ABSL_ATTRIBUTE_PURE_FUNCTION __attribute__((pure))
+#else
+#define ABSL_ATTRIBUTE_PURE_FUNCTION
+#endif
+
+#endif  // ABSL_BASE_ATTRIBUTES_H_
diff --git a/src/absl/base/call_once.h b/src/absl/base/call_once.h
new file mode 100644 (file)
index 0000000..96109f5
--- /dev/null
@@ -0,0 +1,219 @@
+// Copyright 2017 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// -----------------------------------------------------------------------------
+// File: call_once.h
+// -----------------------------------------------------------------------------
+//
+// This header file provides an Abseil version of `std::call_once` for invoking
+// a given function at most once, across all threads. This Abseil version is
+// faster than the C++11 version and incorporates the C++17 argument-passing
+// fix, so that (for example) non-const references may be passed to the invoked
+// function.
+
+#ifndef ABSL_BASE_CALL_ONCE_H_
+#define ABSL_BASE_CALL_ONCE_H_
+
+#include <algorithm>
+#include <atomic>
+#include <cstdint>
+#include <type_traits>
+#include <utility>
+
+#include "absl/base/internal/invoke.h"
+#include "absl/base/internal/low_level_scheduling.h"
+#include "absl/base/internal/raw_logging.h"
+#include "absl/base/internal/scheduling_mode.h"
+#include "absl/base/internal/spinlock_wait.h"
+#include "absl/base/macros.h"
+#include "absl/base/optimization.h"
+#include "absl/base/port.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+
+class once_flag;
+
+namespace base_internal {
+std::atomic<uint32_t>* ControlWord(absl::once_flag* flag);
+}  // namespace base_internal
+
+// call_once()
+//
+// For all invocations using a given `once_flag`, invokes a given `fn` exactly
+// once across all threads. The first call to `call_once()` with a particular
+// `once_flag` argument (that does not throw an exception) will run the
+// specified function with the provided `args`; other calls with the same
+// `once_flag` argument will not run the function, but will wait
+// for the provided function to finish running (if it is still running).
+//
+// This mechanism provides a safe, simple, and fast mechanism for one-time
+// initialization in a multi-threaded process.
+//
+// Example:
+//
+// class MyInitClass {
+//  public:
+//  ...
+//  mutable absl::once_flag once_;
+//
+//  MyInitClass* init() const {
+//    absl::call_once(once_, &MyInitClass::Init, this);
+//    return ptr_;
+//  }
+//
+template <typename Callable, typename... Args>
+void call_once(absl::once_flag& flag, Callable&& fn, Args&&... args);
+
+// once_flag
+//
+// Objects of this type are used to distinguish calls to `call_once()` and
+// ensure the provided function is only invoked once across all threads. This
+// type is not copyable or movable. However, it has a `constexpr`
+// constructor, and is safe to use as a namespace-scoped global variable.
+class once_flag {
+ public:
+  constexpr once_flag() : control_(0) {}
+  once_flag(const once_flag&) = delete;
+  once_flag& operator=(const once_flag&) = delete;
+
+ private:
+  friend std::atomic<uint32_t>* base_internal::ControlWord(once_flag* flag);
+  std::atomic<uint32_t> control_;
+};
+
+//------------------------------------------------------------------------------
+// End of public interfaces.
+// Implementation details follow.
+//------------------------------------------------------------------------------
+
+namespace base_internal {
+
+// Like call_once, but uses KERNEL_ONLY scheduling. Intended to be used to
+// initialize entities used by the scheduler implementation.
+template <typename Callable, typename... Args>
+void LowLevelCallOnce(absl::once_flag* flag, Callable&& fn, Args&&... args);
+
+// Disables scheduling while on stack when scheduling mode is non-cooperative.
+// No effect for cooperative scheduling modes.
+class SchedulingHelper {
+ public:
+  explicit SchedulingHelper(base_internal::SchedulingMode mode) : mode_(mode) {
+    if (mode_ == base_internal::SCHEDULE_KERNEL_ONLY) {
+      guard_result_ = base_internal::SchedulingGuard::DisableRescheduling();
+    }
+  }
+
+  ~SchedulingHelper() {
+    if (mode_ == base_internal::SCHEDULE_KERNEL_ONLY) {
+      base_internal::SchedulingGuard::EnableRescheduling(guard_result_);
+    }
+  }
+
+ private:
+  base_internal::SchedulingMode mode_;
+  bool guard_result_;
+};
+
+// Bit patterns for call_once state machine values.  Internal implementation
+// detail, not for use by clients.
+//
+// The bit patterns are arbitrarily chosen from unlikely values, to aid in
+// debugging.  However, kOnceInit must be 0, so that a zero-initialized
+// once_flag will be valid for immediate use.
+enum {
+  kOnceInit = 0,
+  kOnceRunning = 0x65C2937B,
+  kOnceWaiter = 0x05A308D2,
+  // A very small constant is chosen for kOnceDone so that it fit in a single
+  // compare with immediate instruction for most common ISAs.  This is verified
+  // for x86, POWER and ARM.
+  kOnceDone = 221,    // Random Number
+};
+
+template <typename Callable, typename... Args>
+ABSL_ATTRIBUTE_NOINLINE
+void CallOnceImpl(std::atomic<uint32_t>* control,
+                  base_internal::SchedulingMode scheduling_mode, Callable&& fn,
+                  Args&&... args) {
+#ifndef NDEBUG
+  {
+    uint32_t old_control = control->load(std::memory_order_relaxed);
+    if (old_control != kOnceInit &&
+        old_control != kOnceRunning &&
+        old_control != kOnceWaiter &&
+        old_control != kOnceDone) {
+      ABSL_RAW_LOG(FATAL, "Unexpected value for control word: 0x%lx",
+                   static_cast<unsigned long>(old_control));  // NOLINT
+    }
+  }
+#endif  // NDEBUG
+  static const base_internal::SpinLockWaitTransition trans[] = {
+      {kOnceInit, kOnceRunning, true},
+      {kOnceRunning, kOnceWaiter, false},
+      {kOnceDone, kOnceDone, true}};
+
+  // Must do this before potentially modifying control word's state.
+  base_internal::SchedulingHelper maybe_disable_scheduling(scheduling_mode);
+  // Short circuit the simplest case to avoid procedure call overhead.
+  // The base_internal::SpinLockWait() call returns either kOnceInit or
+  // kOnceDone. If it returns kOnceDone, it must have loaded the control word
+  // with std::memory_order_acquire and seen a value of kOnceDone.
+  uint32_t old_control = kOnceInit;
+  if (control->compare_exchange_strong(old_control, kOnceRunning,
+                                       std::memory_order_relaxed) ||
+      base_internal::SpinLockWait(control, ABSL_ARRAYSIZE(trans), trans,
+                                  scheduling_mode) == kOnceInit) {
+    base_internal::invoke(std::forward<Callable>(fn),
+                          std::forward<Args>(args)...);
+    old_control =
+        control->exchange(base_internal::kOnceDone, std::memory_order_release);
+    if (old_control == base_internal::kOnceWaiter) {
+      base_internal::SpinLockWake(control, true);
+    }
+  }  // else *control is already kOnceDone
+}
+
+inline std::atomic<uint32_t>* ControlWord(once_flag* flag) {
+  return &flag->control_;
+}
+
+template <typename Callable, typename... Args>
+void LowLevelCallOnce(absl::once_flag* flag, Callable&& fn, Args&&... args) {
+  std::atomic<uint32_t>* once = base_internal::ControlWord(flag);
+  uint32_t s = once->load(std::memory_order_acquire);
+  if (ABSL_PREDICT_FALSE(s != base_internal::kOnceDone)) {
+    base_internal::CallOnceImpl(once, base_internal::SCHEDULE_KERNEL_ONLY,
+                                std::forward<Callable>(fn),
+                                std::forward<Args>(args)...);
+  }
+}
+
+}  // namespace base_internal
+
+template <typename Callable, typename... Args>
+void call_once(absl::once_flag& flag, Callable&& fn, Args&&... args) {
+  std::atomic<uint32_t>* once = base_internal::ControlWord(&flag);
+  uint32_t s = once->load(std::memory_order_acquire);
+  if (ABSL_PREDICT_FALSE(s != base_internal::kOnceDone)) {
+    base_internal::CallOnceImpl(
+        once, base_internal::SCHEDULE_COOPERATIVE_AND_KERNEL,
+        std::forward<Callable>(fn), std::forward<Args>(args)...);
+  }
+}
+
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#endif  // ABSL_BASE_CALL_ONCE_H_
diff --git a/src/absl/base/casts.h b/src/absl/base/casts.h
new file mode 100644 (file)
index 0000000..83c6912
--- /dev/null
@@ -0,0 +1,187 @@
+//
+// Copyright 2017 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// -----------------------------------------------------------------------------
+// File: casts.h
+// -----------------------------------------------------------------------------
+//
+// This header file defines casting templates to fit use cases not covered by
+// the standard casts provided in the C++ standard. As with all cast operations,
+// use these with caution and only if alternatives do not exist.
+
+#ifndef ABSL_BASE_CASTS_H_
+#define ABSL_BASE_CASTS_H_
+
+#include <cstring>
+#include <memory>
+#include <type_traits>
+#include <utility>
+
+#include "absl/base/internal/identity.h"
+#include "absl/base/macros.h"
+#include "absl/meta/type_traits.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+
+namespace internal_casts {
+
+template <class Dest, class Source>
+struct is_bitcastable
+    : std::integral_constant<
+          bool,
+          sizeof(Dest) == sizeof(Source) &&
+              type_traits_internal::is_trivially_copyable<Source>::value &&
+              type_traits_internal::is_trivially_copyable<Dest>::value &&
+              std::is_default_constructible<Dest>::value> {};
+
+}  // namespace internal_casts
+
+// implicit_cast()
+//
+// Performs an implicit conversion between types following the language
+// rules for implicit conversion; if an implicit conversion is otherwise
+// allowed by the language in the given context, this function performs such an
+// implicit conversion.
+//
+// Example:
+//
+//   // If the context allows implicit conversion:
+//   From from;
+//   To to = from;
+//
+//   // Such code can be replaced by:
+//   implicit_cast<To>(from);
+//
+// An `implicit_cast()` may also be used to annotate numeric type conversions
+// that, although safe, may produce compiler warnings (such as `long` to `int`).
+// Additionally, an `implicit_cast()` is also useful within return statements to
+// indicate a specific implicit conversion is being undertaken.
+//
+// Example:
+//
+//   return implicit_cast<double>(size_in_bytes) / capacity_;
+//
+// Annotating code with `implicit_cast()` allows you to explicitly select
+// particular overloads and template instantiations, while providing a safer
+// cast than `reinterpret_cast()` or `static_cast()`.
+//
+// Additionally, an `implicit_cast()` can be used to allow upcasting within a
+// type hierarchy where incorrect use of `static_cast()` could accidentally
+// allow downcasting.
+//
+// Finally, an `implicit_cast()` can be used to perform implicit conversions
+// from unrelated types that otherwise couldn't be implicitly cast directly;
+// C++ will normally only implicitly cast "one step" in such conversions.
+//
+// That is, if C is a type which can be implicitly converted to B, with B being
+// a type that can be implicitly converted to A, an `implicit_cast()` can be
+// used to convert C to B (which the compiler can then implicitly convert to A
+// using language rules).
+//
+// Example:
+//
+//   // Assume an object C is convertible to B, which is implicitly convertible
+//   // to A
+//   A a = implicit_cast<B>(C);
+//
+// Such implicit cast chaining may be useful within template logic.
+template <typename To>
+constexpr To implicit_cast(typename absl::internal::identity_t<To> to) {
+  return to;
+}
+
+// bit_cast()
+//
+// Performs a bitwise cast on a type without changing the underlying bit
+// representation of that type's value. The two types must be of the same size
+// and both types must be trivially copyable. As with most casts, use with
+// caution. A `bit_cast()` might be needed when you need to temporarily treat a
+// type as some other type, such as in the following cases:
+//
+//    * Serialization (casting temporarily to `char *` for those purposes is
+//      always allowed by the C++ standard)
+//    * Managing the individual bits of a type within mathematical operations
+//      that are not normally accessible through that type
+//    * Casting non-pointer types to pointer types (casting the other way is
+//      allowed by `reinterpret_cast()` but round-trips cannot occur the other
+//      way).
+//
+// Example:
+//
+//   float f = 3.14159265358979;
+//   int i = bit_cast<int32_t>(f);
+//   // i = 0x40490fdb
+//
+// Casting non-pointer types to pointer types and then dereferencing them
+// traditionally produces undefined behavior.
+//
+// Example:
+//
+//   // WRONG
+//   float f = 3.14159265358979;            // WRONG
+//   int i = * reinterpret_cast<int*>(&f);  // WRONG
+//
+// The address-casting method produces undefined behavior according to the ISO
+// C++ specification section [basic.lval]. Roughly, this section says: if an
+// object in memory has one type, and a program accesses it with a different
+// type, the result is undefined behavior for most values of "different type".
+//
+// Such casting results in type punning: holding an object in memory of one type
+// and reading its bits back using a different type. A `bit_cast()` avoids this
+// issue by implementing its casts using `memcpy()`, which avoids introducing
+// this undefined behavior.
+//
+// NOTE: The requirements here are more strict than the bit_cast of standard
+// proposal p0476 due to the need for workarounds and lack of intrinsics.
+// Specifically, this implementation also requires `Dest` to be
+// default-constructible.
+template <
+    typename Dest, typename Source,
+    typename std::enable_if<internal_casts::is_bitcastable<Dest, Source>::value,
+                            int>::type = 0>
+inline Dest bit_cast(const Source& source) {
+  Dest dest;
+  memcpy(static_cast<void*>(std::addressof(dest)),
+         static_cast<const void*>(std::addressof(source)), sizeof(dest));
+  return dest;
+}
+
+// NOTE: This overload is only picked if the requirements of bit_cast are
+// not met. It is therefore UB, but is provided temporarily as previous
+// versions of this function template were unchecked. Do not use this in
+// new code.
+template <
+    typename Dest, typename Source,
+    typename std::enable_if<
+        !internal_casts::is_bitcastable<Dest, Source>::value,
+        int>::type = 0>
+ABSL_DEPRECATED(
+    "absl::bit_cast type requirements were violated. Update the types "
+    "being used such that they are the same size and are both "
+    "TriviallyCopyable.")
+inline Dest bit_cast(const Source& source) {
+  static_assert(sizeof(Dest) == sizeof(Source),
+                "Source and destination types should have equal sizes.");
+
+  Dest dest;
+  memcpy(&dest, &source, sizeof(dest));
+  return dest;
+}
+
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#endif  // ABSL_BASE_CASTS_H_
diff --git a/src/absl/base/config.h b/src/absl/base/config.h
new file mode 100644 (file)
index 0000000..a3a778d
--- /dev/null
@@ -0,0 +1,746 @@
+//
+// Copyright 2017 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// -----------------------------------------------------------------------------
+// File: config.h
+// -----------------------------------------------------------------------------
+//
+// This header file defines a set of macros for checking the presence of
+// important compiler and platform features. Such macros can be used to
+// produce portable code by parameterizing compilation based on the presence or
+// lack of a given feature.
+//
+// We define a "feature" as some interface we wish to program to: for example,
+// a library function or system call. A value of `1` indicates support for
+// that feature; any other value indicates the feature support is undefined.
+//
+// Example:
+//
+// Suppose a programmer wants to write a program that uses the 'mmap()' system
+// call. The Abseil macro for that feature (`ABSL_HAVE_MMAP`) allows you to
+// selectively include the `mmap.h` header and bracket code using that feature
+// in the macro:
+//
+//   #include "absl/base/config.h"
+//
+//   #ifdef ABSL_HAVE_MMAP
+//   #include "sys/mman.h"
+//   #endif  //ABSL_HAVE_MMAP
+//
+//   ...
+//   #ifdef ABSL_HAVE_MMAP
+//   void *ptr = mmap(...);
+//   ...
+//   #endif  // ABSL_HAVE_MMAP
+
+#ifndef ABSL_BASE_CONFIG_H_
+#define ABSL_BASE_CONFIG_H_
+
+// Included for the __GLIBC__ macro (or similar macros on other systems).
+#include <limits.h>
+
+#ifdef __cplusplus
+// Included for __GLIBCXX__, _LIBCPP_VERSION
+#include <cstddef>
+#endif  // __cplusplus
+
+#if defined(__APPLE__)
+// Included for TARGET_OS_IPHONE, __IPHONE_OS_VERSION_MIN_REQUIRED,
+// __IPHONE_8_0.
+#include <Availability.h>
+#include <TargetConditionals.h>
+#endif
+
+#include "absl/base/options.h"
+#include "absl/base/policy_checks.h"
+
+// Helper macro to convert a CPP variable to a string literal.
+#define ABSL_INTERNAL_DO_TOKEN_STR(x) #x
+#define ABSL_INTERNAL_TOKEN_STR(x) ABSL_INTERNAL_DO_TOKEN_STR(x)
+
+// -----------------------------------------------------------------------------
+// Abseil namespace annotations
+// -----------------------------------------------------------------------------
+
+// ABSL_NAMESPACE_BEGIN/ABSL_NAMESPACE_END
+//
+// An annotation placed at the beginning/end of each `namespace absl` scope.
+// This is used to inject an inline namespace.
+//
+// The proper way to write Abseil code in the `absl` namespace is:
+//
+// namespace absl {
+// ABSL_NAMESPACE_BEGIN
+//
+// void Foo();  // absl::Foo().
+//
+// ABSL_NAMESPACE_END
+// }  // namespace absl
+//
+// Users of Abseil should not use these macros, because users of Abseil should
+// not write `namespace absl {` in their own code for any reason.  (Abseil does
+// not support forward declarations of its own types, nor does it support
+// user-provided specialization of Abseil templates.  Code that violates these
+// rules may be broken without warning.)
+#if !defined(ABSL_OPTION_USE_INLINE_NAMESPACE) || \
+    !defined(ABSL_OPTION_INLINE_NAMESPACE_NAME)
+#error options.h is misconfigured.
+#endif
+
+// Check that ABSL_OPTION_INLINE_NAMESPACE_NAME is neither "head" nor ""
+#if defined(__cplusplus) && ABSL_OPTION_USE_INLINE_NAMESPACE == 1
+
+#define ABSL_INTERNAL_INLINE_NAMESPACE_STR \
+  ABSL_INTERNAL_TOKEN_STR(ABSL_OPTION_INLINE_NAMESPACE_NAME)
+
+static_assert(ABSL_INTERNAL_INLINE_NAMESPACE_STR[0] != '\0',
+              "options.h misconfigured: ABSL_OPTION_INLINE_NAMESPACE_NAME must "
+              "not be empty.");
+static_assert(ABSL_INTERNAL_INLINE_NAMESPACE_STR[0] != 'h' ||
+                  ABSL_INTERNAL_INLINE_NAMESPACE_STR[1] != 'e' ||
+                  ABSL_INTERNAL_INLINE_NAMESPACE_STR[2] != 'a' ||
+                  ABSL_INTERNAL_INLINE_NAMESPACE_STR[3] != 'd' ||
+                  ABSL_INTERNAL_INLINE_NAMESPACE_STR[4] != '\0',
+              "options.h misconfigured: ABSL_OPTION_INLINE_NAMESPACE_NAME must "
+              "be changed to a new, unique identifier name.");
+
+#endif
+
+#if ABSL_OPTION_USE_INLINE_NAMESPACE == 0
+#define ABSL_NAMESPACE_BEGIN
+#define ABSL_NAMESPACE_END
+#define ABSL_INTERNAL_C_SYMBOL(x) x
+#elif ABSL_OPTION_USE_INLINE_NAMESPACE == 1
+#define ABSL_NAMESPACE_BEGIN \
+  inline namespace ABSL_OPTION_INLINE_NAMESPACE_NAME {
+#define ABSL_NAMESPACE_END }
+#define ABSL_INTERNAL_C_SYMBOL_HELPER_2(x, v) x##_##v
+#define ABSL_INTERNAL_C_SYMBOL_HELPER_1(x, v) \
+  ABSL_INTERNAL_C_SYMBOL_HELPER_2(x, v)
+#define ABSL_INTERNAL_C_SYMBOL(x) \
+  ABSL_INTERNAL_C_SYMBOL_HELPER_1(x, ABSL_OPTION_INLINE_NAMESPACE_NAME)
+#else
+#error options.h is misconfigured.
+#endif
+
+// -----------------------------------------------------------------------------
+// Compiler Feature Checks
+// -----------------------------------------------------------------------------
+
+// ABSL_HAVE_BUILTIN()
+//
+// Checks whether the compiler supports a Clang Feature Checking Macro, and if
+// so, checks whether it supports the provided builtin function "x" where x
+// is one of the functions noted in
+// https://clang.llvm.org/docs/LanguageExtensions.html
+//
+// Note: Use this macro to avoid an extra level of #ifdef __has_builtin check.
+// http://releases.llvm.org/3.3/tools/clang/docs/LanguageExtensions.html
+#ifdef __has_builtin
+#define ABSL_HAVE_BUILTIN(x) __has_builtin(x)
+#else
+#define ABSL_HAVE_BUILTIN(x) 0
+#endif
+
+#if defined(__is_identifier)
+#define ABSL_INTERNAL_HAS_KEYWORD(x) !(__is_identifier(x))
+#else
+#define ABSL_INTERNAL_HAS_KEYWORD(x) 0
+#endif
+
+#ifdef __has_feature
+#define ABSL_HAVE_FEATURE(f) __has_feature(f)
+#else
+#define ABSL_HAVE_FEATURE(f) 0
+#endif
+
+// ABSL_HAVE_TLS is defined to 1 when __thread should be supported.
+// We assume __thread is supported on Linux when compiled with Clang or compiled
+// against libstdc++ with _GLIBCXX_HAVE_TLS defined.
+#ifdef ABSL_HAVE_TLS
+#error ABSL_HAVE_TLS cannot be directly set
+#elif defined(__linux__) && (defined(__clang__) || defined(_GLIBCXX_HAVE_TLS))
+#define ABSL_HAVE_TLS 1
+#endif
+
+// ABSL_HAVE_STD_IS_TRIVIALLY_DESTRUCTIBLE
+//
+// Checks whether `std::is_trivially_destructible<T>` is supported.
+//
+// Notes: All supported compilers using libc++ support this feature, as does
+// gcc >= 4.8.1 using libstdc++, and Visual Studio.
+#ifdef ABSL_HAVE_STD_IS_TRIVIALLY_DESTRUCTIBLE
+#error ABSL_HAVE_STD_IS_TRIVIALLY_DESTRUCTIBLE cannot be directly set
+#elif defined(_LIBCPP_VERSION) ||                                        \
+    (!defined(__clang__) && defined(__GNUC__) && defined(__GLIBCXX__) && \
+     (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8))) ||        \
+    defined(_MSC_VER)
+#define ABSL_HAVE_STD_IS_TRIVIALLY_DESTRUCTIBLE 1
+#endif
+
+// ABSL_HAVE_STD_IS_TRIVIALLY_CONSTRUCTIBLE
+//
+// Checks whether `std::is_trivially_default_constructible<T>` and
+// `std::is_trivially_copy_constructible<T>` are supported.
+
+// ABSL_HAVE_STD_IS_TRIVIALLY_ASSIGNABLE
+//
+// Checks whether `std::is_trivially_copy_assignable<T>` is supported.
+
+// Notes: Clang with libc++ supports these features, as does gcc >= 5.1 with
+// either libc++ or libstdc++, and Visual Studio (but not NVCC).
+#if defined(ABSL_HAVE_STD_IS_TRIVIALLY_CONSTRUCTIBLE)
+#error ABSL_HAVE_STD_IS_TRIVIALLY_CONSTRUCTIBLE cannot be directly set
+#elif defined(ABSL_HAVE_STD_IS_TRIVIALLY_ASSIGNABLE)
+#error ABSL_HAVE_STD_IS_TRIVIALLY_ASSIGNABLE cannot directly set
+#elif (defined(__clang__) && defined(_LIBCPP_VERSION)) ||        \
+    (!defined(__clang__) && defined(__GNUC__) &&                 \
+     (__GNUC__ > 7 || (__GNUC__ == 7 && __GNUC_MINOR__ >= 4)) && \
+     (defined(_LIBCPP_VERSION) || defined(__GLIBCXX__))) ||      \
+    (defined(_MSC_VER) && !defined(__NVCC__))
+#define ABSL_HAVE_STD_IS_TRIVIALLY_CONSTRUCTIBLE 1
+#define ABSL_HAVE_STD_IS_TRIVIALLY_ASSIGNABLE 1
+#endif
+
+// ABSL_HAVE_SOURCE_LOCATION_CURRENT
+//
+// Indicates whether `absl::SourceLocation::current()` will return useful
+// information in some contexts.
+#ifndef ABSL_HAVE_SOURCE_LOCATION_CURRENT
+#if ABSL_INTERNAL_HAS_KEYWORD(__builtin_LINE) && \
+    ABSL_INTERNAL_HAS_KEYWORD(__builtin_FILE)
+#define ABSL_HAVE_SOURCE_LOCATION_CURRENT 1
+#elif defined(__GNUC__) && __GNUC__ >= 5
+#define ABSL_HAVE_SOURCE_LOCATION_CURRENT 1
+#endif
+#endif
+
+// ABSL_HAVE_THREAD_LOCAL
+//
+// Checks whether C++11's `thread_local` storage duration specifier is
+// supported.
+#ifdef ABSL_HAVE_THREAD_LOCAL
+#error ABSL_HAVE_THREAD_LOCAL cannot be directly set
+#elif defined(__APPLE__)
+// Notes:
+// * Xcode's clang did not support `thread_local` until version 8, and
+//   even then not for all iOS < 9.0.
+// * Xcode 9.3 started disallowing `thread_local` for 32-bit iOS simulator
+//   targeting iOS 9.x.
+// * Xcode 10 moves the deployment target check for iOS < 9.0 to link time
+//   making ABSL_HAVE_FEATURE unreliable there.
+//
+#if ABSL_HAVE_FEATURE(cxx_thread_local) && \
+    !(TARGET_OS_IPHONE && __IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_9_0)
+#define ABSL_HAVE_THREAD_LOCAL 1
+#endif
+#else  // !defined(__APPLE__)
+#define ABSL_HAVE_THREAD_LOCAL 1
+#endif
+
+// There are platforms for which TLS should not be used even though the compiler
+// makes it seem like it's supported (Android NDK < r12b for example).
+// This is primarily because of linker problems and toolchain misconfiguration:
+// Abseil does not intend to support this indefinitely. Currently, the newest
+// toolchain that we intend to support that requires this behavior is the
+// r11 NDK - allowing for a 5 year support window on that means this option
+// is likely to be removed around June of 2021.
+// TLS isn't supported until NDK r12b per
+// https://developer.android.com/ndk/downloads/revision_history.html
+// Since NDK r16, `__NDK_MAJOR__` and `__NDK_MINOR__` are defined in
+// <android/ndk-version.h>. For NDK < r16, users should define these macros,
+// e.g. `-D__NDK_MAJOR__=11 -D__NKD_MINOR__=0` for NDK r11.
+#if defined(__ANDROID__) && defined(__clang__)
+#if __has_include(<android/ndk-version.h>)
+#include <android/ndk-version.h>
+#endif  // __has_include(<android/ndk-version.h>)
+#if defined(__ANDROID__) && defined(__clang__) && defined(__NDK_MAJOR__) && \
+    defined(__NDK_MINOR__) &&                                               \
+    ((__NDK_MAJOR__ < 12) || ((__NDK_MAJOR__ == 12) && (__NDK_MINOR__ < 1)))
+#undef ABSL_HAVE_TLS
+#undef ABSL_HAVE_THREAD_LOCAL
+#endif
+#endif  // defined(__ANDROID__) && defined(__clang__)
+
+// ABSL_HAVE_INTRINSIC_INT128
+//
+// Checks whether the __int128 compiler extension for a 128-bit integral type is
+// supported.
+//
+// Note: __SIZEOF_INT128__ is defined by Clang and GCC when __int128 is
+// supported, but we avoid using it in certain cases:
+// * On Clang:
+//   * Building using Clang for Windows, where the Clang runtime library has
+//     128-bit support only on LP64 architectures, but Windows is LLP64.
+// * On Nvidia's nvcc:
+//   * nvcc also defines __GNUC__ and __SIZEOF_INT128__, but not all versions
+//     actually support __int128.
+
+
+// R packages can't use intrinsic int128 because -Wpedantic gives an
+// R CMD check warning. Disable it here.
+// #ifdef ABSL_HAVE_INTRINSIC_INT128
+// #error ABSL_HAVE_INTRINSIC_INT128 cannot be directly set
+// #elif defined(__SIZEOF_INT128__)
+// #if (defined(__clang__) && !defined(_WIN32)) || \
+//     (defined(__CUDACC__) && __CUDACC_VER_MAJOR__ >= 9) ||                \
+//     (defined(__GNUC__) && !defined(__clang__) && !defined(__CUDACC__))
+// #define ABSL_HAVE_INTRINSIC_INT128 1
+// #elif defined(__CUDACC__)
+// // __CUDACC_VER__ is a full version number before CUDA 9, and is defined to a
+// // string explaining that it has been removed starting with CUDA 9. We use
+// // nested #ifs because there is no short-circuiting in the preprocessor.
+// // NOTE: `__CUDACC__` could be undefined while `__CUDACC_VER__` is defined.
+// #if __CUDACC_VER__ >= 70000
+// #define ABSL_HAVE_INTRINSIC_INT128 1
+// #endif  // __CUDACC_VER__ >= 70000
+// #endif  // defined(__CUDACC__)
+// #endif  // ABSL_HAVE_INTRINSIC_INT128
+
+// ABSL_HAVE_EXCEPTIONS
+//
+// Checks whether the compiler both supports and enables exceptions. Many
+// compilers support a "no exceptions" mode that disables exceptions.
+//
+// Generally, when ABSL_HAVE_EXCEPTIONS is not defined:
+//
+// * Code using `throw` and `try` may not compile.
+// * The `noexcept` specifier will still compile and behave as normal.
+// * The `noexcept` operator may still return `false`.
+//
+// For further details, consult the compiler's documentation.
+#ifdef ABSL_HAVE_EXCEPTIONS
+#error ABSL_HAVE_EXCEPTIONS cannot be directly set.
+
+#elif defined(__clang__)
+
+#if __clang_major__ > 3 || (__clang_major__ == 3 && __clang_minor__ >= 6)
+// Clang >= 3.6
+#if ABSL_HAVE_FEATURE(cxx_exceptions)
+#define ABSL_HAVE_EXCEPTIONS 1
+#endif  // ABSL_HAVE_FEATURE(cxx_exceptions)
+#else
+// Clang < 3.6
+// http://releases.llvm.org/3.6.0/tools/clang/docs/ReleaseNotes.html#the-exceptions-macro
+#if defined(__EXCEPTIONS) && ABSL_HAVE_FEATURE(cxx_exceptions)
+#define ABSL_HAVE_EXCEPTIONS 1
+#endif  // defined(__EXCEPTIONS) && ABSL_HAVE_FEATURE(cxx_exceptions)
+#endif  // __clang_major__ > 3 || (__clang_major__ == 3 && __clang_minor__ >= 6)
+
+// Handle remaining special cases and default to exceptions being supported.
+#elif !(defined(__GNUC__) && (__GNUC__ < 5) && !defined(__EXCEPTIONS)) &&    \
+    !(defined(__GNUC__) && (__GNUC__ >= 5) && !defined(__cpp_exceptions)) && \
+    !(defined(_MSC_VER) && !defined(_CPPUNWIND))
+#define ABSL_HAVE_EXCEPTIONS 1
+#endif
+
+// -----------------------------------------------------------------------------
+// Platform Feature Checks
+// -----------------------------------------------------------------------------
+
+// Currently supported operating systems and associated preprocessor
+// symbols:
+//
+//   Linux and Linux-derived           __linux__
+//   Android                           __ANDROID__ (implies __linux__)
+//   Linux (non-Android)               __linux__ && !__ANDROID__
+//   Darwin (macOS and iOS)            __APPLE__
+//   Akaros (http://akaros.org)        __ros__
+//   Windows                           _WIN32
+//   NaCL                              __native_client__
+//   AsmJS                             __asmjs__
+//   WebAssembly                       __wasm__
+//   Fuchsia                           __Fuchsia__
+//
+// Note that since Android defines both __ANDROID__ and __linux__, one
+// may probe for either Linux or Android by simply testing for __linux__.
+
+// ABSL_HAVE_MMAP
+//
+// Checks whether the platform has an mmap(2) implementation as defined in
+// POSIX.1-2001.
+#ifdef ABSL_HAVE_MMAP
+#error ABSL_HAVE_MMAP cannot be directly set
+#elif defined(__linux__) || defined(__APPLE__) || defined(__FreeBSD__) ||   \
+    defined(__ros__) || defined(__native_client__) || defined(__asmjs__) || \
+    defined(__wasm__) || defined(__Fuchsia__) || defined(__sun) || \
+    defined(__ASYLO__) || defined(__myriad2__)
+#define ABSL_HAVE_MMAP 1
+#endif
+
+// ABSL_HAVE_PTHREAD_GETSCHEDPARAM
+//
+// Checks whether the platform implements the pthread_(get|set)schedparam(3)
+// functions as defined in POSIX.1-2001.
+#ifdef ABSL_HAVE_PTHREAD_GETSCHEDPARAM
+#error ABSL_HAVE_PTHREAD_GETSCHEDPARAM cannot be directly set
+#elif defined(__linux__) || defined(__APPLE__) || defined(__FreeBSD__) || \
+    defined(__ros__)
+#define ABSL_HAVE_PTHREAD_GETSCHEDPARAM 1
+#endif
+
+// ABSL_HAVE_SCHED_GETCPU
+//
+// Checks whether sched_getcpu is available.
+#ifdef ABSL_HAVE_SCHED_GETCPU
+#error ABSL_HAVE_SCHED_GETCPU cannot be directly set
+#elif defined(__linux__)
+#define ABSL_HAVE_SCHED_GETCPU 1
+#endif
+
+// ABSL_HAVE_SCHED_YIELD
+//
+// Checks whether the platform implements sched_yield(2) as defined in
+// POSIX.1-2001.
+#ifdef ABSL_HAVE_SCHED_YIELD
+#error ABSL_HAVE_SCHED_YIELD cannot be directly set
+#elif defined(__linux__) || defined(__ros__) || defined(__native_client__)
+#define ABSL_HAVE_SCHED_YIELD 1
+#endif
+
+// ABSL_HAVE_SEMAPHORE_H
+//
+// Checks whether the platform supports the <semaphore.h> header and sem_init(3)
+// family of functions as standardized in POSIX.1-2001.
+//
+// Note: While Apple provides <semaphore.h> for both iOS and macOS, it is
+// explicitly deprecated and will cause build failures if enabled for those
+// platforms.  We side-step the issue by not defining it here for Apple
+// platforms.
+#ifdef ABSL_HAVE_SEMAPHORE_H
+#error ABSL_HAVE_SEMAPHORE_H cannot be directly set
+#elif defined(__linux__) || defined(__ros__)
+#define ABSL_HAVE_SEMAPHORE_H 1
+#endif
+
+// ABSL_HAVE_ALARM
+//
+// Checks whether the platform supports the <signal.h> header and alarm(2)
+// function as standardized in POSIX.1-2001.
+#ifdef ABSL_HAVE_ALARM
+#error ABSL_HAVE_ALARM cannot be directly set
+#elif defined(__GOOGLE_GRTE_VERSION__)
+// feature tests for Google's GRTE
+#define ABSL_HAVE_ALARM 1
+#elif defined(__GLIBC__)
+// feature test for glibc
+#define ABSL_HAVE_ALARM 1
+#elif defined(_MSC_VER)
+// feature tests for Microsoft's library
+#elif defined(__MINGW32__)
+// mingw32 doesn't provide alarm(2):
+// https://osdn.net/projects/mingw/scm/git/mingw-org-wsl/blobs/5.2-trunk/mingwrt/include/unistd.h
+// mingw-w64 provides a no-op implementation:
+// https://sourceforge.net/p/mingw-w64/mingw-w64/ci/master/tree/mingw-w64-crt/misc/alarm.c
+#elif defined(__EMSCRIPTEN__)
+// emscripten doesn't support signals
+#elif defined(__Fuchsia__)
+// Signals don't exist on fuchsia.
+#elif defined(__native_client__)
+#else
+// other standard libraries
+#define ABSL_HAVE_ALARM 1
+#endif
+
+// ABSL_IS_LITTLE_ENDIAN
+// ABSL_IS_BIG_ENDIAN
+//
+// Checks the endianness of the platform.
+//
+// Notes: uses the built in endian macros provided by GCC (since 4.6) and
+// Clang (since 3.2); see
+// https://gcc.gnu.org/onlinedocs/cpp/Common-Predefined-Macros.html.
+// Otherwise, if _WIN32, assume little endian. Otherwise, bail with an error.
+#if defined(ABSL_IS_BIG_ENDIAN)
+#error "ABSL_IS_BIG_ENDIAN cannot be directly set."
+#endif
+#if defined(ABSL_IS_LITTLE_ENDIAN)
+#error "ABSL_IS_LITTLE_ENDIAN cannot be directly set."
+#endif
+
+#if (defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) && \
+     __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)
+#define ABSL_IS_LITTLE_ENDIAN 1
+#elif defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && \
+    __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
+#define ABSL_IS_BIG_ENDIAN 1
+#elif defined(_WIN32)
+#define ABSL_IS_LITTLE_ENDIAN 1
+#else
+#error "absl endian detection needs to be set up for your compiler"
+#endif
+
+// macOS 10.13 and iOS 10.11 don't let you use <any>, <optional>, or <variant>
+// even though the headers exist and are publicly noted to work.  See
+// https://github.com/abseil/abseil-cpp/issues/207 and
+// https://developer.apple.com/documentation/xcode_release_notes/xcode_10_release_notes
+// libc++ spells out the availability requirements in the file
+// llvm-project/libcxx/include/__config via the #define
+// _LIBCPP_AVAILABILITY_BAD_OPTIONAL_ACCESS.
+#if defined(__APPLE__) && defined(_LIBCPP_VERSION) && \
+  ((defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) && \
+   __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ < 101400) || \
+  (defined(__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__) && \
+   __ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__ < 120000) || \
+  (defined(__ENVIRONMENT_WATCH_OS_VERSION_MIN_REQUIRED__) && \
+   __ENVIRONMENT_WATCH_OS_VERSION_MIN_REQUIRED__ < 50000) || \
+  (defined(__ENVIRONMENT_TV_OS_VERSION_MIN_REQUIRED__) && \
+   __ENVIRONMENT_TV_OS_VERSION_MIN_REQUIRED__ < 120000))
+#define ABSL_INTERNAL_APPLE_CXX17_TYPES_UNAVAILABLE 1
+#else
+#define ABSL_INTERNAL_APPLE_CXX17_TYPES_UNAVAILABLE 0
+#endif
+
+// ABSL_HAVE_STD_ANY
+//
+// Checks whether C++17 std::any is available by checking whether <any> exists.
+#ifdef ABSL_HAVE_STD_ANY
+#error "ABSL_HAVE_STD_ANY cannot be directly set."
+#endif
+
+#ifdef __has_include
+#if __has_include(<any>) && defined(__cplusplus) && __cplusplus >= 201703L && \
+    !ABSL_INTERNAL_APPLE_CXX17_TYPES_UNAVAILABLE
+#define ABSL_HAVE_STD_ANY 1
+#endif
+#endif
+
+// ABSL_HAVE_STD_OPTIONAL
+//
+// Checks whether C++17 std::optional is available.
+#ifdef ABSL_HAVE_STD_OPTIONAL
+#error "ABSL_HAVE_STD_OPTIONAL cannot be directly set."
+#endif
+
+#ifdef __has_include
+#if __has_include(<optional>) && defined(__cplusplus) && \
+    __cplusplus >= 201703L && !ABSL_INTERNAL_APPLE_CXX17_TYPES_UNAVAILABLE
+#define ABSL_HAVE_STD_OPTIONAL 1
+#endif
+#endif
+
+// ABSL_HAVE_STD_VARIANT
+//
+// Checks whether C++17 std::variant is available.
+#ifdef ABSL_HAVE_STD_VARIANT
+#error "ABSL_HAVE_STD_VARIANT cannot be directly set."
+#endif
+
+#ifdef __has_include
+#if __has_include(<variant>) && defined(__cplusplus) && \
+    __cplusplus >= 201703L && !ABSL_INTERNAL_APPLE_CXX17_TYPES_UNAVAILABLE
+#define ABSL_HAVE_STD_VARIANT 1
+#endif
+#endif
+
+// ABSL_HAVE_STD_STRING_VIEW
+//
+// Checks whether C++17 std::string_view is available.
+#ifdef ABSL_HAVE_STD_STRING_VIEW
+#error "ABSL_HAVE_STD_STRING_VIEW cannot be directly set."
+#endif
+
+#ifdef __has_include
+#if __has_include(<string_view>) && defined(__cplusplus) && \
+    __cplusplus >= 201703L
+#define ABSL_HAVE_STD_STRING_VIEW 1
+#endif
+#endif
+
+// For MSVC, `__has_include` is supported in VS 2017 15.3, which is later than
+// the support for <optional>, <any>, <string_view>, <variant>. So we use
+// _MSC_VER to check whether we have VS 2017 RTM (when <optional>, <any>,
+// <string_view>, <variant> is implemented) or higher. Also, `__cplusplus` is
+// not correctly set by MSVC, so we use `_MSVC_LANG` to check the language
+// version.
+// TODO(zhangxy): fix tests before enabling aliasing for `std::any`.
+#if defined(_MSC_VER) && _MSC_VER >= 1910 &&         \
+    ((defined(_MSVC_LANG) && _MSVC_LANG > 201402) || \
+     (defined(__cplusplus) && __cplusplus > 201402))
+// #define ABSL_HAVE_STD_ANY 1
+#define ABSL_HAVE_STD_OPTIONAL 1
+#define ABSL_HAVE_STD_VARIANT 1
+#define ABSL_HAVE_STD_STRING_VIEW 1
+#endif
+
+// ABSL_USES_STD_ANY
+//
+// Indicates whether absl::any is an alias for std::any.
+#if !defined(ABSL_OPTION_USE_STD_ANY)
+#error options.h is misconfigured.
+#elif ABSL_OPTION_USE_STD_ANY == 0 || \
+    (ABSL_OPTION_USE_STD_ANY == 2 && !defined(ABSL_HAVE_STD_ANY))
+#undef ABSL_USES_STD_ANY
+#elif ABSL_OPTION_USE_STD_ANY == 1 || \
+    (ABSL_OPTION_USE_STD_ANY == 2 && defined(ABSL_HAVE_STD_ANY))
+#define ABSL_USES_STD_ANY 1
+#else
+#error options.h is misconfigured.
+#endif
+
+// ABSL_USES_STD_OPTIONAL
+//
+// Indicates whether absl::optional is an alias for std::optional.
+#if !defined(ABSL_OPTION_USE_STD_OPTIONAL)
+#error options.h is misconfigured.
+#elif ABSL_OPTION_USE_STD_OPTIONAL == 0 || \
+    (ABSL_OPTION_USE_STD_OPTIONAL == 2 && !defined(ABSL_HAVE_STD_OPTIONAL))
+#undef ABSL_USES_STD_OPTIONAL
+#elif ABSL_OPTION_USE_STD_OPTIONAL == 1 || \
+    (ABSL_OPTION_USE_STD_OPTIONAL == 2 && defined(ABSL_HAVE_STD_OPTIONAL))
+#define ABSL_USES_STD_OPTIONAL 1
+#else
+#error options.h is misconfigured.
+#endif
+
+// ABSL_USES_STD_VARIANT
+//
+// Indicates whether absl::variant is an alias for std::variant.
+#if !defined(ABSL_OPTION_USE_STD_VARIANT)
+#error options.h is misconfigured.
+#elif ABSL_OPTION_USE_STD_VARIANT == 0 || \
+    (ABSL_OPTION_USE_STD_VARIANT == 2 && !defined(ABSL_HAVE_STD_VARIANT))
+#undef ABSL_USES_STD_VARIANT
+#elif ABSL_OPTION_USE_STD_VARIANT == 1 || \
+    (ABSL_OPTION_USE_STD_VARIANT == 2 && defined(ABSL_HAVE_STD_VARIANT))
+#define ABSL_USES_STD_VARIANT 1
+#else
+#error options.h is misconfigured.
+#endif
+
+// ABSL_USES_STD_STRING_VIEW
+//
+// Indicates whether absl::string_view is an alias for std::string_view.
+#if !defined(ABSL_OPTION_USE_STD_STRING_VIEW)
+#error options.h is misconfigured.
+#elif ABSL_OPTION_USE_STD_STRING_VIEW == 0 || \
+    (ABSL_OPTION_USE_STD_STRING_VIEW == 2 &&  \
+     !defined(ABSL_HAVE_STD_STRING_VIEW))
+#undef ABSL_USES_STD_STRING_VIEW
+#elif ABSL_OPTION_USE_STD_STRING_VIEW == 1 || \
+    (ABSL_OPTION_USE_STD_STRING_VIEW == 2 &&  \
+     defined(ABSL_HAVE_STD_STRING_VIEW))
+#define ABSL_USES_STD_STRING_VIEW 1
+#else
+#error options.h is misconfigured.
+#endif
+
+// In debug mode, MSVC 2017's std::variant throws a EXCEPTION_ACCESS_VIOLATION
+// SEH exception from emplace for variant<SomeStruct> when constructing the
+// struct can throw. This defeats some of variant_test and
+// variant_exception_safety_test.
+#if defined(_MSC_VER) && _MSC_VER >= 1700 && defined(_DEBUG)
+#define ABSL_INTERNAL_MSVC_2017_DBG_MODE
+#endif
+
+// ABSL_INTERNAL_MANGLED_NS
+// ABSL_INTERNAL_MANGLED_BACKREFERENCE
+//
+// Internal macros for building up mangled names in our internal fork of CCTZ.
+// This implementation detail is only needed and provided for the MSVC build.
+//
+// These macros both expand to string literals.  ABSL_INTERNAL_MANGLED_NS is
+// the mangled spelling of the `absl` namespace, and
+// ABSL_INTERNAL_MANGLED_BACKREFERENCE is a back-reference integer representing
+// the proper count to skip past the CCTZ fork namespace names.  (This number
+// is one larger when there is an inline namespace name to skip.)
+#if defined(_MSC_VER)
+#if ABSL_OPTION_USE_INLINE_NAMESPACE == 0
+#define ABSL_INTERNAL_MANGLED_NS "absl"
+#define ABSL_INTERNAL_MANGLED_BACKREFERENCE "5"
+#else
+#define ABSL_INTERNAL_MANGLED_NS \
+  ABSL_INTERNAL_TOKEN_STR(ABSL_OPTION_INLINE_NAMESPACE_NAME) "@absl"
+#define ABSL_INTERNAL_MANGLED_BACKREFERENCE "6"
+#endif
+#endif
+
+#undef ABSL_INTERNAL_HAS_KEYWORD
+
+// ABSL_DLL
+//
+// When building Abseil as a DLL, this macro expands to `__declspec(dllexport)`
+// so we can annotate symbols appropriately as being exported. When used in
+// headers consuming a DLL, this macro expands to `__declspec(dllimport)` so
+// that consumers know the symbol is defined inside the DLL. In all other cases,
+// the macro expands to nothing.
+#if defined(_MSC_VER)
+#if defined(ABSL_BUILD_DLL)
+#define ABSL_DLL __declspec(dllexport)
+#elif defined(ABSL_CONSUME_DLL)
+#define ABSL_DLL __declspec(dllimport)
+#else
+#define ABSL_DLL
+#endif
+#else
+#define ABSL_DLL
+#endif  // defined(_MSC_VER)
+
+// ABSL_HAVE_MEMORY_SANITIZER
+//
+// MemorySanitizer (MSan) is a detector of uninitialized reads. It consists of
+// a compiler instrumentation module and a run-time library.
+#ifdef ABSL_HAVE_MEMORY_SANITIZER
+#error "ABSL_HAVE_MEMORY_SANITIZER cannot be directly set."
+#elif defined(MEMORY_SANITIZER)
+// The MEMORY_SANITIZER macro is deprecated but we will continue to honor it
+// for now.
+#define ABSL_HAVE_MEMORY_SANITIZER 1
+#elif defined(__SANITIZE_MEMORY__)
+#define ABSL_HAVE_MEMORY_SANITIZER 1
+#elif !defined(__native_client__) && ABSL_HAVE_FEATURE(memory_sanitizer)
+#define ABSL_HAVE_MEMORY_SANITIZER 1
+#endif
+
+// ABSL_HAVE_THREAD_SANITIZER
+//
+// ThreadSanitizer (TSan) is a fast data race detector.
+#ifdef ABSL_HAVE_THREAD_SANITIZER
+#error "ABSL_HAVE_THREAD_SANITIZER cannot be directly set."
+#elif defined(THREAD_SANITIZER)
+// The THREAD_SANITIZER macro is deprecated but we will continue to honor it
+// for now.
+#define ABSL_HAVE_THREAD_SANITIZER 1
+#elif defined(__SANITIZE_THREAD__)
+#define ABSL_HAVE_THREAD_SANITIZER 1
+#elif ABSL_HAVE_FEATURE(thread_sanitizer)
+#define ABSL_HAVE_THREAD_SANITIZER 1
+#endif
+
+// ABSL_HAVE_ADDRESS_SANITIZER
+//
+// AddressSanitizer (ASan) is a fast memory error detector.
+#ifdef ABSL_HAVE_ADDRESS_SANITIZER
+#error "ABSL_HAVE_ADDRESS_SANITIZER cannot be directly set."
+#elif defined(ADDRESS_SANITIZER)
+// The ADDRESS_SANITIZER macro is deprecated but we will continue to honor it
+// for now.
+#define ABSL_HAVE_ADDRESS_SANITIZER 1
+#elif defined(__SANITIZE_ADDRESS__)
+#define ABSL_HAVE_ADDRESS_SANITIZER 1
+#elif ABSL_HAVE_FEATURE(address_sanitizer)
+#define ABSL_HAVE_ADDRESS_SANITIZER 1
+#endif
+
+// ABSL_HAVE_CLASS_TEMPLATE_ARGUMENT_DEDUCTION
+//
+// Class template argument deduction is a language feature added in C++17.
+#ifdef ABSL_HAVE_CLASS_TEMPLATE_ARGUMENT_DEDUCTION
+#error "ABSL_HAVE_CLASS_TEMPLATE_ARGUMENT_DEDUCTION cannot be directly set."
+#elif defined(__cpp_deduction_guides)
+#define ABSL_HAVE_CLASS_TEMPLATE_ARGUMENT_DEDUCTION 1
+#endif
+
+#endif  // ABSL_BASE_CONFIG_H_
diff --git a/src/absl/base/const_init.h b/src/absl/base/const_init.h
new file mode 100644 (file)
index 0000000..16520b6
--- /dev/null
@@ -0,0 +1,76 @@
+// Copyright 2017 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// -----------------------------------------------------------------------------
+// kConstInit
+// -----------------------------------------------------------------------------
+//
+// A constructor tag used to mark an object as safe for use as a global
+// variable, avoiding the usual lifetime issues that can affect globals.
+
+#ifndef ABSL_BASE_CONST_INIT_H_
+#define ABSL_BASE_CONST_INIT_H_
+
+#include "absl/base/config.h"
+
+// In general, objects with static storage duration (such as global variables)
+// can trigger tricky object lifetime situations.  Attempting to access them
+// from the constructors or destructors of other global objects can result in
+// undefined behavior, unless their constructors and destructors are designed
+// with this issue in mind.
+//
+// The normal way to deal with this issue in C++11 is to use constant
+// initialization and trivial destructors.
+//
+// Constant initialization is guaranteed to occur before any other code
+// executes.  Constructors that are declared 'constexpr' are eligible for
+// constant initialization.  You can annotate a variable declaration with the
+// ABSL_CONST_INIT macro to express this intent.  For compilers that support
+// it, this annotation will cause a compilation error for declarations that
+// aren't subject to constant initialization (perhaps because a runtime value
+// was passed as a constructor argument).
+//
+// On program shutdown, lifetime issues can be avoided on global objects by
+// ensuring that they contain  trivial destructors.  A class has a trivial
+// destructor unless it has a user-defined destructor, a virtual method or base
+// class, or a data member or base class with a non-trivial destructor of its
+// own.  Objects with static storage duration and a trivial destructor are not
+// cleaned up on program shutdown, and are thus safe to access from other code
+// running during shutdown.
+//
+// For a few core Abseil classes, we make a best effort to allow for safe global
+// instances, even though these classes have non-trivial destructors.  These
+// objects can be created with the absl::kConstInit tag.  For example:
+//   ABSL_CONST_INIT absl::Mutex global_mutex(absl::kConstInit);
+//
+// The line above declares a global variable of type absl::Mutex which can be
+// accessed at any point during startup or shutdown.  global_mutex's destructor
+// will still run, but will not invalidate the object.  Note that C++ specifies
+// that accessing an object after its destructor has run results in undefined
+// behavior, but this pattern works on the toolchains we support.
+//
+// The absl::kConstInit tag should only be used to define objects with static
+// or thread_local storage duration.
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+
+enum ConstInitType {
+  kConstInit,
+};
+
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#endif  // ABSL_BASE_CONST_INIT_H_
diff --git a/src/absl/base/dynamic_annotations.h b/src/absl/base/dynamic_annotations.h
new file mode 100644 (file)
index 0000000..880cbf6
--- /dev/null
@@ -0,0 +1,496 @@
+// Copyright 2017 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// This file defines dynamic annotations for use with dynamic analysis tool
+// such as valgrind, PIN, etc.
+//
+// Dynamic annotation is a source code annotation that affects the generated
+// code (that is, the annotation is not a comment). Each such annotation is
+// attached to a particular instruction and/or to a particular object (address)
+// in the program.
+//
+// The annotations that should be used by users are macros in all upper-case
+// (e.g., ABSL_ANNOTATE_THREAD_NAME).
+//
+// Actual implementation of these macros may differ depending on the dynamic
+// analysis tool being used.
+//
+// This file supports the following configurations:
+// - Dynamic Annotations enabled (with static thread-safety warnings disabled).
+//   In this case, macros expand to functions implemented by Thread Sanitizer,
+//   when building with TSan. When not provided an external implementation,
+//   dynamic_annotations.cc provides no-op implementations.
+//
+// - Static Clang thread-safety warnings enabled.
+//   When building with a Clang compiler that supports thread-safety warnings,
+//   a subset of annotations can be statically-checked at compile-time. We
+//   expand these macros to static-inline functions that can be analyzed for
+//   thread-safety, but afterwards elided when building the final binary.
+//
+// - All annotations are disabled.
+//   If neither Dynamic Annotations nor Clang thread-safety warnings are
+//   enabled, then all annotation-macros expand to empty.
+
+#ifndef ABSL_BASE_DYNAMIC_ANNOTATIONS_H_
+#define ABSL_BASE_DYNAMIC_ANNOTATIONS_H_
+
+#include <stddef.h>
+
+#include "absl/base/attributes.h"
+#include "absl/base/config.h"
+#ifdef __cplusplus
+#include "absl/base/macros.h"
+#endif
+
+// TODO(rogeeff): Remove after the backward compatibility period.
+#include "absl/base/internal/dynamic_annotations.h"  // IWYU pragma: export
+
+// -------------------------------------------------------------------------
+// Decide which features are enabled.
+
+#ifdef ABSL_HAVE_THREAD_SANITIZER
+
+#define ABSL_INTERNAL_RACE_ANNOTATIONS_ENABLED 1
+#define ABSL_INTERNAL_READS_ANNOTATIONS_ENABLED 1
+#define ABSL_INTERNAL_WRITES_ANNOTATIONS_ENABLED 1
+#define ABSL_INTERNAL_ANNOTALYSIS_ENABLED 0
+#define ABSL_INTERNAL_READS_WRITES_ANNOTATIONS_ENABLED 1
+
+#else
+
+#define ABSL_INTERNAL_RACE_ANNOTATIONS_ENABLED 0
+#define ABSL_INTERNAL_READS_ANNOTATIONS_ENABLED 0
+#define ABSL_INTERNAL_WRITES_ANNOTATIONS_ENABLED 0
+
+// Clang provides limited support for static thread-safety analysis through a
+// feature called Annotalysis. We configure macro-definitions according to
+// whether Annotalysis support is available. When running in opt-mode, GCC
+// will issue a warning, if these attributes are compiled. Only include them
+// when compiling using Clang.
+
+#if defined(__clang__)
+#define ABSL_INTERNAL_ANNOTALYSIS_ENABLED 1
+#if !defined(SWIG)
+#define ABSL_INTERNAL_IGNORE_READS_ATTRIBUTE_ENABLED 1
+#endif
+#else
+#define ABSL_INTERNAL_ANNOTALYSIS_ENABLED 0
+#endif
+
+// Read/write annotations are enabled in Annotalysis mode; disabled otherwise.
+#define ABSL_INTERNAL_READS_WRITES_ANNOTATIONS_ENABLED \
+  ABSL_INTERNAL_ANNOTALYSIS_ENABLED
+
+#endif  // ABSL_HAVE_THREAD_SANITIZER
+
+#ifdef __cplusplus
+#define ABSL_INTERNAL_BEGIN_EXTERN_C extern "C" {
+#define ABSL_INTERNAL_END_EXTERN_C }  // extern "C"
+#define ABSL_INTERNAL_GLOBAL_SCOPED(F) ::F
+#define ABSL_INTERNAL_STATIC_INLINE inline
+#else
+#define ABSL_INTERNAL_BEGIN_EXTERN_C  // empty
+#define ABSL_INTERNAL_END_EXTERN_C    // empty
+#define ABSL_INTERNAL_GLOBAL_SCOPED(F) F
+#define ABSL_INTERNAL_STATIC_INLINE static inline
+#endif
+
+// -------------------------------------------------------------------------
+// Define race annotations.
+
+#if ABSL_INTERNAL_RACE_ANNOTATIONS_ENABLED == 1
+// Some of the symbols used in this section (e.g. AnnotateBenignRaceSized) are
+// defined by the compiler-based santizer implementation, not by the Abseil
+// library. Therefore they do not use ABSL_INTERNAL_C_SYMBOL.
+
+// -------------------------------------------------------------
+// Annotations that suppress errors. It is usually better to express the
+// program's synchronization using the other annotations, but these can be used
+// when all else fails.
+
+// Report that we may have a benign race at `pointer`, with size
+// "sizeof(*(pointer))". `pointer` must be a non-void* pointer. Insert at the
+// point where `pointer` has been allocated, preferably close to the point
+// where the race happens. See also ABSL_ANNOTATE_BENIGN_RACE_STATIC.
+#define ABSL_ANNOTATE_BENIGN_RACE(pointer, description) \
+  ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateBenignRaceSized)  \
+  (__FILE__, __LINE__, pointer, sizeof(*(pointer)), description)
+
+// Same as ABSL_ANNOTATE_BENIGN_RACE(`address`, `description`), but applies to
+// the memory range [`address`, `address`+`size`).
+#define ABSL_ANNOTATE_BENIGN_RACE_SIZED(address, size, description) \
+  ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateBenignRaceSized)              \
+  (__FILE__, __LINE__, address, size, description)
+
+// Enable (`enable`!=0) or disable (`enable`==0) race detection for all threads.
+// This annotation could be useful if you want to skip expensive race analysis
+// during some period of program execution, e.g. during initialization.
+#define ABSL_ANNOTATE_ENABLE_RACE_DETECTION(enable)        \
+  ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateEnableRaceDetection) \
+  (__FILE__, __LINE__, enable)
+
+// -------------------------------------------------------------
+// Annotations useful for debugging.
+
+// Report the current thread `name` to a race detector.
+#define ABSL_ANNOTATE_THREAD_NAME(name) \
+  ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateThreadName)(__FILE__, __LINE__, name)
+
+// -------------------------------------------------------------
+// Annotations useful when implementing locks. They are not normally needed by
+// modules that merely use locks. The `lock` argument is a pointer to the lock
+// object.
+
+// Report that a lock has been created at address `lock`.
+#define ABSL_ANNOTATE_RWLOCK_CREATE(lock) \
+  ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateRWLockCreate)(__FILE__, __LINE__, lock)
+
+// Report that a linker initialized lock has been created at address `lock`.
+#ifdef ABSL_HAVE_THREAD_SANITIZER
+#define ABSL_ANNOTATE_RWLOCK_CREATE_STATIC(lock)          \
+  ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateRWLockCreateStatic) \
+  (__FILE__, __LINE__, lock)
+#else
+#define ABSL_ANNOTATE_RWLOCK_CREATE_STATIC(lock) \
+  ABSL_ANNOTATE_RWLOCK_CREATE(lock)
+#endif
+
+// Report that the lock at address `lock` is about to be destroyed.
+#define ABSL_ANNOTATE_RWLOCK_DESTROY(lock) \
+  ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateRWLockDestroy)(__FILE__, __LINE__, lock)
+
+// Report that the lock at address `lock` has been acquired.
+// `is_w`=1 for writer lock, `is_w`=0 for reader lock.
+#define ABSL_ANNOTATE_RWLOCK_ACQUIRED(lock, is_w)     \
+  ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateRWLockAcquired) \
+  (__FILE__, __LINE__, lock, is_w)
+
+// Report that the lock at address `lock` is about to be released.
+// `is_w`=1 for writer lock, `is_w`=0 for reader lock.
+#define ABSL_ANNOTATE_RWLOCK_RELEASED(lock, is_w)     \
+  ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateRWLockReleased) \
+  (__FILE__, __LINE__, lock, is_w)
+
+// Apply ABSL_ANNOTATE_BENIGN_RACE_SIZED to a static variable `static_var`.
+#define ABSL_ANNOTATE_BENIGN_RACE_STATIC(static_var, description)      \
+  namespace {                                                          \
+  class static_var##_annotator {                                       \
+   public:                                                             \
+    static_var##_annotator() {                                         \
+      ABSL_ANNOTATE_BENIGN_RACE_SIZED(&static_var, sizeof(static_var), \
+                                      #static_var ": " description);   \
+    }                                                                  \
+  };                                                                   \
+  static static_var##_annotator the##static_var##_annotator;           \
+  }  // namespace
+
+// Function prototypes of annotations provided by the compiler-based sanitizer
+// implementation.
+ABSL_INTERNAL_BEGIN_EXTERN_C
+void AnnotateRWLockCreate(const char* file, int line,
+                          const volatile void* lock);
+void AnnotateRWLockCreateStatic(const char* file, int line,
+                                const volatile void* lock);
+void AnnotateRWLockDestroy(const char* file, int line,
+                           const volatile void* lock);
+void AnnotateRWLockAcquired(const char* file, int line,
+                            const volatile void* lock, long is_w);  // NOLINT
+void AnnotateRWLockReleased(const char* file, int line,
+                            const volatile void* lock, long is_w);  // NOLINT
+void AnnotateBenignRace(const char* file, int line,
+                        const volatile void* address, const char* description);
+void AnnotateBenignRaceSized(const char* file, int line,
+                             const volatile void* address, size_t size,
+                             const char* description);
+void AnnotateThreadName(const char* file, int line, const char* name);
+void AnnotateEnableRaceDetection(const char* file, int line, int enable);
+ABSL_INTERNAL_END_EXTERN_C
+
+#else  // ABSL_INTERNAL_RACE_ANNOTATIONS_ENABLED == 0
+
+#define ABSL_ANNOTATE_RWLOCK_CREATE(lock)                            // empty
+#define ABSL_ANNOTATE_RWLOCK_CREATE_STATIC(lock)                     // empty
+#define ABSL_ANNOTATE_RWLOCK_DESTROY(lock)                           // empty
+#define ABSL_ANNOTATE_RWLOCK_ACQUIRED(lock, is_w)                    // empty
+#define ABSL_ANNOTATE_RWLOCK_RELEASED(lock, is_w)                    // empty
+#define ABSL_ANNOTATE_BENIGN_RACE(address, description)              // empty
+#define ABSL_ANNOTATE_BENIGN_RACE_SIZED(address, size, description)  // empty
+#define ABSL_ANNOTATE_THREAD_NAME(name)                              // empty
+#define ABSL_ANNOTATE_ENABLE_RACE_DETECTION(enable)                  // empty
+#define ABSL_ANNOTATE_BENIGN_RACE_STATIC(static_var, description)    // empty
+
+#endif  // ABSL_INTERNAL_RACE_ANNOTATIONS_ENABLED
+
+// -------------------------------------------------------------------------
+// Define memory annotations.
+
+#ifdef ABSL_HAVE_MEMORY_SANITIZER
+
+#include <sanitizer/msan_interface.h>
+
+#define ABSL_ANNOTATE_MEMORY_IS_INITIALIZED(address, size) \
+  __msan_unpoison(address, size)
+
+#define ABSL_ANNOTATE_MEMORY_IS_UNINITIALIZED(address, size) \
+  __msan_allocated_memory(address, size)
+
+#else  // !defined(ABSL_HAVE_MEMORY_SANITIZER)
+
+// TODO(rogeeff): remove this branch
+#ifdef ABSL_HAVE_THREAD_SANITIZER
+#define ABSL_ANNOTATE_MEMORY_IS_INITIALIZED(address, size) \
+  do {                                                     \
+    (void)(address);                                       \
+    (void)(size);                                          \
+  } while (0)
+#define ABSL_ANNOTATE_MEMORY_IS_UNINITIALIZED(address, size) \
+  do {                                                       \
+    (void)(address);                                         \
+    (void)(size);                                            \
+  } while (0)
+#else
+
+#define ABSL_ANNOTATE_MEMORY_IS_INITIALIZED(address, size)    // empty
+#define ABSL_ANNOTATE_MEMORY_IS_UNINITIALIZED(address, size)  // empty
+
+#endif
+
+#endif  // ABSL_HAVE_MEMORY_SANITIZER
+
+// -------------------------------------------------------------------------
+// Define IGNORE_READS_BEGIN/_END attributes.
+
+#if defined(ABSL_INTERNAL_IGNORE_READS_ATTRIBUTE_ENABLED)
+
+#define ABSL_INTERNAL_IGNORE_READS_BEGIN_ATTRIBUTE \
+  __attribute((exclusive_lock_function("*")))
+#define ABSL_INTERNAL_IGNORE_READS_END_ATTRIBUTE \
+  __attribute((unlock_function("*")))
+
+#else  // !defined(ABSL_INTERNAL_IGNORE_READS_ATTRIBUTE_ENABLED)
+
+#define ABSL_INTERNAL_IGNORE_READS_BEGIN_ATTRIBUTE  // empty
+#define ABSL_INTERNAL_IGNORE_READS_END_ATTRIBUTE    // empty
+
+#endif  // defined(ABSL_INTERNAL_IGNORE_READS_ATTRIBUTE_ENABLED)
+
+// -------------------------------------------------------------------------
+// Define IGNORE_READS_BEGIN/_END annotations.
+
+#if ABSL_INTERNAL_READS_ANNOTATIONS_ENABLED == 1
+// Some of the symbols used in this section (e.g. AnnotateIgnoreReadsBegin) are
+// defined by the compiler-based implementation, not by the Abseil
+// library. Therefore they do not use ABSL_INTERNAL_C_SYMBOL.
+
+// Request the analysis tool to ignore all reads in the current thread until
+// ABSL_ANNOTATE_IGNORE_READS_END is called. Useful to ignore intentional racey
+// reads, while still checking other reads and all writes.
+// See also ABSL_ANNOTATE_UNPROTECTED_READ.
+#define ABSL_ANNOTATE_IGNORE_READS_BEGIN()              \
+  ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateIgnoreReadsBegin) \
+  (__FILE__, __LINE__)
+
+// Stop ignoring reads.
+#define ABSL_ANNOTATE_IGNORE_READS_END()              \
+  ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateIgnoreReadsEnd) \
+  (__FILE__, __LINE__)
+
+// Function prototypes of annotations provided by the compiler-based sanitizer
+// implementation.
+ABSL_INTERNAL_BEGIN_EXTERN_C
+void AnnotateIgnoreReadsBegin(const char* file, int line)
+    ABSL_INTERNAL_IGNORE_READS_BEGIN_ATTRIBUTE;
+void AnnotateIgnoreReadsEnd(const char* file,
+                            int line) ABSL_INTERNAL_IGNORE_READS_END_ATTRIBUTE;
+ABSL_INTERNAL_END_EXTERN_C
+
+#elif defined(ABSL_INTERNAL_ANNOTALYSIS_ENABLED)
+
+// When Annotalysis is enabled without Dynamic Annotations, the use of
+// static-inline functions allows the annotations to be read at compile-time,
+// while still letting the compiler elide the functions from the final build.
+//
+// TODO(delesley) -- The exclusive lock here ignores writes as well, but
+// allows IGNORE_READS_AND_WRITES to work properly.
+
+#define ABSL_ANNOTATE_IGNORE_READS_BEGIN()                          \
+  ABSL_INTERNAL_GLOBAL_SCOPED(                                      \
+      ABSL_INTERNAL_C_SYMBOL(AbslInternalAnnotateIgnoreReadsBegin)) \
+  ()
+
+#define ABSL_ANNOTATE_IGNORE_READS_END()                          \
+  ABSL_INTERNAL_GLOBAL_SCOPED(                                    \
+      ABSL_INTERNAL_C_SYMBOL(AbslInternalAnnotateIgnoreReadsEnd)) \
+  ()
+
+ABSL_INTERNAL_STATIC_INLINE void ABSL_INTERNAL_C_SYMBOL(
+    AbslInternalAnnotateIgnoreReadsBegin)()
+    ABSL_INTERNAL_IGNORE_READS_BEGIN_ATTRIBUTE {}
+
+ABSL_INTERNAL_STATIC_INLINE void ABSL_INTERNAL_C_SYMBOL(
+    AbslInternalAnnotateIgnoreReadsEnd)()
+    ABSL_INTERNAL_IGNORE_READS_END_ATTRIBUTE {}
+
+#else
+
+#define ABSL_ANNOTATE_IGNORE_READS_BEGIN()  // empty
+#define ABSL_ANNOTATE_IGNORE_READS_END()    // empty
+
+#endif
+
+// -------------------------------------------------------------------------
+// Define IGNORE_WRITES_BEGIN/_END annotations.
+
+#if ABSL_INTERNAL_WRITES_ANNOTATIONS_ENABLED == 1
+
+// Similar to ABSL_ANNOTATE_IGNORE_READS_BEGIN, but ignore writes instead.
+#define ABSL_ANNOTATE_IGNORE_WRITES_BEGIN() \
+  ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateIgnoreWritesBegin)(__FILE__, __LINE__)
+
+// Stop ignoring writes.
+#define ABSL_ANNOTATE_IGNORE_WRITES_END() \
+  ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateIgnoreWritesEnd)(__FILE__, __LINE__)
+
+// Function prototypes of annotations provided by the compiler-based sanitizer
+// implementation.
+ABSL_INTERNAL_BEGIN_EXTERN_C
+void AnnotateIgnoreWritesBegin(const char* file, int line);
+void AnnotateIgnoreWritesEnd(const char* file, int line);
+ABSL_INTERNAL_END_EXTERN_C
+
+#else
+
+#define ABSL_ANNOTATE_IGNORE_WRITES_BEGIN()  // empty
+#define ABSL_ANNOTATE_IGNORE_WRITES_END()    // empty
+
+#endif
+
+// -------------------------------------------------------------------------
+// Define the ABSL_ANNOTATE_IGNORE_READS_AND_WRITES_* annotations using the more
+// primitive annotations defined above.
+//
+//     Instead of doing
+//        ABSL_ANNOTATE_IGNORE_READS_BEGIN();
+//        ... = x;
+//        ABSL_ANNOTATE_IGNORE_READS_END();
+//     one can use
+//        ... = ABSL_ANNOTATE_UNPROTECTED_READ(x);
+
+#if defined(ABSL_INTERNAL_READS_WRITES_ANNOTATIONS_ENABLED)
+
+// Start ignoring all memory accesses (both reads and writes).
+#define ABSL_ANNOTATE_IGNORE_READS_AND_WRITES_BEGIN() \
+  do {                                                \
+    ABSL_ANNOTATE_IGNORE_READS_BEGIN();               \
+    ABSL_ANNOTATE_IGNORE_WRITES_BEGIN();              \
+  } while (0)
+
+// Stop ignoring both reads and writes.
+#define ABSL_ANNOTATE_IGNORE_READS_AND_WRITES_END() \
+  do {                                              \
+    ABSL_ANNOTATE_IGNORE_WRITES_END();              \
+    ABSL_ANNOTATE_IGNORE_READS_END();               \
+  } while (0)
+
+#ifdef __cplusplus
+// ABSL_ANNOTATE_UNPROTECTED_READ is the preferred way to annotate racey reads.
+#define ABSL_ANNOTATE_UNPROTECTED_READ(x) \
+  absl::base_internal::AnnotateUnprotectedRead(x)
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace base_internal {
+
+template <typename T>
+inline T AnnotateUnprotectedRead(const volatile T& x) {  // NOLINT
+  ABSL_ANNOTATE_IGNORE_READS_BEGIN();
+  T res = x;
+  ABSL_ANNOTATE_IGNORE_READS_END();
+  return res;
+}
+
+}  // namespace base_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
+#endif
+
+#else
+
+#define ABSL_ANNOTATE_IGNORE_READS_AND_WRITES_BEGIN()  // empty
+#define ABSL_ANNOTATE_IGNORE_READS_AND_WRITES_END()    // empty
+#define ABSL_ANNOTATE_UNPROTECTED_READ(x) (x)
+
+#endif
+
+#ifdef __cplusplus
+#ifdef ABSL_HAVE_THREAD_SANITIZER
+ABSL_INTERNAL_BEGIN_EXTERN_C
+int RunningOnValgrind();
+double ValgrindSlowdown();
+ABSL_INTERNAL_END_EXTERN_C
+#else
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace base_internal {
+ABSL_DEPRECATED(
+    "Don't use this interface. It is misleading and is being deleted.")
+ABSL_ATTRIBUTE_ALWAYS_INLINE inline int RunningOnValgrind() { return 0; }
+ABSL_DEPRECATED(
+    "Don't use this interface. It is misleading and is being deleted.")
+ABSL_ATTRIBUTE_ALWAYS_INLINE inline double ValgrindSlowdown() { return 1.0; }
+}  // namespace base_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+using absl::base_internal::RunningOnValgrind;
+using absl::base_internal::ValgrindSlowdown;
+#endif
+#endif
+
+// -------------------------------------------------------------------------
+// Address sanitizer annotations
+
+#ifdef ABSL_HAVE_ADDRESS_SANITIZER
+// Describe the current state of a contiguous container such as e.g.
+// std::vector or std::string. For more details see
+// sanitizer/common_interface_defs.h, which is provided by the compiler.
+#include <sanitizer/common_interface_defs.h>
+
+#define ABSL_ANNOTATE_CONTIGUOUS_CONTAINER(beg, end, old_mid, new_mid) \
+  __sanitizer_annotate_contiguous_container(beg, end, old_mid, new_mid)
+#define ABSL_ADDRESS_SANITIZER_REDZONE(name) \
+  struct {                                   \
+    char x[8] __attribute__((aligned(8)));   \
+  } name
+
+#else
+
+#define ABSL_ANNOTATE_CONTIGUOUS_CONTAINER(beg, end, old_mid, new_mid)  // empty
+#define ABSL_ADDRESS_SANITIZER_REDZONE(name) static_assert(true, "")
+
+#endif  // ABSL_HAVE_ADDRESS_SANITIZER
+
+// -------------------------------------------------------------------------
+// Undefine the macros intended only for this file.
+
+#undef ABSL_INTERNAL_RACE_ANNOTATIONS_ENABLED
+#undef ABSL_INTERNAL_READS_ANNOTATIONS_ENABLED
+#undef ABSL_INTERNAL_WRITES_ANNOTATIONS_ENABLED
+#undef ABSL_INTERNAL_ANNOTALYSIS_ENABLED
+#undef ABSL_INTERNAL_READS_WRITES_ANNOTATIONS_ENABLED
+#undef ABSL_INTERNAL_BEGIN_EXTERN_C
+#undef ABSL_INTERNAL_END_EXTERN_C
+#undef ABSL_INTERNAL_STATIC_INLINE
+
+#endif  // ABSL_BASE_DYNAMIC_ANNOTATIONS_H_
diff --git a/src/absl/base/internal/atomic_hook.h b/src/absl/base/internal/atomic_hook.h
new file mode 100644 (file)
index 0000000..ae21cd7
--- /dev/null
@@ -0,0 +1,200 @@
+// Copyright 2017 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef ABSL_BASE_INTERNAL_ATOMIC_HOOK_H_
+#define ABSL_BASE_INTERNAL_ATOMIC_HOOK_H_
+
+#include <atomic>
+#include <cassert>
+#include <cstdint>
+#include <utility>
+
+#include "absl/base/attributes.h"
+#include "absl/base/config.h"
+
+#if defined(_MSC_VER) && !defined(__clang__)
+#define ABSL_HAVE_WORKING_CONSTEXPR_STATIC_INIT 0
+#else
+#define ABSL_HAVE_WORKING_CONSTEXPR_STATIC_INIT 1
+#endif
+
+#if defined(_MSC_VER)
+#define ABSL_HAVE_WORKING_ATOMIC_POINTER 0
+#else
+#define ABSL_HAVE_WORKING_ATOMIC_POINTER 1
+#endif
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace base_internal {
+
+template <typename T>
+class AtomicHook;
+
+// To workaround AtomicHook not being constant-initializable on some platforms,
+// prefer to annotate instances with `ABSL_INTERNAL_ATOMIC_HOOK_ATTRIBUTES`
+// instead of `ABSL_CONST_INIT`.
+#if ABSL_HAVE_WORKING_CONSTEXPR_STATIC_INIT
+#define ABSL_INTERNAL_ATOMIC_HOOK_ATTRIBUTES ABSL_CONST_INIT
+#else
+#define ABSL_INTERNAL_ATOMIC_HOOK_ATTRIBUTES
+#endif
+
+// `AtomicHook` is a helper class, templatized on a raw function pointer type,
+// for implementing Abseil customization hooks.  It is a callable object that
+// dispatches to the registered hook.  Objects of type `AtomicHook` must have
+// static or thread storage duration.
+//
+// A default constructed object performs a no-op (and returns a default
+// constructed object) if no hook has been registered.
+//
+// Hooks can be pre-registered via constant initialization, for example:
+//
+// ABSL_INTERNAL_ATOMIC_HOOK_ATTRIBUTES static AtomicHook<void(*)()>
+//     my_hook(DefaultAction);
+//
+// and then changed at runtime via a call to `Store()`.
+//
+// Reads and writes guarantee memory_order_acquire/memory_order_release
+// semantics.
+template <typename ReturnType, typename... Args>
+class AtomicHook<ReturnType (*)(Args...)> {
+ public:
+  using FnPtr = ReturnType (*)(Args...);
+
+  // Constructs an object that by default performs a no-op (and
+  // returns a default constructed object) when no hook as been registered.
+  constexpr AtomicHook() : AtomicHook(DummyFunction) {}
+
+  // Constructs an object that by default dispatches to/returns the
+  // pre-registered default_fn when no hook has been registered at runtime.
+#if ABSL_HAVE_WORKING_ATOMIC_POINTER && ABSL_HAVE_WORKING_CONSTEXPR_STATIC_INIT
+  explicit constexpr AtomicHook(FnPtr default_fn)
+      : hook_(default_fn), default_fn_(default_fn) {}
+#elif ABSL_HAVE_WORKING_CONSTEXPR_STATIC_INIT
+  explicit constexpr AtomicHook(FnPtr default_fn)
+      : hook_(kUninitialized), default_fn_(default_fn) {}
+#else
+  // As of January 2020, on all known versions of MSVC this constructor runs in
+  // the global constructor sequence.  If `Store()` is called by a dynamic
+  // initializer, we want to preserve the value, even if this constructor runs
+  // after the call to `Store()`.  If not, `hook_` will be
+  // zero-initialized by the linker and we have no need to set it.
+  // https://developercommunity.visualstudio.com/content/problem/336946/class-with-constexpr-constructor-not-using-static.html
+  explicit constexpr AtomicHook(FnPtr default_fn)
+      : /* hook_(deliberately omitted), */ default_fn_(default_fn) {
+    static_assert(kUninitialized == 0, "here we rely on zero-initialization");
+  }
+#endif
+
+  // Stores the provided function pointer as the value for this hook.
+  //
+  // This is intended to be called once.  Multiple calls are legal only if the
+  // same function pointer is provided for each call.  The store is implemented
+  // as a memory_order_release operation, and read accesses are implemented as
+  // memory_order_acquire.
+  void Store(FnPtr fn) {
+    bool success = DoStore(fn);
+    static_cast<void>(success);
+    assert(success);
+  }
+
+  // Invokes the registered callback.  If no callback has yet been registered, a
+  // default-constructed object of the appropriate type is returned instead.
+  template <typename... CallArgs>
+  ReturnType operator()(CallArgs&&... args) const {
+    return DoLoad()(std::forward<CallArgs>(args)...);
+  }
+
+  // Returns the registered callback, or nullptr if none has been registered.
+  // Useful if client code needs to conditionalize behavior based on whether a
+  // callback was registered.
+  //
+  // Note that atomic_hook.Load()() and atomic_hook() have different semantics:
+  // operator()() will perform a no-op if no callback was registered, while
+  // Load()() will dereference a null function pointer.  Prefer operator()() to
+  // Load()() unless you must conditionalize behavior on whether a hook was
+  // registered.
+  FnPtr Load() const {
+    FnPtr ptr = DoLoad();
+    return (ptr == DummyFunction) ? nullptr : ptr;
+  }
+
+ private:
+  static ReturnType DummyFunction(Args...) {
+    return ReturnType();
+  }
+
+  // Current versions of MSVC (as of September 2017) have a broken
+  // implementation of std::atomic<T*>:  Its constructor attempts to do the
+  // equivalent of a reinterpret_cast in a constexpr context, which is not
+  // allowed.
+  //
+  // This causes an issue when building with LLVM under Windows.  To avoid this,
+  // we use a less-efficient, intptr_t-based implementation on Windows.
+#if ABSL_HAVE_WORKING_ATOMIC_POINTER
+  // Return the stored value, or DummyFunction if no value has been stored.
+  FnPtr DoLoad() const { return hook_.load(std::memory_order_acquire); }
+
+  // Store the given value.  Returns false if a different value was already
+  // stored to this object.
+  bool DoStore(FnPtr fn) {
+    assert(fn);
+    FnPtr expected = default_fn_;
+    const bool store_succeeded = hook_.compare_exchange_strong(
+        expected, fn, std::memory_order_acq_rel, std::memory_order_acquire);
+    const bool same_value_already_stored = (expected == fn);
+    return store_succeeded || same_value_already_stored;
+  }
+
+  std::atomic<FnPtr> hook_;
+#else  // !ABSL_HAVE_WORKING_ATOMIC_POINTER
+  // Use a sentinel value unlikely to be the address of an actual function.
+  static constexpr intptr_t kUninitialized = 0;
+
+  static_assert(sizeof(intptr_t) >= sizeof(FnPtr),
+                "intptr_t can't contain a function pointer");
+
+  FnPtr DoLoad() const {
+    const intptr_t value = hook_.load(std::memory_order_acquire);
+    if (value == kUninitialized) {
+      return default_fn_;
+    }
+    return reinterpret_cast<FnPtr>(value);
+  }
+
+  bool DoStore(FnPtr fn) {
+    assert(fn);
+    const auto value = reinterpret_cast<intptr_t>(fn);
+    intptr_t expected = kUninitialized;
+    const bool store_succeeded = hook_.compare_exchange_strong(
+        expected, value, std::memory_order_acq_rel, std::memory_order_acquire);
+    const bool same_value_already_stored = (expected == value);
+    return store_succeeded || same_value_already_stored;
+  }
+
+  std::atomic<intptr_t> hook_;
+#endif
+
+  const FnPtr default_fn_;
+};
+
+#undef ABSL_HAVE_WORKING_ATOMIC_POINTER
+#undef ABSL_HAVE_WORKING_CONSTEXPR_STATIC_INIT
+
+}  // namespace base_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#endif  // ABSL_BASE_INTERNAL_ATOMIC_HOOK_H_
diff --git a/src/absl/base/internal/cycleclock.cc b/src/absl/base/internal/cycleclock.cc
new file mode 100644 (file)
index 0000000..0e65005
--- /dev/null
@@ -0,0 +1,107 @@
+// Copyright 2017 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// The implementation of CycleClock::Frequency.
+//
+// NOTE: only i386 and x86_64 have been well tested.
+// PPC, sparc, alpha, and ia64 are based on
+//    http://peter.kuscsik.com/wordpress/?p=14
+// with modifications by m3b.  See also
+//    https://setisvn.ssl.berkeley.edu/svn/lib/fftw-3.0.1/kernel/cycle.h
+
+#include "absl/base/internal/cycleclock.h"
+
+#include <atomic>
+#include <chrono>  // NOLINT(build/c++11)
+
+#include "absl/base/internal/unscaledcycleclock.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace base_internal {
+
+#if ABSL_USE_UNSCALED_CYCLECLOCK
+
+namespace {
+
+#ifdef NDEBUG
+#ifdef ABSL_INTERNAL_UNSCALED_CYCLECLOCK_FREQUENCY_IS_CPU_FREQUENCY
+// Not debug mode and the UnscaledCycleClock frequency is the CPU
+// frequency.  Scale the CycleClock to prevent overflow if someone
+// tries to represent the time as cycles since the Unix epoch.
+static constexpr int32_t kShift = 1;
+#else
+// Not debug mode and the UnscaledCycleClock isn't operating at the
+// raw CPU frequency. There is no need to do any scaling, so don't
+// needlessly sacrifice precision.
+static constexpr int32_t kShift = 0;
+#endif
+#else
+// In debug mode use a different shift to discourage depending on a
+// particular shift value.
+static constexpr int32_t kShift = 2;
+#endif
+
+static constexpr double kFrequencyScale = 1.0 / (1 << kShift);
+static std::atomic<CycleClockSourceFunc> cycle_clock_source;
+
+CycleClockSourceFunc LoadCycleClockSource() {
+  // Optimize for the common case (no callback) by first doing a relaxed load;
+  // this is significantly faster on non-x86 platforms.
+  if (cycle_clock_source.load(std::memory_order_relaxed) == nullptr) {
+    return nullptr;
+  }
+  // This corresponds to the store(std::memory_order_release) in
+  // CycleClockSource::Register, and makes sure that any updates made prior to
+  // registering the callback are visible to this thread before the callback is
+  // invoked.
+  return cycle_clock_source.load(std::memory_order_acquire);
+}
+
+}  // namespace
+
+int64_t CycleClock::Now() {
+  auto fn = LoadCycleClockSource();
+  if (fn == nullptr) {
+    return base_internal::UnscaledCycleClock::Now() >> kShift;
+  }
+  return fn() >> kShift;
+}
+
+double CycleClock::Frequency() {
+  return kFrequencyScale * base_internal::UnscaledCycleClock::Frequency();
+}
+
+void CycleClockSource::Register(CycleClockSourceFunc source) {
+  // Corresponds to the load(std::memory_order_acquire) in LoadCycleClockSource.
+  cycle_clock_source.store(source, std::memory_order_release);
+}
+
+#else
+
+int64_t CycleClock::Now() {
+  return std::chrono::duration_cast<std::chrono::nanoseconds>(
+             std::chrono::steady_clock::now().time_since_epoch())
+      .count();
+}
+
+double CycleClock::Frequency() {
+  return 1e9;
+}
+
+#endif
+
+}  // namespace base_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
diff --git a/src/absl/base/internal/cycleclock.h b/src/absl/base/internal/cycleclock.h
new file mode 100644 (file)
index 0000000..a18b584
--- /dev/null
@@ -0,0 +1,94 @@
+//
+// Copyright 2017 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// -----------------------------------------------------------------------------
+// File: cycleclock.h
+// -----------------------------------------------------------------------------
+//
+// This header file defines a `CycleClock`, which yields the value and frequency
+// of a cycle counter that increments at a rate that is approximately constant.
+//
+// NOTE:
+//
+// The cycle counter frequency is not necessarily related to the core clock
+// frequency and should not be treated as such. That is, `CycleClock` cycles are
+// not necessarily "CPU cycles" and code should not rely on that behavior, even
+// if experimentally observed.
+//
+// An arbitrary offset may have been added to the counter at power on.
+//
+// On some platforms, the rate and offset of the counter may differ
+// slightly when read from different CPUs of a multiprocessor. Usually,
+// we try to ensure that the operating system adjusts values periodically
+// so that values agree approximately.   If you need stronger guarantees,
+// consider using alternate interfaces.
+//
+// The CPU is not required to maintain the ordering of a cycle counter read
+// with respect to surrounding instructions.
+
+#ifndef ABSL_BASE_INTERNAL_CYCLECLOCK_H_
+#define ABSL_BASE_INTERNAL_CYCLECLOCK_H_
+
+#include <cstdint>
+
+#include "absl/base/config.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace base_internal {
+
+// -----------------------------------------------------------------------------
+// CycleClock
+// -----------------------------------------------------------------------------
+class CycleClock {
+ public:
+  // CycleClock::Now()
+  //
+  // Returns the value of a cycle counter that counts at a rate that is
+  // approximately constant.
+  static int64_t Now();
+
+  // CycleClock::Frequency()
+  //
+  // Returns the amount by which `CycleClock::Now()` increases per second. Note
+  // that this value may not necessarily match the core CPU clock frequency.
+  static double Frequency();
+
+ private:
+  CycleClock() = delete;  // no instances
+  CycleClock(const CycleClock&) = delete;
+  CycleClock& operator=(const CycleClock&) = delete;
+};
+
+using CycleClockSourceFunc = int64_t (*)();
+
+class CycleClockSource {
+ private:
+  // CycleClockSource::Register()
+  //
+  // Register a function that provides an alternate source for the unscaled CPU
+  // cycle count value. The source function must be async signal safe, must not
+  // call CycleClock::Now(), and must have a frequency that matches that of the
+  // unscaled clock used by CycleClock. A nullptr value resets CycleClock to use
+  // the default source.
+  static void Register(CycleClockSourceFunc source);
+};
+
+}  // namespace base_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#endif  // ABSL_BASE_INTERNAL_CYCLECLOCK_H_
diff --git a/src/absl/base/internal/direct_mmap.h b/src/absl/base/internal/direct_mmap.h
new file mode 100644 (file)
index 0000000..274054c
--- /dev/null
@@ -0,0 +1,169 @@
+// Copyright 2017 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// Functions for directly invoking mmap() via syscall, avoiding the case where
+// mmap() has been locally overridden.
+
+#ifndef ABSL_BASE_INTERNAL_DIRECT_MMAP_H_
+#define ABSL_BASE_INTERNAL_DIRECT_MMAP_H_
+
+#include "absl/base/config.h"
+
+#if ABSL_HAVE_MMAP
+
+#include <sys/mman.h>
+
+#ifdef __linux__
+
+#include <sys/types.h>
+#ifdef __BIONIC__
+#include <sys/syscall.h>
+#else
+#include <syscall.h>
+#endif
+
+#include <linux/unistd.h>
+#include <unistd.h>
+#include <cerrno>
+#include <cstdarg>
+#include <cstdint>
+
+#ifdef __mips__
+// Include definitions of the ABI currently in use.
+#ifdef __BIONIC__
+// Android doesn't have sgidefs.h, but does have asm/sgidefs.h, which has the
+// definitions we need.
+#include <asm/sgidefs.h>
+#else
+#include <sgidefs.h>
+#endif  // __BIONIC__
+#endif  // __mips__
+
+// SYS_mmap and SYS_munmap are not defined in Android.
+#ifdef __BIONIC__
+extern "C" void* __mmap2(void*, size_t, int, int, int, size_t);
+#if defined(__NR_mmap) && !defined(SYS_mmap)
+#define SYS_mmap __NR_mmap
+#endif
+#ifndef SYS_munmap
+#define SYS_munmap __NR_munmap
+#endif
+#endif  // __BIONIC__
+
+#if defined(__NR_mmap2) && !defined(SYS_mmap2)
+#define SYS_mmap2 __NR_mmap2
+#endif
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace base_internal {
+
+// Platform specific logic extracted from
+// https://chromium.googlesource.com/linux-syscall-support/+/master/linux_syscall_support.h
+inline void* DirectMmap(void* start, size_t length, int prot, int flags, int fd,
+                        off64_t offset) noexcept {
+#if defined(__i386__) || defined(__ARM_ARCH_3__) || defined(__ARM_EABI__) || \
+    defined(__m68k__) || defined(__sh__) ||                                  \
+    (defined(__hppa__) && !defined(__LP64__)) ||                             \
+    (defined(__mips__) && _MIPS_SIM == _MIPS_SIM_ABI32) ||                   \
+    (defined(__PPC__) && !defined(__PPC64__)) ||                             \
+    (defined(__riscv) && __riscv_xlen == 32) ||                              \
+    (defined(__s390__) && !defined(__s390x__)) ||                            \
+    (defined(__sparc__) && !defined(__arch64__))
+  // On these architectures, implement mmap with mmap2.
+  static int pagesize = 0;
+  if (pagesize == 0) {
+#if defined(__wasm__) || defined(__asmjs__)
+    pagesize = getpagesize();
+#else
+    pagesize = sysconf(_SC_PAGESIZE);
+#endif
+  }
+  if (offset < 0 || offset % pagesize != 0) {
+    errno = EINVAL;
+    return MAP_FAILED;
+  }
+#ifdef __BIONIC__
+  // SYS_mmap2 has problems on Android API level <= 16.
+  // Workaround by invoking __mmap2() instead.
+  return __mmap2(start, length, prot, flags, fd, offset / pagesize);
+#else
+  return reinterpret_cast<void*>(
+      syscall(SYS_mmap2, start, length, prot, flags, fd,
+              static_cast<off_t>(offset / pagesize)));
+#endif
+#elif defined(__s390x__)
+  // On s390x, mmap() arguments are passed in memory.
+  unsigned long buf[6] = {reinterpret_cast<unsigned long>(start),  // NOLINT
+                          static_cast<unsigned long>(length),      // NOLINT
+                          static_cast<unsigned long>(prot),        // NOLINT
+                          static_cast<unsigned long>(flags),       // NOLINT
+                          static_cast<unsigned long>(fd),          // NOLINT
+                          static_cast<unsigned long>(offset)};     // NOLINT
+  return reinterpret_cast<void*>(syscall(SYS_mmap, buf));
+#elif defined(__x86_64__)
+// The x32 ABI has 32 bit longs, but the syscall interface is 64 bit.
+// We need to explicitly cast to an unsigned 64 bit type to avoid implicit
+// sign extension.  We can't cast pointers directly because those are
+// 32 bits, and gcc will dump ugly warnings about casting from a pointer
+// to an integer of a different size. We also need to make sure __off64_t
+// isn't truncated to 32-bits under x32.
+#define MMAP_SYSCALL_ARG(x) ((uint64_t)(uintptr_t)(x))
+  return reinterpret_cast<void*>(
+      syscall(SYS_mmap, MMAP_SYSCALL_ARG(start), MMAP_SYSCALL_ARG(length),
+              MMAP_SYSCALL_ARG(prot), MMAP_SYSCALL_ARG(flags),
+              MMAP_SYSCALL_ARG(fd), static_cast<uint64_t>(offset)));
+#undef MMAP_SYSCALL_ARG
+#else  // Remaining 64-bit aritectures.
+  static_assert(sizeof(unsigned long) == 8, "Platform is not 64-bit");
+  return reinterpret_cast<void*>(
+      syscall(SYS_mmap, start, length, prot, flags, fd, offset));
+#endif
+}
+
+inline int DirectMunmap(void* start, size_t length) {
+  return static_cast<int>(syscall(SYS_munmap, start, length));
+}
+
+}  // namespace base_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#else  // !__linux__
+
+// For non-linux platforms where we have mmap, just dispatch directly to the
+// actual mmap()/munmap() methods.
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace base_internal {
+
+inline void* DirectMmap(void* start, size_t length, int prot, int flags, int fd,
+                        off_t offset) {
+  return mmap(start, length, prot, flags, fd, offset);
+}
+
+inline int DirectMunmap(void* start, size_t length) {
+  return munmap(start, length);
+}
+
+}  // namespace base_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#endif  // __linux__
+
+#endif  // ABSL_HAVE_MMAP
+
+#endif  // ABSL_BASE_INTERNAL_DIRECT_MMAP_H_
diff --git a/src/absl/base/internal/dynamic_annotations.h b/src/absl/base/internal/dynamic_annotations.h
new file mode 100644 (file)
index 0000000..b23c5ec
--- /dev/null
@@ -0,0 +1,398 @@
+// Copyright 2017 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// This file defines dynamic annotations for use with dynamic analysis tool
+// such as valgrind, PIN, etc.
+//
+// Dynamic annotation is a source code annotation that affects the generated
+// code (that is, the annotation is not a comment). Each such annotation is
+// attached to a particular instruction and/or to a particular object (address)
+// in the program.
+//
+// The annotations that should be used by users are macros in all upper-case
+// (e.g., ANNOTATE_THREAD_NAME).
+//
+// Actual implementation of these macros may differ depending on the dynamic
+// analysis tool being used.
+//
+// This file supports the following configurations:
+// - Dynamic Annotations enabled (with static thread-safety warnings disabled).
+//   In this case, macros expand to functions implemented by Thread Sanitizer,
+//   when building with TSan. When not provided an external implementation,
+//   dynamic_annotations.cc provides no-op implementations.
+//
+// - Static Clang thread-safety warnings enabled.
+//   When building with a Clang compiler that supports thread-safety warnings,
+//   a subset of annotations can be statically-checked at compile-time. We
+//   expand these macros to static-inline functions that can be analyzed for
+//   thread-safety, but afterwards elided when building the final binary.
+//
+// - All annotations are disabled.
+//   If neither Dynamic Annotations nor Clang thread-safety warnings are
+//   enabled, then all annotation-macros expand to empty.
+
+#ifndef ABSL_BASE_INTERNAL_DYNAMIC_ANNOTATIONS_H_
+#define ABSL_BASE_INTERNAL_DYNAMIC_ANNOTATIONS_H_
+
+#include <stddef.h>
+
+#include "absl/base/config.h"
+
+// -------------------------------------------------------------------------
+// Decide which features are enabled
+
+#ifndef DYNAMIC_ANNOTATIONS_ENABLED
+#define DYNAMIC_ANNOTATIONS_ENABLED 0
+#endif
+
+#if defined(__clang__) && !defined(SWIG)
+#define ABSL_INTERNAL_IGNORE_READS_ATTRIBUTE_ENABLED 1
+#endif
+
+#if DYNAMIC_ANNOTATIONS_ENABLED != 0
+
+#define ABSL_INTERNAL_RACE_ANNOTATIONS_ENABLED 1
+#define ABSL_INTERNAL_READS_ANNOTATIONS_ENABLED 1
+#define ABSL_INTERNAL_WRITES_ANNOTATIONS_ENABLED 1
+#define ABSL_INTERNAL_ANNOTALYSIS_ENABLED 0
+#define ABSL_INTERNAL_READS_WRITES_ANNOTATIONS_ENABLED 1
+
+#else
+
+#define ABSL_INTERNAL_RACE_ANNOTATIONS_ENABLED 0
+#define ABSL_INTERNAL_READS_ANNOTATIONS_ENABLED 0
+#define ABSL_INTERNAL_WRITES_ANNOTATIONS_ENABLED 0
+
+// Clang provides limited support for static thread-safety analysis through a
+// feature called Annotalysis. We configure macro-definitions according to
+// whether Annotalysis support is available. When running in opt-mode, GCC
+// will issue a warning, if these attributes are compiled. Only include them
+// when compiling using Clang.
+
+// ANNOTALYSIS_ENABLED == 1 when IGNORE_READ_ATTRIBUTE_ENABLED == 1
+#define ABSL_INTERNAL_ANNOTALYSIS_ENABLED \
+  defined(ABSL_INTERNAL_IGNORE_READS_ATTRIBUTE_ENABLED)
+// Read/write annotations are enabled in Annotalysis mode; disabled otherwise.
+#define ABSL_INTERNAL_READS_WRITES_ANNOTATIONS_ENABLED \
+  ABSL_INTERNAL_ANNOTALYSIS_ENABLED
+#endif
+
+// Memory annotations are also made available to LLVM's Memory Sanitizer
+#if defined(ABSL_HAVE_MEMORY_SANITIZER) && !defined(__native_client__)
+#define ABSL_INTERNAL_MEMORY_ANNOTATIONS_ENABLED 1
+#endif
+
+#ifndef ABSL_INTERNAL_MEMORY_ANNOTATIONS_ENABLED
+#define ABSL_INTERNAL_MEMORY_ANNOTATIONS_ENABLED 0
+#endif
+
+#ifdef __cplusplus
+#define ABSL_INTERNAL_BEGIN_EXTERN_C extern "C" {
+#define ABSL_INTERNAL_END_EXTERN_C }  // extern "C"
+#define ABSL_INTERNAL_GLOBAL_SCOPED(F) ::F
+#define ABSL_INTERNAL_STATIC_INLINE inline
+#else
+#define ABSL_INTERNAL_BEGIN_EXTERN_C  // empty
+#define ABSL_INTERNAL_END_EXTERN_C    // empty
+#define ABSL_INTERNAL_GLOBAL_SCOPED(F) F
+#define ABSL_INTERNAL_STATIC_INLINE static inline
+#endif
+
+// -------------------------------------------------------------------------
+// Define race annotations.
+
+#if ABSL_INTERNAL_RACE_ANNOTATIONS_ENABLED == 1
+
+// -------------------------------------------------------------
+// Annotations that suppress errors. It is usually better to express the
+// program's synchronization using the other annotations, but these can be used
+// when all else fails.
+
+// Report that we may have a benign race at `pointer`, with size
+// "sizeof(*(pointer))". `pointer` must be a non-void* pointer. Insert at the
+// point where `pointer` has been allocated, preferably close to the point
+// where the race happens. See also ANNOTATE_BENIGN_RACE_STATIC.
+#define ANNOTATE_BENIGN_RACE(pointer, description)     \
+  ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateBenignRaceSized) \
+  (__FILE__, __LINE__, pointer, sizeof(*(pointer)), description)
+
+// Same as ANNOTATE_BENIGN_RACE(`address`, `description`), but applies to
+// the memory range [`address`, `address`+`size`).
+#define ANNOTATE_BENIGN_RACE_SIZED(address, size, description) \
+  ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateBenignRaceSized)         \
+  (__FILE__, __LINE__, address, size, description)
+
+// Enable (`enable`!=0) or disable (`enable`==0) race detection for all threads.
+// This annotation could be useful if you want to skip expensive race analysis
+// during some period of program execution, e.g. during initialization.
+#define ANNOTATE_ENABLE_RACE_DETECTION(enable)             \
+  ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateEnableRaceDetection) \
+  (__FILE__, __LINE__, enable)
+
+// -------------------------------------------------------------
+// Annotations useful for debugging.
+
+// Report the current thread `name` to a race detector.
+#define ANNOTATE_THREAD_NAME(name) \
+  ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateThreadName)(__FILE__, __LINE__, name)
+
+// -------------------------------------------------------------
+// Annotations useful when implementing locks. They are not normally needed by
+// modules that merely use locks. The `lock` argument is a pointer to the lock
+// object.
+
+// Report that a lock has been created at address `lock`.
+#define ANNOTATE_RWLOCK_CREATE(lock) \
+  ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateRWLockCreate)(__FILE__, __LINE__, lock)
+
+// Report that a linker initialized lock has been created at address `lock`.
+#ifdef ABSL_HAVE_THREAD_SANITIZER
+#define ANNOTATE_RWLOCK_CREATE_STATIC(lock)               \
+  ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateRWLockCreateStatic) \
+  (__FILE__, __LINE__, lock)
+#else
+#define ANNOTATE_RWLOCK_CREATE_STATIC(lock) ANNOTATE_RWLOCK_CREATE(lock)
+#endif
+
+// Report that the lock at address `lock` is about to be destroyed.
+#define ANNOTATE_RWLOCK_DESTROY(lock) \
+  ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateRWLockDestroy)(__FILE__, __LINE__, lock)
+
+// Report that the lock at address `lock` has been acquired.
+// `is_w`=1 for writer lock, `is_w`=0 for reader lock.
+#define ANNOTATE_RWLOCK_ACQUIRED(lock, is_w)          \
+  ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateRWLockAcquired) \
+  (__FILE__, __LINE__, lock, is_w)
+
+// Report that the lock at address `lock` is about to be released.
+// `is_w`=1 for writer lock, `is_w`=0 for reader lock.
+#define ANNOTATE_RWLOCK_RELEASED(lock, is_w)          \
+  ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateRWLockReleased) \
+  (__FILE__, __LINE__, lock, is_w)
+
+// Apply ANNOTATE_BENIGN_RACE_SIZED to a static variable `static_var`.
+#define ANNOTATE_BENIGN_RACE_STATIC(static_var, description)      \
+  namespace {                                                     \
+  class static_var##_annotator {                                  \
+   public:                                                        \
+    static_var##_annotator() {                                    \
+      ANNOTATE_BENIGN_RACE_SIZED(&static_var, sizeof(static_var), \
+                                 #static_var ": " description);   \
+    }                                                             \
+  };                                                              \
+  static static_var##_annotator the##static_var##_annotator;      \
+  }  // namespace
+
+#else  // ABSL_INTERNAL_RACE_ANNOTATIONS_ENABLED == 0
+
+#define ANNOTATE_RWLOCK_CREATE(lock)                            // empty
+#define ANNOTATE_RWLOCK_CREATE_STATIC(lock)                     // empty
+#define ANNOTATE_RWLOCK_DESTROY(lock)                           // empty
+#define ANNOTATE_RWLOCK_ACQUIRED(lock, is_w)                    // empty
+#define ANNOTATE_RWLOCK_RELEASED(lock, is_w)                    // empty
+#define ANNOTATE_BENIGN_RACE(address, description)              // empty
+#define ANNOTATE_BENIGN_RACE_SIZED(address, size, description)  // empty
+#define ANNOTATE_THREAD_NAME(name)                              // empty
+#define ANNOTATE_ENABLE_RACE_DETECTION(enable)                  // empty
+#define ANNOTATE_BENIGN_RACE_STATIC(static_var, description)    // empty
+
+#endif  // ABSL_INTERNAL_RACE_ANNOTATIONS_ENABLED
+
+// -------------------------------------------------------------------------
+// Define memory annotations.
+
+#if ABSL_INTERNAL_MEMORY_ANNOTATIONS_ENABLED == 1
+
+#include <sanitizer/msan_interface.h>
+
+#define ANNOTATE_MEMORY_IS_INITIALIZED(address, size) \
+  __msan_unpoison(address, size)
+
+#define ANNOTATE_MEMORY_IS_UNINITIALIZED(address, size) \
+  __msan_allocated_memory(address, size)
+
+#else  // ABSL_INTERNAL_MEMORY_ANNOTATIONS_ENABLED == 0
+
+#if DYNAMIC_ANNOTATIONS_ENABLED == 1
+#define ANNOTATE_MEMORY_IS_INITIALIZED(address, size) \
+  do {                                                \
+    (void)(address);                                  \
+    (void)(size);                                     \
+  } while (0)
+#define ANNOTATE_MEMORY_IS_UNINITIALIZED(address, size) \
+  do {                                                  \
+    (void)(address);                                    \
+    (void)(size);                                       \
+  } while (0)
+#else
+#define ANNOTATE_MEMORY_IS_INITIALIZED(address, size)    // empty
+#define ANNOTATE_MEMORY_IS_UNINITIALIZED(address, size)  // empty
+#endif
+
+#endif  // ABSL_INTERNAL_MEMORY_ANNOTATIONS_ENABLED
+
+// -------------------------------------------------------------------------
+// Define IGNORE_READS_BEGIN/_END attributes.
+
+#if defined(ABSL_INTERNAL_IGNORE_READS_ATTRIBUTE_ENABLED)
+
+#define ABSL_INTERNAL_IGNORE_READS_BEGIN_ATTRIBUTE \
+  __attribute((exclusive_lock_function("*")))
+#define ABSL_INTERNAL_IGNORE_READS_END_ATTRIBUTE \
+  __attribute((unlock_function("*")))
+
+#else  // !defined(ABSL_INTERNAL_IGNORE_READS_ATTRIBUTE_ENABLED)
+
+#define ABSL_INTERNAL_IGNORE_READS_BEGIN_ATTRIBUTE  // empty
+#define ABSL_INTERNAL_IGNORE_READS_END_ATTRIBUTE    // empty
+
+#endif  // defined(ABSL_INTERNAL_IGNORE_READS_ATTRIBUTE_ENABLED)
+
+// -------------------------------------------------------------------------
+// Define IGNORE_READS_BEGIN/_END annotations.
+
+#if ABSL_INTERNAL_READS_ANNOTATIONS_ENABLED == 1
+
+// Request the analysis tool to ignore all reads in the current thread until
+// ANNOTATE_IGNORE_READS_END is called. Useful to ignore intentional racey
+// reads, while still checking other reads and all writes.
+// See also ANNOTATE_UNPROTECTED_READ.
+#define ANNOTATE_IGNORE_READS_BEGIN() \
+  ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateIgnoreReadsBegin)(__FILE__, __LINE__)
+
+// Stop ignoring reads.
+#define ANNOTATE_IGNORE_READS_END() \
+  ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateIgnoreReadsEnd)(__FILE__, __LINE__)
+
+#elif defined(ABSL_INTERNAL_ANNOTALYSIS_ENABLED)
+
+// When Annotalysis is enabled without Dynamic Annotations, the use of
+// static-inline functions allows the annotations to be read at compile-time,
+// while still letting the compiler elide the functions from the final build.
+//
+// TODO(delesley) -- The exclusive lock here ignores writes as well, but
+// allows IGNORE_READS_AND_WRITES to work properly.
+
+#define ANNOTATE_IGNORE_READS_BEGIN() \
+  ABSL_INTERNAL_GLOBAL_SCOPED(AbslInternalAnnotateIgnoreReadsBegin)()
+
+#define ANNOTATE_IGNORE_READS_END() \
+  ABSL_INTERNAL_GLOBAL_SCOPED(AbslInternalAnnotateIgnoreReadsEnd)()
+
+#else
+
+#define ANNOTATE_IGNORE_READS_BEGIN()  // empty
+#define ANNOTATE_IGNORE_READS_END()    // empty
+
+#endif
+
+// -------------------------------------------------------------------------
+// Define IGNORE_WRITES_BEGIN/_END annotations.
+
+#if ABSL_INTERNAL_WRITES_ANNOTATIONS_ENABLED == 1
+
+// Similar to ANNOTATE_IGNORE_READS_BEGIN, but ignore writes instead.
+#define ANNOTATE_IGNORE_WRITES_BEGIN() \
+  ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateIgnoreWritesBegin)(__FILE__, __LINE__)
+
+// Stop ignoring writes.
+#define ANNOTATE_IGNORE_WRITES_END() \
+  ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateIgnoreWritesEnd)(__FILE__, __LINE__)
+
+#else
+
+#define ANNOTATE_IGNORE_WRITES_BEGIN()  // empty
+#define ANNOTATE_IGNORE_WRITES_END()    // empty
+
+#endif
+
+// -------------------------------------------------------------------------
+// Define the ANNOTATE_IGNORE_READS_AND_WRITES_* annotations using the more
+// primitive annotations defined above.
+//
+//     Instead of doing
+//        ANNOTATE_IGNORE_READS_BEGIN();
+//        ... = x;
+//        ANNOTATE_IGNORE_READS_END();
+//     one can use
+//        ... = ANNOTATE_UNPROTECTED_READ(x);
+
+#if defined(ABSL_INTERNAL_READS_WRITES_ANNOTATIONS_ENABLED)
+
+// Start ignoring all memory accesses (both reads and writes).
+#define ANNOTATE_IGNORE_READS_AND_WRITES_BEGIN() \
+  do {                                           \
+    ANNOTATE_IGNORE_READS_BEGIN();               \
+    ANNOTATE_IGNORE_WRITES_BEGIN();              \
+  } while (0)
+
+// Stop ignoring both reads and writes.
+#define ANNOTATE_IGNORE_READS_AND_WRITES_END() \
+  do {                                         \
+    ANNOTATE_IGNORE_WRITES_END();              \
+    ANNOTATE_IGNORE_READS_END();               \
+  } while (0)
+
+#ifdef __cplusplus
+// ANNOTATE_UNPROTECTED_READ is the preferred way to annotate racey reads.
+#define ANNOTATE_UNPROTECTED_READ(x) \
+  absl::base_internal::AnnotateUnprotectedRead(x)
+
+#endif
+
+#else
+
+#define ANNOTATE_IGNORE_READS_AND_WRITES_BEGIN()  // empty
+#define ANNOTATE_IGNORE_READS_AND_WRITES_END()    // empty
+#define ANNOTATE_UNPROTECTED_READ(x) (x)
+
+#endif
+
+// -------------------------------------------------------------------------
+// Address sanitizer annotations
+
+#ifdef ABSL_HAVE_ADDRESS_SANITIZER
+// Describe the current state of a contiguous container such as e.g.
+// std::vector or std::string. For more details see
+// sanitizer/common_interface_defs.h, which is provided by the compiler.
+#include <sanitizer/common_interface_defs.h>
+
+#define ANNOTATE_CONTIGUOUS_CONTAINER(beg, end, old_mid, new_mid) \
+  __sanitizer_annotate_contiguous_container(beg, end, old_mid, new_mid)
+#define ADDRESS_SANITIZER_REDZONE(name)    \
+  struct {                                 \
+    char x[8] __attribute__((aligned(8))); \
+  } name
+
+#else
+
+#define ANNOTATE_CONTIGUOUS_CONTAINER(beg, end, old_mid, new_mid)
+#define ADDRESS_SANITIZER_REDZONE(name) static_assert(true, "")
+
+#endif  // ABSL_HAVE_ADDRESS_SANITIZER
+
+// -------------------------------------------------------------------------
+// Undefine the macros intended only for this file.
+
+#undef ABSL_INTERNAL_RACE_ANNOTATIONS_ENABLED
+#undef ABSL_INTERNAL_MEMORY_ANNOTATIONS_ENABLED
+#undef ABSL_INTERNAL_READS_ANNOTATIONS_ENABLED
+#undef ABSL_INTERNAL_WRITES_ANNOTATIONS_ENABLED
+#undef ABSL_INTERNAL_ANNOTALYSIS_ENABLED
+#undef ABSL_INTERNAL_READS_WRITES_ANNOTATIONS_ENABLED
+#undef ABSL_INTERNAL_BEGIN_EXTERN_C
+#undef ABSL_INTERNAL_END_EXTERN_C
+#undef ABSL_INTERNAL_STATIC_INLINE
+
+#endif  // ABSL_BASE_INTERNAL_DYNAMIC_ANNOTATIONS_H_
diff --git a/src/absl/base/internal/endian.h b/src/absl/base/internal/endian.h
new file mode 100644 (file)
index 0000000..dad0e9a
--- /dev/null
@@ -0,0 +1,327 @@
+// Copyright 2017 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#ifndef ABSL_BASE_INTERNAL_ENDIAN_H_
+#define ABSL_BASE_INTERNAL_ENDIAN_H_
+
+// The following guarantees declaration of the byte swap functions
+#ifdef _MSC_VER
+#include <stdlib.h>  // NOLINT(build/include)
+#elif defined(__FreeBSD__)
+#include <sys/endian.h>
+#elif defined(__GLIBC__)
+#include <byteswap.h>  // IWYU pragma: export
+#endif
+
+#include <cstdint>
+#include "absl/base/casts.h"
+#include "absl/base/config.h"
+#include "absl/base/internal/unaligned_access.h"
+#include "absl/base/port.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+
+// Use compiler byte-swapping intrinsics if they are available.  32-bit
+// and 64-bit versions are available in Clang and GCC as of GCC 4.3.0.
+// The 16-bit version is available in Clang and GCC only as of GCC 4.8.0.
+// For simplicity, we enable them all only for GCC 4.8.0 or later.
+#if defined(__clang__) || \
+    (defined(__GNUC__) && \
+     ((__GNUC__ == 4 && __GNUC_MINOR__ >= 8) || __GNUC__ >= 5))
+inline uint64_t gbswap_64(uint64_t host_int) {
+  return __builtin_bswap64(host_int);
+}
+inline uint32_t gbswap_32(uint32_t host_int) {
+  return __builtin_bswap32(host_int);
+}
+inline uint16_t gbswap_16(uint16_t host_int) {
+  return __builtin_bswap16(host_int);
+}
+
+#elif defined(_MSC_VER)
+inline uint64_t gbswap_64(uint64_t host_int) {
+  return _byteswap_uint64(host_int);
+}
+inline uint32_t gbswap_32(uint32_t host_int) {
+  return _byteswap_ulong(host_int);
+}
+inline uint16_t gbswap_16(uint16_t host_int) {
+  return _byteswap_ushort(host_int);
+}
+
+#else
+inline uint64_t gbswap_64(uint64_t host_int) {
+#if defined(__GNUC__) && defined(__x86_64__) && !defined(__APPLE__)
+  // Adapted from /usr/include/byteswap.h.  Not available on Mac.
+  if (__builtin_constant_p(host_int)) {
+    return __bswap_constant_64(host_int);
+  } else {
+    uint64_t result;
+    __asm__("bswap %0" : "=r"(result) : "0"(host_int));
+    return result;
+  }
+#elif defined(__GLIBC__)
+  return bswap_64(host_int);
+#else
+  return (((host_int & uint64_t{0xFF}) << 56) |
+          ((host_int & uint64_t{0xFF00}) << 40) |
+          ((host_int & uint64_t{0xFF0000}) << 24) |
+          ((host_int & uint64_t{0xFF000000}) << 8) |
+          ((host_int & uint64_t{0xFF00000000}) >> 8) |
+          ((host_int & uint64_t{0xFF0000000000}) >> 24) |
+          ((host_int & uint64_t{0xFF000000000000}) >> 40) |
+          ((host_int & uint64_t{0xFF00000000000000}) >> 56));
+#endif  // bswap_64
+}
+
+inline uint32_t gbswap_32(uint32_t host_int) {
+#if defined(__GLIBC__)
+  return bswap_32(host_int);
+#else
+  return (((host_int & uint32_t{0xFF}) << 24) |
+          ((host_int & uint32_t{0xFF00}) << 8) |
+          ((host_int & uint32_t{0xFF0000}) >> 8) |
+          ((host_int & uint32_t{0xFF000000}) >> 24));
+#endif
+}
+
+inline uint16_t gbswap_16(uint16_t host_int) {
+#if defined(__GLIBC__)
+  return bswap_16(host_int);
+#else
+  return (((host_int & uint16_t{0xFF}) << 8) |
+          ((host_int & uint16_t{0xFF00}) >> 8));
+#endif
+}
+
+#endif  // intrinsics available
+
+#ifdef ABSL_IS_LITTLE_ENDIAN
+
+// Definitions for ntohl etc. that don't require us to include
+// netinet/in.h. We wrap gbswap_32 and gbswap_16 in functions rather
+// than just #defining them because in debug mode, gcc doesn't
+// correctly handle the (rather involved) definitions of bswap_32.
+// gcc guarantees that inline functions are as fast as macros, so
+// this isn't a performance hit.
+inline uint16_t ghtons(uint16_t x) { return gbswap_16(x); }
+inline uint32_t ghtonl(uint32_t x) { return gbswap_32(x); }
+inline uint64_t ghtonll(uint64_t x) { return gbswap_64(x); }
+
+#elif defined ABSL_IS_BIG_ENDIAN
+
+// These definitions are simpler on big-endian machines
+// These are functions instead of macros to avoid self-assignment warnings
+// on calls such as "i = ghtnol(i);".  This also provides type checking.
+inline uint16_t ghtons(uint16_t x) { return x; }
+inline uint32_t ghtonl(uint32_t x) { return x; }
+inline uint64_t ghtonll(uint64_t x) { return x; }
+
+#else
+#error \
+    "Unsupported byte order: Either ABSL_IS_BIG_ENDIAN or " \
+       "ABSL_IS_LITTLE_ENDIAN must be defined"
+#endif  // byte order
+
+inline uint16_t gntohs(uint16_t x) { return ghtons(x); }
+inline uint32_t gntohl(uint32_t x) { return ghtonl(x); }
+inline uint64_t gntohll(uint64_t x) { return ghtonll(x); }
+
+// Utilities to convert numbers between the current hosts's native byte
+// order and little-endian byte order
+//
+// Load/Store methods are alignment safe
+namespace little_endian {
+// Conversion functions.
+#ifdef ABSL_IS_LITTLE_ENDIAN
+
+inline uint16_t FromHost16(uint16_t x) { return x; }
+inline uint16_t ToHost16(uint16_t x) { return x; }
+
+inline uint32_t FromHost32(uint32_t x) { return x; }
+inline uint32_t ToHost32(uint32_t x) { return x; }
+
+inline uint64_t FromHost64(uint64_t x) { return x; }
+inline uint64_t ToHost64(uint64_t x) { return x; }
+
+inline constexpr bool IsLittleEndian() { return true; }
+
+#elif defined ABSL_IS_BIG_ENDIAN
+
+inline uint16_t FromHost16(uint16_t x) { return gbswap_16(x); }
+inline uint16_t ToHost16(uint16_t x) { return gbswap_16(x); }
+
+inline uint32_t FromHost32(uint32_t x) { return gbswap_32(x); }
+inline uint32_t ToHost32(uint32_t x) { return gbswap_32(x); }
+
+inline uint64_t FromHost64(uint64_t x) { return gbswap_64(x); }
+inline uint64_t ToHost64(uint64_t x) { return gbswap_64(x); }
+
+inline constexpr bool IsLittleEndian() { return false; }
+
+#endif /* ENDIAN */
+
+inline uint8_t FromHost(uint8_t x) { return x; }
+inline uint16_t FromHost(uint16_t x) { return FromHost16(x); }
+inline uint32_t FromHost(uint32_t x) { return FromHost32(x); }
+inline uint64_t FromHost(uint64_t x) { return FromHost64(x); }
+inline uint8_t ToHost(uint8_t x) { return x; }
+inline uint16_t ToHost(uint16_t x) { return ToHost16(x); }
+inline uint32_t ToHost(uint32_t x) { return ToHost32(x); }
+inline uint64_t ToHost(uint64_t x) { return ToHost64(x); }
+
+inline int8_t FromHost(int8_t x) { return x; }
+inline int16_t FromHost(int16_t x) {
+  return bit_cast<int16_t>(FromHost16(bit_cast<uint16_t>(x)));
+}
+inline int32_t FromHost(int32_t x) {
+  return bit_cast<int32_t>(FromHost32(bit_cast<uint32_t>(x)));
+}
+inline int64_t FromHost(int64_t x) {
+  return bit_cast<int64_t>(FromHost64(bit_cast<uint64_t>(x)));
+}
+inline int8_t ToHost(int8_t x) { return x; }
+inline int16_t ToHost(int16_t x) {
+  return bit_cast<int16_t>(ToHost16(bit_cast<uint16_t>(x)));
+}
+inline int32_t ToHost(int32_t x) {
+  return bit_cast<int32_t>(ToHost32(bit_cast<uint32_t>(x)));
+}
+inline int64_t ToHost(int64_t x) {
+  return bit_cast<int64_t>(ToHost64(bit_cast<uint64_t>(x)));
+}
+
+// Functions to do unaligned loads and stores in little-endian order.
+inline uint16_t Load16(const void *p) {
+  return ToHost16(ABSL_INTERNAL_UNALIGNED_LOAD16(p));
+}
+
+inline void Store16(void *p, uint16_t v) {
+  ABSL_INTERNAL_UNALIGNED_STORE16(p, FromHost16(v));
+}
+
+inline uint32_t Load32(const void *p) {
+  return ToHost32(ABSL_INTERNAL_UNALIGNED_LOAD32(p));
+}
+
+inline void Store32(void *p, uint32_t v) {
+  ABSL_INTERNAL_UNALIGNED_STORE32(p, FromHost32(v));
+}
+
+inline uint64_t Load64(const void *p) {
+  return ToHost64(ABSL_INTERNAL_UNALIGNED_LOAD64(p));
+}
+
+inline void Store64(void *p, uint64_t v) {
+  ABSL_INTERNAL_UNALIGNED_STORE64(p, FromHost64(v));
+}
+
+}  // namespace little_endian
+
+// Utilities to convert numbers between the current hosts's native byte
+// order and big-endian byte order (same as network byte order)
+//
+// Load/Store methods are alignment safe
+namespace big_endian {
+#ifdef ABSL_IS_LITTLE_ENDIAN
+
+inline uint16_t FromHost16(uint16_t x) { return gbswap_16(x); }
+inline uint16_t ToHost16(uint16_t x) { return gbswap_16(x); }
+
+inline uint32_t FromHost32(uint32_t x) { return gbswap_32(x); }
+inline uint32_t ToHost32(uint32_t x) { return gbswap_32(x); }
+
+inline uint64_t FromHost64(uint64_t x) { return gbswap_64(x); }
+inline uint64_t ToHost64(uint64_t x) { return gbswap_64(x); }
+
+inline constexpr bool IsLittleEndian() { return true; }
+
+#elif defined ABSL_IS_BIG_ENDIAN
+
+inline uint16_t FromHost16(uint16_t x) { return x; }
+inline uint16_t ToHost16(uint16_t x) { return x; }
+
+inline uint32_t FromHost32(uint32_t x) { return x; }
+inline uint32_t ToHost32(uint32_t x) { return x; }
+
+inline uint64_t FromHost64(uint64_t x) { return x; }
+inline uint64_t ToHost64(uint64_t x) { return x; }
+
+inline constexpr bool IsLittleEndian() { return false; }
+
+#endif /* ENDIAN */
+
+inline uint8_t FromHost(uint8_t x) { return x; }
+inline uint16_t FromHost(uint16_t x) { return FromHost16(x); }
+inline uint32_t FromHost(uint32_t x) { return FromHost32(x); }
+inline uint64_t FromHost(uint64_t x) { return FromHost64(x); }
+inline uint8_t ToHost(uint8_t x) { return x; }
+inline uint16_t ToHost(uint16_t x) { return ToHost16(x); }
+inline uint32_t ToHost(uint32_t x) { return ToHost32(x); }
+inline uint64_t ToHost(uint64_t x) { return ToHost64(x); }
+
+inline int8_t FromHost(int8_t x) { return x; }
+inline int16_t FromHost(int16_t x) {
+  return bit_cast<int16_t>(FromHost16(bit_cast<uint16_t>(x)));
+}
+inline int32_t FromHost(int32_t x) {
+  return bit_cast<int32_t>(FromHost32(bit_cast<uint32_t>(x)));
+}
+inline int64_t FromHost(int64_t x) {
+  return bit_cast<int64_t>(FromHost64(bit_cast<uint64_t>(x)));
+}
+inline int8_t ToHost(int8_t x) { return x; }
+inline int16_t ToHost(int16_t x) {
+  return bit_cast<int16_t>(ToHost16(bit_cast<uint16_t>(x)));
+}
+inline int32_t ToHost(int32_t x) {
+  return bit_cast<int32_t>(ToHost32(bit_cast<uint32_t>(x)));
+}
+inline int64_t ToHost(int64_t x) {
+  return bit_cast<int64_t>(ToHost64(bit_cast<uint64_t>(x)));
+}
+
+// Functions to do unaligned loads and stores in big-endian order.
+inline uint16_t Load16(const void *p) {
+  return ToHost16(ABSL_INTERNAL_UNALIGNED_LOAD16(p));
+}
+
+inline void Store16(void *p, uint16_t v) {
+  ABSL_INTERNAL_UNALIGNED_STORE16(p, FromHost16(v));
+}
+
+inline uint32_t Load32(const void *p) {
+  return ToHost32(ABSL_INTERNAL_UNALIGNED_LOAD32(p));
+}
+
+inline void Store32(void *p, uint32_t v) {
+  ABSL_INTERNAL_UNALIGNED_STORE32(p, FromHost32(v));
+}
+
+inline uint64_t Load64(const void *p) {
+  return ToHost64(ABSL_INTERNAL_UNALIGNED_LOAD64(p));
+}
+
+inline void Store64(void *p, uint64_t v) {
+  ABSL_INTERNAL_UNALIGNED_STORE64(p, FromHost64(v));
+}
+
+}  // namespace big_endian
+
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#endif  // ABSL_BASE_INTERNAL_ENDIAN_H_
diff --git a/src/absl/base/internal/errno_saver.h b/src/absl/base/internal/errno_saver.h
new file mode 100644 (file)
index 0000000..251de51
--- /dev/null
@@ -0,0 +1,43 @@
+// Copyright 2017 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef ABSL_BASE_INTERNAL_ERRNO_SAVER_H_
+#define ABSL_BASE_INTERNAL_ERRNO_SAVER_H_
+
+#include <cerrno>
+
+#include "absl/base/config.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace base_internal {
+
+// `ErrnoSaver` captures the value of `errno` upon construction and restores it
+// upon deletion.  It is used in low-level code and must be super fast.  Do not
+// add instrumentation, even in debug modes.
+class ErrnoSaver {
+ public:
+  ErrnoSaver() : saved_errno_(errno) {}
+  ~ErrnoSaver() { errno = saved_errno_; }
+  int operator()() const { return saved_errno_; }
+
+ private:
+  const int saved_errno_;
+};
+
+}  // namespace base_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#endif  // ABSL_BASE_INTERNAL_ERRNO_SAVER_H_
diff --git a/src/absl/base/internal/exponential_biased.cc b/src/absl/base/internal/exponential_biased.cc
new file mode 100644 (file)
index 0000000..1b30c06
--- /dev/null
@@ -0,0 +1,93 @@
+// Copyright 2019 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "absl/base/internal/exponential_biased.h"
+
+#include <stdint.h>
+
+#include <algorithm>
+#include <atomic>
+#include <cmath>
+#include <limits>
+
+#include "absl/base/attributes.h"
+#include "absl/base/optimization.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace base_internal {
+
+// The algorithm generates a random number between 0 and 1 and applies the
+// inverse cumulative distribution function for an exponential. Specifically:
+// Let m be the inverse of the sample period, then the probability
+// distribution function is m*exp(-mx) so the CDF is
+// p = 1 - exp(-mx), so
+// q = 1 - p = exp(-mx)
+// log_e(q) = -mx
+// -log_e(q)/m = x
+// log_2(q) * (-log_e(2) * 1/m) = x
+// In the code, q is actually in the range 1 to 2**26, hence the -26 below
+int64_t ExponentialBiased::GetSkipCount(int64_t mean) {
+  if (ABSL_PREDICT_FALSE(!initialized_)) {
+    Initialize();
+  }
+
+  uint64_t rng = NextRandom(rng_);
+  rng_ = rng;
+
+  // Take the top 26 bits as the random number
+  // (This plus the 1<<58 sampling bound give a max possible step of
+  // 5194297183973780480 bytes.)
+  // The uint32_t cast is to prevent a (hard-to-reproduce) NAN
+  // under piii debug for some binaries.
+  double q = static_cast<uint32_t>(rng >> (kPrngNumBits - 26)) + 1.0;
+  // Put the computed p-value through the CDF of a geometric.
+  double interval = bias_ + (std::log2(q) - 26) * (-std::log(2.0) * mean);
+  // Very large values of interval overflow int64_t. To avoid that, we will
+  // cheat and clamp any huge values to (int64_t max)/2. This is a potential
+  // source of bias, but the mean would need to be such a large value that it's
+  // not likely to come up. For example, with a mean of 1e18, the probability of
+  // hitting this condition is about 1/1000. For a mean of 1e17, standard
+  // calculators claim that this event won't happen.
+  if (interval > static_cast<double>(std::numeric_limits<int64_t>::max() / 2)) {
+    // Assume huge values are bias neutral, retain bias for next call.
+    return std::numeric_limits<int64_t>::max() / 2;
+  }
+  double value = std::round(interval);
+  bias_ = interval - value;
+  return value;
+}
+
+int64_t ExponentialBiased::GetStride(int64_t mean) {
+  return GetSkipCount(mean - 1) + 1;
+}
+
+void ExponentialBiased::Initialize() {
+  // We don't get well distributed numbers from `this` so we call NextRandom() a
+  // bunch to mush the bits around. We use a global_rand to handle the case
+  // where the same thread (by memory address) gets created and destroyed
+  // repeatedly.
+  ABSL_CONST_INIT static std::atomic<uint32_t> global_rand(0);
+  uint64_t r = reinterpret_cast<uint64_t>(this) +
+               global_rand.fetch_add(1, std::memory_order_relaxed);
+  for (int i = 0; i < 20; ++i) {
+    r = NextRandom(r);
+  }
+  rng_ = r;
+  initialized_ = true;
+}
+
+}  // namespace base_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
diff --git a/src/absl/base/internal/exponential_biased.h b/src/absl/base/internal/exponential_biased.h
new file mode 100644 (file)
index 0000000..94f79a3
--- /dev/null
@@ -0,0 +1,130 @@
+// Copyright 2019 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef ABSL_BASE_INTERNAL_EXPONENTIAL_BIASED_H_
+#define ABSL_BASE_INTERNAL_EXPONENTIAL_BIASED_H_
+
+#include <stdint.h>
+
+#include "absl/base/config.h"
+#include "absl/base/macros.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace base_internal {
+
+// ExponentialBiased provides a small and fast random number generator for a
+// rounded exponential distribution. This generator manages very little state,
+// and imposes no synchronization overhead. This makes it useful in specialized
+// scenarios requiring minimum overhead, such as stride based periodic sampling.
+//
+// ExponentialBiased provides two closely related functions, GetSkipCount() and
+// GetStride(), both returning a rounded integer defining a number of events
+// required before some event with a given mean probability occurs.
+//
+// The distribution is useful to generate a random wait time or some periodic
+// event with a given mean probability. For example, if an action is supposed to
+// happen on average once every 'N' events, then we can get a random 'stride'
+// counting down how long before the event to happen. For example, if we'd want
+// to sample one in every 1000 'Frobber' calls, our code could look like this:
+//
+//   Frobber::Frobber() {
+//     stride_ = exponential_biased_.GetStride(1000);
+//   }
+//
+//   void Frobber::Frob(int arg) {
+//     if (--stride == 0) {
+//       SampleFrob(arg);
+//       stride_ = exponential_biased_.GetStride(1000);
+//     }
+//     ...
+//   }
+//
+// The rounding of the return value creates a bias, especially for smaller means
+// where the distribution of the fraction is not evenly distributed. We correct
+// this bias by tracking the fraction we rounded up or down on each iteration,
+// effectively tracking the distance between the cumulative value, and the
+// rounded cumulative value. For example, given a mean of 2:
+//
+//   raw = 1.63076, cumulative = 1.63076, rounded = 2, bias = -0.36923
+//   raw = 0.14624, cumulative = 1.77701, rounded = 2, bias =  0.14624
+//   raw = 4.93194, cumulative = 6.70895, rounded = 7, bias = -0.06805
+//   raw = 0.24206, cumulative = 6.95101, rounded = 7, bias =  0.24206
+//   etc...
+//
+// Adjusting with rounding bias is relatively trivial:
+//
+//    double value = bias_ + exponential_distribution(mean)();
+//    double rounded_value = std::round(value);
+//    bias_ = value - rounded_value;
+//    return rounded_value;
+//
+// This class is thread-compatible.
+class ExponentialBiased {
+ public:
+  // The number of bits set by NextRandom.
+  static constexpr int kPrngNumBits = 48;
+
+  // `GetSkipCount()` returns the number of events to skip before some chosen
+  // event happens. For example, randomly tossing a coin, we will on average
+  // throw heads once before we get tails. We can simulate random coin tosses
+  // using GetSkipCount() as:
+  //
+  //   ExponentialBiased eb;
+  //   for (...) {
+  //     int number_of_heads_before_tail = eb.GetSkipCount(1);
+  //     for (int flips = 0; flips < number_of_heads_before_tail; ++flips) {
+  //       printf("head...");
+  //     }
+  //     printf("tail\n");
+  //   }
+  //
+  int64_t GetSkipCount(int64_t mean);
+
+  // GetStride() returns the number of events required for a specific event to
+  // happen. See the class comments for a usage example. `GetStride()` is
+  // equivalent to `GetSkipCount(mean - 1) + 1`. When to use `GetStride()` or
+  // `GetSkipCount()` depends mostly on what best fits the use case.
+  int64_t GetStride(int64_t mean);
+
+  // Computes a random number in the range [0, 1<<(kPrngNumBits+1) - 1]
+  //
+  // This is public to enable testing.
+  static uint64_t NextRandom(uint64_t rnd);
+
+ private:
+  void Initialize();
+
+  uint64_t rng_{0};
+  double bias_{0};
+  bool initialized_{false};
+};
+
+// Returns the next prng value.
+// pRNG is: aX+b mod c with a = 0x5DEECE66D, b =  0xB, c = 1<<48
+// This is the lrand64 generator.
+inline uint64_t ExponentialBiased::NextRandom(uint64_t rnd) {
+  const uint64_t prng_mult = uint64_t{0x5DEECE66D};
+  const uint64_t prng_add = 0xB;
+  const uint64_t prng_mod_power = 48;
+  const uint64_t prng_mod_mask =
+      ~((~static_cast<uint64_t>(0)) << prng_mod_power);
+  return (prng_mult * rnd + prng_add) & prng_mod_mask;
+}
+
+}  // namespace base_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#endif  // ABSL_BASE_INTERNAL_EXPONENTIAL_BIASED_H_
diff --git a/src/absl/base/internal/fast_type_id.h b/src/absl/base/internal/fast_type_id.h
new file mode 100644 (file)
index 0000000..3db59e8
--- /dev/null
@@ -0,0 +1,48 @@
+//
+// Copyright 2020 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#ifndef ABSL_BASE_INTERNAL_FAST_TYPE_ID_H_
+#define ABSL_BASE_INTERNAL_FAST_TYPE_ID_H_
+
+#include "absl/base/config.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace base_internal {
+
+template <typename Type>
+struct FastTypeTag {
+  constexpr static char dummy_var = 0;
+};
+
+template <typename Type>
+constexpr char FastTypeTag<Type>::dummy_var;
+
+// FastTypeId<Type>() evaluates at compile/link-time to a unique pointer for the
+// passed-in type. These are meant to be good match for keys into maps or
+// straight up comparisons.
+using FastTypeIdType = const void*;
+
+template <typename Type>
+constexpr inline FastTypeIdType FastTypeId() {
+  return &FastTypeTag<Type>::dummy_var;
+}
+
+}  // namespace base_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#endif  // ABSL_BASE_INTERNAL_FAST_TYPE_ID_H_
diff --git a/src/absl/base/internal/hide_ptr.h b/src/absl/base/internal/hide_ptr.h
new file mode 100644 (file)
index 0000000..1dba809
--- /dev/null
@@ -0,0 +1,51 @@
+// Copyright 2018 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef ABSL_BASE_INTERNAL_HIDE_PTR_H_
+#define ABSL_BASE_INTERNAL_HIDE_PTR_H_
+
+#include <cstdint>
+
+#include "absl/base/config.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace base_internal {
+
+// Arbitrary value with high bits set. Xor'ing with it is unlikely
+// to map one valid pointer to another valid pointer.
+constexpr uintptr_t HideMask() {
+  return (uintptr_t{0xF03A5F7BU} << (sizeof(uintptr_t) - 4) * 8) | 0xF03A5F7BU;
+}
+
+// Hide a pointer from the leak checker. For internal use only.
+// Differs from absl::IgnoreLeak(ptr) in that absl::IgnoreLeak(ptr) causes ptr
+// and all objects reachable from ptr to be ignored by the leak checker.
+template <class T>
+inline uintptr_t HidePtr(T* ptr) {
+  return reinterpret_cast<uintptr_t>(ptr) ^ HideMask();
+}
+
+// Return a pointer that has been hidden from the leak checker.
+// For internal use only.
+template <class T>
+inline T* UnhidePtr(uintptr_t hidden) {
+  return reinterpret_cast<T*>(hidden ^ HideMask());
+}
+
+}  // namespace base_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#endif  // ABSL_BASE_INTERNAL_HIDE_PTR_H_
diff --git a/src/absl/base/internal/identity.h b/src/absl/base/internal/identity.h
new file mode 100644 (file)
index 0000000..a3154ed
--- /dev/null
@@ -0,0 +1,37 @@
+// Copyright 2017 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#ifndef ABSL_BASE_INTERNAL_IDENTITY_H_
+#define ABSL_BASE_INTERNAL_IDENTITY_H_
+
+#include "absl/base/config.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace internal {
+
+template <typename T>
+struct identity {
+  typedef T type;
+};
+
+template <typename T>
+using identity_t = typename identity<T>::type;
+
+}  // namespace internal
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#endif  // ABSL_BASE_INTERNAL_IDENTITY_H_
diff --git a/src/absl/base/internal/inline_variable.h b/src/absl/base/internal/inline_variable.h
new file mode 100644 (file)
index 0000000..130d8c2
--- /dev/null
@@ -0,0 +1,107 @@
+// Copyright 2017 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef ABSL_BASE_INTERNAL_INLINE_VARIABLE_EMULATION_H_
+#define ABSL_BASE_INTERNAL_INLINE_VARIABLE_EMULATION_H_
+
+#include <type_traits>
+
+#include "absl/base/internal/identity.h"
+
+// File:
+//   This file define a macro that allows the creation of or emulation of C++17
+//   inline variables based on whether or not the feature is supported.
+
+////////////////////////////////////////////////////////////////////////////////
+// Macro: ABSL_INTERNAL_INLINE_CONSTEXPR(type, name, init)
+//
+// Description:
+//   Expands to the equivalent of an inline constexpr instance of the specified
+//   `type` and `name`, initialized to the value `init`. If the compiler being
+//   used is detected as supporting actual inline variables as a language
+//   feature, then the macro expands to an actual inline variable definition.
+//
+// Requires:
+//   `type` is a type that is usable in an extern variable declaration.
+//
+// Requires: `name` is a valid identifier
+//
+// Requires:
+//   `init` is an expression that can be used in the following definition:
+//     constexpr type name = init;
+//
+// Usage:
+//
+//   // Equivalent to: `inline constexpr size_t variant_npos = -1;`
+//   ABSL_INTERNAL_INLINE_CONSTEXPR(size_t, variant_npos, -1);
+//
+// Differences in implementation:
+//   For a direct, language-level inline variable, decltype(name) will be the
+//   type that was specified along with const qualification, whereas for
+//   emulated inline variables, decltype(name) may be different (in practice
+//   it will likely be a reference type).
+////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cpp_inline_variables
+
+// Clang's -Wmissing-variable-declarations option erroneously warned that
+// inline constexpr objects need to be pre-declared. This has now been fixed,
+// but we will need to support this workaround for people building with older
+// versions of clang.
+//
+// Bug: https://bugs.llvm.org/show_bug.cgi?id=35862
+//
+// Note:
+//   identity_t is used here so that the const and name are in the
+//   appropriate place for pointer types, reference types, function pointer
+//   types, etc..
+#if defined(__clang__)
+#define ABSL_INTERNAL_EXTERN_DECL(type, name) \
+  extern const ::absl::internal::identity_t<type> name;
+#else  // Otherwise, just define the macro to do nothing.
+#define ABSL_INTERNAL_EXTERN_DECL(type, name)
+#endif  // defined(__clang__)
+
+// See above comment at top of file for details.
+#define ABSL_INTERNAL_INLINE_CONSTEXPR(type, name, init) \
+  ABSL_INTERNAL_EXTERN_DECL(type, name)                  \
+  inline constexpr ::absl::internal::identity_t<type> name = init
+
+#else
+
+// See above comment at top of file for details.
+//
+// Note:
+//   identity_t is used here so that the const and name are in the
+//   appropriate place for pointer types, reference types, function pointer
+//   types, etc..
+#define ABSL_INTERNAL_INLINE_CONSTEXPR(var_type, name, init)                  \
+  template <class /*AbslInternalDummy*/ = void>                               \
+  struct AbslInternalInlineVariableHolder##name {                             \
+    static constexpr ::absl::internal::identity_t<var_type> kInstance = init; \
+  };                                                                          \
+                                                                              \
+  template <class AbslInternalDummy>                                          \
+  constexpr ::absl::internal::identity_t<var_type>                            \
+      AbslInternalInlineVariableHolder##name<AbslInternalDummy>::kInstance;   \
+                                                                              \
+  static constexpr const ::absl::internal::identity_t<var_type>&              \
+      name = /* NOLINT */                                                     \
+      AbslInternalInlineVariableHolder##name<>::kInstance;                    \
+  static_assert(sizeof(void (*)(decltype(name))) != 0,                        \
+                "Silence unused variable warnings.")
+
+#endif  // __cpp_inline_variables
+
+#endif  // ABSL_BASE_INTERNAL_INLINE_VARIABLE_EMULATION_H_
diff --git a/src/absl/base/internal/invoke.h b/src/absl/base/internal/invoke.h
new file mode 100644 (file)
index 0000000..5c71f32
--- /dev/null
@@ -0,0 +1,187 @@
+// Copyright 2017 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// absl::base_internal::invoke(f, args...) is an implementation of
+// INVOKE(f, args...) from section [func.require] of the C++ standard.
+//
+// [func.require]
+// Define INVOKE (f, t1, t2, ..., tN) as follows:
+// 1. (t1.*f)(t2, ..., tN) when f is a pointer to a member function of a class T
+//    and t1 is an object of type T or a reference to an object of type T or a
+//    reference to an object of a type derived from T;
+// 2. ((*t1).*f)(t2, ..., tN) when f is a pointer to a member function of a
+//    class T and t1 is not one of the types described in the previous item;
+// 3. t1.*f when N == 1 and f is a pointer to member data of a class T and t1 is
+//    an object of type T or a reference to an object of type T or a reference
+//    to an object of a type derived from T;
+// 4. (*t1).*f when N == 1 and f is a pointer to member data of a class T and t1
+//    is not one of the types described in the previous item;
+// 5. f(t1, t2, ..., tN) in all other cases.
+//
+// The implementation is SFINAE-friendly: substitution failure within invoke()
+// isn't an error.
+
+#ifndef ABSL_BASE_INTERNAL_INVOKE_H_
+#define ABSL_BASE_INTERNAL_INVOKE_H_
+
+#include <algorithm>
+#include <type_traits>
+#include <utility>
+
+#include "absl/meta/type_traits.h"
+
+// The following code is internal implementation detail.  See the comment at the
+// top of this file for the API documentation.
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace base_internal {
+
+// The five classes below each implement one of the clauses from the definition
+// of INVOKE. The inner class template Accept<F, Args...> checks whether the
+// clause is applicable; static function template Invoke(f, args...) does the
+// invocation.
+//
+// By separating the clause selection logic from invocation we make sure that
+// Invoke() does exactly what the standard says.
+
+template <typename Derived>
+struct StrippedAccept {
+  template <typename... Args>
+  struct Accept : Derived::template AcceptImpl<typename std::remove_cv<
+                      typename std::remove_reference<Args>::type>::type...> {};
+};
+
+// (t1.*f)(t2, ..., tN) when f is a pointer to a member function of a class T
+// and t1 is an object of type T or a reference to an object of type T or a
+// reference to an object of a type derived from T.
+struct MemFunAndRef : StrippedAccept<MemFunAndRef> {
+  template <typename... Args>
+  struct AcceptImpl : std::false_type {};
+
+  template <typename MemFunType, typename C, typename Obj, typename... Args>
+  struct AcceptImpl<MemFunType C::*, Obj, Args...>
+      : std::integral_constant<bool, std::is_base_of<C, Obj>::value &&
+                                         absl::is_function<MemFunType>::value> {
+  };
+
+  template <typename MemFun, typename Obj, typename... Args>
+  static decltype((std::declval<Obj>().*
+                   std::declval<MemFun>())(std::declval<Args>()...))
+  Invoke(MemFun&& mem_fun, Obj&& obj, Args&&... args) {
+    return (std::forward<Obj>(obj).*
+            std::forward<MemFun>(mem_fun))(std::forward<Args>(args)...);
+  }
+};
+
+// ((*t1).*f)(t2, ..., tN) when f is a pointer to a member function of a
+// class T and t1 is not one of the types described in the previous item.
+struct MemFunAndPtr : StrippedAccept<MemFunAndPtr> {
+  template <typename... Args>
+  struct AcceptImpl : std::false_type {};
+
+  template <typename MemFunType, typename C, typename Ptr, typename... Args>
+  struct AcceptImpl<MemFunType C::*, Ptr, Args...>
+      : std::integral_constant<bool, !std::is_base_of<C, Ptr>::value &&
+                                         absl::is_function<MemFunType>::value> {
+  };
+
+  template <typename MemFun, typename Ptr, typename... Args>
+  static decltype(((*std::declval<Ptr>()).*
+                   std::declval<MemFun>())(std::declval<Args>()...))
+  Invoke(MemFun&& mem_fun, Ptr&& ptr, Args&&... args) {
+    return ((*std::forward<Ptr>(ptr)).*
+            std::forward<MemFun>(mem_fun))(std::forward<Args>(args)...);
+  }
+};
+
+// t1.*f when N == 1 and f is a pointer to member data of a class T and t1 is
+// an object of type T or a reference to an object of type T or a reference
+// to an object of a type derived from T.
+struct DataMemAndRef : StrippedAccept<DataMemAndRef> {
+  template <typename... Args>
+  struct AcceptImpl : std::false_type {};
+
+  template <typename R, typename C, typename Obj>
+  struct AcceptImpl<R C::*, Obj>
+      : std::integral_constant<bool, std::is_base_of<C, Obj>::value &&
+                                         !absl::is_function<R>::value> {};
+
+  template <typename DataMem, typename Ref>
+  static decltype(std::declval<Ref>().*std::declval<DataMem>()) Invoke(
+      DataMem&& data_mem, Ref&& ref) {
+    return std::forward<Ref>(ref).*std::forward<DataMem>(data_mem);
+  }
+};
+
+// (*t1).*f when N == 1 and f is a pointer to member data of a class T and t1
+// is not one of the types described in the previous item.
+struct DataMemAndPtr : StrippedAccept<DataMemAndPtr> {
+  template <typename... Args>
+  struct AcceptImpl : std::false_type {};
+
+  template <typename R, typename C, typename Ptr>
+  struct AcceptImpl<R C::*, Ptr>
+      : std::integral_constant<bool, !std::is_base_of<C, Ptr>::value &&
+                                         !absl::is_function<R>::value> {};
+
+  template <typename DataMem, typename Ptr>
+  static decltype((*std::declval<Ptr>()).*std::declval<DataMem>()) Invoke(
+      DataMem&& data_mem, Ptr&& ptr) {
+    return (*std::forward<Ptr>(ptr)).*std::forward<DataMem>(data_mem);
+  }
+};
+
+// f(t1, t2, ..., tN) in all other cases.
+struct Callable {
+  // Callable doesn't have Accept because it's the last clause that gets picked
+  // when none of the previous clauses are applicable.
+  template <typename F, typename... Args>
+  static decltype(std::declval<F>()(std::declval<Args>()...)) Invoke(
+      F&& f, Args&&... args) {
+    return std::forward<F>(f)(std::forward<Args>(args)...);
+  }
+};
+
+// Resolves to the first matching clause.
+template <typename... Args>
+struct Invoker {
+  typedef typename std::conditional<
+      MemFunAndRef::Accept<Args...>::value, MemFunAndRef,
+      typename std::conditional<
+          MemFunAndPtr::Accept<Args...>::value, MemFunAndPtr,
+          typename std::conditional<
+              DataMemAndRef::Accept<Args...>::value, DataMemAndRef,
+              typename std::conditional<DataMemAndPtr::Accept<Args...>::value,
+                                        DataMemAndPtr, Callable>::type>::type>::
+          type>::type type;
+};
+
+// The result type of Invoke<F, Args...>.
+template <typename F, typename... Args>
+using invoke_result_t = decltype(Invoker<F, Args...>::type::Invoke(
+    std::declval<F>(), std::declval<Args>()...));
+
+// Invoke(f, args...) is an implementation of INVOKE(f, args...) from section
+// [func.require] of the C++ standard.
+template <typename F, typename... Args>
+invoke_result_t<F, Args...> invoke(F&& f, Args&&... args) {
+  return Invoker<F, Args...>::type::Invoke(std::forward<F>(f),
+                                           std::forward<Args>(args)...);
+}
+}  // namespace base_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#endif  // ABSL_BASE_INTERNAL_INVOKE_H_
diff --git a/src/absl/base/internal/low_level_alloc.cc b/src/absl/base/internal/low_level_alloc.cc
new file mode 100644 (file)
index 0000000..229ab91
--- /dev/null
@@ -0,0 +1,620 @@
+// Copyright 2017 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// A low-level allocator that can be used by other low-level
+// modules without introducing dependency cycles.
+// This allocator is slow and wasteful of memory;
+// it should not be used when performance is key.
+
+#include "absl/base/internal/low_level_alloc.h"
+
+#include <type_traits>
+
+#include "absl/base/call_once.h"
+#include "absl/base/config.h"
+#include "absl/base/internal/direct_mmap.h"
+#include "absl/base/internal/scheduling_mode.h"
+#include "absl/base/macros.h"
+#include "absl/base/thread_annotations.h"
+
+// LowLevelAlloc requires that the platform support low-level
+// allocation of virtual memory. Platforms lacking this cannot use
+// LowLevelAlloc.
+#ifndef ABSL_LOW_LEVEL_ALLOC_MISSING
+
+#ifndef _WIN32
+#include <pthread.h>
+#include <signal.h>
+#include <sys/mman.h>
+#include <unistd.h>
+#else
+#include <windows.h>
+#endif
+
+#include <string.h>
+#include <algorithm>
+#include <atomic>
+#include <cerrno>
+#include <cstddef>
+#include <new>                   // for placement-new
+
+#include "absl/base/dynamic_annotations.h"
+#include "absl/base/internal/raw_logging.h"
+#include "absl/base/internal/spinlock.h"
+
+// MAP_ANONYMOUS
+#if defined(__APPLE__)
+// For mmap, Linux defines both MAP_ANONYMOUS and MAP_ANON and says MAP_ANON is
+// deprecated. In Darwin, MAP_ANON is all there is.
+#if !defined MAP_ANONYMOUS
+#define MAP_ANONYMOUS MAP_ANON
+#endif  // !MAP_ANONYMOUS
+#endif  // __APPLE__
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace base_internal {
+
+// A first-fit allocator with amortized logarithmic free() time.
+
+// ---------------------------------------------------------------------------
+static const int kMaxLevel = 30;
+
+namespace {
+// This struct describes one allocated block, or one free block.
+struct AllocList {
+  struct Header {
+    // Size of entire region, including this field. Must be
+    // first. Valid in both allocated and unallocated blocks.
+    uintptr_t size;
+
+    // kMagicAllocated or kMagicUnallocated xor this.
+    uintptr_t magic;
+
+    // Pointer to parent arena.
+    LowLevelAlloc::Arena *arena;
+
+    // Aligns regions to 0 mod 2*sizeof(void*).
+    void *dummy_for_alignment;
+  } header;
+
+  // Next two fields: in unallocated blocks: freelist skiplist data
+  //                  in allocated blocks: overlaps with client data
+
+  // Levels in skiplist used.
+  int levels;
+
+  // Actually has levels elements. The AllocList node may not have room
+  // for all kMaxLevel entries. See max_fit in LLA_SkiplistLevels().
+  AllocList *next[kMaxLevel];
+};
+}  // namespace
+
+// ---------------------------------------------------------------------------
+// A trivial skiplist implementation.  This is used to keep the freelist
+// in address order while taking only logarithmic time per insert and delete.
+
+// An integer approximation of log2(size/base)
+// Requires size >= base.
+static int IntLog2(size_t size, size_t base) {
+  int result = 0;
+  for (size_t i = size; i > base; i >>= 1) {  // i == floor(size/2**result)
+    result++;
+  }
+  //    floor(size / 2**result) <= base < floor(size / 2**(result-1))
+  // =>     log2(size/(base+1)) <= result < 1+log2(size/base)
+  // => result ~= log2(size/base)
+  return result;
+}
+
+// Return a random integer n:  p(n)=1/(2**n) if 1 <= n; p(n)=0 if n < 1.
+static int Random(uint32_t *state) {
+  uint32_t r = *state;
+  int result = 1;
+  while ((((r = r*1103515245 + 12345) >> 30) & 1) == 0) {
+    result++;
+  }
+  *state = r;
+  return result;
+}
+
+// Return a number of skiplist levels for a node of size bytes, where
+// base is the minimum node size.  Compute level=log2(size / base)+n
+// where n is 1 if random is false and otherwise a random number generated with
+// the standard distribution for a skiplist:  See Random() above.
+// Bigger nodes tend to have more skiplist levels due to the log2(size / base)
+// term, so first-fit searches touch fewer nodes.  "level" is clipped so
+// level<kMaxLevel and next[level-1] will fit in the node.
+// 0 < LLA_SkiplistLevels(x,y,false) <= LLA_SkiplistLevels(x,y,true) < kMaxLevel
+static int LLA_SkiplistLevels(size_t size, size_t base, uint32_t *random) {
+  // max_fit is the maximum number of levels that will fit in a node for the
+  // given size.   We can't return more than max_fit, no matter what the
+  // random number generator says.
+  size_t max_fit = (size - offsetof(AllocList, next)) / sizeof(AllocList *);
+  int level = IntLog2(size, base) + (random != nullptr ? Random(random) : 1);
+  if (static_cast<size_t>(level) > max_fit) level = static_cast<int>(max_fit);
+  if (level > kMaxLevel-1) level = kMaxLevel - 1;
+  ABSL_RAW_CHECK(level >= 1, "block not big enough for even one level");
+  return level;
+}
+
+// Return "atleast", the first element of AllocList *head s.t. *atleast >= *e.
+// For 0 <= i < head->levels, set prev[i] to "no_greater", where no_greater
+// points to the last element at level i in the AllocList less than *e, or is
+// head if no such element exists.
+static AllocList *LLA_SkiplistSearch(AllocList *head,
+                                     AllocList *e, AllocList **prev) {
+  AllocList *p = head;
+  for (int level = head->levels - 1; level >= 0; level--) {
+    for (AllocList *n; (n = p->next[level]) != nullptr && n < e; p = n) {
+    }
+    prev[level] = p;
+  }
+  return (head->levels == 0) ? nullptr : prev[0]->next[0];
+}
+
+// Insert element *e into AllocList *head.  Set prev[] as LLA_SkiplistSearch.
+// Requires that e->levels be previously set by the caller (using
+// LLA_SkiplistLevels())
+static void LLA_SkiplistInsert(AllocList *head, AllocList *e,
+                               AllocList **prev) {
+  LLA_SkiplistSearch(head, e, prev);
+  for (; head->levels < e->levels; head->levels++) {  // extend prev pointers
+    prev[head->levels] = head;                        // to all *e's levels
+  }
+  for (int i = 0; i != e->levels; i++) {  // add element to list
+    e->next[i] = prev[i]->next[i];
+    prev[i]->next[i] = e;
+  }
+}
+
+// Remove element *e from AllocList *head.  Set prev[] as LLA_SkiplistSearch().
+// Requires that e->levels be previous set by the caller (using
+// LLA_SkiplistLevels())
+static void LLA_SkiplistDelete(AllocList *head, AllocList *e,
+                               AllocList **prev) {
+  AllocList *found = LLA_SkiplistSearch(head, e, prev);
+  ABSL_RAW_CHECK(e == found, "element not in freelist");
+  for (int i = 0; i != e->levels && prev[i]->next[i] == e; i++) {
+    prev[i]->next[i] = e->next[i];
+  }
+  while (head->levels > 0 && head->next[head->levels - 1] == nullptr) {
+    head->levels--;   // reduce head->levels if level unused
+  }
+}
+
+// ---------------------------------------------------------------------------
+// Arena implementation
+
+// Metadata for an LowLevelAlloc arena instance.
+struct LowLevelAlloc::Arena {
+  // Constructs an arena with the given LowLevelAlloc flags.
+  explicit Arena(uint32_t flags_value);
+
+  base_internal::SpinLock mu;
+  // Head of free list, sorted by address
+  AllocList freelist ABSL_GUARDED_BY(mu);
+  // Count of allocated blocks
+  int32_t allocation_count ABSL_GUARDED_BY(mu);
+  // flags passed to NewArena
+  const uint32_t flags;
+  // Result of sysconf(_SC_PAGESIZE)
+  const size_t pagesize;
+  // Lowest power of two >= max(16, sizeof(AllocList))
+  const size_t round_up;
+  // Smallest allocation block size
+  const size_t min_size;
+  // PRNG state
+  uint32_t random ABSL_GUARDED_BY(mu);
+};
+
+namespace {
+// Static storage space for the lazily-constructed, default global arena
+// instances.  We require this space because the whole point of LowLevelAlloc
+// is to avoid relying on malloc/new.
+alignas(LowLevelAlloc::Arena) unsigned char default_arena_storage[sizeof(
+    LowLevelAlloc::Arena)];
+alignas(LowLevelAlloc::Arena) unsigned char unhooked_arena_storage[sizeof(
+    LowLevelAlloc::Arena)];
+#ifndef ABSL_LOW_LEVEL_ALLOC_ASYNC_SIGNAL_SAFE_MISSING
+alignas(
+    LowLevelAlloc::Arena) unsigned char unhooked_async_sig_safe_arena_storage
+    [sizeof(LowLevelAlloc::Arena)];
+#endif
+
+// We must use LowLevelCallOnce here to construct the global arenas, rather than
+// using function-level statics, to avoid recursively invoking the scheduler.
+absl::once_flag create_globals_once;
+
+void CreateGlobalArenas() {
+  new (&default_arena_storage)
+      LowLevelAlloc::Arena(LowLevelAlloc::kCallMallocHook);
+  new (&unhooked_arena_storage) LowLevelAlloc::Arena(0);
+#ifndef ABSL_LOW_LEVEL_ALLOC_ASYNC_SIGNAL_SAFE_MISSING
+  new (&unhooked_async_sig_safe_arena_storage)
+      LowLevelAlloc::Arena(LowLevelAlloc::kAsyncSignalSafe);
+#endif
+}
+
+// Returns a global arena that does not call into hooks.  Used by NewArena()
+// when kCallMallocHook is not set.
+LowLevelAlloc::Arena* UnhookedArena() {
+  base_internal::LowLevelCallOnce(&create_globals_once, CreateGlobalArenas);
+  return reinterpret_cast<LowLevelAlloc::Arena*>(&unhooked_arena_storage);
+}
+
+#ifndef ABSL_LOW_LEVEL_ALLOC_ASYNC_SIGNAL_SAFE_MISSING
+// Returns a global arena that is async-signal safe.  Used by NewArena() when
+// kAsyncSignalSafe is set.
+LowLevelAlloc::Arena *UnhookedAsyncSigSafeArena() {
+  base_internal::LowLevelCallOnce(&create_globals_once, CreateGlobalArenas);
+  return reinterpret_cast<LowLevelAlloc::Arena *>(
+      &unhooked_async_sig_safe_arena_storage);
+}
+#endif
+
+}  // namespace
+
+// Returns the default arena, as used by LowLevelAlloc::Alloc() and friends.
+LowLevelAlloc::Arena *LowLevelAlloc::DefaultArena() {
+  base_internal::LowLevelCallOnce(&create_globals_once, CreateGlobalArenas);
+  return reinterpret_cast<LowLevelAlloc::Arena*>(&default_arena_storage);
+}
+
+// magic numbers to identify allocated and unallocated blocks
+static const uintptr_t kMagicAllocated = 0x4c833e95U;
+static const uintptr_t kMagicUnallocated = ~kMagicAllocated;
+
+namespace {
+class ABSL_SCOPED_LOCKABLE ArenaLock {
+ public:
+  explicit ArenaLock(LowLevelAlloc::Arena *arena)
+      ABSL_EXCLUSIVE_LOCK_FUNCTION(arena->mu)
+      : arena_(arena) {
+#ifndef ABSL_LOW_LEVEL_ALLOC_ASYNC_SIGNAL_SAFE_MISSING
+    if ((arena->flags & LowLevelAlloc::kAsyncSignalSafe) != 0) {
+      sigset_t all;
+      sigfillset(&all);
+      mask_valid_ = pthread_sigmask(SIG_BLOCK, &all, &mask_) == 0;
+    }
+#endif
+    arena_->mu.Lock();
+  }
+  ~ArenaLock() { ABSL_RAW_CHECK(left_, "haven't left Arena region"); }
+  void Leave() ABSL_UNLOCK_FUNCTION() {
+    arena_->mu.Unlock();
+#ifndef ABSL_LOW_LEVEL_ALLOC_ASYNC_SIGNAL_SAFE_MISSING
+    if (mask_valid_) {
+      const int err = pthread_sigmask(SIG_SETMASK, &mask_, nullptr);
+      if (err != 0) {
+        ABSL_RAW_LOG(FATAL, "pthread_sigmask failed: %d", err);
+      }
+    }
+#endif
+    left_ = true;
+  }
+
+ private:
+  bool left_ = false;  // whether left region
+#ifndef ABSL_LOW_LEVEL_ALLOC_ASYNC_SIGNAL_SAFE_MISSING
+  bool mask_valid_ = false;
+  sigset_t mask_;  // old mask of blocked signals
+#endif
+  LowLevelAlloc::Arena *arena_;
+  ArenaLock(const ArenaLock &) = delete;
+  ArenaLock &operator=(const ArenaLock &) = delete;
+};
+}  // namespace
+
+// create an appropriate magic number for an object at "ptr"
+// "magic" should be kMagicAllocated or kMagicUnallocated
+inline static uintptr_t Magic(uintptr_t magic, AllocList::Header *ptr) {
+  return magic ^ reinterpret_cast<uintptr_t>(ptr);
+}
+
+namespace {
+size_t GetPageSize() {
+#ifdef _WIN32
+  SYSTEM_INFO system_info;
+  GetSystemInfo(&system_info);
+  return std::max(system_info.dwPageSize, system_info.dwAllocationGranularity);
+#elif defined(__wasm__) || defined(__asmjs__)
+  return getpagesize();
+#else
+  return sysconf(_SC_PAGESIZE);
+#endif
+}
+
+size_t RoundedUpBlockSize() {
+  // Round up block sizes to a power of two close to the header size.
+  size_t round_up = 16;
+  while (round_up < sizeof(AllocList::Header)) {
+    round_up += round_up;
+  }
+  return round_up;
+}
+
+}  // namespace
+
+LowLevelAlloc::Arena::Arena(uint32_t flags_value)
+    : mu(base_internal::SCHEDULE_KERNEL_ONLY),
+      allocation_count(0),
+      flags(flags_value),
+      pagesize(GetPageSize()),
+      round_up(RoundedUpBlockSize()),
+      min_size(2 * round_up),
+      random(0) {
+  freelist.header.size = 0;
+  freelist.header.magic =
+      Magic(kMagicUnallocated, &freelist.header);
+  freelist.header.arena = this;
+  freelist.levels = 0;
+  memset(freelist.next, 0, sizeof(freelist.next));
+}
+
+// L < meta_data_arena->mu
+LowLevelAlloc::Arena *LowLevelAlloc::NewArena(int32_t flags) {
+  Arena *meta_data_arena = DefaultArena();
+#ifndef ABSL_LOW_LEVEL_ALLOC_ASYNC_SIGNAL_SAFE_MISSING
+  if ((flags & LowLevelAlloc::kAsyncSignalSafe) != 0) {
+    meta_data_arena = UnhookedAsyncSigSafeArena();
+  } else  // NOLINT(readability/braces)
+#endif
+      if ((flags & LowLevelAlloc::kCallMallocHook) == 0) {
+    meta_data_arena = UnhookedArena();
+  }
+  Arena *result =
+    new (AllocWithArena(sizeof (*result), meta_data_arena)) Arena(flags);
+  return result;
+}
+
+// L < arena->mu, L < arena->arena->mu
+bool LowLevelAlloc::DeleteArena(Arena *arena) {
+  ABSL_RAW_CHECK(
+      arena != nullptr && arena != DefaultArena() && arena != UnhookedArena(),
+      "may not delete default arena");
+  ArenaLock section(arena);
+  if (arena->allocation_count != 0) {
+    section.Leave();
+    return false;
+  }
+  while (arena->freelist.next[0] != nullptr) {
+    AllocList *region = arena->freelist.next[0];
+    size_t size = region->header.size;
+    arena->freelist.next[0] = region->next[0];
+    ABSL_RAW_CHECK(
+        region->header.magic == Magic(kMagicUnallocated, &region->header),
+        "bad magic number in DeleteArena()");
+    ABSL_RAW_CHECK(region->header.arena == arena,
+                   "bad arena pointer in DeleteArena()");
+    ABSL_RAW_CHECK(size % arena->pagesize == 0,
+                   "empty arena has non-page-aligned block size");
+    ABSL_RAW_CHECK(reinterpret_cast<uintptr_t>(region) % arena->pagesize == 0,
+                   "empty arena has non-page-aligned block");
+    int munmap_result;
+#ifdef _WIN32
+    munmap_result = VirtualFree(region, 0, MEM_RELEASE);
+    ABSL_RAW_CHECK(munmap_result != 0,
+                   "LowLevelAlloc::DeleteArena: VitualFree failed");
+#else
+#ifndef ABSL_LOW_LEVEL_ALLOC_ASYNC_SIGNAL_SAFE_MISSING
+    if ((arena->flags & LowLevelAlloc::kAsyncSignalSafe) == 0) {
+      munmap_result = munmap(region, size);
+    } else {
+      munmap_result = base_internal::DirectMunmap(region, size);
+    }
+#else
+    munmap_result = munmap(region, size);
+#endif  // ABSL_LOW_LEVEL_ALLOC_ASYNC_SIGNAL_SAFE_MISSING
+    if (munmap_result != 0) {
+      ABSL_RAW_LOG(FATAL, "LowLevelAlloc::DeleteArena: munmap failed: %d",
+                   errno);
+    }
+#endif  // _WIN32
+  }
+  section.Leave();
+  arena->~Arena();
+  Free(arena);
+  return true;
+}
+
+// ---------------------------------------------------------------------------
+
+// Addition, checking for overflow.  The intent is to die if an external client
+// manages to push through a request that would cause arithmetic to fail.
+static inline uintptr_t CheckedAdd(uintptr_t a, uintptr_t b) {
+  uintptr_t sum = a + b;
+  ABSL_RAW_CHECK(sum >= a, "LowLevelAlloc arithmetic overflow");
+  return sum;
+}
+
+// Return value rounded up to next multiple of align.
+// align must be a power of two.
+static inline uintptr_t RoundUp(uintptr_t addr, uintptr_t align) {
+  return CheckedAdd(addr, align - 1) & ~(align - 1);
+}
+
+// Equivalent to "return prev->next[i]" but with sanity checking
+// that the freelist is in the correct order, that it
+// consists of regions marked "unallocated", and that no two regions
+// are adjacent in memory (they should have been coalesced).
+// L >= arena->mu
+static AllocList *Next(int i, AllocList *prev, LowLevelAlloc::Arena *arena) {
+  ABSL_RAW_CHECK(i < prev->levels, "too few levels in Next()");
+  AllocList *next = prev->next[i];
+  if (next != nullptr) {
+    ABSL_RAW_CHECK(
+        next->header.magic == Magic(kMagicUnallocated, &next->header),
+        "bad magic number in Next()");
+    ABSL_RAW_CHECK(next->header.arena == arena, "bad arena pointer in Next()");
+    if (prev != &arena->freelist) {
+      ABSL_RAW_CHECK(prev < next, "unordered freelist");
+      ABSL_RAW_CHECK(reinterpret_cast<char *>(prev) + prev->header.size <
+                         reinterpret_cast<char *>(next),
+                     "malformed freelist");
+    }
+  }
+  return next;
+}
+
+// Coalesce list item "a" with its successor if they are adjacent.
+static void Coalesce(AllocList *a) {
+  AllocList *n = a->next[0];
+  if (n != nullptr && reinterpret_cast<char *>(a) + a->header.size ==
+                          reinterpret_cast<char *>(n)) {
+    LowLevelAlloc::Arena *arena = a->header.arena;
+    a->header.size += n->header.size;
+    n->header.magic = 0;
+    n->header.arena = nullptr;
+    AllocList *prev[kMaxLevel];
+    LLA_SkiplistDelete(&arena->freelist, n, prev);
+    LLA_SkiplistDelete(&arena->freelist, a, prev);
+    a->levels = LLA_SkiplistLevels(a->header.size, arena->min_size,
+                                   &arena->random);
+    LLA_SkiplistInsert(&arena->freelist, a, prev);
+  }
+}
+
+// Adds block at location "v" to the free list
+// L >= arena->mu
+static void AddToFreelist(void *v, LowLevelAlloc::Arena *arena) {
+  AllocList *f = reinterpret_cast<AllocList *>(
+                        reinterpret_cast<char *>(v) - sizeof (f->header));
+  ABSL_RAW_CHECK(f->header.magic == Magic(kMagicAllocated, &f->header),
+                 "bad magic number in AddToFreelist()");
+  ABSL_RAW_CHECK(f->header.arena == arena,
+                 "bad arena pointer in AddToFreelist()");
+  f->levels = LLA_SkiplistLevels(f->header.size, arena->min_size,
+                                 &arena->random);
+  AllocList *prev[kMaxLevel];
+  LLA_SkiplistInsert(&arena->freelist, f, prev);
+  f->header.magic = Magic(kMagicUnallocated, &f->header);
+  Coalesce(f);                  // maybe coalesce with successor
+  Coalesce(prev[0]);            // maybe coalesce with predecessor
+}
+
+// Frees storage allocated by LowLevelAlloc::Alloc().
+// L < arena->mu
+void LowLevelAlloc::Free(void *v) {
+  if (v != nullptr) {
+    AllocList *f = reinterpret_cast<AllocList *>(
+                        reinterpret_cast<char *>(v) - sizeof (f->header));
+    LowLevelAlloc::Arena *arena = f->header.arena;
+    ArenaLock section(arena);
+    AddToFreelist(v, arena);
+    ABSL_RAW_CHECK(arena->allocation_count > 0, "nothing in arena to free");
+    arena->allocation_count--;
+    section.Leave();
+  }
+}
+
+// allocates and returns a block of size bytes, to be freed with Free()
+// L < arena->mu
+static void *DoAllocWithArena(size_t request, LowLevelAlloc::Arena *arena) {
+  void *result = nullptr;
+  if (request != 0) {
+    AllocList *s;       // will point to region that satisfies request
+    ArenaLock section(arena);
+    // round up with header
+    size_t req_rnd = RoundUp(CheckedAdd(request, sizeof (s->header)),
+                             arena->round_up);
+    for (;;) {      // loop until we find a suitable region
+      // find the minimum levels that a block of this size must have
+      int i = LLA_SkiplistLevels(req_rnd, arena->min_size, nullptr) - 1;
+      if (i < arena->freelist.levels) {   // potential blocks exist
+        AllocList *before = &arena->freelist;  // predecessor of s
+        while ((s = Next(i, before, arena)) != nullptr &&
+               s->header.size < req_rnd) {
+          before = s;
+        }
+        if (s != nullptr) {       // we found a region
+          break;
+        }
+      }
+      // we unlock before mmap() both because mmap() may call a callback hook,
+      // and because it may be slow.
+      arena->mu.Unlock();
+      // mmap generous 64K chunks to decrease
+      // the chances/impact of fragmentation:
+      size_t new_pages_size = RoundUp(req_rnd, arena->pagesize * 16);
+      void *new_pages;
+#ifdef _WIN32
+      new_pages = VirtualAlloc(0, new_pages_size,
+                               MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
+      ABSL_RAW_CHECK(new_pages != nullptr, "VirtualAlloc failed");
+#else
+#ifndef ABSL_LOW_LEVEL_ALLOC_ASYNC_SIGNAL_SAFE_MISSING
+      if ((arena->flags & LowLevelAlloc::kAsyncSignalSafe) != 0) {
+        new_pages = base_internal::DirectMmap(nullptr, new_pages_size,
+            PROT_WRITE|PROT_READ, MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
+      } else {
+        new_pages = mmap(nullptr, new_pages_size, PROT_WRITE | PROT_READ,
+                         MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
+      }
+#else
+      new_pages = mmap(nullptr, new_pages_size, PROT_WRITE | PROT_READ,
+                       MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
+#endif  // ABSL_LOW_LEVEL_ALLOC_ASYNC_SIGNAL_SAFE_MISSING
+      if (new_pages == MAP_FAILED) {
+        ABSL_RAW_LOG(FATAL, "mmap error: %d", errno);
+      }
+
+#endif  // _WIN32
+      arena->mu.Lock();
+      s = reinterpret_cast<AllocList *>(new_pages);
+      s->header.size = new_pages_size;
+      // Pretend the block is allocated; call AddToFreelist() to free it.
+      s->header.magic = Magic(kMagicAllocated, &s->header);
+      s->header.arena = arena;
+      AddToFreelist(&s->levels, arena);  // insert new region into free list
+    }
+    AllocList *prev[kMaxLevel];
+    LLA_SkiplistDelete(&arena->freelist, s, prev);    // remove from free list
+    // s points to the first free region that's big enough
+    if (CheckedAdd(req_rnd, arena->min_size) <= s->header.size) {
+      // big enough to split
+      AllocList *n = reinterpret_cast<AllocList *>
+                        (req_rnd + reinterpret_cast<char *>(s));
+      n->header.size = s->header.size - req_rnd;
+      n->header.magic = Magic(kMagicAllocated, &n->header);
+      n->header.arena = arena;
+      s->header.size = req_rnd;
+      AddToFreelist(&n->levels, arena);
+    }
+    s->header.magic = Magic(kMagicAllocated, &s->header);
+    ABSL_RAW_CHECK(s->header.arena == arena, "");
+    arena->allocation_count++;
+    section.Leave();
+    result = &s->levels;
+  }
+  ABSL_ANNOTATE_MEMORY_IS_UNINITIALIZED(result, request);
+  return result;
+}
+
+void *LowLevelAlloc::Alloc(size_t request) {
+  void *result = DoAllocWithArena(request, DefaultArena());
+  return result;
+}
+
+void *LowLevelAlloc::AllocWithArena(size_t request, Arena *arena) {
+  ABSL_RAW_CHECK(arena != nullptr, "must pass a valid arena");
+  void *result = DoAllocWithArena(request, arena);
+  return result;
+}
+
+}  // namespace base_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#endif  // ABSL_LOW_LEVEL_ALLOC_MISSING
diff --git a/src/absl/base/internal/low_level_alloc.h b/src/absl/base/internal/low_level_alloc.h
new file mode 100644 (file)
index 0000000..db91951
--- /dev/null
@@ -0,0 +1,126 @@
+// Copyright 2017 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#ifndef ABSL_BASE_INTERNAL_LOW_LEVEL_ALLOC_H_
+#define ABSL_BASE_INTERNAL_LOW_LEVEL_ALLOC_H_
+
+// A simple thread-safe memory allocator that does not depend on
+// mutexes or thread-specific data.  It is intended to be used
+// sparingly, and only when malloc() would introduce an unwanted
+// dependency, such as inside the heap-checker, or the Mutex
+// implementation.
+
+// IWYU pragma: private, include "base/low_level_alloc.h"
+
+#include <sys/types.h>
+
+#include <cstdint>
+
+#include "absl/base/attributes.h"
+#include "absl/base/config.h"
+
+// LowLevelAlloc requires that the platform support low-level
+// allocation of virtual memory. Platforms lacking this cannot use
+// LowLevelAlloc.
+#ifdef ABSL_LOW_LEVEL_ALLOC_MISSING
+#error ABSL_LOW_LEVEL_ALLOC_MISSING cannot be directly set
+#elif !defined(ABSL_HAVE_MMAP) && !defined(_WIN32)
+#define ABSL_LOW_LEVEL_ALLOC_MISSING 1
+#endif
+
+// Using LowLevelAlloc with kAsyncSignalSafe isn't supported on Windows or
+// asm.js / WebAssembly.
+// See https://kripken.github.io/emscripten-site/docs/porting/pthreads.html
+// for more information.
+#ifdef ABSL_LOW_LEVEL_ALLOC_ASYNC_SIGNAL_SAFE_MISSING
+#error ABSL_LOW_LEVEL_ALLOC_ASYNC_SIGNAL_SAFE_MISSING cannot be directly set
+#elif defined(_WIN32) || defined(__asmjs__) || defined(__wasm__)
+#define ABSL_LOW_LEVEL_ALLOC_ASYNC_SIGNAL_SAFE_MISSING 1
+#endif
+
+#include <cstddef>
+
+#include "absl/base/port.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace base_internal {
+
+class LowLevelAlloc {
+ public:
+  struct Arena;       // an arena from which memory may be allocated
+
+  // Returns a pointer to a block of at least "request" bytes
+  // that have been newly allocated from the specific arena.
+  // for Alloc() call the DefaultArena() is used.
+  // Returns 0 if passed request==0.
+  // Does not return 0 under other circumstances; it crashes if memory
+  // is not available.
+  static void *Alloc(size_t request) ABSL_ATTRIBUTE_SECTION(malloc_hook);
+  static void *AllocWithArena(size_t request, Arena *arena)
+      ABSL_ATTRIBUTE_SECTION(malloc_hook);
+
+  // Deallocates a region of memory that was previously allocated with
+  // Alloc().   Does nothing if passed 0.   "s" must be either 0,
+  // or must have been returned from a call to Alloc() and not yet passed to
+  // Free() since that call to Alloc().  The space is returned to the arena
+  // from which it was allocated.
+  static void Free(void *s) ABSL_ATTRIBUTE_SECTION(malloc_hook);
+
+  // ABSL_ATTRIBUTE_SECTION(malloc_hook) for Alloc* and Free
+  // are to put all callers of MallocHook::Invoke* in this module
+  // into special section,
+  // so that MallocHook::GetCallerStackTrace can function accurately.
+
+  // Create a new arena.
+  // The root metadata for the new arena is allocated in the
+  // meta_data_arena; the DefaultArena() can be passed for meta_data_arena.
+  // These values may be ored into flags:
+  enum {
+    // Report calls to Alloc() and Free() via the MallocHook interface.
+    // Set in the DefaultArena.
+    kCallMallocHook = 0x0001,
+
+#ifndef ABSL_LOW_LEVEL_ALLOC_ASYNC_SIGNAL_SAFE_MISSING
+    // Make calls to Alloc(), Free() be async-signal-safe. Not set in
+    // DefaultArena(). Not supported on all platforms.
+    kAsyncSignalSafe = 0x0002,
+#endif
+  };
+  // Construct a new arena.  The allocation of the underlying metadata honors
+  // the provided flags.  For example, the call NewArena(kAsyncSignalSafe)
+  // is itself async-signal-safe, as well as generatating an arena that provides
+  // async-signal-safe Alloc/Free.
+  static Arena *NewArena(int32_t flags);
+
+  // Destroys an arena allocated by NewArena and returns true,
+  // provided no allocated blocks remain in the arena.
+  // If allocated blocks remain in the arena, does nothing and
+  // returns false.
+  // It is illegal to attempt to destroy the DefaultArena().
+  static bool DeleteArena(Arena *arena);
+
+  // The default arena that always exists.
+  static Arena *DefaultArena();
+
+ private:
+  LowLevelAlloc();      // no instances
+};
+
+}  // namespace base_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#endif  // ABSL_BASE_INTERNAL_LOW_LEVEL_ALLOC_H_
diff --git a/src/absl/base/internal/low_level_scheduling.h b/src/absl/base/internal/low_level_scheduling.h
new file mode 100644 (file)
index 0000000..9baccc0
--- /dev/null
@@ -0,0 +1,134 @@
+// Copyright 2017 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// Core interfaces and definitions used by by low-level interfaces such as
+// SpinLock.
+
+#ifndef ABSL_BASE_INTERNAL_LOW_LEVEL_SCHEDULING_H_
+#define ABSL_BASE_INTERNAL_LOW_LEVEL_SCHEDULING_H_
+
+#include "absl/base/internal/raw_logging.h"
+#include "absl/base/internal/scheduling_mode.h"
+#include "absl/base/macros.h"
+
+// The following two declarations exist so SchedulingGuard may friend them with
+// the appropriate language linkage.  These callbacks allow libc internals, such
+// as function level statics, to schedule cooperatively when locking.
+extern "C" bool __google_disable_rescheduling(void);
+extern "C" void __google_enable_rescheduling(bool disable_result);
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+class CondVar;
+class Mutex;
+
+namespace synchronization_internal {
+int MutexDelay(int32_t c, int mode);
+}  // namespace synchronization_internal
+
+namespace base_internal {
+
+class SchedulingHelper;  // To allow use of SchedulingGuard.
+class SpinLock;          // To allow use of SchedulingGuard.
+
+// SchedulingGuard
+// Provides guard semantics that may be used to disable cooperative rescheduling
+// of the calling thread within specific program blocks.  This is used to
+// protect resources (e.g. low-level SpinLocks or Domain code) that cooperative
+// scheduling depends on.
+//
+// Domain implementations capable of rescheduling in reaction to involuntary
+// kernel thread actions (e.g blocking due to a pagefault or syscall) must
+// guarantee that an annotated thread is not allowed to (cooperatively)
+// reschedule until the annotated region is complete.
+//
+// It is an error to attempt to use a cooperatively scheduled resource (e.g.
+// Mutex) within a rescheduling-disabled region.
+//
+// All methods are async-signal safe.
+class SchedulingGuard {
+ public:
+  // Returns true iff the calling thread may be cooperatively rescheduled.
+  static bool ReschedulingIsAllowed();
+  SchedulingGuard(const SchedulingGuard&) = delete;
+  SchedulingGuard& operator=(const SchedulingGuard&) = delete;
+
+ private:
+  // Disable cooperative rescheduling of the calling thread.  It may still
+  // initiate scheduling operations (e.g. wake-ups), however, it may not itself
+  // reschedule.  Nestable.  The returned result is opaque, clients should not
+  // attempt to interpret it.
+  // REQUIRES: Result must be passed to a pairing EnableScheduling().
+  static bool DisableRescheduling();
+
+  // Marks the end of a rescheduling disabled region, previously started by
+  // DisableRescheduling().
+  // REQUIRES: Pairs with innermost call (and result) of DisableRescheduling().
+  static void EnableRescheduling(bool disable_result);
+
+  // A scoped helper for {Disable, Enable}Rescheduling().
+  // REQUIRES: destructor must run in same thread as constructor.
+  struct ScopedDisable {
+    ScopedDisable() { disabled = SchedulingGuard::DisableRescheduling(); }
+    ~ScopedDisable() { SchedulingGuard::EnableRescheduling(disabled); }
+
+    bool disabled;
+  };
+
+  // A scoped helper to enable rescheduling temporarily.
+  // REQUIRES: destructor must run in same thread as constructor.
+  class ScopedEnable {
+   public:
+    ScopedEnable();
+    ~ScopedEnable();
+
+   private:
+    int scheduling_disabled_depth_;
+  };
+
+  // Access to SchedulingGuard is explicitly permitted.
+  friend class absl::CondVar;
+  friend class absl::Mutex;
+  friend class SchedulingHelper;
+  friend class SpinLock;
+  friend int absl::synchronization_internal::MutexDelay(int32_t c, int mode);
+};
+
+//------------------------------------------------------------------------------
+// End of public interfaces.
+//------------------------------------------------------------------------------
+
+inline bool SchedulingGuard::ReschedulingIsAllowed() {
+  return false;
+}
+
+inline bool SchedulingGuard::DisableRescheduling() {
+  return false;
+}
+
+inline void SchedulingGuard::EnableRescheduling(bool /* disable_result */) {
+  return;
+}
+
+inline SchedulingGuard::ScopedEnable::ScopedEnable()
+    : scheduling_disabled_depth_(0) {}
+inline SchedulingGuard::ScopedEnable::~ScopedEnable() {
+  ABSL_RAW_CHECK(scheduling_disabled_depth_ == 0, "disable unused warning");
+}
+
+}  // namespace base_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#endif  // ABSL_BASE_INTERNAL_LOW_LEVEL_SCHEDULING_H_
diff --git a/src/absl/base/internal/per_thread_tls.h b/src/absl/base/internal/per_thread_tls.h
new file mode 100644 (file)
index 0000000..cf5e97a
--- /dev/null
@@ -0,0 +1,52 @@
+// Copyright 2017 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef ABSL_BASE_INTERNAL_PER_THREAD_TLS_H_
+#define ABSL_BASE_INTERNAL_PER_THREAD_TLS_H_
+
+// This header defines two macros:
+//
+// If the platform supports thread-local storage:
+//
+// * ABSL_PER_THREAD_TLS_KEYWORD is the C keyword needed to declare a
+//   thread-local variable
+// * ABSL_PER_THREAD_TLS is 1
+//
+// Otherwise:
+//
+// * ABSL_PER_THREAD_TLS_KEYWORD is empty
+// * ABSL_PER_THREAD_TLS is 0
+//
+// Microsoft C supports thread-local storage.
+// GCC supports it if the appropriate version of glibc is available,
+// which the programmer can indicate by defining ABSL_HAVE_TLS
+
+#include "absl/base/port.h"  // For ABSL_HAVE_TLS
+
+#if defined(ABSL_PER_THREAD_TLS)
+#error ABSL_PER_THREAD_TLS cannot be directly set
+#elif defined(ABSL_PER_THREAD_TLS_KEYWORD)
+#error ABSL_PER_THREAD_TLS_KEYWORD cannot be directly set
+#elif defined(ABSL_HAVE_TLS)
+#define ABSL_PER_THREAD_TLS_KEYWORD __thread
+#define ABSL_PER_THREAD_TLS 1
+#elif defined(_MSC_VER)
+#define ABSL_PER_THREAD_TLS_KEYWORD __declspec(thread)
+#define ABSL_PER_THREAD_TLS 1
+#else
+#define ABSL_PER_THREAD_TLS_KEYWORD
+#define ABSL_PER_THREAD_TLS 0
+#endif
+
+#endif  // ABSL_BASE_INTERNAL_PER_THREAD_TLS_H_
diff --git a/src/absl/base/internal/periodic_sampler.cc b/src/absl/base/internal/periodic_sampler.cc
new file mode 100644 (file)
index 0000000..520dabb
--- /dev/null
@@ -0,0 +1,53 @@
+// Copyright 2019 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "absl/base/internal/periodic_sampler.h"
+
+#include <atomic>
+
+#include "absl/base/internal/exponential_biased.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace base_internal {
+
+int64_t PeriodicSamplerBase::GetExponentialBiased(int period) noexcept {
+  return rng_.GetStride(period);
+}
+
+bool PeriodicSamplerBase::SubtleConfirmSample() noexcept {
+  int current_period = period();
+
+  // Deal with period case 0 (always off) and 1 (always on)
+  if (ABSL_PREDICT_FALSE(current_period < 2)) {
+    stride_ = 0;
+    return current_period == 1;
+  }
+
+  // Check if this is the first call to Sample()
+  if (ABSL_PREDICT_FALSE(stride_ == 1)) {
+    stride_ = static_cast<uint64_t>(-GetExponentialBiased(current_period));
+    if (static_cast<int64_t>(stride_) < -1) {
+      ++stride_;
+      return false;
+    }
+  }
+
+  stride_ = static_cast<uint64_t>(-GetExponentialBiased(current_period));
+  return true;
+}
+
+}  // namespace base_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
diff --git a/src/absl/base/internal/periodic_sampler.h b/src/absl/base/internal/periodic_sampler.h
new file mode 100644 (file)
index 0000000..f8a8679
--- /dev/null
@@ -0,0 +1,211 @@
+// Copyright 2019 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef ABSL_BASE_INTERNAL_PERIODIC_SAMPLER_H_
+#define ABSL_BASE_INTERNAL_PERIODIC_SAMPLER_H_
+
+#include <stdint.h>
+
+#include <atomic>
+
+#include "absl/base/internal/exponential_biased.h"
+#include "absl/base/optimization.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace base_internal {
+
+// PeriodicSamplerBase provides the basic period sampler implementation.
+//
+// This is the base class for the templated PeriodicSampler class, which holds
+// a global std::atomic value identified by a user defined tag, such that
+// each specific PeriodSampler implementation holds its own global period.
+//
+// PeriodicSamplerBase is thread-compatible except where stated otherwise.
+class PeriodicSamplerBase {
+ public:
+  // PeriodicSamplerBase is trivial / copyable / movable / destructible.
+  PeriodicSamplerBase() = default;
+  PeriodicSamplerBase(PeriodicSamplerBase&&) = default;
+  PeriodicSamplerBase(const PeriodicSamplerBase&) = default;
+
+  // Returns true roughly once every `period` calls. This is established by a
+  // randomly picked `stride` that is counted down on each call to `Sample`.
+  // This stride is picked such that the probability of `Sample()` returning
+  // true is 1 in `period`.
+  inline bool Sample() noexcept;
+
+  // The below methods are intended for optimized use cases where the
+  // size of the inlined fast path code is highly important. Applications
+  // should use the `Sample()` method unless they have proof that their
+  // specific use case requires the optimizations offered by these methods.
+  //
+  // An example of such a use case is SwissTable sampling. All sampling checks
+  // are in inlined SwissTable methods, and the number of call sites is huge.
+  // In this case, the inlined code size added to each translation unit calling
+  // SwissTable methods is non-trivial.
+  //
+  // The `SubtleMaybeSample()` function spuriously returns true even if the
+  // function should not be sampled, applications MUST match each call to
+  // 'SubtleMaybeSample()' returning true with a `SubtleConfirmSample()` call,
+  // and use the result of the latter as the sampling decision.
+  // In other words: the code should logically be equivalent to:
+  //
+  //    if (SubtleMaybeSample() && SubtleConfirmSample()) {
+  //      // Sample this call
+  //    }
+  //
+  // In the 'inline-size' optimized case, the `SubtleConfirmSample()` call can
+  // be placed out of line, for example, the typical use case looks as follows:
+  //
+  //   // --- frobber.h -----------
+  //   void FrobberSampled();
+  //
+  //   inline void FrobberImpl() {
+  //     // ...
+  //   }
+  //
+  //   inline void Frobber() {
+  //     if (ABSL_PREDICT_FALSE(sampler.SubtleMaybeSample())) {
+  //       FrobberSampled();
+  //     } else {
+  //       FrobberImpl();
+  //     }
+  //   }
+  //
+  //   // --- frobber.cc -----------
+  //   void FrobberSampled() {
+  //     if (!sampler.SubtleConfirmSample())) {
+  //       // Spurious false positive
+  //       FrobberImpl();
+  //       return;
+  //     }
+  //
+  //     // Sampled execution
+  //     // ...
+  //   }
+  inline bool SubtleMaybeSample() noexcept;
+  bool SubtleConfirmSample() noexcept;
+
+ protected:
+  // We explicitly don't use a virtual destructor as this class is never
+  // virtually destroyed, and it keeps the class trivial, which avoids TLS
+  // prologue and epilogue code for our TLS instances.
+  ~PeriodicSamplerBase() = default;
+
+  // Returns the next stride for our sampler.
+  // This function is virtual for testing purposes only.
+  virtual int64_t GetExponentialBiased(int period) noexcept;
+
+ private:
+  // Returns the current period of this sampler. Thread-safe.
+  virtual int period() const noexcept = 0;
+
+  // Keep and decrement stride_ as an unsigned integer, but compare the value
+  // to zero casted as a signed int. clang and msvc do not create optimum code
+  // if we use signed for the combined decrement and sign comparison.
+  //
+  // Below 3 alternative options, all compiles generate the best code
+  // using the unsigned increment <---> signed int comparison option.
+  //
+  // Option 1:
+  //   int64_t stride_;
+  //   if (ABSL_PREDICT_TRUE(++stride_ < 0)) { ... }
+  //
+  //   GCC   x64 (OK) : https://gcc.godbolt.org/z/R5MzzA
+  //   GCC   ppc (OK) : https://gcc.godbolt.org/z/z7NZAt
+  //   Clang x64 (BAD): https://gcc.godbolt.org/z/t4gPsd
+  //   ICC   x64 (OK) : https://gcc.godbolt.org/z/rE6s8W
+  //   MSVC  x64 (OK) : https://gcc.godbolt.org/z/ARMXqS
+  //
+  // Option 2:
+  //   int64_t stride_ = 0;
+  //   if (ABSL_PREDICT_TRUE(--stride_ >= 0)) { ... }
+  //
+  //   GCC   x64 (OK) : https://gcc.godbolt.org/z/jSQxYK
+  //   GCC   ppc (OK) : https://gcc.godbolt.org/z/VJdYaA
+  //   Clang x64 (BAD): https://gcc.godbolt.org/z/Xm4NjX
+  //   ICC   x64 (OK) : https://gcc.godbolt.org/z/4snaFd
+  //   MSVC  x64 (BAD): https://gcc.godbolt.org/z/BgnEKE
+  //
+  // Option 3:
+  //   uint64_t stride_;
+  //   if (ABSL_PREDICT_TRUE(static_cast<int64_t>(++stride_) < 0)) { ... }
+  //
+  //   GCC   x64 (OK) : https://gcc.godbolt.org/z/bFbfPy
+  //   GCC   ppc (OK) : https://gcc.godbolt.org/z/S9KkUE
+  //   Clang x64 (OK) : https://gcc.godbolt.org/z/UYzRb4
+  //   ICC   x64 (OK) : https://gcc.godbolt.org/z/ptTNfD
+  //   MSVC  x64 (OK) : https://gcc.godbolt.org/z/76j4-5
+  uint64_t stride_ = 0;
+  ExponentialBiased rng_;
+};
+
+inline bool PeriodicSamplerBase::SubtleMaybeSample() noexcept {
+  // See comments on `stride_` for the unsigned increment / signed compare.
+  if (ABSL_PREDICT_TRUE(static_cast<int64_t>(++stride_) < 0)) {
+    return false;
+  }
+  return true;
+}
+
+inline bool PeriodicSamplerBase::Sample() noexcept {
+  return ABSL_PREDICT_FALSE(SubtleMaybeSample()) ? SubtleConfirmSample()
+                                                 : false;
+}
+
+// PeriodicSampler is a concreted periodic sampler implementation.
+// The user provided Tag identifies the implementation, and is required to
+// isolate the global state of this instance from other instances.
+//
+// Typical use case:
+//
+//   struct HashTablezTag {};
+//   thread_local PeriodicSampler sampler;
+//
+//   void HashTableSamplingLogic(...) {
+//     if (sampler.Sample()) {
+//       HashTableSlowSamplePath(...);
+//     }
+//   }
+//
+template <typename Tag, int default_period = 0>
+class PeriodicSampler final : public PeriodicSamplerBase {
+ public:
+  ~PeriodicSampler() = default;
+
+  int period() const noexcept final {
+    return period_.load(std::memory_order_relaxed);
+  }
+
+  // Sets the global period for this sampler. Thread-safe.
+  // Setting a period of 0 disables the sampler, i.e., every call to Sample()
+  // will return false. Setting a period of 1 puts the sampler in 'always on'
+  // mode, i.e., every call to Sample() returns true.
+  static void SetGlobalPeriod(int period) {
+    period_.store(period, std::memory_order_relaxed);
+  }
+
+ private:
+  static std::atomic<int> period_;
+};
+
+template <typename Tag, int default_period>
+std::atomic<int> PeriodicSampler<Tag, default_period>::period_(default_period);
+
+}  // namespace base_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#endif  // ABSL_BASE_INTERNAL_PERIODIC_SAMPLER_H_
diff --git a/src/absl/base/internal/pretty_function.h b/src/absl/base/internal/pretty_function.h
new file mode 100644 (file)
index 0000000..35d5167
--- /dev/null
@@ -0,0 +1,33 @@
+// Copyright 2017 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef ABSL_BASE_INTERNAL_PRETTY_FUNCTION_H_
+#define ABSL_BASE_INTERNAL_PRETTY_FUNCTION_H_
+
+// ABSL_PRETTY_FUNCTION
+//
+// In C++11, __func__ gives the undecorated name of the current function.  That
+// is, "main", not "int main()".  Various compilers give extra macros to get the
+// decorated function name, including return type and arguments, to
+// differentiate between overload sets.  ABSL_PRETTY_FUNCTION is a portable
+// version of these macros which forwards to the correct macro on each compiler.
+#if defined(_MSC_VER)
+#define ABSL_PRETTY_FUNCTION __FUNCSIG__
+#elif defined(__GNUC__)
+#define ABSL_PRETTY_FUNCTION __PRETTY_FUNCTION__
+#else
+#error "Unsupported compiler"
+#endif
+
+#endif  // ABSL_BASE_INTERNAL_PRETTY_FUNCTION_H_
diff --git a/src/absl/base/internal/raw_logging.cc b/src/absl/base/internal/raw_logging.cc
new file mode 100644 (file)
index 0000000..985efec
--- /dev/null
@@ -0,0 +1,245 @@
+#include "cpp-compat.h"
+// Copyright 2017 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "absl/base/internal/raw_logging.h"
+
+#include <stddef.h>
+#include <cstdarg>
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
+
+#include "absl/base/attributes.h"
+#include "absl/base/config.h"
+#include "absl/base/internal/atomic_hook.h"
+#include "absl/base/log_severity.h"
+
+// We know how to perform low-level writes to stderr in POSIX and Windows.  For
+// these platforms, we define the token ABSL_LOW_LEVEL_WRITE_SUPPORTED.
+// Much of raw_logging.cc becomes a no-op when we can't output messages,
+// although a FATAL ABSL_RAW_LOG message will still abort the process.
+
+// ABSL_HAVE_POSIX_WRITE is defined when the platform provides posix write()
+// (as from unistd.h)
+//
+// This preprocessor token is also defined in raw_io.cc.  If you need to copy
+// this, consider moving both to config.h instead.
+#if defined(__linux__) || defined(__APPLE__) || defined(__FreeBSD__) || \
+    defined(__Fuchsia__) || defined(__native_client__) || \
+    defined(__EMSCRIPTEN__) || defined(__ASYLO__)
+
+#include <unistd.h>
+
+#define ABSL_HAVE_POSIX_WRITE 1
+#define ABSL_LOW_LEVEL_WRITE_SUPPORTED 1
+#else
+#undef ABSL_HAVE_POSIX_WRITE
+#endif
+
+// ABSL_HAVE_SYSCALL_WRITE is defined when the platform provides the syscall
+//   syscall(SYS_write, /*int*/ fd, /*char* */ buf, /*size_t*/ len);
+// for low level operations that want to avoid libc.
+#if (defined(__linux__) || defined(__FreeBSD__)) && !defined(__ANDROID__)
+#include <sys/syscall.h>
+#define ABSL_HAVE_SYSCALL_WRITE 1
+#define ABSL_LOW_LEVEL_WRITE_SUPPORTED 1
+#else
+#undef ABSL_HAVE_SYSCALL_WRITE
+#endif
+
+#ifdef _WIN32
+#include <io.h>
+
+#define ABSL_HAVE_RAW_IO 1
+#define ABSL_LOW_LEVEL_WRITE_SUPPORTED 1
+#else
+#undef ABSL_HAVE_RAW_IO
+#endif
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace raw_logging_internal {
+namespace {
+
+// TODO(gfalcon): We want raw-logging to work on as many platforms as possible.
+// Explicitly `#error` out when not `ABSL_LOW_LEVEL_WRITE_SUPPORTED`, except for
+// a selected set of platforms for which we expect not to be able to raw log.
+
+ABSL_INTERNAL_ATOMIC_HOOK_ATTRIBUTES
+    absl::base_internal::AtomicHook<LogPrefixHook>
+        log_prefix_hook;
+ABSL_INTERNAL_ATOMIC_HOOK_ATTRIBUTES
+    absl::base_internal::AtomicHook<AbortHook>
+        abort_hook;
+
+#ifdef ABSL_LOW_LEVEL_WRITE_SUPPORTED
+constexpr char kTruncated[] = " ... (message truncated)\n";
+
+// sprintf the format to the buffer, adjusting *buf and *size to reflect the
+// consumed bytes, and return whether the message fit without truncation.  If
+// truncation occurred, if possible leave room in the buffer for the message
+// kTruncated[].
+bool VADoRawLog(char** buf, int* size, const char* format, va_list ap)
+    ABSL_PRINTF_ATTRIBUTE(3, 0);
+bool VADoRawLog(char** buf, int* size, const char* format, va_list ap) {
+  int n = vsnprintf(*buf, *size, format, ap);
+  bool result = true;
+  if (n < 0 || n > *size) {
+    result = false;
+    if (static_cast<size_t>(*size) > sizeof(kTruncated)) {
+      n = *size - sizeof(kTruncated);  // room for truncation message
+    } else {
+      n = 0;  // no room for truncation message
+    }
+  }
+  *size -= n;
+  *buf += n;
+  return result;
+}
+#endif  // ABSL_LOW_LEVEL_WRITE_SUPPORTED
+
+constexpr int kLogBufSize = 3000;
+
+// CAVEAT: vsnprintf called from *DoRawLog below has some (exotic) code paths
+// that invoke malloc() and getenv() that might acquire some locks.
+
+// Helper for RawLog below.
+// *DoRawLog writes to *buf of *size and move them past the written portion.
+// It returns true iff there was no overflow or error.
+bool DoRawLog(char** buf, int* size, const char* format, ...)
+    ABSL_PRINTF_ATTRIBUTE(3, 4);
+bool DoRawLog(char** buf, int* size, const char* format, ...) {
+  va_list ap;
+  va_start(ap, format);
+  int n = vsnprintf(*buf, *size, format, ap);
+  va_end(ap);
+  if (n < 0 || n > *size) return false;
+  *size -= n;
+  *buf += n;
+  return true;
+}
+
+void RawLogVA(absl::LogSeverity severity, const char* file, int line,
+              const char* format, va_list ap) ABSL_PRINTF_ATTRIBUTE(4, 0);
+void RawLogVA(absl::LogSeverity severity, const char* file, int line,
+              const char* format, va_list ap) {
+  char buffer[kLogBufSize];
+  char* buf = buffer;
+  int size = sizeof(buffer);
+#ifdef ABSL_LOW_LEVEL_WRITE_SUPPORTED
+  bool enabled = true;
+#else
+  bool enabled = false;
+#endif
+
+#ifdef ABSL_MIN_LOG_LEVEL
+  if (severity < static_cast<absl::LogSeverity>(ABSL_MIN_LOG_LEVEL) &&
+      severity < absl::LogSeverity::kFatal) {
+    enabled = false;
+  }
+#endif
+
+  auto log_prefix_hook_ptr = log_prefix_hook.Load();
+  if (log_prefix_hook_ptr) {
+    enabled = log_prefix_hook_ptr(severity, file, line, &buf, &size);
+  } else {
+    if (enabled) {
+      DoRawLog(&buf, &size, "[%s : %d] RAW: ", file, line);
+    }
+  }
+  const char* const prefix_end = buf;
+
+#ifdef ABSL_LOW_LEVEL_WRITE_SUPPORTED
+  if (enabled) {
+    bool no_chop = VADoRawLog(&buf, &size, format, ap);
+    if (no_chop) {
+      DoRawLog(&buf, &size, "\n");
+    } else {
+      DoRawLog(&buf, &size, "%s", kTruncated);
+    }
+    SafeWriteToStderr(buffer, strlen(buffer));
+  }
+#else
+  static_cast<void>(format);
+  static_cast<void>(ap);
+#endif
+
+  // Abort the process after logging a FATAL message, even if the output itself
+  // was suppressed.
+  if (severity == absl::LogSeverity::kFatal) {
+    abort_hook(file, line, buffer, prefix_end, buffer + kLogBufSize);
+    // dd: R CMD check will fail if abort() is used
+    // abort();
+    cpp_compat_abort();
+  }
+}
+
+// Non-formatting version of RawLog().
+//
+// TODO(gfalcon): When string_view no longer depends on base, change this
+// interface to take its message as a string_view instead.
+void DefaultInternalLog(absl::LogSeverity severity, const char* file, int line,
+                        const std::string& message) {
+  RawLog(severity, file, line, "%.*s", static_cast<int>(message.size()),
+         message.data());
+}
+
+}  // namespace
+
+void SafeWriteToStderr(const char *s, size_t len) {
+#if defined(ABSL_HAVE_SYSCALL_WRITE)
+  syscall(SYS_write, STDERR_FILENO, s, len);
+#elif defined(ABSL_HAVE_POSIX_WRITE)
+  write(STDERR_FILENO, s, len);
+#elif defined(ABSL_HAVE_RAW_IO)
+  _write(/* stderr */ 2, s, len);
+#else
+  // stderr logging unsupported on this platform
+  (void) s;
+  (void) len;
+#endif
+}
+
+void RawLog(absl::LogSeverity severity, const char* file, int line,
+            const char* format, ...) {
+  va_list ap;
+  va_start(ap, format);
+  RawLogVA(severity, file, line, format, ap);
+  va_end(ap);
+}
+
+bool RawLoggingFullySupported() {
+#ifdef ABSL_LOW_LEVEL_WRITE_SUPPORTED
+  return true;
+#else  // !ABSL_LOW_LEVEL_WRITE_SUPPORTED
+  return false;
+#endif  // !ABSL_LOW_LEVEL_WRITE_SUPPORTED
+}
+
+ABSL_INTERNAL_ATOMIC_HOOK_ATTRIBUTES ABSL_DLL
+    absl::base_internal::AtomicHook<InternalLogFunction>
+        internal_log_function(DefaultInternalLog);
+
+void RegisterLogPrefixHook(LogPrefixHook func) { log_prefix_hook.Store(func); }
+
+void RegisterAbortHook(AbortHook func) { abort_hook.Store(func); }
+
+void RegisterInternalLogFunction(InternalLogFunction func) {
+  internal_log_function.Store(func);
+}
+
+}  // namespace raw_logging_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
diff --git a/src/absl/base/internal/raw_logging.h b/src/absl/base/internal/raw_logging.h
new file mode 100644 (file)
index 0000000..47d7af8
--- /dev/null
@@ -0,0 +1,205 @@
+// Copyright 2017 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// Thread-safe logging routines that do not allocate any memory or
+// acquire any locks, and can therefore be used by low-level memory
+// allocation, synchronization, and signal-handling code.
+
+#ifndef ABSL_BASE_INTERNAL_RAW_LOGGING_H_
+#define ABSL_BASE_INTERNAL_RAW_LOGGING_H_
+
+#include <string>
+
+#include "absl/base/attributes.h"
+#include "absl/base/config.h"
+#include "absl/base/internal/atomic_hook.h"
+#include "absl/base/log_severity.h"
+#include "absl/base/macros.h"
+#include "absl/base/optimization.h"
+#include "absl/base/port.h"
+
+// This is similar to LOG(severity) << format..., but
+// * it is to be used ONLY by low-level modules that can't use normal LOG()
+// * it is designed to be a low-level logger that does not allocate any
+//   memory and does not need any locks, hence:
+// * it logs straight and ONLY to STDERR w/o buffering
+// * it uses an explicit printf-format and arguments list
+// * it will silently chop off really long message strings
+// Usage example:
+//   ABSL_RAW_LOG(ERROR, "Failed foo with %i: %s", status, error);
+// This will print an almost standard log line like this to stderr only:
+//   E0821 211317 file.cc:123] RAW: Failed foo with 22: bad_file
+
+// __VA_ARGS__ isn't passed along properly on Windows and we don't ever log
+// to stderr because R CMD check won't let us; so ignore log messages.
+#ifdef _WIN32
+
+#define ABSL_RAW_LOG(severity, ...)
+
+#else
+
+#define ABSL_RAW_LOG(severity, ...)                                            \
+  do {                                                                         \
+    constexpr const char* absl_raw_logging_internal_basename =                 \
+        ::absl::raw_logging_internal::Basename(__FILE__,                       \
+                                               sizeof(__FILE__) - 1);          \
+    ::absl::raw_logging_internal::RawLog(ABSL_RAW_LOGGING_INTERNAL_##severity, \
+                                         absl_raw_logging_internal_basename,   \
+                                         __LINE__, __VA_ARGS__);               \
+  } while (0)                                                  \
+
+#endif
+
+// Similar to CHECK(condition) << message, but for low-level modules:
+// we use only ABSL_RAW_LOG that does not allocate memory.
+// We do not want to provide args list here to encourage this usage:
+//   if (!cond)  ABSL_RAW_LOG(FATAL, "foo ...", hard_to_compute_args);
+// so that the args are not computed when not needed.
+#define ABSL_RAW_CHECK(condition, message)                             \
+  do {                                                                 \
+    if (ABSL_PREDICT_FALSE(!(condition))) {                            \
+      ABSL_RAW_LOG(FATAL, "Check %s failed: %s", #condition, message); \
+    }                                                                  \
+  } while (0)
+
+// ABSL_INTERNAL_LOG and ABSL_INTERNAL_CHECK work like the RAW variants above,
+// except that if the richer log library is linked into the binary, we dispatch
+// to that instead.  This is potentially useful for internal logging and
+// assertions, where we are using RAW_LOG neither for its async-signal-safety
+// nor for its non-allocating nature, but rather because raw logging has very
+// few other dependencies.
+//
+// The API is a subset of the above: each macro only takes two arguments.  Use
+// StrCat if you need to build a richer message.
+#define ABSL_INTERNAL_LOG(severity, message)                                 \
+  do {                                                                       \
+    constexpr const char* absl_raw_logging_internal_filename = __FILE__;     \
+    ::absl::raw_logging_internal::internal_log_function(                     \
+        ABSL_RAW_LOGGING_INTERNAL_##severity,                                \
+        absl_raw_logging_internal_filename, __LINE__, message);              \
+    if (ABSL_RAW_LOGGING_INTERNAL_##severity == ::absl::LogSeverity::kFatal) \
+      ABSL_INTERNAL_UNREACHABLE;                                             \
+  } while (0)
+
+#define ABSL_INTERNAL_CHECK(condition, message)                    \
+  do {                                                             \
+    if (ABSL_PREDICT_FALSE(!(condition))) {                        \
+      std::string death_message = "Check " #condition " failed: "; \
+      death_message += std::string(message);                       \
+      ABSL_INTERNAL_LOG(FATAL, death_message);                     \
+    }                                                              \
+  } while (0)
+
+#define ABSL_RAW_LOGGING_INTERNAL_INFO ::absl::LogSeverity::kInfo
+#define ABSL_RAW_LOGGING_INTERNAL_WARNING ::absl::LogSeverity::kWarning
+#define ABSL_RAW_LOGGING_INTERNAL_ERROR ::absl::LogSeverity::kError
+#define ABSL_RAW_LOGGING_INTERNAL_FATAL ::absl::LogSeverity::kFatal
+#define ABSL_RAW_LOGGING_INTERNAL_LEVEL(severity) \
+  ::absl::NormalizeLogSeverity(severity)
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace raw_logging_internal {
+
+// Helper function to implement ABSL_RAW_LOG
+// Logs format... at "severity" level, reporting it
+// as called from file:line.
+// This does not allocate memory or acquire locks.
+void RawLog(absl::LogSeverity severity, const char* file, int line,
+            const char* format, ...) ABSL_PRINTF_ATTRIBUTE(4, 5);
+
+// Writes the provided buffer directly to stderr, in a safe, low-level manner.
+//
+// In POSIX this means calling write(), which is async-signal safe and does
+// not malloc.  If the platform supports the SYS_write syscall, we invoke that
+// directly to side-step any libc interception.
+void SafeWriteToStderr(const char *s, size_t len);
+
+// compile-time function to get the "base" filename, that is, the part of
+// a filename after the last "/" or "\" path separator.  The search starts at
+// the end of the string; the second parameter is the length of the string.
+constexpr const char* Basename(const char* fname, int offset) {
+  return offset == 0 || fname[offset - 1] == '/' || fname[offset - 1] == '\\'
+             ? fname + offset
+             : Basename(fname, offset - 1);
+}
+
+// For testing only.
+// Returns true if raw logging is fully supported. When it is not
+// fully supported, no messages will be emitted, but a log at FATAL
+// severity will cause an abort.
+//
+// TODO(gfalcon): Come up with a better name for this method.
+bool RawLoggingFullySupported();
+
+// Function type for a raw_logging customization hook for suppressing messages
+// by severity, and for writing custom prefixes on non-suppressed messages.
+//
+// The installed hook is called for every raw log invocation.  The message will
+// be logged to stderr only if the hook returns true.  FATAL errors will cause
+// the process to abort, even if writing to stderr is suppressed.  The hook is
+// also provided with an output buffer, where it can write a custom log message
+// prefix.
+//
+// The raw_logging system does not allocate memory or grab locks.  User-provided
+// hooks must avoid these operations, and must not throw exceptions.
+//
+// 'severity' is the severity level of the message being written.
+// 'file' and 'line' are the file and line number where the ABSL_RAW_LOG macro
+// was located.
+// 'buffer' and 'buf_size' are pointers to the buffer and buffer size.  If the
+// hook writes a prefix, it must increment *buffer and decrement *buf_size
+// accordingly.
+using LogPrefixHook = bool (*)(absl::LogSeverity severity, const char* file,
+                               int line, char** buffer, int* buf_size);
+
+// Function type for a raw_logging customization hook called to abort a process
+// when a FATAL message is logged.  If the provided AbortHook() returns, the
+// logging system will call abort().
+//
+// 'file' and 'line' are the file and line number where the ABSL_RAW_LOG macro
+// was located.
+// The NUL-terminated logged message lives in the buffer between 'buf_start'
+// and 'buf_end'.  'prefix_end' points to the first non-prefix character of the
+// buffer (as written by the LogPrefixHook.)
+using AbortHook = void (*)(const char* file, int line, const char* buf_start,
+                           const char* prefix_end, const char* buf_end);
+
+// Internal logging function for ABSL_INTERNAL_LOG to dispatch to.
+//
+// TODO(gfalcon): When string_view no longer depends on base, change this
+// interface to take its message as a string_view instead.
+using InternalLogFunction = void (*)(absl::LogSeverity severity,
+                                     const char* file, int line,
+                                     const std::string& message);
+
+ABSL_INTERNAL_ATOMIC_HOOK_ATTRIBUTES ABSL_DLL extern base_internal::AtomicHook<
+    InternalLogFunction>
+    internal_log_function;
+
+// Registers hooks of the above types.  Only a single hook of each type may be
+// registered.  It is an error to call these functions multiple times with
+// different input arguments.
+//
+// These functions are safe to call at any point during initialization; they do
+// not block or malloc, and are async-signal safe.
+void RegisterLogPrefixHook(LogPrefixHook func);
+void RegisterAbortHook(AbortHook func);
+void RegisterInternalLogFunction(InternalLogFunction func);
+
+}  // namespace raw_logging_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#endif  // ABSL_BASE_INTERNAL_RAW_LOGGING_H_
diff --git a/src/absl/base/internal/scheduling_mode.h b/src/absl/base/internal/scheduling_mode.h
new file mode 100644 (file)
index 0000000..8be5ab6
--- /dev/null
@@ -0,0 +1,58 @@
+// Copyright 2017 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// Core interfaces and definitions used by by low-level interfaces such as
+// SpinLock.
+
+#ifndef ABSL_BASE_INTERNAL_SCHEDULING_MODE_H_
+#define ABSL_BASE_INTERNAL_SCHEDULING_MODE_H_
+
+#include "absl/base/config.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace base_internal {
+
+// Used to describe how a thread may be scheduled.  Typically associated with
+// the declaration of a resource supporting synchronized access.
+//
+// SCHEDULE_COOPERATIVE_AND_KERNEL:
+// Specifies that when waiting, a cooperative thread (e.g. a Fiber) may
+// reschedule (using base::scheduling semantics); allowing other cooperative
+// threads to proceed.
+//
+// SCHEDULE_KERNEL_ONLY: (Also described as "non-cooperative")
+// Specifies that no cooperative scheduling semantics may be used, even if the
+// current thread is itself cooperatively scheduled.  This means that
+// cooperative threads will NOT allow other cooperative threads to execute in
+// their place while waiting for a resource of this type.  Host operating system
+// semantics (e.g. a futex) may still be used.
+//
+// When optional, clients should strongly prefer SCHEDULE_COOPERATIVE_AND_KERNEL
+// by default.  SCHEDULE_KERNEL_ONLY should only be used for resources on which
+// base::scheduling (e.g. the implementation of a Scheduler) may depend.
+//
+// NOTE: Cooperative resources may not be nested below non-cooperative ones.
+// This means that it is invalid to to acquire a SCHEDULE_COOPERATIVE_AND_KERNEL
+// resource if a SCHEDULE_KERNEL_ONLY resource is already held.
+enum SchedulingMode {
+  SCHEDULE_KERNEL_ONLY = 0,         // Allow scheduling only the host OS.
+  SCHEDULE_COOPERATIVE_AND_KERNEL,  // Also allow cooperative scheduling.
+};
+
+}  // namespace base_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#endif  // ABSL_BASE_INTERNAL_SCHEDULING_MODE_H_
diff --git a/src/absl/base/internal/scoped_set_env.cc b/src/absl/base/internal/scoped_set_env.cc
new file mode 100644 (file)
index 0000000..8a934cb
--- /dev/null
@@ -0,0 +1,81 @@
+// Copyright 2019 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "absl/base/internal/scoped_set_env.h"
+
+#ifdef _WIN32
+#include <windows.h>
+#endif
+
+#include <cstdlib>
+
+#include "absl/base/internal/raw_logging.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace base_internal {
+
+namespace {
+
+#ifdef _WIN32
+const int kMaxEnvVarValueSize = 1024;
+#endif
+
+void SetEnvVar(const char* name, const char* value) {
+#ifdef _WIN32
+  SetEnvironmentVariableA(name, value);
+#else
+  if (value == nullptr) {
+    ::unsetenv(name);
+  } else {
+    ::setenv(name, value, 1);
+  }
+#endif
+}
+
+}  // namespace
+
+ScopedSetEnv::ScopedSetEnv(const char* var_name, const char* new_value)
+    : var_name_(var_name), was_unset_(false) {
+#ifdef _WIN32
+  char buf[kMaxEnvVarValueSize];
+  auto get_res = GetEnvironmentVariableA(var_name_.c_str(), buf, sizeof(buf));
+  ABSL_INTERNAL_CHECK(get_res < sizeof(buf), "value exceeds buffer size");
+
+  if (get_res == 0) {
+    was_unset_ = (GetLastError() == ERROR_ENVVAR_NOT_FOUND);
+  } else {
+    old_value_.assign(buf, get_res);
+  }
+
+  SetEnvironmentVariableA(var_name_.c_str(), new_value);
+#else
+  const char* val = ::getenv(var_name_.c_str());
+  if (val == nullptr) {
+    was_unset_ = true;
+  } else {
+    old_value_ = val;
+  }
+#endif
+
+  SetEnvVar(var_name_.c_str(), new_value);
+}
+
+ScopedSetEnv::~ScopedSetEnv() {
+  SetEnvVar(var_name_.c_str(), was_unset_ ? nullptr : old_value_.c_str());
+}
+
+}  // namespace base_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
diff --git a/src/absl/base/internal/scoped_set_env.h b/src/absl/base/internal/scoped_set_env.h
new file mode 100644 (file)
index 0000000..19ec7b5
--- /dev/null
@@ -0,0 +1,45 @@
+//
+// Copyright 2019 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#ifndef ABSL_BASE_INTERNAL_SCOPED_SET_ENV_H_
+#define ABSL_BASE_INTERNAL_SCOPED_SET_ENV_H_
+
+#include <string>
+
+#include "absl/base/config.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace base_internal {
+
+class ScopedSetEnv {
+ public:
+  ScopedSetEnv(const char* var_name, const char* new_value);
+  ~ScopedSetEnv();
+
+ private:
+  std::string var_name_;
+  std::string old_value_;
+
+  // True if the environment variable was initially not set.
+  bool was_unset_;
+};
+
+}  // namespace base_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#endif  // ABSL_BASE_INTERNAL_SCOPED_SET_ENV_H_
diff --git a/src/absl/base/internal/spinlock.cc b/src/absl/base/internal/spinlock.cc
new file mode 100644 (file)
index 0000000..35c0696
--- /dev/null
@@ -0,0 +1,229 @@
+// Copyright 2017 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "absl/base/internal/spinlock.h"
+
+#include <algorithm>
+#include <atomic>
+#include <limits>
+
+#include "absl/base/attributes.h"
+#include "absl/base/internal/atomic_hook.h"
+#include "absl/base/internal/cycleclock.h"
+#include "absl/base/internal/spinlock_wait.h"
+#include "absl/base/internal/sysinfo.h" /* For NumCPUs() */
+#include "absl/base/call_once.h"
+
+// Description of lock-word:
+//  31..00: [............................3][2][1][0]
+//
+//     [0]: kSpinLockHeld
+//     [1]: kSpinLockCooperative
+//     [2]: kSpinLockDisabledScheduling
+// [31..3]: ONLY kSpinLockSleeper OR
+//          Wait time in cycles >> PROFILE_TIMESTAMP_SHIFT
+//
+// Detailed descriptions:
+//
+// Bit [0]: The lock is considered held iff kSpinLockHeld is set.
+//
+// Bit [1]: Eligible waiters (e.g. Fibers) may co-operatively reschedule when
+//          contended iff kSpinLockCooperative is set.
+//
+// Bit [2]: This bit is exclusive from bit [1].  It is used only by a
+//          non-cooperative lock.  When set, indicates that scheduling was
+//          successfully disabled when the lock was acquired.  May be unset,
+//          even if non-cooperative, if a ThreadIdentity did not yet exist at
+//          time of acquisition.
+//
+// Bit [3]: If this is the only upper bit ([31..3]) set then this lock was
+//          acquired without contention, however, at least one waiter exists.
+//
+//          Otherwise, bits [31..3] represent the time spent by the current lock
+//          holder to acquire the lock.  There may be outstanding waiter(s).
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace base_internal {
+
+ABSL_INTERNAL_ATOMIC_HOOK_ATTRIBUTES static base_internal::AtomicHook<void (*)(
+    const void *lock, int64_t wait_cycles)>
+    submit_profile_data;
+
+void RegisterSpinLockProfiler(void (*fn)(const void *contendedlock,
+                                         int64_t wait_cycles)) {
+  submit_profile_data.Store(fn);
+}
+
+// Static member variable definitions.
+constexpr uint32_t SpinLock::kSpinLockHeld;
+constexpr uint32_t SpinLock::kSpinLockCooperative;
+constexpr uint32_t SpinLock::kSpinLockDisabledScheduling;
+constexpr uint32_t SpinLock::kSpinLockSleeper;
+constexpr uint32_t SpinLock::kWaitTimeMask;
+
+// Uncommon constructors.
+SpinLock::SpinLock(base_internal::SchedulingMode mode)
+    : lockword_(IsCooperative(mode) ? kSpinLockCooperative : 0) {
+  ABSL_TSAN_MUTEX_CREATE(this, __tsan_mutex_not_static);
+}
+
+// Monitor the lock to see if its value changes within some time period
+// (adaptive_spin_count loop iterations). The last value read from the lock
+// is returned from the method.
+uint32_t SpinLock::SpinLoop() {
+  // We are already in the slow path of SpinLock, initialize the
+  // adaptive_spin_count here.
+  ABSL_CONST_INIT static absl::once_flag init_adaptive_spin_count;
+  ABSL_CONST_INIT static int adaptive_spin_count = 0;
+  base_internal::LowLevelCallOnce(&init_adaptive_spin_count, []() {
+    adaptive_spin_count = base_internal::NumCPUs() > 1 ? 1000 : 1;
+  });
+
+  int c = adaptive_spin_count;
+  uint32_t lock_value;
+  do {
+    lock_value = lockword_.load(std::memory_order_relaxed);
+  } while ((lock_value & kSpinLockHeld) != 0 && --c > 0);
+  return lock_value;
+}
+
+void SpinLock::SlowLock() {
+  uint32_t lock_value = SpinLoop();
+  lock_value = TryLockInternal(lock_value, 0);
+  if ((lock_value & kSpinLockHeld) == 0) {
+    return;
+  }
+
+  base_internal::SchedulingMode scheduling_mode;
+  if ((lock_value & kSpinLockCooperative) != 0) {
+    scheduling_mode = base_internal::SCHEDULE_COOPERATIVE_AND_KERNEL;
+  } else {
+    scheduling_mode = base_internal::SCHEDULE_KERNEL_ONLY;
+  }
+
+  // The lock was not obtained initially, so this thread needs to wait for
+  // it.  Record the current timestamp in the local variable wait_start_time
+  // so the total wait time can be stored in the lockword once this thread
+  // obtains the lock.
+  int64_t wait_start_time = CycleClock::Now();
+  uint32_t wait_cycles = 0;
+  int lock_wait_call_count = 0;
+  while ((lock_value & kSpinLockHeld) != 0) {
+    // If the lock is currently held, but not marked as having a sleeper, mark
+    // it as having a sleeper.
+    if ((lock_value & kWaitTimeMask) == 0) {
+      // Here, just "mark" that the thread is going to sleep.  Don't store the
+      // lock wait time in the lock -- the lock word stores the amount of time
+      // that the current holder waited before acquiring the lock, not the wait
+      // time of any thread currently waiting to acquire it.
+      if (lockword_.compare_exchange_strong(
+              lock_value, lock_value | kSpinLockSleeper,
+              std::memory_order_relaxed, std::memory_order_relaxed)) {
+        // Successfully transitioned to kSpinLockSleeper.  Pass
+        // kSpinLockSleeper to the SpinLockWait routine to properly indicate
+        // the last lock_value observed.
+        lock_value |= kSpinLockSleeper;
+      } else if ((lock_value & kSpinLockHeld) == 0) {
+        // Lock is free again, so try and acquire it before sleeping.  The
+        // new lock state will be the number of cycles this thread waited if
+        // this thread obtains the lock.
+        lock_value = TryLockInternal(lock_value, wait_cycles);
+        continue;   // Skip the delay at the end of the loop.
+      } else if ((lock_value & kWaitTimeMask) == 0) {
+        // The lock is still held, without a waiter being marked, but something
+        // else about the lock word changed, causing our CAS to fail. For
+        // example, a new lock holder may have acquired the lock with
+        // kSpinLockDisabledScheduling set, whereas the previous holder had not
+        // set that flag. In this case, attempt again to mark ourselves as a
+        // waiter.
+        continue;
+      }
+    }
+
+    // SpinLockDelay() calls into fiber scheduler, we need to see
+    // synchronization there to avoid false positives.
+    ABSL_TSAN_MUTEX_PRE_DIVERT(this, 0);
+    // Wait for an OS specific delay.
+    base_internal::SpinLockDelay(&lockword_, lock_value, ++lock_wait_call_count,
+                                 scheduling_mode);
+    ABSL_TSAN_MUTEX_POST_DIVERT(this, 0);
+    // Spin again after returning from the wait routine to give this thread
+    // some chance of obtaining the lock.
+    lock_value = SpinLoop();
+    wait_cycles = EncodeWaitCycles(wait_start_time, CycleClock::Now());
+    lock_value = TryLockInternal(lock_value, wait_cycles);
+  }
+}
+
+void SpinLock::SlowUnlock(uint32_t lock_value) {
+  base_internal::SpinLockWake(&lockword_,
+                              false);  // wake waiter if necessary
+
+  // If our acquisition was contended, collect contentionz profile info.  We
+  // reserve a unitary wait time to represent that a waiter exists without our
+  // own acquisition having been contended.
+  if ((lock_value & kWaitTimeMask) != kSpinLockSleeper) {
+    const uint64_t wait_cycles = DecodeWaitCycles(lock_value);
+    ABSL_TSAN_MUTEX_PRE_DIVERT(this, 0);
+    submit_profile_data(this, wait_cycles);
+    ABSL_TSAN_MUTEX_POST_DIVERT(this, 0);
+  }
+}
+
+// We use the upper 29 bits of the lock word to store the time spent waiting to
+// acquire this lock.  This is reported by contentionz profiling.  Since the
+// lower bits of the cycle counter wrap very quickly on high-frequency
+// processors we divide to reduce the granularity to 2^kProfileTimestampShift
+// sized units.  On a 4Ghz machine this will lose track of wait times greater
+// than (2^29/4 Ghz)*128 =~ 17.2 seconds.  Such waits should be extremely rare.
+static constexpr int kProfileTimestampShift = 7;
+
+// We currently reserve the lower 3 bits.
+static constexpr int kLockwordReservedShift = 3;
+
+uint32_t SpinLock::EncodeWaitCycles(int64_t wait_start_time,
+                                    int64_t wait_end_time) {
+  static const int64_t kMaxWaitTime =
+      std::numeric_limits<uint32_t>::max() >> kLockwordReservedShift;
+  int64_t scaled_wait_time =
+      (wait_end_time - wait_start_time) >> kProfileTimestampShift;
+
+  // Return a representation of the time spent waiting that can be stored in
+  // the lock word's upper bits.
+  uint32_t clamped = static_cast<uint32_t>(
+      std::min(scaled_wait_time, kMaxWaitTime) << kLockwordReservedShift);
+
+  if (clamped == 0) {
+    return kSpinLockSleeper;  // Just wake waiters, but don't record contention.
+  }
+  // Bump up value if necessary to avoid returning kSpinLockSleeper.
+  const uint32_t kMinWaitTime =
+      kSpinLockSleeper + (1 << kLockwordReservedShift);
+  if (clamped == kSpinLockSleeper) {
+    return kMinWaitTime;
+  }
+  return clamped;
+}
+
+uint64_t SpinLock::DecodeWaitCycles(uint32_t lock_value) {
+  // Cast to uint32_t first to ensure bits [63:32] are cleared.
+  const uint64_t scaled_wait_time =
+      static_cast<uint32_t>(lock_value & kWaitTimeMask);
+  return scaled_wait_time << (kProfileTimestampShift - kLockwordReservedShift);
+}
+
+}  // namespace base_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
diff --git a/src/absl/base/internal/spinlock.h b/src/absl/base/internal/spinlock.h
new file mode 100644 (file)
index 0000000..c73b5e0
--- /dev/null
@@ -0,0 +1,246 @@
+//
+// Copyright 2017 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+//  Most users requiring mutual exclusion should use Mutex.
+//  SpinLock is provided for use in two situations:
+//   - for use in code that Mutex itself depends on
+//   - for async signal safety (see below)
+
+// SpinLock is async signal safe.  If a spinlock is used within a signal
+// handler, all code that acquires the lock must ensure that the signal cannot
+// arrive while they are holding the lock.  Typically, this is done by blocking
+// the signal.
+
+#ifndef ABSL_BASE_INTERNAL_SPINLOCK_H_
+#define ABSL_BASE_INTERNAL_SPINLOCK_H_
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <atomic>
+
+#include "absl/base/attributes.h"
+#include "absl/base/const_init.h"
+#include "absl/base/dynamic_annotations.h"
+#include "absl/base/internal/low_level_scheduling.h"
+#include "absl/base/internal/raw_logging.h"
+#include "absl/base/internal/scheduling_mode.h"
+#include "absl/base/internal/tsan_mutex_interface.h"
+#include "absl/base/macros.h"
+#include "absl/base/port.h"
+#include "absl/base/thread_annotations.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace base_internal {
+
+class ABSL_LOCKABLE SpinLock {
+ public:
+  SpinLock() : lockword_(kSpinLockCooperative) {
+    ABSL_TSAN_MUTEX_CREATE(this, __tsan_mutex_not_static);
+  }
+
+  // Constructors that allow non-cooperative spinlocks to be created for use
+  // inside thread schedulers.  Normal clients should not use these.
+  explicit SpinLock(base_internal::SchedulingMode mode);
+
+  // Constructor for global SpinLock instances.  See absl/base/const_init.h.
+  constexpr SpinLock(absl::ConstInitType, base_internal::SchedulingMode mode)
+      : lockword_(IsCooperative(mode) ? kSpinLockCooperative : 0) {}
+
+  // For global SpinLock instances prefer trivial destructor when possible.
+  // Default but non-trivial destructor in some build configurations causes an
+  // extra static initializer.
+#ifdef ABSL_INTERNAL_HAVE_TSAN_INTERFACE
+  ~SpinLock() { ABSL_TSAN_MUTEX_DESTROY(this, __tsan_mutex_not_static); }
+#else
+  ~SpinLock() = default;
+#endif
+
+  // Acquire this SpinLock.
+  inline void Lock() ABSL_EXCLUSIVE_LOCK_FUNCTION() {
+    ABSL_TSAN_MUTEX_PRE_LOCK(this, 0);
+    if (!TryLockImpl()) {
+      SlowLock();
+    }
+    ABSL_TSAN_MUTEX_POST_LOCK(this, 0, 0);
+  }
+
+  // Try to acquire this SpinLock without blocking and return true if the
+  // acquisition was successful.  If the lock was not acquired, false is
+  // returned.  If this SpinLock is free at the time of the call, TryLock
+  // will return true with high probability.
+  inline bool TryLock() ABSL_EXCLUSIVE_TRYLOCK_FUNCTION(true) {
+    ABSL_TSAN_MUTEX_PRE_LOCK(this, __tsan_mutex_try_lock);
+    bool res = TryLockImpl();
+    ABSL_TSAN_MUTEX_POST_LOCK(
+        this, __tsan_mutex_try_lock | (res ? 0 : __tsan_mutex_try_lock_failed),
+        0);
+    return res;
+  }
+
+  // Release this SpinLock, which must be held by the calling thread.
+  inline void Unlock() ABSL_UNLOCK_FUNCTION() {
+    ABSL_TSAN_MUTEX_PRE_UNLOCK(this, 0);
+    uint32_t lock_value = lockword_.load(std::memory_order_relaxed);
+    lock_value = lockword_.exchange(lock_value & kSpinLockCooperative,
+                                    std::memory_order_release);
+
+    if ((lock_value & kSpinLockDisabledScheduling) != 0) {
+      base_internal::SchedulingGuard::EnableRescheduling(true);
+    }
+    if ((lock_value & kWaitTimeMask) != 0) {
+      // Collect contentionz profile info, and speed the wakeup of any waiter.
+      // The wait_cycles value indicates how long this thread spent waiting
+      // for the lock.
+      SlowUnlock(lock_value);
+    }
+    ABSL_TSAN_MUTEX_POST_UNLOCK(this, 0);
+  }
+
+  // Determine if the lock is held.  When the lock is held by the invoking
+  // thread, true will always be returned. Intended to be used as
+  // CHECK(lock.IsHeld()).
+  inline bool IsHeld() const {
+    return (lockword_.load(std::memory_order_relaxed) & kSpinLockHeld) != 0;
+  }
+
+ protected:
+  // These should not be exported except for testing.
+
+  // Store number of cycles between wait_start_time and wait_end_time in a
+  // lock value.
+  static uint32_t EncodeWaitCycles(int64_t wait_start_time,
+                                   int64_t wait_end_time);
+
+  // Extract number of wait cycles in a lock value.
+  static uint64_t DecodeWaitCycles(uint32_t lock_value);
+
+  // Provide access to protected method above.  Use for testing only.
+  friend struct SpinLockTest;
+
+ private:
+  // lockword_ is used to store the following:
+  //
+  // bit[0] encodes whether a lock is being held.
+  // bit[1] encodes whether a lock uses cooperative scheduling.
+  // bit[2] encodes whether the current lock holder disabled scheduling when
+  //        acquiring the lock. Only set when kSpinLockHeld is also set.
+  // bit[3:31] encodes time a lock spent on waiting as a 29-bit unsigned int.
+  //        This is set by the lock holder to indicate how long it waited on
+  //        the lock before eventually acquiring it. The number of cycles is
+  //        encoded as a 29-bit unsigned int, or in the case that the current
+  //        holder did not wait but another waiter is queued, the LSB
+  //        (kSpinLockSleeper) is set. The implementation does not explicitly
+  //        track the number of queued waiters beyond this. It must always be
+  //        assumed that waiters may exist if the current holder was required to
+  //        queue.
+  //
+  // Invariant: if the lock is not held, the value is either 0 or
+  // kSpinLockCooperative.
+  static constexpr uint32_t kSpinLockHeld = 1;
+  static constexpr uint32_t kSpinLockCooperative = 2;
+  static constexpr uint32_t kSpinLockDisabledScheduling = 4;
+  static constexpr uint32_t kSpinLockSleeper = 8;
+  // Includes kSpinLockSleeper.
+  static constexpr uint32_t kWaitTimeMask =
+      ~(kSpinLockHeld | kSpinLockCooperative | kSpinLockDisabledScheduling);
+
+  // Returns true if the provided scheduling mode is cooperative.
+  static constexpr bool IsCooperative(
+      base_internal::SchedulingMode scheduling_mode) {
+    return scheduling_mode == base_internal::SCHEDULE_COOPERATIVE_AND_KERNEL;
+  }
+
+  uint32_t TryLockInternal(uint32_t lock_value, uint32_t wait_cycles);
+  void SlowLock() ABSL_ATTRIBUTE_COLD;
+  void SlowUnlock(uint32_t lock_value) ABSL_ATTRIBUTE_COLD;
+  uint32_t SpinLoop();
+
+  inline bool TryLockImpl() {
+    uint32_t lock_value = lockword_.load(std::memory_order_relaxed);
+    return (TryLockInternal(lock_value, 0) & kSpinLockHeld) == 0;
+  }
+
+  std::atomic<uint32_t> lockword_;
+
+  SpinLock(const SpinLock&) = delete;
+  SpinLock& operator=(const SpinLock&) = delete;
+};
+
+// Corresponding locker object that arranges to acquire a spinlock for
+// the duration of a C++ scope.
+class ABSL_SCOPED_LOCKABLE SpinLockHolder {
+ public:
+  inline explicit SpinLockHolder(SpinLock* l) ABSL_EXCLUSIVE_LOCK_FUNCTION(l)
+      : lock_(l) {
+    l->Lock();
+  }
+  inline ~SpinLockHolder() ABSL_UNLOCK_FUNCTION() { lock_->Unlock(); }
+
+  SpinLockHolder(const SpinLockHolder&) = delete;
+  SpinLockHolder& operator=(const SpinLockHolder&) = delete;
+
+ private:
+  SpinLock* lock_;
+};
+
+// Register a hook for profiling support.
+//
+// The function pointer registered here will be called whenever a spinlock is
+// contended.  The callback is given an opaque handle to the contended spinlock
+// and the number of wait cycles.  This is thread-safe, but only a single
+// profiler can be registered.  It is an error to call this function multiple
+// times with different arguments.
+void RegisterSpinLockProfiler(void (*fn)(const void* lock,
+                                         int64_t wait_cycles));
+
+//------------------------------------------------------------------------------
+// Public interface ends here.
+//------------------------------------------------------------------------------
+
+// If (result & kSpinLockHeld) == 0, then *this was successfully locked.
+// Otherwise, returns last observed value for lockword_.
+inline uint32_t SpinLock::TryLockInternal(uint32_t lock_value,
+                                          uint32_t wait_cycles) {
+  if ((lock_value & kSpinLockHeld) != 0) {
+    return lock_value;
+  }
+
+  uint32_t sched_disabled_bit = 0;
+  if ((lock_value & kSpinLockCooperative) == 0) {
+    // For non-cooperative locks we must make sure we mark ourselves as
+    // non-reschedulable before we attempt to CompareAndSwap.
+    if (base_internal::SchedulingGuard::DisableRescheduling()) {
+      sched_disabled_bit = kSpinLockDisabledScheduling;
+    }
+  }
+
+  if (!lockword_.compare_exchange_strong(
+          lock_value,
+          kSpinLockHeld | lock_value | wait_cycles | sched_disabled_bit,
+          std::memory_order_acquire, std::memory_order_relaxed)) {
+    base_internal::SchedulingGuard::EnableRescheduling(sched_disabled_bit != 0);
+  }
+
+  return lock_value;
+}
+
+}  // namespace base_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#endif  // ABSL_BASE_INTERNAL_SPINLOCK_H_
diff --git a/src/absl/base/internal/spinlock_akaros.inc b/src/absl/base/internal/spinlock_akaros.inc
new file mode 100644 (file)
index 0000000..7b0cada
--- /dev/null
@@ -0,0 +1,35 @@
+// Copyright 2017 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// This file is an Akaros-specific part of spinlock_wait.cc
+
+#include <atomic>
+
+#include "absl/base/internal/scheduling_mode.h"
+
+extern "C" {
+
+ABSL_ATTRIBUTE_WEAK void ABSL_INTERNAL_C_SYMBOL(AbslInternalSpinLockDelay)(
+    std::atomic<uint32_t>* /* lock_word */, uint32_t /* value */,
+    int /* loop */, absl::base_internal::SchedulingMode /* mode */) {
+  // In Akaros, one must take care not to call anything that could cause a
+  // malloc(), a blocking system call, or a uthread_yield() while holding a
+  // spinlock. Our callers assume will not call into libraries or other
+  // arbitrary code.
+}
+
+ABSL_ATTRIBUTE_WEAK void ABSL_INTERNAL_C_SYMBOL(AbslInternalSpinLockWake)(
+    std::atomic<uint32_t>* /* lock_word */, bool /* all */) {}
+
+}  // extern "C"
diff --git a/src/absl/base/internal/spinlock_linux.inc b/src/absl/base/internal/spinlock_linux.inc
new file mode 100644 (file)
index 0000000..202f7cd
--- /dev/null
@@ -0,0 +1,74 @@
+// Copyright 2018 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// This file is a Linux-specific part of spinlock_wait.cc
+
+#include <linux/futex.h>
+#include <sys/syscall.h>
+#include <unistd.h>
+
+#include <atomic>
+#include <climits>
+#include <cstdint>
+#include <ctime>
+
+#include "absl/base/attributes.h"
+#include "absl/base/internal/errno_saver.h"
+
+// The SpinLock lockword is `std::atomic<uint32_t>`. Here we assert that
+// `std::atomic<uint32_t>` is bitwise equivalent of the `int` expected
+// by SYS_futex. We also assume that reads/writes done to the lockword
+// by SYS_futex have rational semantics with regard to the
+// std::atomic<> API. C++ provides no guarantees of these assumptions,
+// but they are believed to hold in practice.
+static_assert(sizeof(std::atomic<uint32_t>) == sizeof(int),
+              "SpinLock lockword has the wrong size for a futex");
+
+// Some Android headers are missing these definitions even though they
+// support these futex operations.
+#ifdef __BIONIC__
+#ifndef SYS_futex
+#define SYS_futex __NR_futex
+#endif
+#ifndef FUTEX_PRIVATE_FLAG
+#define FUTEX_PRIVATE_FLAG 128
+#endif
+#endif
+
+#if defined(__NR_futex_time64) && !defined(SYS_futex_time64)
+#define SYS_futex_time64 __NR_futex_time64
+#endif
+
+#if defined(SYS_futex_time64) && !defined(SYS_futex)
+#define SYS_futex SYS_futex_time64
+#endif
+
+extern "C" {
+
+ABSL_ATTRIBUTE_WEAK void ABSL_INTERNAL_C_SYMBOL(AbslInternalSpinLockDelay)(
+    std::atomic<uint32_t> *w, uint32_t value, int loop,
+    absl::base_internal::SchedulingMode) {
+  absl::base_internal::ErrnoSaver errno_saver;
+  struct timespec tm;
+  tm.tv_sec = 0;
+  tm.tv_nsec = absl::base_internal::SpinLockSuggestedDelayNS(loop);
+  syscall(SYS_futex, w, FUTEX_WAIT | FUTEX_PRIVATE_FLAG, value, &tm);
+}
+
+ABSL_ATTRIBUTE_WEAK void ABSL_INTERNAL_C_SYMBOL(AbslInternalSpinLockWake)(
+    std::atomic<uint32_t> *w, bool all) {
+  syscall(SYS_futex, w, FUTEX_WAKE | FUTEX_PRIVATE_FLAG, all ? INT_MAX : 1, 0);
+}
+
+}  // extern "C"
diff --git a/src/absl/base/internal/spinlock_posix.inc b/src/absl/base/internal/spinlock_posix.inc
new file mode 100644 (file)
index 0000000..4f6f887
--- /dev/null
@@ -0,0 +1,46 @@
+// Copyright 2017 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// This file is a Posix-specific part of spinlock_wait.cc
+
+#include <sched.h>
+
+#include <atomic>
+#include <ctime>
+
+#include "absl/base/internal/errno_saver.h"
+#include "absl/base/internal/scheduling_mode.h"
+#include "absl/base/port.h"
+
+extern "C" {
+
+ABSL_ATTRIBUTE_WEAK void ABSL_INTERNAL_C_SYMBOL(AbslInternalSpinLockDelay)(
+    std::atomic<uint32_t>* /* lock_word */, uint32_t /* value */, int loop,
+    absl::base_internal::SchedulingMode /* mode */) {
+  absl::base_internal::ErrnoSaver errno_saver;
+  if (loop == 0) {
+  } else if (loop == 1) {
+    sched_yield();
+  } else {
+    struct timespec tm;
+    tm.tv_sec = 0;
+    tm.tv_nsec = absl::base_internal::SpinLockSuggestedDelayNS(loop);
+    nanosleep(&tm, nullptr);
+  }
+}
+
+ABSL_ATTRIBUTE_WEAK void ABSL_INTERNAL_C_SYMBOL(AbslInternalSpinLockWake)(
+    std::atomic<uint32_t>* /* lock_word */, bool /* all */) {}
+
+}  // extern "C"
diff --git a/src/absl/base/internal/spinlock_wait.cc b/src/absl/base/internal/spinlock_wait.cc
new file mode 100644 (file)
index 0000000..fa824be
--- /dev/null
@@ -0,0 +1,81 @@
+// Copyright 2017 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// The OS-specific header included below must provide two calls:
+// AbslInternalSpinLockDelay() and AbslInternalSpinLockWake().
+// See spinlock_wait.h for the specs.
+
+#include <atomic>
+#include <cstdint>
+
+#include "absl/base/internal/spinlock_wait.h"
+
+#if defined(_WIN32)
+#include "absl/base/internal/spinlock_win32.inc"
+#elif defined(__linux__)
+#include "absl/base/internal/spinlock_linux.inc"
+#elif defined(__akaros__)
+#include "absl/base/internal/spinlock_akaros.inc"
+#else
+#include "absl/base/internal/spinlock_posix.inc"
+#endif
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace base_internal {
+
+// See spinlock_wait.h for spec.
+uint32_t SpinLockWait(std::atomic<uint32_t> *w, int n,
+                      const SpinLockWaitTransition trans[],
+                      base_internal::SchedulingMode scheduling_mode) {
+  int loop = 0;
+  for (;;) {
+    uint32_t v = w->load(std::memory_order_acquire);
+    int i;
+    for (i = 0; i != n && v != trans[i].from; i++) {
+    }
+    if (i == n) {
+      SpinLockDelay(w, v, ++loop, scheduling_mode);  // no matching transition
+    } else if (trans[i].to == v ||                   // null transition
+               w->compare_exchange_strong(v, trans[i].to,
+                                          std::memory_order_acquire,
+                                          std::memory_order_relaxed)) {
+      if (trans[i].done) return v;
+    }
+  }
+}
+
+static std::atomic<uint64_t> delay_rand;
+
+// Return a suggested delay in nanoseconds for iteration number "loop"
+int SpinLockSuggestedDelayNS(int loop) {
+  // Weak pseudo-random number generator to get some spread between threads
+  // when many are spinning.
+  uint64_t r = delay_rand.load(std::memory_order_relaxed);
+  r = 0x5deece66dLL * r + 0xb;   // numbers from nrand48()
+  delay_rand.store(r, std::memory_order_relaxed);
+
+  if (loop < 0 || loop > 32) {   // limit loop to 0..32
+    loop = 32;
+  }
+  const int kMinDelay = 128 << 10;  // 128us
+  // Double delay every 8 iterations, up to 16x (2ms).
+  int delay = kMinDelay << (loop / 8);
+  // Randomize in delay..2*delay range, for resulting 128us..4ms range.
+  return delay | ((delay - 1) & static_cast<int>(r));
+}
+
+}  // namespace base_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
diff --git a/src/absl/base/internal/spinlock_wait.h b/src/absl/base/internal/spinlock_wait.h
new file mode 100644 (file)
index 0000000..579bd09
--- /dev/null
@@ -0,0 +1,93 @@
+// Copyright 2017 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef ABSL_BASE_INTERNAL_SPINLOCK_WAIT_H_
+#define ABSL_BASE_INTERNAL_SPINLOCK_WAIT_H_
+
+// Operations to make atomic transitions on a word, and to allow
+// waiting for those transitions to become possible.
+
+#include <stdint.h>
+#include <atomic>
+
+#include "absl/base/internal/scheduling_mode.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace base_internal {
+
+// SpinLockWait() waits until it can perform one of several transitions from
+// "from" to "to".  It returns when it performs a transition where done==true.
+struct SpinLockWaitTransition {
+  uint32_t from;
+  uint32_t to;
+  bool done;
+};
+
+// Wait until *w can transition from trans[i].from to trans[i].to for some i
+// satisfying 0<=i<n && trans[i].done, atomically make the transition,
+// then return the old value of *w.   Make any other atomic transitions
+// where !trans[i].done, but continue waiting.
+uint32_t SpinLockWait(std::atomic<uint32_t> *w, int n,
+                      const SpinLockWaitTransition trans[],
+                      SchedulingMode scheduling_mode);
+
+// If possible, wake some thread that has called SpinLockDelay(w, ...). If `all`
+// is true, wake all such threads. On some systems, this may be a no-op; on
+// those systems, threads calling SpinLockDelay() will always wake eventually
+// even if SpinLockWake() is never called.
+void SpinLockWake(std::atomic<uint32_t> *w, bool all);
+
+// Wait for an appropriate spin delay on iteration "loop" of a
+// spin loop on location *w, whose previously observed value was "value".
+// SpinLockDelay() may do nothing, may yield the CPU, may sleep a clock tick,
+// or may wait for a call to SpinLockWake(w).
+void SpinLockDelay(std::atomic<uint32_t> *w, uint32_t value, int loop,
+                   base_internal::SchedulingMode scheduling_mode);
+
+// Helper used by AbslInternalSpinLockDelay.
+// Returns a suggested delay in nanoseconds for iteration number "loop".
+int SpinLockSuggestedDelayNS(int loop);
+
+}  // namespace base_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+// In some build configurations we pass --detect-odr-violations to the
+// gold linker.  This causes it to flag weak symbol overrides as ODR
+// violations.  Because ODR only applies to C++ and not C,
+// --detect-odr-violations ignores symbols not mangled with C++ names.
+// By changing our extension points to be extern "C", we dodge this
+// check.
+extern "C" {
+void ABSL_INTERNAL_C_SYMBOL(AbslInternalSpinLockWake)(std::atomic<uint32_t> *w,
+                                                      bool all);
+void ABSL_INTERNAL_C_SYMBOL(AbslInternalSpinLockDelay)(
+    std::atomic<uint32_t> *w, uint32_t value, int loop,
+    absl::base_internal::SchedulingMode scheduling_mode);
+}
+
+inline void absl::base_internal::SpinLockWake(std::atomic<uint32_t> *w,
+                                              bool all) {
+  ABSL_INTERNAL_C_SYMBOL(AbslInternalSpinLockWake)(w, all);
+}
+
+inline void absl::base_internal::SpinLockDelay(
+    std::atomic<uint32_t> *w, uint32_t value, int loop,
+    absl::base_internal::SchedulingMode scheduling_mode) {
+  ABSL_INTERNAL_C_SYMBOL(AbslInternalSpinLockDelay)
+  (w, value, loop, scheduling_mode);
+}
+
+#endif  // ABSL_BASE_INTERNAL_SPINLOCK_WAIT_H_
diff --git a/src/absl/base/internal/spinlock_win32.inc b/src/absl/base/internal/spinlock_win32.inc
new file mode 100644 (file)
index 0000000..9d22481
--- /dev/null
@@ -0,0 +1,37 @@
+// Copyright 2017 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// This file is a Win32-specific part of spinlock_wait.cc
+
+#include <windows.h>
+#include <atomic>
+#include "absl/base/internal/scheduling_mode.h"
+
+extern "C" {
+
+void ABSL_INTERNAL_C_SYMBOL(AbslInternalSpinLockDelay)(
+    std::atomic<uint32_t>* /* lock_word */, uint32_t /* value */, int loop,
+    absl::base_internal::SchedulingMode /* mode */) {
+  if (loop == 0) {
+  } else if (loop == 1) {
+    Sleep(0);
+  } else {
+    Sleep(absl::base_internal::SpinLockSuggestedDelayNS(loop) / 1000000);
+  }
+}
+
+void ABSL_INTERNAL_C_SYMBOL(AbslInternalSpinLockWake)(
+    std::atomic<uint32_t>* /* lock_word */, bool /* all */) {}
+
+}  // extern "C"
diff --git a/src/absl/base/internal/strerror.cc b/src/absl/base/internal/strerror.cc
new file mode 100644 (file)
index 0000000..0d6226f
--- /dev/null
@@ -0,0 +1,88 @@
+// Copyright 2020 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "absl/base/internal/strerror.h"
+
+#include <array>
+#include <cerrno>
+#include <cstddef>
+#include <cstdio>
+#include <cstring>
+#include <string>
+#include <type_traits>
+
+#include "absl/base/internal/errno_saver.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace base_internal {
+namespace {
+
+const char* StrErrorAdaptor(int errnum, char* buf, size_t buflen) {
+#if defined(_WIN32)
+  int rc = strerror_s(buf, buflen, errnum);
+  buf[buflen - 1] = '\0';  // guarantee NUL termination
+  if (rc == 0 && strncmp(buf, "Unknown error", buflen) == 0) *buf = '\0';
+  return buf;
+#else
+  // The type of `ret` is platform-specific; both of these branches must compile
+  // either way but only one will execute on any given platform:
+  auto ret = strerror_r(errnum, buf, buflen);
+  if (std::is_same<decltype(ret), int>::value) {
+    // XSI `strerror_r`; `ret` is `int`:
+    if (ret) *buf = '\0';
+    return buf;
+  } else {
+    // GNU `strerror_r`; `ret` is `char *`:
+    return reinterpret_cast<const char*>(ret);
+  }
+#endif
+}
+
+std::string StrErrorInternal(int errnum) {
+  char buf[100];
+  const char* str = StrErrorAdaptor(errnum, buf, sizeof buf);
+  if (*str == '\0') {
+    snprintf(buf, sizeof buf, "Unknown error %d", errnum);
+    str = buf;
+  }
+  return str;
+}
+
+// kSysNerr is the number of errors from a recent glibc. `StrError()` falls back
+// to `StrErrorAdaptor()` if the value is larger than this.
+constexpr int kSysNerr = 135;
+
+std::array<std::string, kSysNerr>* NewStrErrorTable() {
+  auto* table = new std::array<std::string, kSysNerr>;
+  for (int i = 0; i < static_cast<int>(table->size()); ++i) {
+    (*table)[i] = StrErrorInternal(i);
+  }
+  return table;
+}
+
+}  // namespace
+
+std::string StrError(int errnum) {
+  absl::base_internal::ErrnoSaver errno_saver;
+  static const auto* table = NewStrErrorTable();
+  if (errnum >= 0 && errnum < static_cast<int>(table->size())) {
+    return (*table)[errnum];
+  }
+  return StrErrorInternal(errnum);
+}
+
+}  // namespace base_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
diff --git a/src/absl/base/internal/strerror.h b/src/absl/base/internal/strerror.h
new file mode 100644 (file)
index 0000000..3500973
--- /dev/null
@@ -0,0 +1,39 @@
+// Copyright 2020 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef ABSL_BASE_INTERNAL_STRERROR_H_
+#define ABSL_BASE_INTERNAL_STRERROR_H_
+
+#include <string>
+
+#include "absl/base/config.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace base_internal {
+
+// A portable and thread-safe alternative to C89's `strerror`.
+//
+// The C89 specification of `strerror` is not suitable for use in a
+// multi-threaded application as the returned string may be changed by calls to
+// `strerror` from another thread.  The many non-stdlib alternatives differ
+// enough in their names, availability, and semantics to justify this wrapper
+// around them.  `errno` will not be modified by a call to `absl::StrError`.
+std::string StrError(int errnum);
+
+}  // namespace base_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#endif  // ABSL_BASE_INTERNAL_STRERROR_H_
diff --git a/src/absl/base/internal/sysinfo.cc b/src/absl/base/internal/sysinfo.cc
new file mode 100644 (file)
index 0000000..7d264d8
--- /dev/null
@@ -0,0 +1,444 @@
+#include "cpp-compat.h"
+// Copyright 2017 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "absl/base/internal/sysinfo.h"
+
+#include "absl/base/attributes.h"
+
+#ifdef _WIN32
+#include <windows.h>
+#else
+#include <fcntl.h>
+#include <pthread.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+#endif
+
+#ifdef __linux__
+#include <sys/syscall.h>
+#endif
+
+#if defined(__APPLE__) || defined(__FreeBSD__)
+#include <sys/sysctl.h>
+#endif
+
+#if defined(__myriad2__)
+#include <rtems.h>
+#endif
+
+#include <string.h>
+
+#include <cassert>
+#include <cstdint>
+#include <cstdio>
+#include <cstdlib>
+#include <ctime>
+#include <limits>
+#include <thread>  // NOLINT(build/c++11)
+#include <utility>
+#include <vector>
+
+#include "absl/base/call_once.h"
+#include "absl/base/config.h"
+#include "absl/base/internal/raw_logging.h"
+#include "absl/base/internal/spinlock.h"
+#include "absl/base/internal/unscaledcycleclock.h"
+#include "absl/base/thread_annotations.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace base_internal {
+
+static int GetNumCPUs() {
+#if defined(__myriad2__)
+  return 1;
+#else
+  // Other possibilities:
+  //  - Read /sys/devices/system/cpu/online and use cpumask_parse()
+  //  - sysconf(_SC_NPROCESSORS_ONLN)
+  return std::thread::hardware_concurrency();
+#endif
+}
+
+#if defined(_WIN32)
+
+static double GetNominalCPUFrequency() {
+#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP) && \
+    !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
+  // UWP apps don't have access to the registry and currently don't provide an
+  // API informing about CPU nominal frequency.
+  return 1.0;
+#else
+#pragma comment(lib, "advapi32.lib")  // For Reg* functions.
+  HKEY key;
+  // Use the Reg* functions rather than the SH functions because shlwapi.dll
+  // pulls in gdi32.dll which makes process destruction much more costly.
+  if (RegOpenKeyExA(HKEY_LOCAL_MACHINE,
+                    "HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0", 0,
+                    KEY_READ, &key) == ERROR_SUCCESS) {
+    DWORD type = 0;
+    DWORD data = 0;
+    DWORD data_size = sizeof(data);
+    auto result = RegQueryValueExA(key, "~MHz", 0, &type,
+                                   reinterpret_cast<LPBYTE>(&data), &data_size);
+    RegCloseKey(key);
+    if (result == ERROR_SUCCESS && type == REG_DWORD &&
+        data_size == sizeof(data)) {
+      return data * 1e6;  // Value is MHz.
+    }
+  }
+  return 1.0;
+#endif  // WINAPI_PARTITION_APP && !WINAPI_PARTITION_DESKTOP
+}
+
+#elif defined(CTL_HW) && defined(HW_CPU_FREQ)
+
+static double GetNominalCPUFrequency() {
+  unsigned freq;
+  size_t size = sizeof(freq);
+  int mib[2] = {CTL_HW, HW_CPU_FREQ};
+  if (sysctl(mib, 2, &freq, &size, nullptr, 0) == 0) {
+    return static_cast<double>(freq);
+  }
+  return 1.0;
+}
+
+#else
+
+// Helper function for reading a long from a file. Returns true if successful
+// and the memory location pointed to by value is set to the value read.
+static bool ReadLongFromFile(const char *file, long *value) {
+  bool ret = false;
+  int fd = open(file, O_RDONLY);
+  if (fd != -1) {
+    char line[1024];
+    char *err;
+    memset(line, '\0', sizeof(line));
+    int len = read(fd, line, sizeof(line) - 1);
+    if (len <= 0) {
+      ret = false;
+    } else {
+      const long temp_value = strtol(line, &err, 10);
+      if (line[0] != '\0' && (*err == '\n' || *err == '\0')) {
+        *value = temp_value;
+        ret = true;
+      }
+    }
+    close(fd);
+  }
+  return ret;
+}
+
+#if defined(ABSL_INTERNAL_UNSCALED_CYCLECLOCK_FREQUENCY_IS_CPU_FREQUENCY)
+
+// Reads a monotonic time source and returns a value in
+// nanoseconds. The returned value uses an arbitrary epoch, not the
+// Unix epoch.
+static int64_t ReadMonotonicClockNanos() {
+  struct timespec t;
+#ifdef CLOCK_MONOTONIC_RAW
+  int rc = clock_gettime(CLOCK_MONOTONIC_RAW, &t);
+#else
+  int rc = clock_gettime(CLOCK_MONOTONIC, &t);
+#endif
+  if (rc != 0) {
+    perror("clock_gettime() failed");
+    // dd: R CMD check will fail if abort() is used
+    // abort();
+    cpp_compat_abort();
+  }
+  return int64_t{t.tv_sec} * 1000000000 + t.tv_nsec;
+}
+
+class UnscaledCycleClockWrapperForInitializeFrequency {
+ public:
+  static int64_t Now() { return base_internal::UnscaledCycleClock::Now(); }
+};
+
+struct TimeTscPair {
+  int64_t time;  // From ReadMonotonicClockNanos().
+  int64_t tsc;   // From UnscaledCycleClock::Now().
+};
+
+// Returns a pair of values (monotonic kernel time, TSC ticks) that
+// approximately correspond to each other.  This is accomplished by
+// doing several reads and picking the reading with the lowest
+// latency.  This approach is used to minimize the probability that
+// our thread was preempted between clock reads.
+static TimeTscPair GetTimeTscPair() {
+  int64_t best_latency = std::numeric_limits<int64_t>::max();
+  TimeTscPair best;
+  for (int i = 0; i < 10; ++i) {
+    int64_t t0 = ReadMonotonicClockNanos();
+    int64_t tsc = UnscaledCycleClockWrapperForInitializeFrequency::Now();
+    int64_t t1 = ReadMonotonicClockNanos();
+    int64_t latency = t1 - t0;
+    if (latency < best_latency) {
+      best_latency = latency;
+      best.time = t0;
+      best.tsc = tsc;
+    }
+  }
+  return best;
+}
+
+// Measures and returns the TSC frequency by taking a pair of
+// measurements approximately `sleep_nanoseconds` apart.
+static double MeasureTscFrequencyWithSleep(int sleep_nanoseconds) {
+  auto t0 = GetTimeTscPair();
+  struct timespec ts;
+  ts.tv_sec = 0;
+  ts.tv_nsec = sleep_nanoseconds;
+  while (nanosleep(&ts, &ts) != 0 && errno == EINTR) {}
+  auto t1 = GetTimeTscPair();
+  double elapsed_ticks = t1.tsc - t0.tsc;
+  double elapsed_time = (t1.time - t0.time) * 1e-9;
+  return elapsed_ticks / elapsed_time;
+}
+
+// Measures and returns the TSC frequency by calling
+// MeasureTscFrequencyWithSleep(), doubling the sleep interval until the
+// frequency measurement stabilizes.
+static double MeasureTscFrequency() {
+  double last_measurement = -1.0;
+  int sleep_nanoseconds = 1000000;  // 1 millisecond.
+  for (int i = 0; i < 8; ++i) {
+    double measurement = MeasureTscFrequencyWithSleep(sleep_nanoseconds);
+    if (measurement * 0.99 < last_measurement &&
+        last_measurement < measurement * 1.01) {
+      // Use the current measurement if it is within 1% of the
+      // previous measurement.
+      return measurement;
+    }
+    last_measurement = measurement;
+    sleep_nanoseconds *= 2;
+  }
+  return last_measurement;
+}
+
+#endif  // ABSL_INTERNAL_UNSCALED_CYCLECLOCK_FREQUENCY_IS_CPU_FREQUENCY
+
+static double GetNominalCPUFrequency() {
+  long freq = 0;
+
+  // Google's production kernel has a patch to export the TSC
+  // frequency through sysfs. If the kernel is exporting the TSC
+  // frequency use that. There are issues where cpuinfo_max_freq
+  // cannot be relied on because the BIOS may be exporting an invalid
+  // p-state (on x86) or p-states may be used to put the processor in
+  // a new mode (turbo mode). Essentially, those frequencies cannot
+  // always be relied upon. The same reasons apply to /proc/cpuinfo as
+  // well.
+  if (ReadLongFromFile("/sys/devices/system/cpu/cpu0/tsc_freq_khz", &freq)) {
+    return freq * 1e3;  // Value is kHz.
+  }
+
+#if defined(ABSL_INTERNAL_UNSCALED_CYCLECLOCK_FREQUENCY_IS_CPU_FREQUENCY)
+  // On these platforms, the TSC frequency is the nominal CPU
+  // frequency.  But without having the kernel export it directly
+  // though /sys/devices/system/cpu/cpu0/tsc_freq_khz, there is no
+  // other way to reliably get the TSC frequency, so we have to
+  // measure it ourselves.  Some CPUs abuse cpuinfo_max_freq by
+  // exporting "fake" frequencies for implementing new features. For
+  // example, Intel's turbo mode is enabled by exposing a p-state
+  // value with a higher frequency than that of the real TSC
+  // rate. Because of this, we prefer to measure the TSC rate
+  // ourselves on i386 and x86-64.
+  return MeasureTscFrequency();
+#else
+
+  // If CPU scaling is in effect, we want to use the *maximum*
+  // frequency, not whatever CPU speed some random processor happens
+  // to be using now.
+  if (ReadLongFromFile("/sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_max_freq",
+                       &freq)) {
+    return freq * 1e3;  // Value is kHz.
+  }
+
+  return 1.0;
+#endif  // !ABSL_INTERNAL_UNSCALED_CYCLECLOCK_FREQUENCY_IS_CPU_FREQUENCY
+}
+
+#endif
+
+ABSL_CONST_INIT static once_flag init_num_cpus_once;
+ABSL_CONST_INIT static int num_cpus = 0;
+
+// NumCPUs() may be called before main() and before malloc is properly
+// initialized, therefore this must not allocate memory.
+int NumCPUs() {
+  base_internal::LowLevelCallOnce(
+      &init_num_cpus_once, []() { num_cpus = GetNumCPUs(); });
+  return num_cpus;
+}
+
+// A default frequency of 0.0 might be dangerous if it is used in division.
+ABSL_CONST_INIT static once_flag init_nominal_cpu_frequency_once;
+ABSL_CONST_INIT static double nominal_cpu_frequency = 1.0;
+
+// NominalCPUFrequency() may be called before main() and before malloc is
+// properly initialized, therefore this must not allocate memory.
+double NominalCPUFrequency() {
+  base_internal::LowLevelCallOnce(
+      &init_nominal_cpu_frequency_once,
+      []() { nominal_cpu_frequency = GetNominalCPUFrequency(); });
+  return nominal_cpu_frequency;
+}
+
+#if defined(_WIN32)
+
+pid_t GetTID() {
+  return pid_t{GetCurrentThreadId()};
+}
+
+#elif defined(__linux__)
+
+#ifndef SYS_gettid
+#define SYS_gettid __NR_gettid
+#endif
+
+pid_t GetTID() {
+  return syscall(SYS_gettid);
+}
+
+#elif defined(__akaros__)
+
+pid_t GetTID() {
+  // Akaros has a concept of "vcore context", which is the state the program
+  // is forced into when we need to make a user-level scheduling decision, or
+  // run a signal handler.  This is analogous to the interrupt context that a
+  // CPU might enter if it encounters some kind of exception.
+  //
+  // There is no current thread context in vcore context, but we need to give
+  // a reasonable answer if asked for a thread ID (e.g., in a signal handler).
+  // Thread 0 always exists, so if we are in vcore context, we return that.
+  //
+  // Otherwise, we know (since we are using pthreads) that the uthread struct
+  // current_uthread is pointing to is the first element of a
+  // struct pthread_tcb, so we extract and return the thread ID from that.
+  //
+  // TODO(dcross): Akaros anticipates moving the thread ID to the uthread
+  // structure at some point. We should modify this code to remove the cast
+  // when that happens.
+  if (in_vcore_context())
+    return 0;
+  return reinterpret_cast<struct pthread_tcb *>(current_uthread)->id;
+}
+
+#elif defined(__myriad2__)
+
+pid_t GetTID() {
+  uint32_t tid;
+  rtems_task_ident(RTEMS_SELF, 0, &tid);
+  return tid;
+}
+
+#else
+
+// Fallback implementation of GetTID using pthread_getspecific.
+ABSL_CONST_INIT static once_flag tid_once;
+ABSL_CONST_INIT static pthread_key_t tid_key;
+ABSL_CONST_INIT static absl::base_internal::SpinLock tid_lock(
+    absl::kConstInit, base_internal::SCHEDULE_KERNEL_ONLY);
+
+// We set a bit per thread in this array to indicate that an ID is in
+// use. ID 0 is unused because it is the default value returned by
+// pthread_getspecific().
+ABSL_CONST_INIT static std::vector<uint32_t> *tid_array
+    ABSL_GUARDED_BY(tid_lock) = nullptr;
+static constexpr int kBitsPerWord = 32;  // tid_array is uint32_t.
+
+// Returns the TID to tid_array.
+static void FreeTID(void *v) {
+  intptr_t tid = reinterpret_cast<intptr_t>(v);
+  int word = tid / kBitsPerWord;
+  uint32_t mask = ~(1u << (tid % kBitsPerWord));
+  absl::base_internal::SpinLockHolder lock(&tid_lock);
+  assert(0 <= word && static_cast<size_t>(word) < tid_array->size());
+  (*tid_array)[word] &= mask;
+}
+
+static void InitGetTID() {
+  if (pthread_key_create(&tid_key, FreeTID) != 0) {
+    // The logging system calls GetTID() so it can't be used here.
+    perror("pthread_key_create failed");
+    // dd: R CMD check will fail if abort() is used
+    // abort();
+    cpp_compat_abort();
+  }
+
+  // Initialize tid_array.
+  absl::base_internal::SpinLockHolder lock(&tid_lock);
+  tid_array = new std::vector<uint32_t>(1);
+  (*tid_array)[0] = 1;  // ID 0 is never-allocated.
+}
+
+// Return a per-thread small integer ID from pthread's thread-specific data.
+pid_t GetTID() {
+  absl::call_once(tid_once, InitGetTID);
+
+  intptr_t tid = reinterpret_cast<intptr_t>(pthread_getspecific(tid_key));
+  if (tid != 0) {
+    return tid;
+  }
+
+  int bit;  // tid_array[word] = 1u << bit;
+  size_t word;
+  {
+    // Search for the first unused ID.
+    absl::base_internal::SpinLockHolder lock(&tid_lock);
+    // First search for a word in the array that is not all ones.
+    word = 0;
+    while (word < tid_array->size() && ~(*tid_array)[word] == 0) {
+      ++word;
+    }
+    if (word == tid_array->size()) {
+      tid_array->push_back(0);  // No space left, add kBitsPerWord more IDs.
+    }
+    // Search for a zero bit in the word.
+    bit = 0;
+    while (bit < kBitsPerWord && (((*tid_array)[word] >> bit) & 1) != 0) {
+      ++bit;
+    }
+    tid = (word * kBitsPerWord) + bit;
+    (*tid_array)[word] |= 1u << bit;  // Mark the TID as allocated.
+  }
+
+  if (pthread_setspecific(tid_key, reinterpret_cast<void *>(tid)) != 0) {
+    perror("pthread_setspecific failed");
+    cpp_compat_abort();
+  }
+
+  return static_cast<pid_t>(tid);
+}
+
+#endif
+
+// GetCachedTID() caches the thread ID in thread-local storage (which is a
+// userspace construct) to avoid unnecessary system calls. Without this caching,
+// it can take roughly 98ns, while it takes roughly 1ns with this caching.
+pid_t GetCachedTID() {
+#ifdef ABSL_HAVE_THREAD_LOCAL
+  static thread_local pid_t thread_id = GetTID();
+  return thread_id;
+#else
+  return GetTID();
+#endif  // ABSL_HAVE_THREAD_LOCAL
+}
+
+}  // namespace base_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
diff --git a/src/absl/base/internal/sysinfo.h b/src/absl/base/internal/sysinfo.h
new file mode 100644 (file)
index 0000000..119cf1f
--- /dev/null
@@ -0,0 +1,74 @@
+// Copyright 2017 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// This file includes routines to find out characteristics
+// of the machine a program is running on.  It is undoubtedly
+// system-dependent.
+
+// Functions listed here that accept a pid_t as an argument act on the
+// current process if the pid_t argument is 0
+// All functions here are thread-hostile due to file caching unless
+// commented otherwise.
+
+#ifndef ABSL_BASE_INTERNAL_SYSINFO_H_
+#define ABSL_BASE_INTERNAL_SYSINFO_H_
+
+#ifndef _WIN32
+#include <sys/types.h>
+#endif
+
+#include <cstdint>
+
+#include "absl/base/config.h"
+#include "absl/base/port.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace base_internal {
+
+// Nominal core processor cycles per second of each processor.   This is _not_
+// necessarily the frequency of the CycleClock counter (see cycleclock.h)
+// Thread-safe.
+double NominalCPUFrequency();
+
+// Number of logical processors (hyperthreads) in system. Thread-safe.
+int NumCPUs();
+
+// Return the thread id of the current thread, as told by the system.
+// No two currently-live threads implemented by the OS shall have the same ID.
+// Thread ids of exited threads may be reused.   Multiple user-level threads
+// may have the same thread ID if multiplexed on the same OS thread.
+//
+// On Linux, you may send a signal to the resulting ID with kill().  However,
+// it is recommended for portability that you use pthread_kill() instead.
+#ifdef _WIN32
+// On Windows, process id and thread id are of the same type according to the
+// return types of GetProcessId() and GetThreadId() are both DWORD, an unsigned
+// 32-bit type.
+using pid_t = uint32_t;
+#endif
+pid_t GetTID();
+
+// Like GetTID(), but caches the result in thread-local storage in order
+// to avoid unnecessary system calls. Note that there are some cases where
+// one must call through to GetTID directly, which is why this exists as a
+// separate function. For example, GetCachedTID() is not safe to call in
+// an asynchronous signal-handling context nor right after a call to fork().
+pid_t GetCachedTID();
+
+}  // namespace base_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#endif  // ABSL_BASE_INTERNAL_SYSINFO_H_
diff --git a/src/absl/base/internal/thread_annotations.h b/src/absl/base/internal/thread_annotations.h
new file mode 100644 (file)
index 0000000..4dab6a9
--- /dev/null
@@ -0,0 +1,271 @@
+// Copyright 2019 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// -----------------------------------------------------------------------------
+// File: thread_annotations.h
+// -----------------------------------------------------------------------------
+//
+// WARNING: This is a backwards compatible header and it will be removed after
+// the migration to prefixed thread annotations is finished; please include
+// "absl/base/thread_annotations.h".
+//
+// This header file contains macro definitions for thread safety annotations
+// that allow developers to document the locking policies of multi-threaded
+// code. The annotations can also help program analysis tools to identify
+// potential thread safety issues.
+//
+// These annotations are implemented using compiler attributes. Using the macros
+// defined here instead of raw attributes allow for portability and future
+// compatibility.
+//
+// When referring to mutexes in the arguments of the attributes, you should
+// use variable names or more complex expressions (e.g. my_object->mutex_)
+// that evaluate to a concrete mutex object whenever possible. If the mutex
+// you want to refer to is not in scope, you may use a member pointer
+// (e.g. &MyClass::mutex_) to refer to a mutex in some (unknown) object.
+
+#ifndef ABSL_BASE_INTERNAL_THREAD_ANNOTATIONS_H_
+#define ABSL_BASE_INTERNAL_THREAD_ANNOTATIONS_H_
+
+#if defined(__clang__)
+#define THREAD_ANNOTATION_ATTRIBUTE__(x)   __attribute__((x))
+#else
+#define THREAD_ANNOTATION_ATTRIBUTE__(x)   // no-op
+#endif
+
+// GUARDED_BY()
+//
+// Documents if a shared field or global variable needs to be protected by a
+// mutex. GUARDED_BY() allows the user to specify a particular mutex that
+// should be held when accessing the annotated variable.
+//
+// Although this annotation (and PT_GUARDED_BY, below) cannot be applied to
+// local variables, a local variable and its associated mutex can often be
+// combined into a small class or struct, thereby allowing the annotation.
+//
+// Example:
+//
+//   class Foo {
+//     Mutex mu_;
+//     int p1_ GUARDED_BY(mu_);
+//     ...
+//   };
+#define GUARDED_BY(x) THREAD_ANNOTATION_ATTRIBUTE__(guarded_by(x))
+
+// PT_GUARDED_BY()
+//
+// Documents if the memory location pointed to by a pointer should be guarded
+// by a mutex when dereferencing the pointer.
+//
+// Example:
+//   class Foo {
+//     Mutex mu_;
+//     int *p1_ PT_GUARDED_BY(mu_);
+//     ...
+//   };
+//
+// Note that a pointer variable to a shared memory location could itself be a
+// shared variable.
+//
+// Example:
+//
+//   // `q_`, guarded by `mu1_`, points to a shared memory location that is
+//   // guarded by `mu2_`:
+//   int *q_ GUARDED_BY(mu1_) PT_GUARDED_BY(mu2_);
+#define PT_GUARDED_BY(x) THREAD_ANNOTATION_ATTRIBUTE__(pt_guarded_by(x))
+
+// ACQUIRED_AFTER() / ACQUIRED_BEFORE()
+//
+// Documents the acquisition order between locks that can be held
+// simultaneously by a thread. For any two locks that need to be annotated
+// to establish an acquisition order, only one of them needs the annotation.
+// (i.e. You don't have to annotate both locks with both ACQUIRED_AFTER
+// and ACQUIRED_BEFORE.)
+//
+// As with GUARDED_BY, this is only applicable to mutexes that are shared
+// fields or global variables.
+//
+// Example:
+//
+//   Mutex m1_;
+//   Mutex m2_ ACQUIRED_AFTER(m1_);
+#define ACQUIRED_AFTER(...) \
+  THREAD_ANNOTATION_ATTRIBUTE__(acquired_after(__VA_ARGS__))
+
+#define ACQUIRED_BEFORE(...) \
+  THREAD_ANNOTATION_ATTRIBUTE__(acquired_before(__VA_ARGS__))
+
+// EXCLUSIVE_LOCKS_REQUIRED() / SHARED_LOCKS_REQUIRED()
+//
+// Documents a function that expects a mutex to be held prior to entry.
+// The mutex is expected to be held both on entry to, and exit from, the
+// function.
+//
+// An exclusive lock allows read-write access to the guarded data member(s), and
+// only one thread can acquire a lock exclusively at any one time. A shared lock
+// allows read-only access, and any number of threads can acquire a shared lock
+// concurrently.
+//
+// Generally, non-const methods should be annotated with
+// EXCLUSIVE_LOCKS_REQUIRED, while const methods should be annotated with
+// SHARED_LOCKS_REQUIRED.
+//
+// Example:
+//
+//   Mutex mu1, mu2;
+//   int a GUARDED_BY(mu1);
+//   int b GUARDED_BY(mu2);
+//
+//   void foo() EXCLUSIVE_LOCKS_REQUIRED(mu1, mu2) { ... }
+//   void bar() const SHARED_LOCKS_REQUIRED(mu1, mu2) { ... }
+#define EXCLUSIVE_LOCKS_REQUIRED(...) \
+  THREAD_ANNOTATION_ATTRIBUTE__(exclusive_locks_required(__VA_ARGS__))
+
+#define SHARED_LOCKS_REQUIRED(...) \
+  THREAD_ANNOTATION_ATTRIBUTE__(shared_locks_required(__VA_ARGS__))
+
+// LOCKS_EXCLUDED()
+//
+// Documents the locks acquired in the body of the function. These locks
+// cannot be held when calling this function (as Abseil's `Mutex` locks are
+// non-reentrant).
+#define LOCKS_EXCLUDED(...) \
+  THREAD_ANNOTATION_ATTRIBUTE__(locks_excluded(__VA_ARGS__))
+
+// LOCK_RETURNED()
+//
+// Documents a function that returns a mutex without acquiring it.  For example,
+// a public getter method that returns a pointer to a private mutex should
+// be annotated with LOCK_RETURNED.
+#define LOCK_RETURNED(x) \
+  THREAD_ANNOTATION_ATTRIBUTE__(lock_returned(x))
+
+// LOCKABLE
+//
+// Documents if a class/type is a lockable type (such as the `Mutex` class).
+#define LOCKABLE \
+  THREAD_ANNOTATION_ATTRIBUTE__(lockable)
+
+// SCOPED_LOCKABLE
+//
+// Documents if a class does RAII locking (such as the `MutexLock` class).
+// The constructor should use `LOCK_FUNCTION()` to specify the mutex that is
+// acquired, and the destructor should use `UNLOCK_FUNCTION()` with no
+// arguments; the analysis will assume that the destructor unlocks whatever the
+// constructor locked.
+#define SCOPED_LOCKABLE \
+  THREAD_ANNOTATION_ATTRIBUTE__(scoped_lockable)
+
+// EXCLUSIVE_LOCK_FUNCTION()
+//
+// Documents functions that acquire a lock in the body of a function, and do
+// not release it.
+#define EXCLUSIVE_LOCK_FUNCTION(...) \
+  THREAD_ANNOTATION_ATTRIBUTE__(exclusive_lock_function(__VA_ARGS__))
+
+// SHARED_LOCK_FUNCTION()
+//
+// Documents functions that acquire a shared (reader) lock in the body of a
+// function, and do not release it.
+#define SHARED_LOCK_FUNCTION(...) \
+  THREAD_ANNOTATION_ATTRIBUTE__(shared_lock_function(__VA_ARGS__))
+
+// UNLOCK_FUNCTION()
+//
+// Documents functions that expect a lock to be held on entry to the function,
+// and release it in the body of the function.
+#define UNLOCK_FUNCTION(...) \
+  THREAD_ANNOTATION_ATTRIBUTE__(unlock_function(__VA_ARGS__))
+
+// EXCLUSIVE_TRYLOCK_FUNCTION() / SHARED_TRYLOCK_FUNCTION()
+//
+// Documents functions that try to acquire a lock, and return success or failure
+// (or a non-boolean value that can be interpreted as a boolean).
+// The first argument should be `true` for functions that return `true` on
+// success, or `false` for functions that return `false` on success. The second
+// argument specifies the mutex that is locked on success. If unspecified, this
+// mutex is assumed to be `this`.
+#define EXCLUSIVE_TRYLOCK_FUNCTION(...) \
+  THREAD_ANNOTATION_ATTRIBUTE__(exclusive_trylock_function(__VA_ARGS__))
+
+#define SHARED_TRYLOCK_FUNCTION(...) \
+  THREAD_ANNOTATION_ATTRIBUTE__(shared_trylock_function(__VA_ARGS__))
+
+// ASSERT_EXCLUSIVE_LOCK() / ASSERT_SHARED_LOCK()
+//
+// Documents functions that dynamically check to see if a lock is held, and fail
+// if it is not held.
+#define ASSERT_EXCLUSIVE_LOCK(...) \
+  THREAD_ANNOTATION_ATTRIBUTE__(assert_exclusive_lock(__VA_ARGS__))
+
+#define ASSERT_SHARED_LOCK(...) \
+  THREAD_ANNOTATION_ATTRIBUTE__(assert_shared_lock(__VA_ARGS__))
+
+// NO_THREAD_SAFETY_ANALYSIS
+//
+// Turns off thread safety checking within the body of a particular function.
+// This annotation is used to mark functions that are known to be correct, but
+// the locking behavior is more complicated than the analyzer can handle.
+#define NO_THREAD_SAFETY_ANALYSIS \
+  THREAD_ANNOTATION_ATTRIBUTE__(no_thread_safety_analysis)
+
+//------------------------------------------------------------------------------
+// Tool-Supplied Annotations
+//------------------------------------------------------------------------------
+
+// TS_UNCHECKED should be placed around lock expressions that are not valid
+// C++ syntax, but which are present for documentation purposes.  These
+// annotations will be ignored by the analysis.
+#define TS_UNCHECKED(x) ""
+
+// TS_FIXME is used to mark lock expressions that are not valid C++ syntax.
+// It is used by automated tools to mark and disable invalid expressions.
+// The annotation should either be fixed, or changed to TS_UNCHECKED.
+#define TS_FIXME(x) ""
+
+// Like NO_THREAD_SAFETY_ANALYSIS, this turns off checking within the body of
+// a particular function.  However, this attribute is used to mark functions
+// that are incorrect and need to be fixed.  It is used by automated tools to
+// avoid breaking the build when the analysis is updated.
+// Code owners are expected to eventually fix the routine.
+#define NO_THREAD_SAFETY_ANALYSIS_FIXME  NO_THREAD_SAFETY_ANALYSIS
+
+// Similar to NO_THREAD_SAFETY_ANALYSIS_FIXME, this macro marks a GUARDED_BY
+// annotation that needs to be fixed, because it is producing thread safety
+// warning.  It disables the GUARDED_BY.
+#define GUARDED_BY_FIXME(x)
+
+// Disables warnings for a single read operation.  This can be used to avoid
+// warnings when it is known that the read is not actually involved in a race,
+// but the compiler cannot confirm that.
+#define TS_UNCHECKED_READ(x) thread_safety_analysis::ts_unchecked_read(x)
+
+
+namespace thread_safety_analysis {
+
+// Takes a reference to a guarded data member, and returns an unguarded
+// reference.
+template <typename T>
+inline const T& ts_unchecked_read(const T& v) NO_THREAD_SAFETY_ANALYSIS {
+  return v;
+}
+
+template <typename T>
+inline T& ts_unchecked_read(T& v) NO_THREAD_SAFETY_ANALYSIS {
+  return v;
+}
+
+}  // namespace thread_safety_analysis
+
+#endif  // ABSL_BASE_INTERNAL_THREAD_ANNOTATIONS_H_
diff --git a/src/absl/base/internal/thread_identity.cc b/src/absl/base/internal/thread_identity.cc
new file mode 100644 (file)
index 0000000..9950e63
--- /dev/null
@@ -0,0 +1,155 @@
+// Copyright 2017 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "absl/base/internal/thread_identity.h"
+
+#ifndef _WIN32
+#include <pthread.h>
+#include <signal.h>
+#endif
+
+#include <atomic>
+#include <cassert>
+#include <memory>
+
+#include "absl/base/attributes.h"
+#include "absl/base/call_once.h"
+#include "absl/base/internal/raw_logging.h"
+#include "absl/base/internal/spinlock.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace base_internal {
+
+#if ABSL_THREAD_IDENTITY_MODE != ABSL_THREAD_IDENTITY_MODE_USE_CPP11
+namespace {
+// Used to co-ordinate one-time creation of our pthread_key
+absl::once_flag init_thread_identity_key_once;
+pthread_key_t thread_identity_pthread_key;
+std::atomic<bool> pthread_key_initialized(false);
+
+void AllocateThreadIdentityKey(ThreadIdentityReclaimerFunction reclaimer) {
+  pthread_key_create(&thread_identity_pthread_key, reclaimer);
+  pthread_key_initialized.store(true, std::memory_order_release);
+}
+}  // namespace
+#endif
+
+#if ABSL_THREAD_IDENTITY_MODE == ABSL_THREAD_IDENTITY_MODE_USE_TLS || \
+    ABSL_THREAD_IDENTITY_MODE == ABSL_THREAD_IDENTITY_MODE_USE_CPP11
+// The actual TLS storage for a thread's currently associated ThreadIdentity.
+// This is referenced by inline accessors in the header.
+// "protected" visibility ensures that if multiple instances of Abseil code
+// exist within a process (via dlopen() or similar), references to
+// thread_identity_ptr from each instance of the code will refer to
+// *different* instances of this ptr.
+// Apple platforms have the visibility attribute, but issue a compile warning
+// that protected visibility is unsupported.
+#if ABSL_HAVE_ATTRIBUTE(visibility) && !defined(__APPLE__)
+__attribute__((visibility("protected")))
+#endif  // ABSL_HAVE_ATTRIBUTE(visibility) && !defined(__APPLE__)
+#if ABSL_PER_THREAD_TLS
+// Prefer __thread to thread_local as benchmarks indicate it is a bit faster.
+ABSL_PER_THREAD_TLS_KEYWORD ThreadIdentity* thread_identity_ptr = nullptr;
+#elif defined(ABSL_HAVE_THREAD_LOCAL)
+thread_local ThreadIdentity* thread_identity_ptr = nullptr;
+#endif  // ABSL_PER_THREAD_TLS
+#endif  // TLS or CPP11
+
+void SetCurrentThreadIdentity(
+    ThreadIdentity* identity, ThreadIdentityReclaimerFunction reclaimer) {
+  assert(CurrentThreadIdentityIfPresent() == nullptr);
+  // Associate our destructor.
+  // NOTE: This call to pthread_setspecific is currently the only immovable
+  // barrier to CurrentThreadIdentity() always being async signal safe.
+#if ABSL_THREAD_IDENTITY_MODE == ABSL_THREAD_IDENTITY_MODE_USE_POSIX_SETSPECIFIC
+  // NOTE: Not async-safe.  But can be open-coded.
+  absl::call_once(init_thread_identity_key_once, AllocateThreadIdentityKey,
+                  reclaimer);
+
+#if defined(__EMSCRIPTEN__) || defined(__MINGW32__)
+  // Emscripten and MinGW pthread implementations does not support signals.
+  // See https://kripken.github.io/emscripten-site/docs/porting/pthreads.html
+  // for more information.
+  pthread_setspecific(thread_identity_pthread_key,
+                      reinterpret_cast<void*>(identity));
+#else
+  // We must mask signals around the call to setspecific as with current glibc,
+  // a concurrent getspecific (needed for GetCurrentThreadIdentityIfPresent())
+  // may zero our value.
+  //
+  // While not officially async-signal safe, getspecific within a signal handler
+  // is otherwise OK.
+  sigset_t all_signals;
+  sigset_t curr_signals;
+  sigfillset(&all_signals);
+  pthread_sigmask(SIG_SETMASK, &all_signals, &curr_signals);
+  pthread_setspecific(thread_identity_pthread_key,
+                      reinterpret_cast<void*>(identity));
+  pthread_sigmask(SIG_SETMASK, &curr_signals, nullptr);
+#endif  // !__EMSCRIPTEN__ && !__MINGW32__
+
+#elif ABSL_THREAD_IDENTITY_MODE == ABSL_THREAD_IDENTITY_MODE_USE_TLS
+  // NOTE: Not async-safe.  But can be open-coded.
+  absl::call_once(init_thread_identity_key_once, AllocateThreadIdentityKey,
+                  reclaimer);
+  pthread_setspecific(thread_identity_pthread_key,
+                      reinterpret_cast<void*>(identity));
+  thread_identity_ptr = identity;
+#elif ABSL_THREAD_IDENTITY_MODE == ABSL_THREAD_IDENTITY_MODE_USE_CPP11
+  thread_local std::unique_ptr<ThreadIdentity, ThreadIdentityReclaimerFunction>
+      holder(identity, reclaimer);
+  thread_identity_ptr = identity;
+#else
+#error Unimplemented ABSL_THREAD_IDENTITY_MODE
+#endif
+}
+
+#if ABSL_THREAD_IDENTITY_MODE == ABSL_THREAD_IDENTITY_MODE_USE_TLS || \
+    ABSL_THREAD_IDENTITY_MODE == ABSL_THREAD_IDENTITY_MODE_USE_CPP11
+
+// Please see the comment on `CurrentThreadIdentityIfPresent` in
+// thread_identity.h. When we cannot expose thread_local variables in
+// headers, we opt for the correct-but-slower option of not inlining this
+// function.
+#ifndef ABSL_INTERNAL_INLINE_CURRENT_THREAD_IDENTITY_IF_PRESENT
+ThreadIdentity* CurrentThreadIdentityIfPresent() { return thread_identity_ptr; }
+#endif
+#endif
+
+void ClearCurrentThreadIdentity() {
+#if ABSL_THREAD_IDENTITY_MODE == ABSL_THREAD_IDENTITY_MODE_USE_TLS || \
+    ABSL_THREAD_IDENTITY_MODE == ABSL_THREAD_IDENTITY_MODE_USE_CPP11
+  thread_identity_ptr = nullptr;
+#elif ABSL_THREAD_IDENTITY_MODE == \
+      ABSL_THREAD_IDENTITY_MODE_USE_POSIX_SETSPECIFIC
+  // pthread_setspecific expected to clear value on destruction
+  assert(CurrentThreadIdentityIfPresent() == nullptr);
+#endif
+}
+
+#if ABSL_THREAD_IDENTITY_MODE == ABSL_THREAD_IDENTITY_MODE_USE_POSIX_SETSPECIFIC
+ThreadIdentity* CurrentThreadIdentityIfPresent() {
+  bool initialized = pthread_key_initialized.load(std::memory_order_acquire);
+  if (!initialized) {
+    return nullptr;
+  }
+  return reinterpret_cast<ThreadIdentity*>(
+      pthread_getspecific(thread_identity_pthread_key));
+}
+#endif
+
+}  // namespace base_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
diff --git a/src/absl/base/internal/thread_identity.h b/src/absl/base/internal/thread_identity.h
new file mode 100644 (file)
index 0000000..6e25b92
--- /dev/null
@@ -0,0 +1,265 @@
+// Copyright 2017 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// Each active thread has an ThreadIdentity that may represent the thread in
+// various level interfaces.  ThreadIdentity objects are never deallocated.
+// When a thread terminates, its ThreadIdentity object may be reused for a
+// thread created later.
+
+#ifndef ABSL_BASE_INTERNAL_THREAD_IDENTITY_H_
+#define ABSL_BASE_INTERNAL_THREAD_IDENTITY_H_
+
+#ifndef _WIN32
+#include <pthread.h>
+// Defines __GOOGLE_GRTE_VERSION__ (via glibc-specific features.h) when
+// supported.
+#include <unistd.h>
+#endif
+
+#include <atomic>
+#include <cstdint>
+
+#include "absl/base/config.h"
+#include "absl/base/internal/per_thread_tls.h"
+#include "absl/base/optimization.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+
+struct SynchLocksHeld;
+struct SynchWaitParams;
+
+namespace base_internal {
+
+class SpinLock;
+struct ThreadIdentity;
+
+// Used by the implementation of absl::Mutex and absl::CondVar.
+struct PerThreadSynch {
+  // The internal representation of absl::Mutex and absl::CondVar rely
+  // on the alignment of PerThreadSynch. Both store the address of the
+  // PerThreadSynch in the high-order bits of their internal state,
+  // which means the low kLowZeroBits of the address of PerThreadSynch
+  // must be zero.
+  static constexpr int kLowZeroBits = 8;
+  static constexpr int kAlignment = 1 << kLowZeroBits;
+
+  // Returns the associated ThreadIdentity.
+  // This can be implemented as a cast because we guarantee
+  // PerThreadSynch is the first element of ThreadIdentity.
+  ThreadIdentity* thread_identity() {
+    return reinterpret_cast<ThreadIdentity*>(this);
+  }
+
+  PerThreadSynch *next;  // Circular waiter queue; initialized to 0.
+  PerThreadSynch *skip;  // If non-zero, all entries in Mutex queue
+                         // up to and including "skip" have same
+                         // condition as this, and will be woken later
+  bool may_skip;         // if false while on mutex queue, a mutex unlocker
+                         // is using this PerThreadSynch as a terminator.  Its
+                         // skip field must not be filled in because the loop
+                         // might then skip over the terminator.
+  bool wake;             // This thread is to be woken from a Mutex.
+  // If "x" is on a waiter list for a mutex, "x->cond_waiter" is true iff the
+  // waiter is waiting on the mutex as part of a CV Wait or Mutex Await.
+  //
+  // The value of "x->cond_waiter" is meaningless if "x" is not on a
+  // Mutex waiter list.
+  bool cond_waiter;
+  bool maybe_unlocking;  // Valid at head of Mutex waiter queue;
+                         // true if UnlockSlow could be searching
+                         // for a waiter to wake.  Used for an optimization
+                         // in Enqueue().  true is always a valid value.
+                         // Can be reset to false when the unlocker or any
+                         // writer releases the lock, or a reader fully
+                         // releases the lock.  It may not be set to false
+                         // by a reader that decrements the count to
+                         // non-zero. protected by mutex spinlock
+  bool suppress_fatal_errors;  // If true, try to proceed even in the face
+                               // of broken invariants.  This is used within
+                               // fatal signal handlers to improve the
+                               // chances of debug logging information being
+                               // output successfully.
+  int priority;                // Priority of thread (updated every so often).
+
+  // State values:
+  //   kAvailable: This PerThreadSynch is available.
+  //   kQueued: This PerThreadSynch is unavailable, it's currently queued on a
+  //            Mutex or CondVar waistlist.
+  //
+  // Transitions from kQueued to kAvailable require a release
+  // barrier. This is needed as a waiter may use "state" to
+  // independently observe that it's no longer queued.
+  //
+  // Transitions from kAvailable to kQueued require no barrier, they
+  // are externally ordered by the Mutex.
+  enum State {
+    kAvailable,
+    kQueued
+  };
+  std::atomic<State> state;
+
+  // The wait parameters of the current wait.  waitp is null if the
+  // thread is not waiting. Transitions from null to non-null must
+  // occur before the enqueue commit point (state = kQueued in
+  // Enqueue() and CondVarEnqueue()). Transitions from non-null to
+  // null must occur after the wait is finished (state = kAvailable in
+  // Mutex::Block() and CondVar::WaitCommon()). This field may be
+  // changed only by the thread that describes this PerThreadSynch.  A
+  // special case is Fer(), which calls Enqueue() on another thread,
+  // but with an identical SynchWaitParams pointer, thus leaving the
+  // pointer unchanged.
+  SynchWaitParams* waitp;
+
+  intptr_t readers;     // Number of readers in mutex.
+
+  // When priority will next be read (cycles).
+  int64_t next_priority_read_cycles;
+
+  // Locks held; used during deadlock detection.
+  // Allocated in Synch_GetAllLocks() and freed in ReclaimThreadIdentity().
+  SynchLocksHeld *all_locks;
+};
+
+// The instances of this class are allocated in NewThreadIdentity() with an
+// alignment of PerThreadSynch::kAlignment.
+struct ThreadIdentity {
+  // Must be the first member.  The Mutex implementation requires that
+  // the PerThreadSynch object associated with each thread is
+  // PerThreadSynch::kAlignment aligned.  We provide this alignment on
+  // ThreadIdentity itself.
+  PerThreadSynch per_thread_synch;
+
+  // Private: Reserved for absl::synchronization_internal::Waiter.
+  struct WaiterState {
+    alignas(void*) char data[128];
+  } waiter_state;
+
+  // Used by PerThreadSem::{Get,Set}ThreadBlockedCounter().
+  std::atomic<int>* blocked_count_ptr;
+
+  // The following variables are mostly read/written just by the
+  // thread itself.  The only exception is that these are read by
+  // a ticker thread as a hint.
+  std::atomic<int> ticker;      // Tick counter, incremented once per second.
+  std::atomic<int> wait_start;  // Ticker value when thread started waiting.
+  std::atomic<bool> is_idle;    // Has thread become idle yet?
+
+  ThreadIdentity* next;
+};
+
+// Returns the ThreadIdentity object representing the calling thread; guaranteed
+// to be unique for its lifetime.  The returned object will remain valid for the
+// program's lifetime; although it may be re-assigned to a subsequent thread.
+// If one does not exist, return nullptr instead.
+//
+// Does not malloc(*), and is async-signal safe.
+// [*] Technically pthread_setspecific() does malloc on first use; however this
+// is handled internally within tcmalloc's initialization already.
+//
+// New ThreadIdentity objects can be constructed and associated with a thread
+// by calling GetOrCreateCurrentThreadIdentity() in per-thread-sem.h.
+ThreadIdentity* CurrentThreadIdentityIfPresent();
+
+using ThreadIdentityReclaimerFunction = void (*)(void*);
+
+// Sets the current thread identity to the given value.  'reclaimer' is a
+// pointer to the global function for cleaning up instances on thread
+// destruction.
+void SetCurrentThreadIdentity(ThreadIdentity* identity,
+                              ThreadIdentityReclaimerFunction reclaimer);
+
+// Removes the currently associated ThreadIdentity from the running thread.
+// This must be called from inside the ThreadIdentityReclaimerFunction, and only
+// from that function.
+void ClearCurrentThreadIdentity();
+
+// May be chosen at compile time via: -DABSL_FORCE_THREAD_IDENTITY_MODE=<mode
+// index>
+#ifdef ABSL_THREAD_IDENTITY_MODE_USE_POSIX_SETSPECIFIC
+#error ABSL_THREAD_IDENTITY_MODE_USE_POSIX_SETSPECIFIC cannot be direcly set
+#else
+#define ABSL_THREAD_IDENTITY_MODE_USE_POSIX_SETSPECIFIC 0
+#endif
+
+#ifdef ABSL_THREAD_IDENTITY_MODE_USE_TLS
+#error ABSL_THREAD_IDENTITY_MODE_USE_TLS cannot be direcly set
+#else
+#define ABSL_THREAD_IDENTITY_MODE_USE_TLS 1
+#endif
+
+#ifdef ABSL_THREAD_IDENTITY_MODE_USE_CPP11
+#error ABSL_THREAD_IDENTITY_MODE_USE_CPP11 cannot be direcly set
+#else
+#define ABSL_THREAD_IDENTITY_MODE_USE_CPP11 2
+#endif
+
+#ifdef ABSL_THREAD_IDENTITY_MODE
+#error ABSL_THREAD_IDENTITY_MODE cannot be direcly set
+#elif defined(ABSL_FORCE_THREAD_IDENTITY_MODE)
+#define ABSL_THREAD_IDENTITY_MODE ABSL_FORCE_THREAD_IDENTITY_MODE
+#elif defined(_WIN32) && !defined(__MINGW32__)
+#define ABSL_THREAD_IDENTITY_MODE ABSL_THREAD_IDENTITY_MODE_USE_CPP11
+#elif defined(__APPLE__) && defined(ABSL_HAVE_THREAD_LOCAL)
+#define ABSL_THREAD_IDENTITY_MODE ABSL_THREAD_IDENTITY_MODE_USE_CPP11
+#elif ABSL_PER_THREAD_TLS && defined(__GOOGLE_GRTE_VERSION__) &&        \
+    (__GOOGLE_GRTE_VERSION__ >= 20140228L)
+// Support for async-safe TLS was specifically added in GRTEv4.  It's not
+// present in the upstream eglibc.
+// Note:  Current default for production systems.
+#define ABSL_THREAD_IDENTITY_MODE ABSL_THREAD_IDENTITY_MODE_USE_TLS
+#else
+#define ABSL_THREAD_IDENTITY_MODE \
+  ABSL_THREAD_IDENTITY_MODE_USE_POSIX_SETSPECIFIC
+#endif
+
+#if ABSL_THREAD_IDENTITY_MODE == ABSL_THREAD_IDENTITY_MODE_USE_TLS || \
+    ABSL_THREAD_IDENTITY_MODE == ABSL_THREAD_IDENTITY_MODE_USE_CPP11
+
+#if ABSL_PER_THREAD_TLS
+ABSL_CONST_INIT extern ABSL_PER_THREAD_TLS_KEYWORD ThreadIdentity*
+    thread_identity_ptr;
+#elif defined(ABSL_HAVE_THREAD_LOCAL)
+ABSL_CONST_INIT extern thread_local ThreadIdentity* thread_identity_ptr;
+#else
+#error Thread-local storage not detected on this platform
+#endif
+
+// thread_local variables cannot be in headers exposed by DLLs or in certain
+// build configurations on Apple platforms. However, it is important for
+// performance reasons in general that `CurrentThreadIdentityIfPresent` be
+// inlined. In the other cases we opt to have the function not be inlined. Note
+// that `CurrentThreadIdentityIfPresent` is declared above so we can exclude
+// this entire inline definition.
+#if !defined(__APPLE__) && !defined(ABSL_BUILD_DLL) && \
+    !defined(ABSL_CONSUME_DLL)
+#define ABSL_INTERNAL_INLINE_CURRENT_THREAD_IDENTITY_IF_PRESENT 1
+#endif
+
+#ifdef ABSL_INTERNAL_INLINE_CURRENT_THREAD_IDENTITY_IF_PRESENT
+inline ThreadIdentity* CurrentThreadIdentityIfPresent() {
+  return thread_identity_ptr;
+}
+#endif
+
+#elif ABSL_THREAD_IDENTITY_MODE != \
+    ABSL_THREAD_IDENTITY_MODE_USE_POSIX_SETSPECIFIC
+#error Unknown ABSL_THREAD_IDENTITY_MODE
+#endif
+
+}  // namespace base_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#endif  // ABSL_BASE_INTERNAL_THREAD_IDENTITY_H_
diff --git a/src/absl/base/internal/throw_delegate.cc b/src/absl/base/internal/throw_delegate.cc
new file mode 100644 (file)
index 0000000..c260ff1
--- /dev/null
@@ -0,0 +1,212 @@
+// Copyright 2017 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "absl/base/internal/throw_delegate.h"
+
+#include <cstdlib>
+#include <functional>
+#include <new>
+#include <stdexcept>
+
+#include "absl/base/config.h"
+#include "absl/base/internal/raw_logging.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace base_internal {
+
+// NOTE: The various STL exception throwing functions are placed within the
+// #ifdef blocks so the symbols aren't exposed on platforms that don't support
+// them, such as the Android NDK. For example, ANGLE fails to link when building
+// within AOSP without them, since the STL functions don't exist.
+namespace {
+#ifdef ABSL_HAVE_EXCEPTIONS
+template <typename T>
+[[noreturn]] void Throw(const T& error) {
+  throw error;
+}
+#endif
+}  // namespace
+
+void ThrowStdLogicError(const std::string& what_arg) {
+#ifdef ABSL_HAVE_EXCEPTIONS
+  Throw(std::logic_error(what_arg));
+#else
+  ABSL_RAW_LOG(FATAL, "%s", what_arg.c_str());
+  std::abort();
+#endif
+}
+void ThrowStdLogicError(const char* what_arg) {
+#ifdef ABSL_HAVE_EXCEPTIONS
+  Throw(std::logic_error(what_arg));
+#else
+  ABSL_RAW_LOG(FATAL, "%s", what_arg);
+  std::abort();
+#endif
+}
+void ThrowStdInvalidArgument(const std::string& what_arg) {
+#ifdef ABSL_HAVE_EXCEPTIONS
+  Throw(std::invalid_argument(what_arg));
+#else
+  ABSL_RAW_LOG(FATAL, "%s", what_arg.c_str());
+  std::abort();
+#endif
+}
+void ThrowStdInvalidArgument(const char* what_arg) {
+#ifdef ABSL_HAVE_EXCEPTIONS
+  Throw(std::invalid_argument(what_arg));
+#else
+  ABSL_RAW_LOG(FATAL, "%s", what_arg);
+  std::abort();
+#endif
+}
+
+void ThrowStdDomainError(const std::string& what_arg) {
+#ifdef ABSL_HAVE_EXCEPTIONS
+  Throw(std::domain_error(what_arg));
+#else
+  ABSL_RAW_LOG(FATAL, "%s", what_arg.c_str());
+  std::abort();
+#endif
+}
+void ThrowStdDomainError(const char* what_arg) {
+#ifdef ABSL_HAVE_EXCEPTIONS
+  Throw(std::domain_error(what_arg));
+#else
+  ABSL_RAW_LOG(FATAL, "%s", what_arg);
+  std::abort();
+#endif
+}
+
+void ThrowStdLengthError(const std::string& what_arg) {
+#ifdef ABSL_HAVE_EXCEPTIONS
+  Throw(std::length_error(what_arg));
+#else
+  ABSL_RAW_LOG(FATAL, "%s", what_arg.c_str());
+  std::abort();
+#endif
+}
+void ThrowStdLengthError(const char* what_arg) {
+#ifdef ABSL_HAVE_EXCEPTIONS
+  Throw(std::length_error(what_arg));
+#else
+  ABSL_RAW_LOG(FATAL, "%s", what_arg);
+  std::abort();
+#endif
+}
+
+void ThrowStdOutOfRange(const std::string& what_arg) {
+#ifdef ABSL_HAVE_EXCEPTIONS
+  Throw(std::out_of_range(what_arg));
+#else
+  ABSL_RAW_LOG(FATAL, "%s", what_arg.c_str());
+  std::abort();
+#endif
+}
+void ThrowStdOutOfRange(const char* what_arg) {
+#ifdef ABSL_HAVE_EXCEPTIONS
+  Throw(std::out_of_range(what_arg));
+#else
+  ABSL_RAW_LOG(FATAL, "%s", what_arg);
+  std::abort();
+#endif
+}
+
+void ThrowStdRuntimeError(const std::string& what_arg) {
+#ifdef ABSL_HAVE_EXCEPTIONS
+  Throw(std::runtime_error(what_arg));
+#else
+  ABSL_RAW_LOG(FATAL, "%s", what_arg.c_str());
+  std::abort();
+#endif
+}
+void ThrowStdRuntimeError(const char* what_arg) {
+#ifdef ABSL_HAVE_EXCEPTIONS
+  Throw(std::runtime_error(what_arg));
+#else
+  ABSL_RAW_LOG(FATAL, "%s", what_arg);
+  std::abort();
+#endif
+}
+
+void ThrowStdRangeError(const std::string& what_arg) {
+#ifdef ABSL_HAVE_EXCEPTIONS
+  Throw(std::range_error(what_arg));
+#else
+  ABSL_RAW_LOG(FATAL, "%s", what_arg.c_str());
+  std::abort();
+#endif
+}
+void ThrowStdRangeError(const char* what_arg) {
+#ifdef ABSL_HAVE_EXCEPTIONS
+  Throw(std::range_error(what_arg));
+#else
+  ABSL_RAW_LOG(FATAL, "%s", what_arg);
+  std::abort();
+#endif
+}
+
+void ThrowStdOverflowError(const std::string& what_arg) {
+#ifdef ABSL_HAVE_EXCEPTIONS
+  Throw(std::overflow_error(what_arg));
+#else
+  ABSL_RAW_LOG(FATAL, "%s", what_arg.c_str());
+  std::abort();
+#endif
+}
+void ThrowStdOverflowError(const char* what_arg) {
+#ifdef ABSL_HAVE_EXCEPTIONS
+  Throw(std::overflow_error(what_arg));
+#else
+  ABSL_RAW_LOG(FATAL, "%s", what_arg);
+  std::abort();
+#endif
+}
+
+void ThrowStdUnderflowError(const std::string& what_arg) {
+#ifdef ABSL_HAVE_EXCEPTIONS
+  Throw(std::underflow_error(what_arg));
+#else
+  ABSL_RAW_LOG(FATAL, "%s", what_arg.c_str());
+  std::abort();
+#endif
+}
+void ThrowStdUnderflowError(const char* what_arg) {
+#ifdef ABSL_HAVE_EXCEPTIONS
+  Throw(std::underflow_error(what_arg));
+#else
+  ABSL_RAW_LOG(FATAL, "%s", what_arg);
+  std::abort();
+#endif
+}
+
+void ThrowStdBadFunctionCall() {
+#ifdef ABSL_HAVE_EXCEPTIONS
+  Throw(std::bad_function_call());
+#else
+  std::abort();
+#endif
+}
+
+void ThrowStdBadAlloc() {
+#ifdef ABSL_HAVE_EXCEPTIONS
+  Throw(std::bad_alloc());
+#else
+  std::abort();
+#endif
+}
+
+}  // namespace base_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
diff --git a/src/absl/base/internal/throw_delegate.h b/src/absl/base/internal/throw_delegate.h
new file mode 100644 (file)
index 0000000..075f527
--- /dev/null
@@ -0,0 +1,75 @@
+//
+// Copyright 2017 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#ifndef ABSL_BASE_INTERNAL_THROW_DELEGATE_H_
+#define ABSL_BASE_INTERNAL_THROW_DELEGATE_H_
+
+#include <string>
+
+#include "absl/base/config.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace base_internal {
+
+// Helper functions that allow throwing exceptions consistently from anywhere.
+// The main use case is for header-based libraries (eg templates), as they will
+// be built by many different targets with their own compiler options.
+// In particular, this will allow a safe way to throw exceptions even if the
+// caller is compiled with -fno-exceptions.  This is intended for implementing
+// things like map<>::at(), which the standard documents as throwing an
+// exception on error.
+//
+// Using other techniques like #if tricks could lead to ODR violations.
+//
+// You shouldn't use it unless you're writing code that you know will be built
+// both with and without exceptions and you need to conform to an interface
+// that uses exceptions.
+
+[[noreturn]] void ThrowStdLogicError(const std::string& what_arg);
+[[noreturn]] void ThrowStdLogicError(const char* what_arg);
+[[noreturn]] void ThrowStdInvalidArgument(const std::string& what_arg);
+[[noreturn]] void ThrowStdInvalidArgument(const char* what_arg);
+[[noreturn]] void ThrowStdDomainError(const std::string& what_arg);
+[[noreturn]] void ThrowStdDomainError(const char* what_arg);
+[[noreturn]] void ThrowStdLengthError(const std::string& what_arg);
+[[noreturn]] void ThrowStdLengthError(const char* what_arg);
+[[noreturn]] void ThrowStdOutOfRange(const std::string& what_arg);
+[[noreturn]] void ThrowStdOutOfRange(const char* what_arg);
+[[noreturn]] void ThrowStdRuntimeError(const std::string& what_arg);
+[[noreturn]] void ThrowStdRuntimeError(const char* what_arg);
+[[noreturn]] void ThrowStdRangeError(const std::string& what_arg);
+[[noreturn]] void ThrowStdRangeError(const char* what_arg);
+[[noreturn]] void ThrowStdOverflowError(const std::string& what_arg);
+[[noreturn]] void ThrowStdOverflowError(const char* what_arg);
+[[noreturn]] void ThrowStdUnderflowError(const std::string& what_arg);
+[[noreturn]] void ThrowStdUnderflowError(const char* what_arg);
+
+[[noreturn]] void ThrowStdBadFunctionCall();
+[[noreturn]] void ThrowStdBadAlloc();
+
+// ThrowStdBadArrayNewLength() cannot be consistently supported because
+// std::bad_array_new_length is missing in libstdc++ until 4.9.0.
+// https://gcc.gnu.org/onlinedocs/gcc-4.8.3/libstdc++/api/a01379_source.html
+// https://gcc.gnu.org/onlinedocs/gcc-4.9.0/libstdc++/api/a01327_source.html
+// libcxx (as of 3.2) and msvc (as of 2015) both have it.
+// [[noreturn]] void ThrowStdBadArrayNewLength();
+
+}  // namespace base_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#endif  // ABSL_BASE_INTERNAL_THROW_DELEGATE_H_
diff --git a/src/absl/base/internal/tsan_mutex_interface.h b/src/absl/base/internal/tsan_mutex_interface.h
new file mode 100644 (file)
index 0000000..39207d8
--- /dev/null
@@ -0,0 +1,68 @@
+// Copyright 2017 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// This file is intended solely for spinlock.h.
+// It provides ThreadSanitizer annotations for custom mutexes.
+// See <sanitizer/tsan_interface.h> for meaning of these annotations.
+
+#ifndef ABSL_BASE_INTERNAL_TSAN_MUTEX_INTERFACE_H_
+#define ABSL_BASE_INTERNAL_TSAN_MUTEX_INTERFACE_H_
+
+#include "absl/base/config.h"
+
+// ABSL_INTERNAL_HAVE_TSAN_INTERFACE
+// Macro intended only for internal use.
+//
+// Checks whether LLVM Thread Sanitizer interfaces are available.
+// First made available in LLVM 5.0 (Sep 2017).
+#ifdef ABSL_INTERNAL_HAVE_TSAN_INTERFACE
+#error "ABSL_INTERNAL_HAVE_TSAN_INTERFACE cannot be directly set."
+#endif
+
+#if defined(ABSL_HAVE_THREAD_SANITIZER) && defined(__has_include)
+#if __has_include(<sanitizer/tsan_interface.h>)
+#define ABSL_INTERNAL_HAVE_TSAN_INTERFACE 1
+#endif
+#endif
+
+#ifdef ABSL_INTERNAL_HAVE_TSAN_INTERFACE
+#include <sanitizer/tsan_interface.h>
+
+#define ABSL_TSAN_MUTEX_CREATE __tsan_mutex_create
+#define ABSL_TSAN_MUTEX_DESTROY __tsan_mutex_destroy
+#define ABSL_TSAN_MUTEX_PRE_LOCK __tsan_mutex_pre_lock
+#define ABSL_TSAN_MUTEX_POST_LOCK __tsan_mutex_post_lock
+#define ABSL_TSAN_MUTEX_PRE_UNLOCK __tsan_mutex_pre_unlock
+#define ABSL_TSAN_MUTEX_POST_UNLOCK __tsan_mutex_post_unlock
+#define ABSL_TSAN_MUTEX_PRE_SIGNAL __tsan_mutex_pre_signal
+#define ABSL_TSAN_MUTEX_POST_SIGNAL __tsan_mutex_post_signal
+#define ABSL_TSAN_MUTEX_PRE_DIVERT __tsan_mutex_pre_divert
+#define ABSL_TSAN_MUTEX_POST_DIVERT __tsan_mutex_post_divert
+
+#else
+
+#define ABSL_TSAN_MUTEX_CREATE(...)
+#define ABSL_TSAN_MUTEX_DESTROY(...)
+#define ABSL_TSAN_MUTEX_PRE_LOCK(...)
+#define ABSL_TSAN_MUTEX_POST_LOCK(...)
+#define ABSL_TSAN_MUTEX_PRE_UNLOCK(...)
+#define ABSL_TSAN_MUTEX_POST_UNLOCK(...)
+#define ABSL_TSAN_MUTEX_PRE_SIGNAL(...)
+#define ABSL_TSAN_MUTEX_POST_SIGNAL(...)
+#define ABSL_TSAN_MUTEX_PRE_DIVERT(...)
+#define ABSL_TSAN_MUTEX_POST_DIVERT(...)
+
+#endif
+
+#endif  // ABSL_BASE_INTERNAL_TSAN_MUTEX_INTERFACE_H_
diff --git a/src/absl/base/internal/unaligned_access.h b/src/absl/base/internal/unaligned_access.h
new file mode 100644 (file)
index 0000000..093dd9b
--- /dev/null
@@ -0,0 +1,82 @@
+//
+// Copyright 2017 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#ifndef ABSL_BASE_INTERNAL_UNALIGNED_ACCESS_H_
+#define ABSL_BASE_INTERNAL_UNALIGNED_ACCESS_H_
+
+#include <string.h>
+
+#include <cstdint>
+
+#include "absl/base/attributes.h"
+#include "absl/base/config.h"
+
+// unaligned APIs
+
+// Portable handling of unaligned loads, stores, and copies.
+
+// The unaligned API is C++ only.  The declarations use C++ features
+// (namespaces, inline) which are absent or incompatible in C.
+#if defined(__cplusplus)
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace base_internal {
+
+inline uint16_t UnalignedLoad16(const void *p) {
+  uint16_t t;
+  memcpy(&t, p, sizeof t);
+  return t;
+}
+
+inline uint32_t UnalignedLoad32(const void *p) {
+  uint32_t t;
+  memcpy(&t, p, sizeof t);
+  return t;
+}
+
+inline uint64_t UnalignedLoad64(const void *p) {
+  uint64_t t;
+  memcpy(&t, p, sizeof t);
+  return t;
+}
+
+inline void UnalignedStore16(void *p, uint16_t v) { memcpy(p, &v, sizeof v); }
+
+inline void UnalignedStore32(void *p, uint32_t v) { memcpy(p, &v, sizeof v); }
+
+inline void UnalignedStore64(void *p, uint64_t v) { memcpy(p, &v, sizeof v); }
+
+}  // namespace base_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#define ABSL_INTERNAL_UNALIGNED_LOAD16(_p) \
+  (absl::base_internal::UnalignedLoad16(_p))
+#define ABSL_INTERNAL_UNALIGNED_LOAD32(_p) \
+  (absl::base_internal::UnalignedLoad32(_p))
+#define ABSL_INTERNAL_UNALIGNED_LOAD64(_p) \
+  (absl::base_internal::UnalignedLoad64(_p))
+
+#define ABSL_INTERNAL_UNALIGNED_STORE16(_p, _val) \
+  (absl::base_internal::UnalignedStore16(_p, _val))
+#define ABSL_INTERNAL_UNALIGNED_STORE32(_p, _val) \
+  (absl::base_internal::UnalignedStore32(_p, _val))
+#define ABSL_INTERNAL_UNALIGNED_STORE64(_p, _val) \
+  (absl::base_internal::UnalignedStore64(_p, _val))
+
+#endif  // defined(__cplusplus), end of unaligned API
+
+#endif  // ABSL_BASE_INTERNAL_UNALIGNED_ACCESS_H_
diff --git a/src/absl/base/internal/unscaledcycleclock.cc b/src/absl/base/internal/unscaledcycleclock.cc
new file mode 100644 (file)
index 0000000..1545288
--- /dev/null
@@ -0,0 +1,138 @@
+// Copyright 2017 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "absl/base/internal/unscaledcycleclock.h"
+
+#if ABSL_USE_UNSCALED_CYCLECLOCK
+
+#if defined(_WIN32)
+#include <intrin.h>
+#endif
+
+#if defined(__powerpc__) || defined(__ppc__)
+#ifdef __GLIBC__
+#include <sys/platform/ppc.h>
+#elif defined(__FreeBSD__)
+#include <sys/sysctl.h>
+#include <sys/types.h>
+#endif
+#endif
+
+#include "absl/base/internal/sysinfo.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace base_internal {
+
+#if defined(__i386__)
+
+int64_t UnscaledCycleClock::Now() {
+  int64_t ret;
+  __asm__ volatile("rdtsc" : "=A"(ret));
+  return ret;
+}
+
+double UnscaledCycleClock::Frequency() {
+  return base_internal::NominalCPUFrequency();
+}
+
+#elif defined(__x86_64__)
+
+int64_t UnscaledCycleClock::Now() {
+  uint64_t low, high;
+  __asm__ volatile("rdtsc" : "=a"(low), "=d"(high));
+  return (high << 32) | low;
+}
+
+double UnscaledCycleClock::Frequency() {
+  return base_internal::NominalCPUFrequency();
+}
+
+#elif defined(__powerpc__) || defined(__ppc__)
+
+int64_t UnscaledCycleClock::Now() {
+#ifdef __GLIBC__
+  return __ppc_get_timebase();
+#else
+#ifdef __powerpc64__
+  int64_t tbr;
+  asm volatile("mfspr %0, 268" : "=r"(tbr));
+  return tbr;
+#else
+  int32_t tbu, tbl, tmp;
+  asm volatile(
+      "0:\n"
+      "mftbu %[hi32]\n"
+      "mftb %[lo32]\n"
+      "mftbu %[tmp]\n"
+      "cmpw %[tmp],%[hi32]\n"
+      "bne 0b\n"
+      : [ hi32 ] "=r"(tbu), [ lo32 ] "=r"(tbl), [ tmp ] "=r"(tmp));
+  return (static_cast<int64_t>(tbu) << 32) | tbl;
+#endif
+#endif
+}
+
+double UnscaledCycleClock::Frequency() {
+#ifdef __GLIBC__
+  return __ppc_get_timebase_freq();
+#elif defined(__FreeBSD__)
+  static once_flag init_timebase_frequency_once;
+  static double timebase_frequency = 0.0;
+  base_internal::LowLevelCallOnce(&init_timebase_frequency_once, [&]() {
+    size_t length = sizeof(timebase_frequency);
+    sysctlbyname("kern.timecounter.tc.timebase.frequency", &timebase_frequency,
+                 &length, nullptr, 0);
+  });
+  return timebase_frequency;
+#else
+#error Must implement UnscaledCycleClock::Frequency()
+#endif
+}
+
+#elif defined(__aarch64__)
+
+// System timer of ARMv8 runs at a different frequency than the CPU's.
+// The frequency is fixed, typically in the range 1-50MHz.  It can be
+// read at CNTFRQ special register.  We assume the OS has set up
+// the virtual timer properly.
+int64_t UnscaledCycleClock::Now() {
+  int64_t virtual_timer_value;
+  asm volatile("mrs %0, cntvct_el0" : "=r"(virtual_timer_value));
+  return virtual_timer_value;
+}
+
+double UnscaledCycleClock::Frequency() {
+  uint64_t aarch64_timer_frequency;
+  asm volatile("mrs %0, cntfrq_el0" : "=r"(aarch64_timer_frequency));
+  return aarch64_timer_frequency;
+}
+
+#elif defined(_M_IX86) || defined(_M_X64)
+
+#pragma intrinsic(__rdtsc)
+
+int64_t UnscaledCycleClock::Now() { return __rdtsc(); }
+
+double UnscaledCycleClock::Frequency() {
+  return base_internal::NominalCPUFrequency();
+}
+
+#endif
+
+}  // namespace base_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#endif  // ABSL_USE_UNSCALED_CYCLECLOCK
diff --git a/src/absl/base/internal/unscaledcycleclock.h b/src/absl/base/internal/unscaledcycleclock.h
new file mode 100644 (file)
index 0000000..82f2c87
--- /dev/null
@@ -0,0 +1,124 @@
+// Copyright 2017 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// UnscaledCycleClock
+//    An UnscaledCycleClock yields the value and frequency of a cycle counter
+//    that increments at a rate that is approximately constant.
+//    This class is for internal use only, you should consider using CycleClock
+//    instead.
+//
+// Notes:
+// The cycle counter frequency is not necessarily the core clock frequency.
+// That is, CycleCounter cycles are not necessarily "CPU cycles".
+//
+// An arbitrary offset may have been added to the counter at power on.
+//
+// On some platforms, the rate and offset of the counter may differ
+// slightly when read from different CPUs of a multiprocessor.  Usually,
+// we try to ensure that the operating system adjusts values periodically
+// so that values agree approximately.   If you need stronger guarantees,
+// consider using alternate interfaces.
+//
+// The CPU is not required to maintain the ordering of a cycle counter read
+// with respect to surrounding instructions.
+
+#ifndef ABSL_BASE_INTERNAL_UNSCALEDCYCLECLOCK_H_
+#define ABSL_BASE_INTERNAL_UNSCALEDCYCLECLOCK_H_
+
+#include <cstdint>
+
+#if defined(__APPLE__)
+#include <TargetConditionals.h>
+#endif
+
+#include "absl/base/port.h"
+
+// The following platforms have an implementation of a hardware counter.
+#if defined(__i386__) || defined(__x86_64__) || defined(__aarch64__) || \
+  defined(__powerpc__) || defined(__ppc__) || \
+  defined(_M_IX86) || defined(_M_X64)
+#define ABSL_HAVE_UNSCALED_CYCLECLOCK_IMPLEMENTATION 1
+#else
+#define ABSL_HAVE_UNSCALED_CYCLECLOCK_IMPLEMENTATION 0
+#endif
+
+// The following platforms often disable access to the hardware
+// counter (through a sandbox) even if the underlying hardware has a
+// usable counter. The CycleTimer interface also requires a *scaled*
+// CycleClock that runs at atleast 1 MHz. We've found some Android
+// ARM64 devices where this is not the case, so we disable it by
+// default on Android ARM64.
+#if defined(__native_client__) ||                      \
+    (defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE) || \
+    (defined(__ANDROID__) && defined(__aarch64__))
+#define ABSL_USE_UNSCALED_CYCLECLOCK_DEFAULT 0
+#else
+#define ABSL_USE_UNSCALED_CYCLECLOCK_DEFAULT 1
+#endif
+
+// UnscaledCycleClock is an optional internal feature.
+// Use "#if ABSL_USE_UNSCALED_CYCLECLOCK" to test for its presence.
+// Can be overridden at compile-time via -DABSL_USE_UNSCALED_CYCLECLOCK=0|1
+#if !defined(ABSL_USE_UNSCALED_CYCLECLOCK)
+#define ABSL_USE_UNSCALED_CYCLECLOCK               \
+  (ABSL_HAVE_UNSCALED_CYCLECLOCK_IMPLEMENTATION && \
+   ABSL_USE_UNSCALED_CYCLECLOCK_DEFAULT)
+#endif
+
+#if ABSL_USE_UNSCALED_CYCLECLOCK
+
+// This macro can be used to test if UnscaledCycleClock::Frequency()
+// is NominalCPUFrequency() on a particular platform.
+#if  (defined(__i386__) || defined(__x86_64__) || \
+      defined(_M_IX86) || defined(_M_X64))
+#define ABSL_INTERNAL_UNSCALED_CYCLECLOCK_FREQUENCY_IS_CPU_FREQUENCY
+#endif
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace time_internal {
+class UnscaledCycleClockWrapperForGetCurrentTime;
+}  // namespace time_internal
+
+namespace base_internal {
+class CycleClock;
+class UnscaledCycleClockWrapperForInitializeFrequency;
+
+class UnscaledCycleClock {
+ private:
+  UnscaledCycleClock() = delete;
+
+  // Return the value of a cycle counter that counts at a rate that is
+  // approximately constant.
+  static int64_t Now();
+
+  // Return the how much UnscaledCycleClock::Now() increases per second.
+  // This is not necessarily the core CPU clock frequency.
+  // It may be the nominal value report by the kernel, rather than a measured
+  // value.
+  static double Frequency();
+
+  // Allowed users
+  friend class base_internal::CycleClock;
+  friend class time_internal::UnscaledCycleClockWrapperForGetCurrentTime;
+  friend class base_internal::UnscaledCycleClockWrapperForInitializeFrequency;
+};
+
+}  // namespace base_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#endif  // ABSL_USE_UNSCALED_CYCLECLOCK
+
+#endif  // ABSL_BASE_INTERNAL_UNSCALEDCYCLECLOCK_H_
diff --git a/src/absl/base/log_severity.cc b/src/absl/base/log_severity.cc
new file mode 100644 (file)
index 0000000..72312af
--- /dev/null
@@ -0,0 +1,27 @@
+// Copyright 2017 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "absl/base/log_severity.h"
+
+#include <ostream>
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+
+std::ostream& operator<<(std::ostream& os, absl::LogSeverity s) {
+  if (s == absl::NormalizeLogSeverity(s)) return os << absl::LogSeverityName(s);
+  return os << "absl::LogSeverity(" << static_cast<int>(s) << ")";
+}
+ABSL_NAMESPACE_END
+}  // namespace absl
diff --git a/src/absl/base/log_severity.h b/src/absl/base/log_severity.h
new file mode 100644 (file)
index 0000000..2236422
--- /dev/null
@@ -0,0 +1,121 @@
+// Copyright 2017 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef ABSL_BASE_LOG_SEVERITY_H_
+#define ABSL_BASE_LOG_SEVERITY_H_
+
+#include <array>
+#include <ostream>
+
+#include "absl/base/attributes.h"
+#include "absl/base/config.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+
+// absl::LogSeverity
+//
+// Four severity levels are defined. Logging APIs should terminate the program
+// when a message is logged at severity `kFatal`; the other levels have no
+// special semantics.
+//
+// Values other than the four defined levels (e.g. produced by `static_cast`)
+// are valid, but their semantics when passed to a function, macro, or flag
+// depend on the function, macro, or flag. The usual behavior is to normalize
+// such values to a defined severity level, however in some cases values other
+// than the defined levels are useful for comparison.
+//
+// Example:
+//
+//   // Effectively disables all logging:
+//   SetMinLogLevel(static_cast<absl::LogSeverity>(100));
+//
+// Abseil flags may be defined with type `LogSeverity`. Dependency layering
+// constraints require that the `AbslParseFlag()` overload be declared and
+// defined in the flags library itself rather than here. The `AbslUnparseFlag()`
+// overload is defined there as well for consistency.
+//
+// absl::LogSeverity Flag String Representation
+//
+// An `absl::LogSeverity` has a string representation used for parsing
+// command-line flags based on the enumerator name (e.g. `kFatal`) or
+// its unprefixed name (without the `k`) in any case-insensitive form. (E.g.
+// "FATAL", "fatal" or "Fatal" are all valid.) Unparsing such flags produces an
+// unprefixed string representation in all caps (e.g. "FATAL") or an integer.
+//
+// Additionally, the parser accepts arbitrary integers (as if the type were
+// `int`).
+//
+// Examples:
+//
+//   --my_log_level=kInfo
+//   --my_log_level=INFO
+//   --my_log_level=info
+//   --my_log_level=0
+//
+// Unparsing a flag produces the same result as `absl::LogSeverityName()` for
+// the standard levels and a base-ten integer otherwise.
+enum class LogSeverity : int {
+  kInfo = 0,
+  kWarning = 1,
+  kError = 2,
+  kFatal = 3,
+};
+
+// LogSeverities()
+//
+// Returns an iterable of all standard `absl::LogSeverity` values, ordered from
+// least to most severe.
+constexpr std::array<absl::LogSeverity, 4> LogSeverities() {
+  return {{absl::LogSeverity::kInfo, absl::LogSeverity::kWarning,
+           absl::LogSeverity::kError, absl::LogSeverity::kFatal}};
+}
+
+// LogSeverityName()
+//
+// Returns the all-caps string representation (e.g. "INFO") of the specified
+// severity level if it is one of the standard levels and "UNKNOWN" otherwise.
+constexpr const char* LogSeverityName(absl::LogSeverity s) {
+  return s == absl::LogSeverity::kInfo
+             ? "INFO"
+             : s == absl::LogSeverity::kWarning
+                   ? "WARNING"
+                   : s == absl::LogSeverity::kError
+                         ? "ERROR"
+                         : s == absl::LogSeverity::kFatal ? "FATAL" : "UNKNOWN";
+}
+
+// NormalizeLogSeverity()
+//
+// Values less than `kInfo` normalize to `kInfo`; values greater than `kFatal`
+// normalize to `kError` (**NOT** `kFatal`).
+constexpr absl::LogSeverity NormalizeLogSeverity(absl::LogSeverity s) {
+  return s < absl::LogSeverity::kInfo
+             ? absl::LogSeverity::kInfo
+             : s > absl::LogSeverity::kFatal ? absl::LogSeverity::kError : s;
+}
+constexpr absl::LogSeverity NormalizeLogSeverity(int s) {
+  return absl::NormalizeLogSeverity(static_cast<absl::LogSeverity>(s));
+}
+
+// operator<<
+//
+// The exact representation of a streamed `absl::LogSeverity` is deliberately
+// unspecified; do not rely on it.
+std::ostream& operator<<(std::ostream& os, absl::LogSeverity s);
+
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#endif  // ABSL_BASE_LOG_SEVERITY_H_
diff --git a/src/absl/base/macros.h b/src/absl/base/macros.h
new file mode 100644 (file)
index 0000000..3e085a9
--- /dev/null
@@ -0,0 +1,158 @@
+//
+// Copyright 2017 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// -----------------------------------------------------------------------------
+// File: macros.h
+// -----------------------------------------------------------------------------
+//
+// This header file defines the set of language macros used within Abseil code.
+// For the set of macros used to determine supported compilers and platforms,
+// see absl/base/config.h instead.
+//
+// This code is compiled directly on many platforms, including client
+// platforms like Windows, Mac, and embedded systems.  Before making
+// any changes here, make sure that you're not breaking any platforms.
+
+#ifndef ABSL_BASE_MACROS_H_
+#define ABSL_BASE_MACROS_H_
+
+#include <cassert>
+#include <cstddef>
+
+#include "absl/base/attributes.h"
+#include "absl/base/config.h"
+#include "absl/base/optimization.h"
+#include "absl/base/port.h"
+
+// ABSL_ARRAYSIZE()
+//
+// Returns the number of elements in an array as a compile-time constant, which
+// can be used in defining new arrays. If you use this macro on a pointer by
+// mistake, you will get a compile-time error.
+#define ABSL_ARRAYSIZE(array) \
+  (sizeof(::absl::macros_internal::ArraySizeHelper(array)))
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace macros_internal {
+// Note: this internal template function declaration is used by ABSL_ARRAYSIZE.
+// The function doesn't need a definition, as we only use its type.
+template <typename T, size_t N>
+auto ArraySizeHelper(const T (&array)[N]) -> char (&)[N];
+}  // namespace macros_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+// ABSL_BAD_CALL_IF()
+//
+// Used on a function overload to trap bad calls: any call that matches the
+// overload will cause a compile-time error. This macro uses a clang-specific
+// "enable_if" attribute, as described at
+// https://clang.llvm.org/docs/AttributeReference.html#enable-if
+//
+// Overloads which use this macro should be bracketed by
+// `#ifdef ABSL_BAD_CALL_IF`.
+//
+// Example:
+//
+//   int isdigit(int c);
+//   #ifdef ABSL_BAD_CALL_IF
+//   int isdigit(int c)
+//     ABSL_BAD_CALL_IF(c <= -1 || c > 255,
+//                       "'c' must have the value of an unsigned char or EOF");
+//   #endif // ABSL_BAD_CALL_IF
+#if ABSL_HAVE_ATTRIBUTE(enable_if)
+#define ABSL_BAD_CALL_IF(expr, msg) \
+  __attribute__((enable_if(expr, "Bad call trap"), unavailable(msg)))
+#endif
+
+// ABSL_ASSERT()
+//
+// In C++11, `assert` can't be used portably within constexpr functions.
+// ABSL_ASSERT functions as a runtime assert but works in C++11 constexpr
+// functions.  Example:
+//
+// constexpr double Divide(double a, double b) {
+//   return ABSL_ASSERT(b != 0), a / b;
+// }
+//
+// This macro is inspired by
+// https://akrzemi1.wordpress.com/2017/05/18/asserts-in-constexpr-functions/
+#if defined(NDEBUG)
+#define ABSL_ASSERT(expr) \
+  (false ? static_cast<void>(expr) : static_cast<void>(0))
+#else
+#define ABSL_ASSERT(expr)                           \
+  (ABSL_PREDICT_TRUE((expr)) ? static_cast<void>(0) \
+                             : [] { assert(false && #expr); }())  // NOLINT
+#endif
+
+// `ABSL_INTERNAL_HARDENING_ABORT()` controls how `ABSL_HARDENING_ASSERT()`
+// aborts the program in release mode (when NDEBUG is defined). The
+// implementation should abort the program as quickly as possible and ideally it
+// should not be possible to ignore the abort request.
+#if (ABSL_HAVE_BUILTIN(__builtin_trap) &&         \
+     ABSL_HAVE_BUILTIN(__builtin_unreachable)) || \
+    (defined(__GNUC__) && !defined(__clang__))
+#define ABSL_INTERNAL_HARDENING_ABORT() \
+  do {                                  \
+    __builtin_trap();                   \
+    __builtin_unreachable();            \
+  } while (false)
+#else
+#define ABSL_INTERNAL_HARDENING_ABORT() abort()
+#endif
+
+// ABSL_HARDENING_ASSERT()
+//
+// `ABSL_HARDENING_ASSERT()` is like `ABSL_ASSERT()`, but used to implement
+// runtime assertions that should be enabled in hardened builds even when
+// `NDEBUG` is defined.
+//
+// When `NDEBUG` is not defined, `ABSL_HARDENING_ASSERT()` is identical to
+// `ABSL_ASSERT()`.
+//
+// See `ABSL_OPTION_HARDENED` in `absl/base/options.h` for more information on
+// hardened mode.
+#if ABSL_OPTION_HARDENED == 1 && defined(NDEBUG)
+#define ABSL_HARDENING_ASSERT(expr)                 \
+  (ABSL_PREDICT_TRUE((expr)) ? static_cast<void>(0) \
+                             : [] { ABSL_INTERNAL_HARDENING_ABORT(); }())
+#else
+#define ABSL_HARDENING_ASSERT(expr) ABSL_ASSERT(expr)
+#endif
+
+#ifdef ABSL_HAVE_EXCEPTIONS
+#define ABSL_INTERNAL_TRY try
+#define ABSL_INTERNAL_CATCH_ANY catch (...)
+#define ABSL_INTERNAL_RETHROW do { throw; } while (false)
+#else  // ABSL_HAVE_EXCEPTIONS
+#define ABSL_INTERNAL_TRY if (true)
+#define ABSL_INTERNAL_CATCH_ANY else if (false)
+#define ABSL_INTERNAL_RETHROW do {} while (false)
+#endif  // ABSL_HAVE_EXCEPTIONS
+
+// `ABSL_INTERNAL_UNREACHABLE` is an unreachable statement.  A program which
+// reaches one has undefined behavior, and the compiler may optimize
+// accordingly.
+#if defined(__GNUC__) || ABSL_HAVE_BUILTIN(__builtin_unreachable)
+#define ABSL_INTERNAL_UNREACHABLE __builtin_unreachable()
+#elif defined(_MSC_VER)
+#define ABSL_INTERNAL_UNREACHABLE __assume(0)
+#else
+#define ABSL_INTERNAL_UNREACHABLE
+#endif
+
+#endif  // ABSL_BASE_MACROS_H_
diff --git a/src/absl/base/optimization.h b/src/absl/base/optimization.h
new file mode 100644 (file)
index 0000000..d090be1
--- /dev/null
@@ -0,0 +1,244 @@
+//
+// Copyright 2017 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// -----------------------------------------------------------------------------
+// File: optimization.h
+// -----------------------------------------------------------------------------
+//
+// This header file defines portable macros for performance optimization.
+
+#ifndef ABSL_BASE_OPTIMIZATION_H_
+#define ABSL_BASE_OPTIMIZATION_H_
+
+#include <assert.h>
+
+#include "absl/base/config.h"
+
+// ABSL_BLOCK_TAIL_CALL_OPTIMIZATION
+//
+// Instructs the compiler to avoid optimizing tail-call recursion. This macro is
+// useful when you wish to preserve the existing function order within a stack
+// trace for logging, debugging, or profiling purposes.
+//
+// Example:
+//
+//   int f() {
+//     int result = g();
+//     ABSL_BLOCK_TAIL_CALL_OPTIMIZATION();
+//     return result;
+//   }
+#if defined(__pnacl__)
+#define ABSL_BLOCK_TAIL_CALL_OPTIMIZATION() if (volatile int x = 0) { (void)x; }
+#elif defined(__clang__)
+// Clang will not tail call given inline volatile assembly.
+#define ABSL_BLOCK_TAIL_CALL_OPTIMIZATION() __asm__ __volatile__("")
+#elif defined(__GNUC__)
+// GCC will not tail call given inline volatile assembly.
+#define ABSL_BLOCK_TAIL_CALL_OPTIMIZATION() __asm__ __volatile__("")
+#elif defined(_MSC_VER)
+#include <intrin.h>
+// The __nop() intrinsic blocks the optimisation.
+#define ABSL_BLOCK_TAIL_CALL_OPTIMIZATION() __nop()
+#else
+#define ABSL_BLOCK_TAIL_CALL_OPTIMIZATION() if (volatile int x = 0) { (void)x; }
+#endif
+
+// ABSL_CACHELINE_SIZE
+//
+// Explicitly defines the size of the L1 cache for purposes of alignment.
+// Setting the cacheline size allows you to specify that certain objects be
+// aligned on a cacheline boundary with `ABSL_CACHELINE_ALIGNED` declarations.
+// (See below.)
+//
+// NOTE: this macro should be replaced with the following C++17 features, when
+// those are generally available:
+//
+//   * `std::hardware_constructive_interference_size`
+//   * `std::hardware_destructive_interference_size`
+//
+// See http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0154r1.html
+// for more information.
+#if defined(__GNUC__)
+// Cache line alignment
+#if defined(__i386__) || defined(__x86_64__)
+#define ABSL_CACHELINE_SIZE 64
+#elif defined(__powerpc64__)
+#define ABSL_CACHELINE_SIZE 128
+#elif defined(__aarch64__)
+// We would need to read special register ctr_el0 to find out L1 dcache size.
+// This value is a good estimate based on a real aarch64 machine.
+#define ABSL_CACHELINE_SIZE 64
+#elif defined(__arm__)
+// Cache line sizes for ARM: These values are not strictly correct since
+// cache line sizes depend on implementations, not architectures.  There
+// are even implementations with cache line sizes configurable at boot
+// time.
+#if defined(__ARM_ARCH_5T__)
+#define ABSL_CACHELINE_SIZE 32
+#elif defined(__ARM_ARCH_7A__)
+#define ABSL_CACHELINE_SIZE 64
+#endif
+#endif
+
+#ifndef ABSL_CACHELINE_SIZE
+// A reasonable default guess.  Note that overestimates tend to waste more
+// space, while underestimates tend to waste more time.
+#define ABSL_CACHELINE_SIZE 64
+#endif
+
+// ABSL_CACHELINE_ALIGNED
+//
+// Indicates that the declared object be cache aligned using
+// `ABSL_CACHELINE_SIZE` (see above). Cacheline aligning objects allows you to
+// load a set of related objects in the L1 cache for performance improvements.
+// Cacheline aligning objects properly allows constructive memory sharing and
+// prevents destructive (or "false") memory sharing.
+//
+// NOTE: callers should replace uses of this macro with `alignas()` using
+// `std::hardware_constructive_interference_size` and/or
+// `std::hardware_destructive_interference_size` when C++17 becomes available to
+// them.
+//
+// See http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0154r1.html
+// for more information.
+//
+// On some compilers, `ABSL_CACHELINE_ALIGNED` expands to an `__attribute__`
+// or `__declspec` attribute. For compilers where this is not known to work,
+// the macro expands to nothing.
+//
+// No further guarantees are made here. The result of applying the macro
+// to variables and types is always implementation-defined.
+//
+// WARNING: It is easy to use this attribute incorrectly, even to the point
+// of causing bugs that are difficult to diagnose, crash, etc. It does not
+// of itself guarantee that objects are aligned to a cache line.
+//
+// NOTE: Some compilers are picky about the locations of annotations such as
+// this attribute, so prefer to put it at the beginning of your declaration.
+// For example,
+//
+//   ABSL_CACHELINE_ALIGNED static Foo* foo = ...
+//
+//   class ABSL_CACHELINE_ALIGNED Bar { ...
+//
+// Recommendations:
+//
+// 1) Consult compiler documentation; this comment is not kept in sync as
+//    toolchains evolve.
+// 2) Verify your use has the intended effect. This often requires inspecting
+//    the generated machine code.
+// 3) Prefer applying this attribute to individual variables. Avoid
+//    applying it to types. This tends to localize the effect.
+#define ABSL_CACHELINE_ALIGNED __attribute__((aligned(ABSL_CACHELINE_SIZE)))
+#elif defined(_MSC_VER)
+#define ABSL_CACHELINE_SIZE 64
+#define ABSL_CACHELINE_ALIGNED __declspec(align(ABSL_CACHELINE_SIZE))
+#else
+#define ABSL_CACHELINE_SIZE 64
+#define ABSL_CACHELINE_ALIGNED
+#endif
+
+// ABSL_PREDICT_TRUE, ABSL_PREDICT_FALSE
+//
+// Enables the compiler to prioritize compilation using static analysis for
+// likely paths within a boolean branch.
+//
+// Example:
+//
+//   if (ABSL_PREDICT_TRUE(expression)) {
+//     return result;                        // Faster if more likely
+//   } else {
+//     return 0;
+//   }
+//
+// Compilers can use the information that a certain branch is not likely to be
+// taken (for instance, a CHECK failure) to optimize for the common case in
+// the absence of better information (ie. compiling gcc with `-fprofile-arcs`).
+//
+// Recommendation: Modern CPUs dynamically predict branch execution paths,
+// typically with accuracy greater than 97%. As a result, annotating every
+// branch in a codebase is likely counterproductive; however, annotating
+// specific branches that are both hot and consistently mispredicted is likely
+// to yield performance improvements.
+#if ABSL_HAVE_BUILTIN(__builtin_expect) || \
+    (defined(__GNUC__) && !defined(__clang__))
+#define ABSL_PREDICT_FALSE(x) (__builtin_expect(false || (x), false))
+#define ABSL_PREDICT_TRUE(x) (__builtin_expect(false || (x), true))
+#else
+#define ABSL_PREDICT_FALSE(x) (x)
+#define ABSL_PREDICT_TRUE(x) (x)
+#endif
+
+// ABSL_INTERNAL_ASSUME(cond)
+// Informs the compiler that a condition is always true and that it can assume
+// it to be true for optimization purposes. The call has undefined behavior if
+// the condition is false.
+// In !NDEBUG mode, the condition is checked with an assert().
+// NOTE: The expression must not have side effects, as it will only be evaluated
+// in some compilation modes and not others.
+//
+// Example:
+//
+//   int x = ...;
+//   ABSL_INTERNAL_ASSUME(x >= 0);
+//   // The compiler can optimize the division to a simple right shift using the
+//   // assumption specified above.
+//   int y = x / 16;
+//
+#if !defined(NDEBUG)
+#define ABSL_INTERNAL_ASSUME(cond) assert(cond)
+#elif ABSL_HAVE_BUILTIN(__builtin_assume)
+#define ABSL_INTERNAL_ASSUME(cond) __builtin_assume(cond)
+#elif defined(__GNUC__) || ABSL_HAVE_BUILTIN(__builtin_unreachable)
+#define ABSL_INTERNAL_ASSUME(cond)        \
+  do {                                    \
+    if (!(cond)) __builtin_unreachable(); \
+  } while (0)
+#elif defined(_MSC_VER)
+#define ABSL_INTERNAL_ASSUME(cond) __assume(cond)
+#else
+#define ABSL_INTERNAL_ASSUME(cond)      \
+  do {                                  \
+    static_cast<void>(false && (cond)); \
+  } while (0)
+#endif
+
+// ABSL_INTERNAL_UNIQUE_SMALL_NAME(cond)
+// This macro forces small unique name on a static file level symbols like
+// static local variables or static functions. This is intended to be used in
+// macro definitions to optimize the cost of generated code. Do NOT use it on
+// symbols exported from translation unit since it may cause a link time
+// conflict.
+//
+// Example:
+//
+// #define MY_MACRO(txt)
+// namespace {
+//  char VeryVeryLongVarName[] ABSL_INTERNAL_UNIQUE_SMALL_NAME() = txt;
+//  const char* VeryVeryLongFuncName() ABSL_INTERNAL_UNIQUE_SMALL_NAME();
+//  const char* VeryVeryLongFuncName() { return txt; }
+// }
+//
+
+#if defined(__GNUC__)
+#define ABSL_INTERNAL_UNIQUE_SMALL_NAME2(x) #x
+#define ABSL_INTERNAL_UNIQUE_SMALL_NAME1(x) ABSL_INTERNAL_UNIQUE_SMALL_NAME2(x)
+#define ABSL_INTERNAL_UNIQUE_SMALL_NAME() \
+  asm(ABSL_INTERNAL_UNIQUE_SMALL_NAME1(.absl.__COUNTER__))
+#else
+#define ABSL_INTERNAL_UNIQUE_SMALL_NAME()
+#endif
+
+#endif  // ABSL_BASE_OPTIMIZATION_H_
diff --git a/src/absl/base/options.h b/src/absl/base/options.h
new file mode 100644 (file)
index 0000000..eca879a
--- /dev/null
@@ -0,0 +1,238 @@
+// Copyright 2019 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// -----------------------------------------------------------------------------
+// File: options.h
+// -----------------------------------------------------------------------------
+//
+// This file contains Abseil configuration options for setting specific
+// implementations instead of letting Abseil determine which implementation to
+// use at compile-time. Setting these options may be useful for package or build
+// managers who wish to guarantee ABI stability within binary builds (which are
+// otherwise difficult to enforce).
+//
+// *** IMPORTANT NOTICE FOR PACKAGE MANAGERS:  It is important that
+// maintainers of package managers who wish to package Abseil read and
+// understand this file! ***
+//
+// Abseil contains a number of possible configuration endpoints, based on
+// parameters such as the detected platform, language version, or command-line
+// flags used to invoke the underlying binary. As is the case with all
+// libraries, binaries which contain Abseil code must ensure that separate
+// packages use the same compiled copy of Abseil to avoid a diamond dependency
+// problem, which can occur if two packages built with different Abseil
+// configuration settings are linked together. Diamond dependency problems in
+// C++ may manifest as violations to the One Definition Rule (ODR) (resulting in
+// linker errors), or undefined behavior (resulting in crashes).
+//
+// Diamond dependency problems can be avoided if all packages utilize the same
+// exact version of Abseil. Building from source code with the same compilation
+// parameters is the easiest way to avoid such dependency problems. However, for
+// package managers who cannot control such compilation parameters, we are
+// providing the file to allow you to inject ABI (Application Binary Interface)
+// stability across builds. Settings options in this file will neither change
+// API nor ABI, providing a stable copy of Abseil between packages.
+//
+// Care must be taken to keep options within these configurations isolated
+// from any other dynamic settings, such as command-line flags which could alter
+// these options. This file is provided specifically to help build and package
+// managers provide a stable copy of Abseil within their libraries and binaries;
+// other developers should not have need to alter the contents of this file.
+//
+// -----------------------------------------------------------------------------
+// Usage
+// -----------------------------------------------------------------------------
+//
+// For any particular package release, set the appropriate definitions within
+// this file to whatever value makes the most sense for your package(s). Note
+// that, by default, most of these options, at the moment, affect the
+// implementation of types; future options may affect other implementation
+// details.
+//
+// NOTE: the defaults within this file all assume that Abseil can select the
+// proper Abseil implementation at compile-time, which will not be sufficient
+// to guarantee ABI stability to package managers.
+
+#ifndef ABSL_BASE_OPTIONS_H_
+#define ABSL_BASE_OPTIONS_H_
+
+// Include a standard library header to allow configuration based on the
+// standard library in use.
+#ifdef __cplusplus
+#include <ciso646>
+#endif
+
+// -----------------------------------------------------------------------------
+// Type Compatibility Options
+// -----------------------------------------------------------------------------
+//
+// ABSL_OPTION_USE_STD_ANY
+//
+// This option controls whether absl::any is implemented as an alias to
+// std::any, or as an independent implementation.
+//
+// A value of 0 means to use Abseil's implementation.  This requires only C++11
+// support, and is expected to work on every toolchain we support.
+//
+// A value of 1 means to use an alias to std::any.  This requires that all code
+// using Abseil is built in C++17 mode or later.
+//
+// A value of 2 means to detect the C++ version being used to compile Abseil,
+// and use an alias only if a working std::any is available.  This option is
+// useful when you are building your entire program, including all of its
+// dependencies, from source.  It should not be used otherwise -- for example,
+// if you are distributing Abseil in a binary package manager -- since in
+// mode 2, absl::any will name a different type, with a different mangled name
+// and binary layout, depending on the compiler flags passed by the end user.
+// For more info, see https://abseil.io/about/design/dropin-types.
+//
+// User code should not inspect this macro.  To check in the preprocessor if
+// absl::any is a typedef of std::any, use the feature macro ABSL_USES_STD_ANY.
+
+#define ABSL_OPTION_USE_STD_ANY 2
+
+
+// ABSL_OPTION_USE_STD_OPTIONAL
+//
+// This option controls whether absl::optional is implemented as an alias to
+// std::optional, or as an independent implementation.
+//
+// A value of 0 means to use Abseil's implementation.  This requires only C++11
+// support, and is expected to work on every toolchain we support.
+//
+// A value of 1 means to use an alias to std::optional.  This requires that all
+// code using Abseil is built in C++17 mode or later.
+//
+// A value of 2 means to detect the C++ version being used to compile Abseil,
+// and use an alias only if a working std::optional is available.  This option
+// is useful when you are building your program from source.  It should not be
+// used otherwise -- for example, if you are distributing Abseil in a binary
+// package manager -- since in mode 2, absl::optional will name a different
+// type, with a different mangled name and binary layout, depending on the
+// compiler flags passed by the end user.  For more info, see
+// https://abseil.io/about/design/dropin-types.
+
+// User code should not inspect this macro.  To check in the preprocessor if
+// absl::optional is a typedef of std::optional, use the feature macro
+// ABSL_USES_STD_OPTIONAL.
+
+#define ABSL_OPTION_USE_STD_OPTIONAL 2
+
+
+// ABSL_OPTION_USE_STD_STRING_VIEW
+//
+// This option controls whether absl::string_view is implemented as an alias to
+// std::string_view, or as an independent implementation.
+//
+// A value of 0 means to use Abseil's implementation.  This requires only C++11
+// support, and is expected to work on every toolchain we support.
+//
+// A value of 1 means to use an alias to std::string_view.  This requires that
+// all code using Abseil is built in C++17 mode or later.
+//
+// A value of 2 means to detect the C++ version being used to compile Abseil,
+// and use an alias only if a working std::string_view is available.  This
+// option is useful when you are building your program from source.  It should
+// not be used otherwise -- for example, if you are distributing Abseil in a
+// binary package manager -- since in mode 2, absl::string_view will name a
+// different type, with a different mangled name and binary layout, depending on
+// the compiler flags passed by the end user.  For more info, see
+// https://abseil.io/about/design/dropin-types.
+//
+// User code should not inspect this macro.  To check in the preprocessor if
+// absl::string_view is a typedef of std::string_view, use the feature macro
+// ABSL_USES_STD_STRING_VIEW.
+
+#define ABSL_OPTION_USE_STD_STRING_VIEW 2
+
+// ABSL_OPTION_USE_STD_VARIANT
+//
+// This option controls whether absl::variant is implemented as an alias to
+// std::variant, or as an independent implementation.
+//
+// A value of 0 means to use Abseil's implementation.  This requires only C++11
+// support, and is expected to work on every toolchain we support.
+//
+// A value of 1 means to use an alias to std::variant.  This requires that all
+// code using Abseil is built in C++17 mode or later.
+//
+// A value of 2 means to detect the C++ version being used to compile Abseil,
+// and use an alias only if a working std::variant is available.  This option
+// is useful when you are building your program from source.  It should not be
+// used otherwise -- for example, if you are distributing Abseil in a binary
+// package manager -- since in mode 2, absl::variant will name a different
+// type, with a different mangled name and binary layout, depending on the
+// compiler flags passed by the end user.  For more info, see
+// https://abseil.io/about/design/dropin-types.
+//
+// User code should not inspect this macro.  To check in the preprocessor if
+// absl::variant is a typedef of std::variant, use the feature macro
+// ABSL_USES_STD_VARIANT.
+
+#define ABSL_OPTION_USE_STD_VARIANT 2
+
+
+// ABSL_OPTION_USE_INLINE_NAMESPACE
+// ABSL_OPTION_INLINE_NAMESPACE_NAME
+//
+// These options controls whether all entities in the absl namespace are
+// contained within an inner inline namespace.  This does not affect the
+// user-visible API of Abseil, but it changes the mangled names of all symbols.
+//
+// This can be useful as a version tag if you are distributing Abseil in
+// precompiled form.  This will prevent a binary library build of Abseil with
+// one inline namespace being used with headers configured with a different
+// inline namespace name.  Binary packagers are reminded that Abseil does not
+// guarantee any ABI stability in Abseil, so any update of Abseil or
+// configuration change in such a binary package should be combined with a
+// new, unique value for the inline namespace name.
+//
+// A value of 0 means not to use inline namespaces.
+//
+// A value of 1 means to use an inline namespace with the given name inside
+// namespace absl.  If this is set, ABSL_OPTION_INLINE_NAMESPACE_NAME must also
+// be changed to a new, unique identifier name.  In particular "head" is not
+// allowed.
+
+#define ABSL_OPTION_USE_INLINE_NAMESPACE 1
+#define ABSL_OPTION_INLINE_NAMESPACE_NAME lts_20210324
+
+// ABSL_OPTION_HARDENED
+//
+// This option enables a "hardened" build in release mode (in this context,
+// release mode is defined as a build where the `NDEBUG` macro is defined).
+//
+// A value of 0 means that "hardened" mode is not enabled.
+//
+// A value of 1 means that "hardened" mode is enabled.
+//
+// Hardened builds have additional security checks enabled when `NDEBUG` is
+// defined. Defining `NDEBUG` is normally used to turn `assert()` macro into a
+// no-op, as well as disabling other bespoke program consistency checks. By
+// defining ABSL_OPTION_HARDENED to 1, a select set of checks remain enabled in
+// release mode. These checks guard against programming errors that may lead to
+// security vulnerabilities. In release mode, when one of these programming
+// errors is encountered, the program will immediately abort, possibly without
+// any attempt at logging.
+//
+// The checks enabled by this option are not free; they do incur runtime cost.
+//
+// The checks enabled by this option are always active when `NDEBUG` is not
+// defined, even in the case when ABSL_OPTION_HARDENED is defined to 0. The
+// checks enabled by this option may abort the program in a different way and
+// log additional information when `NDEBUG` is not defined.
+
+#define ABSL_OPTION_HARDENED 0
+
+#endif  // ABSL_BASE_OPTIONS_H_
diff --git a/src/absl/base/policy_checks.h b/src/absl/base/policy_checks.h
new file mode 100644 (file)
index 0000000..06b3243
--- /dev/null
@@ -0,0 +1,111 @@
+// Copyright 2017 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// -----------------------------------------------------------------------------
+// File: policy_checks.h
+// -----------------------------------------------------------------------------
+//
+// This header enforces a minimum set of policies at build time, such as the
+// supported compiler and library versions. Unsupported configurations are
+// reported with `#error`. This enforcement is best effort, so successfully
+// compiling this header does not guarantee a supported configuration.
+
+#ifndef ABSL_BASE_POLICY_CHECKS_H_
+#define ABSL_BASE_POLICY_CHECKS_H_
+
+// Included for the __GLIBC_PREREQ macro used below.
+#include <limits.h>
+
+// Included for the _STLPORT_VERSION macro used below.
+#if defined(__cplusplus)
+#include <cstddef>
+#endif
+
+// -----------------------------------------------------------------------------
+// Operating System Check
+// -----------------------------------------------------------------------------
+
+#if defined(__CYGWIN__)
+#error "Cygwin is not supported."
+#endif
+
+// -----------------------------------------------------------------------------
+// Toolchain Check
+// -----------------------------------------------------------------------------
+
+// We support MSVC++ 14.0 update 2 and later.
+// This minimum will go up.
+#if defined(_MSC_FULL_VER) && _MSC_FULL_VER < 190023918 && !defined(__clang__)
+#error "This package requires Visual Studio 2015 Update 2 or higher."
+#endif
+
+// We support gcc 4.7 and later.
+// This minimum will go up.
+#if defined(__GNUC__) && !defined(__clang__)
+#if __GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 7)
+#error "This package requires gcc 4.7 or higher."
+#endif
+#endif
+
+// We support Apple Xcode clang 4.2.1 (version 421.11.65) and later.
+// This corresponds to Apple Xcode version 4.5.
+// This minimum will go up.
+#if defined(__apple_build_version__) && __apple_build_version__ < 4211165
+#error "This package requires __apple_build_version__ of 4211165 or higher."
+#endif
+
+// -----------------------------------------------------------------------------
+// C++ Version Check
+// -----------------------------------------------------------------------------
+
+// Enforce C++11 as the minimum.  Note that Visual Studio has not
+// advanced __cplusplus despite being good enough for our purposes, so
+// so we exempt it from the check.
+#if defined(__cplusplus) && !defined(_MSC_VER)
+#if __cplusplus < 201103L
+#error "C++ versions less than C++11 are not supported."
+#endif
+#endif
+
+// -----------------------------------------------------------------------------
+// Standard Library Check
+// -----------------------------------------------------------------------------
+
+#if defined(_STLPORT_VERSION)
+#error "STLPort is not supported."
+#endif
+
+// -----------------------------------------------------------------------------
+// `char` Size Check
+// -----------------------------------------------------------------------------
+
+// Abseil currently assumes CHAR_BIT == 8. If you would like to use Abseil on a
+// platform where this is not the case, please provide us with the details about
+// your platform so we can consider relaxing this requirement.
+#if CHAR_BIT != 8
+#error "Abseil assumes CHAR_BIT == 8."
+#endif
+
+// -----------------------------------------------------------------------------
+// `int` Size Check
+// -----------------------------------------------------------------------------
+
+// Abseil currently assumes that an int is 4 bytes. If you would like to use
+// Abseil on a platform where this is not the case, please provide us with the
+// details about your platform so we can consider relaxing this requirement.
+#if INT_MAX < 2147483647
+#error "Abseil assumes that int is at least 4 bytes. "
+#endif
+
+#endif  // ABSL_BASE_POLICY_CHECKS_H_
diff --git a/src/absl/base/port.h b/src/absl/base/port.h
new file mode 100644 (file)
index 0000000..5bc4d6c
--- /dev/null
@@ -0,0 +1,25 @@
+// Copyright 2017 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// This files is a forwarding header for other headers containing various
+// portability macros and functions.
+
+#ifndef ABSL_BASE_PORT_H_
+#define ABSL_BASE_PORT_H_
+
+#include "absl/base/attributes.h"
+#include "absl/base/config.h"
+#include "absl/base/optimization.h"
+
+#endif  // ABSL_BASE_PORT_H_
diff --git a/src/absl/base/thread_annotations.h b/src/absl/base/thread_annotations.h
new file mode 100644 (file)
index 0000000..9695f6d
--- /dev/null
@@ -0,0 +1,335 @@
+// Copyright 2017 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// -----------------------------------------------------------------------------
+// File: thread_annotations.h
+// -----------------------------------------------------------------------------
+//
+// This header file contains macro definitions for thread safety annotations
+// that allow developers to document the locking policies of multi-threaded
+// code. The annotations can also help program analysis tools to identify
+// potential thread safety issues.
+//
+// These annotations are implemented using compiler attributes. Using the macros
+// defined here instead of raw attributes allow for portability and future
+// compatibility.
+//
+// When referring to mutexes in the arguments of the attributes, you should
+// use variable names or more complex expressions (e.g. my_object->mutex_)
+// that evaluate to a concrete mutex object whenever possible. If the mutex
+// you want to refer to is not in scope, you may use a member pointer
+// (e.g. &MyClass::mutex_) to refer to a mutex in some (unknown) object.
+
+#ifndef ABSL_BASE_THREAD_ANNOTATIONS_H_
+#define ABSL_BASE_THREAD_ANNOTATIONS_H_
+
+#include "absl/base/attributes.h"
+#include "absl/base/config.h"
+// TODO(mbonadei): Remove after the backward compatibility period.
+#include "absl/base/internal/thread_annotations.h"  // IWYU pragma: export
+
+// ABSL_GUARDED_BY()
+//
+// Documents if a shared field or global variable needs to be protected by a
+// mutex. ABSL_GUARDED_BY() allows the user to specify a particular mutex that
+// should be held when accessing the annotated variable.
+//
+// Although this annotation (and ABSL_PT_GUARDED_BY, below) cannot be applied to
+// local variables, a local variable and its associated mutex can often be
+// combined into a small class or struct, thereby allowing the annotation.
+//
+// Example:
+//
+//   class Foo {
+//     Mutex mu_;
+//     int p1_ ABSL_GUARDED_BY(mu_);
+//     ...
+//   };
+#if ABSL_HAVE_ATTRIBUTE(guarded_by)
+#define ABSL_GUARDED_BY(x) __attribute__((guarded_by(x)))
+#else
+#define ABSL_GUARDED_BY(x)
+#endif
+
+// ABSL_PT_GUARDED_BY()
+//
+// Documents if the memory location pointed to by a pointer should be guarded
+// by a mutex when dereferencing the pointer.
+//
+// Example:
+//   class Foo {
+//     Mutex mu_;
+//     int *p1_ ABSL_PT_GUARDED_BY(mu_);
+//     ...
+//   };
+//
+// Note that a pointer variable to a shared memory location could itself be a
+// shared variable.
+//
+// Example:
+//
+//   // `q_`, guarded by `mu1_`, points to a shared memory location that is
+//   // guarded by `mu2_`:
+//   int *q_ ABSL_GUARDED_BY(mu1_) ABSL_PT_GUARDED_BY(mu2_);
+#if ABSL_HAVE_ATTRIBUTE(pt_guarded_by)
+#define ABSL_PT_GUARDED_BY(x) __attribute__((pt_guarded_by(x)))
+#else
+#define ABSL_PT_GUARDED_BY(x)
+#endif
+
+// ABSL_ACQUIRED_AFTER() / ABSL_ACQUIRED_BEFORE()
+//
+// Documents the acquisition order between locks that can be held
+// simultaneously by a thread. For any two locks that need to be annotated
+// to establish an acquisition order, only one of them needs the annotation.
+// (i.e. You don't have to annotate both locks with both ABSL_ACQUIRED_AFTER
+// and ABSL_ACQUIRED_BEFORE.)
+//
+// As with ABSL_GUARDED_BY, this is only applicable to mutexes that are shared
+// fields or global variables.
+//
+// Example:
+//
+//   Mutex m1_;
+//   Mutex m2_ ABSL_ACQUIRED_AFTER(m1_);
+#if ABSL_HAVE_ATTRIBUTE(acquired_after)
+#define ABSL_ACQUIRED_AFTER(...) __attribute__((acquired_after(__VA_ARGS__)))
+#else
+#define ABSL_ACQUIRED_AFTER(...)
+#endif
+
+#if ABSL_HAVE_ATTRIBUTE(acquired_before)
+#define ABSL_ACQUIRED_BEFORE(...) __attribute__((acquired_before(__VA_ARGS__)))
+#else
+#define ABSL_ACQUIRED_BEFORE(...)
+#endif
+
+// ABSL_EXCLUSIVE_LOCKS_REQUIRED() / ABSL_SHARED_LOCKS_REQUIRED()
+//
+// Documents a function that expects a mutex to be held prior to entry.
+// The mutex is expected to be held both on entry to, and exit from, the
+// function.
+//
+// An exclusive lock allows read-write access to the guarded data member(s), and
+// only one thread can acquire a lock exclusively at any one time. A shared lock
+// allows read-only access, and any number of threads can acquire a shared lock
+// concurrently.
+//
+// Generally, non-const methods should be annotated with
+// ABSL_EXCLUSIVE_LOCKS_REQUIRED, while const methods should be annotated with
+// ABSL_SHARED_LOCKS_REQUIRED.
+//
+// Example:
+//
+//   Mutex mu1, mu2;
+//   int a ABSL_GUARDED_BY(mu1);
+//   int b ABSL_GUARDED_BY(mu2);
+//
+//   void foo() ABSL_EXCLUSIVE_LOCKS_REQUIRED(mu1, mu2) { ... }
+//   void bar() const ABSL_SHARED_LOCKS_REQUIRED(mu1, mu2) { ... }
+#if ABSL_HAVE_ATTRIBUTE(exclusive_locks_required)
+#define ABSL_EXCLUSIVE_LOCKS_REQUIRED(...) \
+  __attribute__((exclusive_locks_required(__VA_ARGS__)))
+#else
+#define ABSL_EXCLUSIVE_LOCKS_REQUIRED(...)
+#endif
+
+#if ABSL_HAVE_ATTRIBUTE(shared_locks_required)
+#define ABSL_SHARED_LOCKS_REQUIRED(...) \
+  __attribute__((shared_locks_required(__VA_ARGS__)))
+#else
+#define ABSL_SHARED_LOCKS_REQUIRED(...)
+#endif
+
+// ABSL_LOCKS_EXCLUDED()
+//
+// Documents the locks acquired in the body of the function. These locks
+// cannot be held when calling this function (as Abseil's `Mutex` locks are
+// non-reentrant).
+#if ABSL_HAVE_ATTRIBUTE(locks_excluded)
+#define ABSL_LOCKS_EXCLUDED(...) __attribute__((locks_excluded(__VA_ARGS__)))
+#else
+#define ABSL_LOCKS_EXCLUDED(...)
+#endif
+
+// ABSL_LOCK_RETURNED()
+//
+// Documents a function that returns a mutex without acquiring it.  For example,
+// a public getter method that returns a pointer to a private mutex should
+// be annotated with ABSL_LOCK_RETURNED.
+#if ABSL_HAVE_ATTRIBUTE(lock_returned)
+#define ABSL_LOCK_RETURNED(x) __attribute__((lock_returned(x)))
+#else
+#define ABSL_LOCK_RETURNED(x)
+#endif
+
+// ABSL_LOCKABLE
+//
+// Documents if a class/type is a lockable type (such as the `Mutex` class).
+#if ABSL_HAVE_ATTRIBUTE(lockable)
+#define ABSL_LOCKABLE __attribute__((lockable))
+#else
+#define ABSL_LOCKABLE
+#endif
+
+// ABSL_SCOPED_LOCKABLE
+//
+// Documents if a class does RAII locking (such as the `MutexLock` class).
+// The constructor should use `LOCK_FUNCTION()` to specify the mutex that is
+// acquired, and the destructor should use `UNLOCK_FUNCTION()` with no
+// arguments; the analysis will assume that the destructor unlocks whatever the
+// constructor locked.
+#if ABSL_HAVE_ATTRIBUTE(scoped_lockable)
+#define ABSL_SCOPED_LOCKABLE __attribute__((scoped_lockable))
+#else
+#define ABSL_SCOPED_LOCKABLE
+#endif
+
+// ABSL_EXCLUSIVE_LOCK_FUNCTION()
+//
+// Documents functions that acquire a lock in the body of a function, and do
+// not release it.
+#if ABSL_HAVE_ATTRIBUTE(exclusive_lock_function)
+#define ABSL_EXCLUSIVE_LOCK_FUNCTION(...) \
+  __attribute__((exclusive_lock_function(__VA_ARGS__)))
+#else
+#define ABSL_EXCLUSIVE_LOCK_FUNCTION(...)
+#endif
+
+// ABSL_SHARED_LOCK_FUNCTION()
+//
+// Documents functions that acquire a shared (reader) lock in the body of a
+// function, and do not release it.
+#if ABSL_HAVE_ATTRIBUTE(shared_lock_function)
+#define ABSL_SHARED_LOCK_FUNCTION(...) \
+  __attribute__((shared_lock_function(__VA_ARGS__)))
+#else
+#define ABSL_SHARED_LOCK_FUNCTION(...)
+#endif
+
+// ABSL_UNLOCK_FUNCTION()
+//
+// Documents functions that expect a lock to be held on entry to the function,
+// and release it in the body of the function.
+#if ABSL_HAVE_ATTRIBUTE(unlock_function)
+#define ABSL_UNLOCK_FUNCTION(...) __attribute__((unlock_function(__VA_ARGS__)))
+#else
+#define ABSL_UNLOCK_FUNCTION(...)
+#endif
+
+// ABSL_EXCLUSIVE_TRYLOCK_FUNCTION() / ABSL_SHARED_TRYLOCK_FUNCTION()
+//
+// Documents functions that try to acquire a lock, and return success or failure
+// (or a non-boolean value that can be interpreted as a boolean).
+// The first argument should be `true` for functions that return `true` on
+// success, or `false` for functions that return `false` on success. The second
+// argument specifies the mutex that is locked on success. If unspecified, this
+// mutex is assumed to be `this`.
+#if ABSL_HAVE_ATTRIBUTE(exclusive_trylock_function)
+#define ABSL_EXCLUSIVE_TRYLOCK_FUNCTION(...) \
+  __attribute__((exclusive_trylock_function(__VA_ARGS__)))
+#else
+#define ABSL_EXCLUSIVE_TRYLOCK_FUNCTION(...)
+#endif
+
+#if ABSL_HAVE_ATTRIBUTE(shared_trylock_function)
+#define ABSL_SHARED_TRYLOCK_FUNCTION(...) \
+  __attribute__((shared_trylock_function(__VA_ARGS__)))
+#else
+#define ABSL_SHARED_TRYLOCK_FUNCTION(...)
+#endif
+
+// ABSL_ASSERT_EXCLUSIVE_LOCK() / ABSL_ASSERT_SHARED_LOCK()
+//
+// Documents functions that dynamically check to see if a lock is held, and fail
+// if it is not held.
+#if ABSL_HAVE_ATTRIBUTE(assert_exclusive_lock)
+#define ABSL_ASSERT_EXCLUSIVE_LOCK(...) \
+  __attribute__((assert_exclusive_lock(__VA_ARGS__)))
+#else
+#define ABSL_ASSERT_EXCLUSIVE_LOCK(...)
+#endif
+
+#if ABSL_HAVE_ATTRIBUTE(assert_shared_lock)
+#define ABSL_ASSERT_SHARED_LOCK(...) \
+  __attribute__((assert_shared_lock(__VA_ARGS__)))
+#else
+#define ABSL_ASSERT_SHARED_LOCK(...)
+#endif
+
+// ABSL_NO_THREAD_SAFETY_ANALYSIS
+//
+// Turns off thread safety checking within the body of a particular function.
+// This annotation is used to mark functions that are known to be correct, but
+// the locking behavior is more complicated than the analyzer can handle.
+#if ABSL_HAVE_ATTRIBUTE(no_thread_safety_analysis)
+#define ABSL_NO_THREAD_SAFETY_ANALYSIS \
+  __attribute__((no_thread_safety_analysis))
+#else
+#define ABSL_NO_THREAD_SAFETY_ANALYSIS
+#endif
+
+//------------------------------------------------------------------------------
+// Tool-Supplied Annotations
+//------------------------------------------------------------------------------
+
+// ABSL_TS_UNCHECKED should be placed around lock expressions that are not valid
+// C++ syntax, but which are present for documentation purposes.  These
+// annotations will be ignored by the analysis.
+#define ABSL_TS_UNCHECKED(x) ""
+
+// ABSL_TS_FIXME is used to mark lock expressions that are not valid C++ syntax.
+// It is used by automated tools to mark and disable invalid expressions.
+// The annotation should either be fixed, or changed to ABSL_TS_UNCHECKED.
+#define ABSL_TS_FIXME(x) ""
+
+// Like ABSL_NO_THREAD_SAFETY_ANALYSIS, this turns off checking within the body
+// of a particular function.  However, this attribute is used to mark functions
+// that are incorrect and need to be fixed.  It is used by automated tools to
+// avoid breaking the build when the analysis is updated.
+// Code owners are expected to eventually fix the routine.
+#define ABSL_NO_THREAD_SAFETY_ANALYSIS_FIXME ABSL_NO_THREAD_SAFETY_ANALYSIS
+
+// Similar to ABSL_NO_THREAD_SAFETY_ANALYSIS_FIXME, this macro marks a
+// ABSL_GUARDED_BY annotation that needs to be fixed, because it is producing
+// thread safety warning. It disables the ABSL_GUARDED_BY.
+#define ABSL_GUARDED_BY_FIXME(x)
+
+// Disables warnings for a single read operation.  This can be used to avoid
+// warnings when it is known that the read is not actually involved in a race,
+// but the compiler cannot confirm that.
+#define ABSL_TS_UNCHECKED_READ(x) absl::base_internal::ts_unchecked_read(x)
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace base_internal {
+
+// Takes a reference to a guarded data member, and returns an unguarded
+// reference.
+// Do not use this function directly, use ABSL_TS_UNCHECKED_READ instead.
+template <typename T>
+inline const T& ts_unchecked_read(const T& v) ABSL_NO_THREAD_SAFETY_ANALYSIS {
+  return v;
+}
+
+template <typename T>
+inline T& ts_unchecked_read(T& v) ABSL_NO_THREAD_SAFETY_ANALYSIS {
+  return v;
+}
+
+}  // namespace base_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#endif  // ABSL_BASE_THREAD_ANNOTATIONS_H_
diff --git a/src/absl/container/btree_map.h b/src/absl/container/btree_map.h
new file mode 100644 (file)
index 0000000..ea49d44
--- /dev/null
@@ -0,0 +1,768 @@
+// Copyright 2018 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// -----------------------------------------------------------------------------
+// File: btree_map.h
+// -----------------------------------------------------------------------------
+//
+// This header file defines B-tree maps: sorted associative containers mapping
+// keys to values.
+//
+//     * `absl::btree_map<>`
+//     * `absl::btree_multimap<>`
+//
+// These B-tree types are similar to the corresponding types in the STL
+// (`std::map` and `std::multimap`) and generally conform to the STL interfaces
+// of those types. However, because they are implemented using B-trees, they
+// are more efficient in most situations.
+//
+// Unlike `std::map` and `std::multimap`, which are commonly implemented using
+// red-black tree nodes, B-tree maps use more generic B-tree nodes able to hold
+// multiple values per node. Holding multiple values per node often makes
+// B-tree maps perform better than their `std::map` counterparts, because
+// multiple entries can be checked within the same cache hit.
+//
+// However, these types should not be considered drop-in replacements for
+// `std::map` and `std::multimap` as there are some API differences, which are
+// noted in this header file.
+//
+// Importantly, insertions and deletions may invalidate outstanding iterators,
+// pointers, and references to elements. Such invalidations are typically only
+// an issue if insertion and deletion operations are interleaved with the use of
+// more than one iterator, pointer, or reference simultaneously. For this
+// reason, `insert()` and `erase()` return a valid iterator at the current
+// position.
+
+#ifndef ABSL_CONTAINER_BTREE_MAP_H_
+#define ABSL_CONTAINER_BTREE_MAP_H_
+
+#include "absl/container/internal/btree.h"  // IWYU pragma: export
+#include "absl/container/internal/btree_container.h"  // IWYU pragma: export
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+
+// absl::btree_map<>
+//
+// An `absl::btree_map<K, V>` is an ordered associative container of
+// unique keys and associated values designed to be a more efficient replacement
+// for `std::map` (in most cases).
+//
+// Keys are sorted using an (optional) comparison function, which defaults to
+// `std::less<K>`.
+//
+// An `absl::btree_map<K, V>` uses a default allocator of
+// `std::allocator<std::pair<const K, V>>` to allocate (and deallocate)
+// nodes, and construct and destruct values within those nodes. You may
+// instead specify a custom allocator `A` (which in turn requires specifying a
+// custom comparator `C`) as in `absl::btree_map<K, V, C, A>`.
+//
+template <typename Key, typename Value, typename Compare = std::less<Key>,
+          typename Alloc = std::allocator<std::pair<const Key, Value>>>
+class btree_map
+    : public container_internal::btree_map_container<
+          container_internal::btree<container_internal::map_params<
+              Key, Value, Compare, Alloc, /*TargetNodeSize=*/256,
+              /*Multi=*/false>>> {
+  using Base = typename btree_map::btree_map_container;
+
+ public:
+  // Constructors and Assignment Operators
+  //
+  // A `btree_map` supports the same overload set as `std::map`
+  // for construction and assignment:
+  //
+  // * Default constructor
+  //
+  //   absl::btree_map<int, std::string> map1;
+  //
+  // * Initializer List constructor
+  //
+  //   absl::btree_map<int, std::string> map2 =
+  //       {{1, "huey"}, {2, "dewey"}, {3, "louie"},};
+  //
+  // * Copy constructor
+  //
+  //   absl::btree_map<int, std::string> map3(map2);
+  //
+  // * Copy assignment operator
+  //
+  //  absl::btree_map<int, std::string> map4;
+  //  map4 = map3;
+  //
+  // * Move constructor
+  //
+  //   // Move is guaranteed efficient
+  //   absl::btree_map<int, std::string> map5(std::move(map4));
+  //
+  // * Move assignment operator
+  //
+  //   // May be efficient if allocators are compatible
+  //   absl::btree_map<int, std::string> map6;
+  //   map6 = std::move(map5);
+  //
+  // * Range constructor
+  //
+  //   std::vector<std::pair<int, std::string>> v = {{1, "a"}, {2, "b"}};
+  //   absl::btree_map<int, std::string> map7(v.begin(), v.end());
+  btree_map() {}
+  using Base::Base;
+
+  // btree_map::begin()
+  //
+  // Returns an iterator to the beginning of the `btree_map`.
+  using Base::begin;
+
+  // btree_map::cbegin()
+  //
+  // Returns a const iterator to the beginning of the `btree_map`.
+  using Base::cbegin;
+
+  // btree_map::end()
+  //
+  // Returns an iterator to the end of the `btree_map`.
+  using Base::end;
+
+  // btree_map::cend()
+  //
+  // Returns a const iterator to the end of the `btree_map`.
+  using Base::cend;
+
+  // btree_map::empty()
+  //
+  // Returns whether or not the `btree_map` is empty.
+  using Base::empty;
+
+  // btree_map::max_size()
+  //
+  // Returns the largest theoretical possible number of elements within a
+  // `btree_map` under current memory constraints. This value can be thought
+  // of as the largest value of `std::distance(begin(), end())` for a
+  // `btree_map<Key, T>`.
+  using Base::max_size;
+
+  // btree_map::size()
+  //
+  // Returns the number of elements currently within the `btree_map`.
+  using Base::size;
+
+  // btree_map::clear()
+  //
+  // Removes all elements from the `btree_map`. Invalidates any references,
+  // pointers, or iterators referring to contained elements.
+  using Base::clear;
+
+  // btree_map::erase()
+  //
+  // Erases elements within the `btree_map`. If an erase occurs, any references,
+  // pointers, or iterators are invalidated.
+  // Overloads are listed below.
+  //
+  // iterator erase(iterator position):
+  // iterator erase(const_iterator position):
+  //
+  //   Erases the element at `position` of the `btree_map`, returning
+  //   the iterator pointing to the element after the one that was erased
+  //   (or end() if none exists).
+  //
+  // iterator erase(const_iterator first, const_iterator last):
+  //
+  //   Erases the elements in the open interval [`first`, `last`), returning
+  //   the iterator pointing to the element after the interval that was erased
+  //   (or end() if none exists).
+  //
+  // template <typename K> size_type erase(const K& key):
+  //
+  //   Erases the element with the matching key, if it exists, returning the
+  //   number of elements erased (0 or 1).
+  using Base::erase;
+
+  // btree_map::insert()
+  //
+  // Inserts an element of the specified value into the `btree_map`,
+  // returning an iterator pointing to the newly inserted element, provided that
+  // an element with the given key does not already exist. If an insertion
+  // occurs, any references, pointers, or iterators are invalidated.
+  // Overloads are listed below.
+  //
+  // std::pair<iterator,bool> insert(const value_type& value):
+  //
+  //   Inserts a value into the `btree_map`. Returns a pair consisting of an
+  //   iterator to the inserted element (or to the element that prevented the
+  //   insertion) and a bool denoting whether the insertion took place.
+  //
+  // std::pair<iterator,bool> insert(value_type&& value):
+  //
+  //   Inserts a moveable value into the `btree_map`. Returns a pair
+  //   consisting of an iterator to the inserted element (or to the element that
+  //   prevented the insertion) and a bool denoting whether the insertion took
+  //   place.
+  //
+  // iterator insert(const_iterator hint, const value_type& value):
+  // iterator insert(const_iterator hint, value_type&& value):
+  //
+  //   Inserts a value, using the position of `hint` as a non-binding suggestion
+  //   for where to begin the insertion search. Returns an iterator to the
+  //   inserted element, or to the existing element that prevented the
+  //   insertion.
+  //
+  // void insert(InputIterator first, InputIterator last):
+  //
+  //   Inserts a range of values [`first`, `last`).
+  //
+  // void insert(std::initializer_list<init_type> ilist):
+  //
+  //   Inserts the elements within the initializer list `ilist`.
+  using Base::insert;
+
+  // btree_map::insert_or_assign()
+  //
+  // Inserts an element of the specified value into the `btree_map` provided
+  // that a value with the given key does not already exist, or replaces the
+  // corresponding mapped type with the forwarded `obj` argument if a key for
+  // that value already exists, returning an iterator pointing to the newly
+  // inserted element. Overloads are listed below.
+  //
+  // pair<iterator, bool> insert_or_assign(const key_type& k, M&& obj):
+  // pair<iterator, bool> insert_or_assign(key_type&& k, M&& obj):
+  //
+  //   Inserts/Assigns (or moves) the element of the specified key into the
+  //   `btree_map`. If the returned bool is true, insertion took place, and if
+  //   it's false, assignment took place.
+  //
+  // iterator insert_or_assign(const_iterator hint,
+  //                           const key_type& k, M&& obj):
+  // iterator insert_or_assign(const_iterator hint, key_type&& k, M&& obj):
+  //
+  //   Inserts/Assigns (or moves) the element of the specified key into the
+  //   `btree_map` using the position of `hint` as a non-binding suggestion
+  //   for where to begin the insertion search.
+  using Base::insert_or_assign;
+
+  // btree_map::emplace()
+  //
+  // Inserts an element of the specified value by constructing it in-place
+  // within the `btree_map`, provided that no element with the given key
+  // already exists.
+  //
+  // The element may be constructed even if there already is an element with the
+  // key in the container, in which case the newly constructed element will be
+  // destroyed immediately. Prefer `try_emplace()` unless your key is not
+  // copyable or moveable.
+  //
+  // If an insertion occurs, any references, pointers, or iterators are
+  // invalidated.
+  using Base::emplace;
+
+  // btree_map::emplace_hint()
+  //
+  // Inserts an element of the specified value by constructing it in-place
+  // within the `btree_map`, using the position of `hint` as a non-binding
+  // suggestion for where to begin the insertion search, and only inserts
+  // provided that no element with the given key already exists.
+  //
+  // The element may be constructed even if there already is an element with the
+  // key in the container, in which case the newly constructed element will be
+  // destroyed immediately. Prefer `try_emplace()` unless your key is not
+  // copyable or moveable.
+  //
+  // If an insertion occurs, any references, pointers, or iterators are
+  // invalidated.
+  using Base::emplace_hint;
+
+  // btree_map::try_emplace()
+  //
+  // Inserts an element of the specified value by constructing it in-place
+  // within the `btree_map`, provided that no element with the given key
+  // already exists. Unlike `emplace()`, if an element with the given key
+  // already exists, we guarantee that no element is constructed.
+  //
+  // If an insertion occurs, any references, pointers, or iterators are
+  // invalidated.
+  //
+  // Overloads are listed below.
+  //
+  //   std::pair<iterator, bool> try_emplace(const key_type& k, Args&&... args):
+  //   std::pair<iterator, bool> try_emplace(key_type&& k, Args&&... args):
+  //
+  // Inserts (via copy or move) the element of the specified key into the
+  // `btree_map`.
+  //
+  //   iterator try_emplace(const_iterator hint,
+  //                        const key_type& k, Args&&... args):
+  //   iterator try_emplace(const_iterator hint, key_type&& k, Args&&... args):
+  //
+  // Inserts (via copy or move) the element of the specified key into the
+  // `btree_map` using the position of `hint` as a non-binding suggestion
+  // for where to begin the insertion search.
+  using Base::try_emplace;
+
+  // btree_map::extract()
+  //
+  // Extracts the indicated element, erasing it in the process, and returns it
+  // as a C++17-compatible node handle. Overloads are listed below.
+  //
+  // node_type extract(const_iterator position):
+  //
+  //   Extracts the element at the indicated position and returns a node handle
+  //   owning that extracted data.
+  //
+  // template <typename K> node_type extract(const K& k):
+  //
+  //   Extracts the element with the key matching the passed key value and
+  //   returns a node handle owning that extracted data. If the `btree_map`
+  //   does not contain an element with a matching key, this function returns an
+  //   empty node handle.
+  //
+  // NOTE: when compiled in an earlier version of C++ than C++17,
+  // `node_type::key()` returns a const reference to the key instead of a
+  // mutable reference. We cannot safely return a mutable reference without
+  // std::launder (which is not available before C++17).
+  //
+  // NOTE: In this context, `node_type` refers to the C++17 concept of a
+  // move-only type that owns and provides access to the elements in associative
+  // containers (https://en.cppreference.com/w/cpp/container/node_handle).
+  // It does NOT refer to the data layout of the underlying btree.
+  using Base::extract;
+
+  // btree_map::merge()
+  //
+  // Extracts elements from a given `source` btree_map into this
+  // `btree_map`. If the destination `btree_map` already contains an
+  // element with an equivalent key, that element is not extracted.
+  using Base::merge;
+
+  // btree_map::swap(btree_map& other)
+  //
+  // Exchanges the contents of this `btree_map` with those of the `other`
+  // btree_map, avoiding invocation of any move, copy, or swap operations on
+  // individual elements.
+  //
+  // All iterators and references on the `btree_map` remain valid, excepting
+  // for the past-the-end iterator, which is invalidated.
+  using Base::swap;
+
+  // btree_map::at()
+  //
+  // Returns a reference to the mapped value of the element with key equivalent
+  // to the passed key.
+  using Base::at;
+
+  // btree_map::contains()
+  //
+  // template <typename K> bool contains(const K& key) const:
+  //
+  // Determines whether an element comparing equal to the given `key` exists
+  // within the `btree_map`, returning `true` if so or `false` otherwise.
+  //
+  // Supports heterogeneous lookup, provided that the map is provided a
+  // compatible heterogeneous comparator.
+  using Base::contains;
+
+  // btree_map::count()
+  //
+  // template <typename K> size_type count(const K& key) const:
+  //
+  // Returns the number of elements comparing equal to the given `key` within
+  // the `btree_map`. Note that this function will return either `1` or `0`
+  // since duplicate elements are not allowed within a `btree_map`.
+  //
+  // Supports heterogeneous lookup, provided that the map is provided a
+  // compatible heterogeneous comparator.
+  using Base::count;
+
+  // btree_map::equal_range()
+  //
+  // Returns a half-open range [first, last), defined by a `std::pair` of two
+  // iterators, containing all elements with the passed key in the `btree_map`.
+  using Base::equal_range;
+
+  // btree_map::find()
+  //
+  // template <typename K> iterator find(const K& key):
+  // template <typename K> const_iterator find(const K& key) const:
+  //
+  // Finds an element with the passed `key` within the `btree_map`.
+  //
+  // Supports heterogeneous lookup, provided that the map is provided a
+  // compatible heterogeneous comparator.
+  using Base::find;
+
+  // btree_map::operator[]()
+  //
+  // Returns a reference to the value mapped to the passed key within the
+  // `btree_map`, performing an `insert()` if the key does not already
+  // exist.
+  //
+  // If an insertion occurs, any references, pointers, or iterators are
+  // invalidated. Otherwise iterators are not affected and references are not
+  // invalidated. Overloads are listed below.
+  //
+  // T& operator[](key_type&& key):
+  // T& operator[](const key_type& key):
+  //
+  //   Inserts a value_type object constructed in-place if the element with the
+  //   given key does not exist.
+  using Base::operator[];
+
+  // btree_map::get_allocator()
+  //
+  // Returns the allocator function associated with this `btree_map`.
+  using Base::get_allocator;
+
+  // btree_map::key_comp();
+  //
+  // Returns the key comparator associated with this `btree_map`.
+  using Base::key_comp;
+
+  // btree_map::value_comp();
+  //
+  // Returns the value comparator associated with this `btree_map`.
+  using Base::value_comp;
+};
+
+// absl::swap(absl::btree_map<>, absl::btree_map<>)
+//
+// Swaps the contents of two `absl::btree_map` containers.
+template <typename K, typename V, typename C, typename A>
+void swap(btree_map<K, V, C, A> &x, btree_map<K, V, C, A> &y) {
+  return x.swap(y);
+}
+
+// absl::erase_if(absl::btree_map<>, Pred)
+//
+// Erases all elements that satisfy the predicate pred from the container.
+template <typename K, typename V, typename C, typename A, typename Pred>
+void erase_if(btree_map<K, V, C, A> &map, Pred pred) {
+  for (auto it = map.begin(); it != map.end();) {
+    if (pred(*it)) {
+      it = map.erase(it);
+    } else {
+      ++it;
+    }
+  }
+}
+
+// absl::btree_multimap
+//
+// An `absl::btree_multimap<K, V>` is an ordered associative container of
+// keys and associated values designed to be a more efficient replacement for
+// `std::multimap` (in most cases). Unlike `absl::btree_map`, a B-tree multimap
+// allows multiple elements with equivalent keys.
+//
+// Keys are sorted using an (optional) comparison function, which defaults to
+// `std::less<K>`.
+//
+// An `absl::btree_multimap<K, V>` uses a default allocator of
+// `std::allocator<std::pair<const K, V>>` to allocate (and deallocate)
+// nodes, and construct and destruct values within those nodes. You may
+// instead specify a custom allocator `A` (which in turn requires specifying a
+// custom comparator `C`) as in `absl::btree_multimap<K, V, C, A>`.
+//
+template <typename Key, typename Value, typename Compare = std::less<Key>,
+          typename Alloc = std::allocator<std::pair<const Key, Value>>>
+class btree_multimap
+    : public container_internal::btree_multimap_container<
+          container_internal::btree<container_internal::map_params<
+              Key, Value, Compare, Alloc, /*TargetNodeSize=*/256,
+              /*Multi=*/true>>> {
+  using Base = typename btree_multimap::btree_multimap_container;
+
+ public:
+  // Constructors and Assignment Operators
+  //
+  // A `btree_multimap` supports the same overload set as `std::multimap`
+  // for construction and assignment:
+  //
+  // * Default constructor
+  //
+  //   absl::btree_multimap<int, std::string> map1;
+  //
+  // * Initializer List constructor
+  //
+  //   absl::btree_multimap<int, std::string> map2 =
+  //       {{1, "huey"}, {2, "dewey"}, {3, "louie"},};
+  //
+  // * Copy constructor
+  //
+  //   absl::btree_multimap<int, std::string> map3(map2);
+  //
+  // * Copy assignment operator
+  //
+  //  absl::btree_multimap<int, std::string> map4;
+  //  map4 = map3;
+  //
+  // * Move constructor
+  //
+  //   // Move is guaranteed efficient
+  //   absl::btree_multimap<int, std::string> map5(std::move(map4));
+  //
+  // * Move assignment operator
+  //
+  //   // May be efficient if allocators are compatible
+  //   absl::btree_multimap<int, std::string> map6;
+  //   map6 = std::move(map5);
+  //
+  // * Range constructor
+  //
+  //   std::vector<std::pair<int, std::string>> v = {{1, "a"}, {2, "b"}};
+  //   absl::btree_multimap<int, std::string> map7(v.begin(), v.end());
+  btree_multimap() {}
+  using Base::Base;
+
+  // btree_multimap::begin()
+  //
+  // Returns an iterator to the beginning of the `btree_multimap`.
+  using Base::begin;
+
+  // btree_multimap::cbegin()
+  //
+  // Returns a const iterator to the beginning of the `btree_multimap`.
+  using Base::cbegin;
+
+  // btree_multimap::end()
+  //
+  // Returns an iterator to the end of the `btree_multimap`.
+  using Base::end;
+
+  // btree_multimap::cend()
+  //
+  // Returns a const iterator to the end of the `btree_multimap`.
+  using Base::cend;
+
+  // btree_multimap::empty()
+  //
+  // Returns whether or not the `btree_multimap` is empty.
+  using Base::empty;
+
+  // btree_multimap::max_size()
+  //
+  // Returns the largest theoretical possible number of elements within a
+  // `btree_multimap` under current memory constraints. This value can be
+  // thought of as the largest value of `std::distance(begin(), end())` for a
+  // `btree_multimap<Key, T>`.
+  using Base::max_size;
+
+  // btree_multimap::size()
+  //
+  // Returns the number of elements currently within the `btree_multimap`.
+  using Base::size;
+
+  // btree_multimap::clear()
+  //
+  // Removes all elements from the `btree_multimap`. Invalidates any references,
+  // pointers, or iterators referring to contained elements.
+  using Base::clear;
+
+  // btree_multimap::erase()
+  //
+  // Erases elements within the `btree_multimap`. If an erase occurs, any
+  // references, pointers, or iterators are invalidated.
+  // Overloads are listed below.
+  //
+  // iterator erase(iterator position):
+  // iterator erase(const_iterator position):
+  //
+  //   Erases the element at `position` of the `btree_multimap`, returning
+  //   the iterator pointing to the element after the one that was erased
+  //   (or end() if none exists).
+  //
+  // iterator erase(const_iterator first, const_iterator last):
+  //
+  //   Erases the elements in the open interval [`first`, `last`), returning
+  //   the iterator pointing to the element after the interval that was erased
+  //   (or end() if none exists).
+  //
+  // template <typename K> size_type erase(const K& key):
+  //
+  //   Erases the elements matching the key, if any exist, returning the
+  //   number of elements erased.
+  using Base::erase;
+
+  // btree_multimap::insert()
+  //
+  // Inserts an element of the specified value into the `btree_multimap`,
+  // returning an iterator pointing to the newly inserted element.
+  // Any references, pointers, or iterators are invalidated.  Overloads are
+  // listed below.
+  //
+  // iterator insert(const value_type& value):
+  //
+  //   Inserts a value into the `btree_multimap`, returning an iterator to the
+  //   inserted element.
+  //
+  // iterator insert(value_type&& value):
+  //
+  //   Inserts a moveable value into the `btree_multimap`, returning an iterator
+  //   to the inserted element.
+  //
+  // iterator insert(const_iterator hint, const value_type& value):
+  // iterator insert(const_iterator hint, value_type&& value):
+  //
+  //   Inserts a value, using the position of `hint` as a non-binding suggestion
+  //   for where to begin the insertion search. Returns an iterator to the
+  //   inserted element.
+  //
+  // void insert(InputIterator first, InputIterator last):
+  //
+  //   Inserts a range of values [`first`, `last`).
+  //
+  // void insert(std::initializer_list<init_type> ilist):
+  //
+  //   Inserts the elements within the initializer list `ilist`.
+  using Base::insert;
+
+  // btree_multimap::emplace()
+  //
+  // Inserts an element of the specified value by constructing it in-place
+  // within the `btree_multimap`. Any references, pointers, or iterators are
+  // invalidated.
+  using Base::emplace;
+
+  // btree_multimap::emplace_hint()
+  //
+  // Inserts an element of the specified value by constructing it in-place
+  // within the `btree_multimap`, using the position of `hint` as a non-binding
+  // suggestion for where to begin the insertion search.
+  //
+  // Any references, pointers, or iterators are invalidated.
+  using Base::emplace_hint;
+
+  // btree_multimap::extract()
+  //
+  // Extracts the indicated element, erasing it in the process, and returns it
+  // as a C++17-compatible node handle. Overloads are listed below.
+  //
+  // node_type extract(const_iterator position):
+  //
+  //   Extracts the element at the indicated position and returns a node handle
+  //   owning that extracted data.
+  //
+  // template <typename K> node_type extract(const K& k):
+  //
+  //   Extracts the element with the key matching the passed key value and
+  //   returns a node handle owning that extracted data. If the `btree_multimap`
+  //   does not contain an element with a matching key, this function returns an
+  //   empty node handle.
+  //
+  // NOTE: when compiled in an earlier version of C++ than C++17,
+  // `node_type::key()` returns a const reference to the key instead of a
+  // mutable reference. We cannot safely return a mutable reference without
+  // std::launder (which is not available before C++17).
+  //
+  // NOTE: In this context, `node_type` refers to the C++17 concept of a
+  // move-only type that owns and provides access to the elements in associative
+  // containers (https://en.cppreference.com/w/cpp/container/node_handle).
+  // It does NOT refer to the data layout of the underlying btree.
+  using Base::extract;
+
+  // btree_multimap::merge()
+  //
+  // Extracts elements from a given `source` btree_multimap into this
+  // `btree_multimap`. If the destination `btree_multimap` already contains an
+  // element with an equivalent key, that element is not extracted.
+  using Base::merge;
+
+  // btree_multimap::swap(btree_multimap& other)
+  //
+  // Exchanges the contents of this `btree_multimap` with those of the `other`
+  // btree_multimap, avoiding invocation of any move, copy, or swap operations
+  // on individual elements.
+  //
+  // All iterators and references on the `btree_multimap` remain valid,
+  // excepting for the past-the-end iterator, which is invalidated.
+  using Base::swap;
+
+  // btree_multimap::contains()
+  //
+  // template <typename K> bool contains(const K& key) const:
+  //
+  // Determines whether an element comparing equal to the given `key` exists
+  // within the `btree_multimap`, returning `true` if so or `false` otherwise.
+  //
+  // Supports heterogeneous lookup, provided that the map is provided a
+  // compatible heterogeneous comparator.
+  using Base::contains;
+
+  // btree_multimap::count()
+  //
+  // template <typename K> size_type count(const K& key) const:
+  //
+  // Returns the number of elements comparing equal to the given `key` within
+  // the `btree_multimap`.
+  //
+  // Supports heterogeneous lookup, provided that the map is provided a
+  // compatible heterogeneous comparator.
+  using Base::count;
+
+  // btree_multimap::equal_range()
+  //
+  // Returns a half-open range [first, last), defined by a `std::pair` of two
+  // iterators, containing all elements with the passed key in the
+  // `btree_multimap`.
+  using Base::equal_range;
+
+  // btree_multimap::find()
+  //
+  // template <typename K> iterator find(const K& key):
+  // template <typename K> const_iterator find(const K& key) const:
+  //
+  // Finds an element with the passed `key` within the `btree_multimap`.
+  //
+  // Supports heterogeneous lookup, provided that the map is provided a
+  // compatible heterogeneous comparator.
+  using Base::find;
+
+  // btree_multimap::get_allocator()
+  //
+  // Returns the allocator function associated with this `btree_multimap`.
+  using Base::get_allocator;
+
+  // btree_multimap::key_comp();
+  //
+  // Returns the key comparator associated with this `btree_multimap`.
+  using Base::key_comp;
+
+  // btree_multimap::value_comp();
+  //
+  // Returns the value comparator associated with this `btree_multimap`.
+  using Base::value_comp;
+};
+
+// absl::swap(absl::btree_multimap<>, absl::btree_multimap<>)
+//
+// Swaps the contents of two `absl::btree_multimap` containers.
+template <typename K, typename V, typename C, typename A>
+void swap(btree_multimap<K, V, C, A> &x, btree_multimap<K, V, C, A> &y) {
+  return x.swap(y);
+}
+
+// absl::erase_if(absl::btree_multimap<>, Pred)
+//
+// Erases all elements that satisfy the predicate pred from the container.
+template <typename K, typename V, typename C, typename A, typename Pred>
+void erase_if(btree_multimap<K, V, C, A> &map, Pred pred) {
+  for (auto it = map.begin(); it != map.end();) {
+    if (pred(*it)) {
+      it = map.erase(it);
+    } else {
+      ++it;
+    }
+  }
+}
+
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#endif  // ABSL_CONTAINER_BTREE_MAP_H_
diff --git a/src/absl/container/btree_set.h b/src/absl/container/btree_set.h
new file mode 100644 (file)
index 0000000..21ef0a0
--- /dev/null
@@ -0,0 +1,683 @@
+// Copyright 2018 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// -----------------------------------------------------------------------------
+// File: btree_set.h
+// -----------------------------------------------------------------------------
+//
+// This header file defines B-tree sets: sorted associative containers of
+// values.
+//
+//     * `absl::btree_set<>`
+//     * `absl::btree_multiset<>`
+//
+// These B-tree types are similar to the corresponding types in the STL
+// (`std::set` and `std::multiset`) and generally conform to the STL interfaces
+// of those types. However, because they are implemented using B-trees, they
+// are more efficient in most situations.
+//
+// Unlike `std::set` and `std::multiset`, which are commonly implemented using
+// red-black tree nodes, B-tree sets use more generic B-tree nodes able to hold
+// multiple values per node. Holding multiple values per node often makes
+// B-tree sets perform better than their `std::set` counterparts, because
+// multiple entries can be checked within the same cache hit.
+//
+// However, these types should not be considered drop-in replacements for
+// `std::set` and `std::multiset` as there are some API differences, which are
+// noted in this header file.
+//
+// Importantly, insertions and deletions may invalidate outstanding iterators,
+// pointers, and references to elements. Such invalidations are typically only
+// an issue if insertion and deletion operations are interleaved with the use of
+// more than one iterator, pointer, or reference simultaneously. For this
+// reason, `insert()` and `erase()` return a valid iterator at the current
+// position.
+
+#ifndef ABSL_CONTAINER_BTREE_SET_H_
+#define ABSL_CONTAINER_BTREE_SET_H_
+
+#include "absl/container/internal/btree.h"  // IWYU pragma: export
+#include "absl/container/internal/btree_container.h"  // IWYU pragma: export
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+
+// absl::btree_set<>
+//
+// An `absl::btree_set<K>` is an ordered associative container of unique key
+// values designed to be a more efficient replacement for `std::set` (in most
+// cases).
+//
+// Keys are sorted using an (optional) comparison function, which defaults to
+// `std::less<K>`.
+//
+// An `absl::btree_set<K>` uses a default allocator of `std::allocator<K>` to
+// allocate (and deallocate) nodes, and construct and destruct values within
+// those nodes. You may instead specify a custom allocator `A` (which in turn
+// requires specifying a custom comparator `C`) as in
+// `absl::btree_set<K, C, A>`.
+//
+template <typename Key, typename Compare = std::less<Key>,
+          typename Alloc = std::allocator<Key>>
+class btree_set
+    : public container_internal::btree_set_container<
+          container_internal::btree<container_internal::set_params<
+              Key, Compare, Alloc, /*TargetNodeSize=*/256,
+              /*Multi=*/false>>> {
+  using Base = typename btree_set::btree_set_container;
+
+ public:
+  // Constructors and Assignment Operators
+  //
+  // A `btree_set` supports the same overload set as `std::set`
+  // for construction and assignment:
+  //
+  // * Default constructor
+  //
+  //   absl::btree_set<std::string> set1;
+  //
+  // * Initializer List constructor
+  //
+  //   absl::btree_set<std::string> set2 =
+  //       {{"huey"}, {"dewey"}, {"louie"},};
+  //
+  // * Copy constructor
+  //
+  //   absl::btree_set<std::string> set3(set2);
+  //
+  // * Copy assignment operator
+  //
+  //  absl::btree_set<std::string> set4;
+  //  set4 = set3;
+  //
+  // * Move constructor
+  //
+  //   // Move is guaranteed efficient
+  //   absl::btree_set<std::string> set5(std::move(set4));
+  //
+  // * Move assignment operator
+  //
+  //   // May be efficient if allocators are compatible
+  //   absl::btree_set<std::string> set6;
+  //   set6 = std::move(set5);
+  //
+  // * Range constructor
+  //
+  //   std::vector<std::string> v = {"a", "b"};
+  //   absl::btree_set<std::string> set7(v.begin(), v.end());
+  btree_set() {}
+  using Base::Base;
+
+  // btree_set::begin()
+  //
+  // Returns an iterator to the beginning of the `btree_set`.
+  using Base::begin;
+
+  // btree_set::cbegin()
+  //
+  // Returns a const iterator to the beginning of the `btree_set`.
+  using Base::cbegin;
+
+  // btree_set::end()
+  //
+  // Returns an iterator to the end of the `btree_set`.
+  using Base::end;
+
+  // btree_set::cend()
+  //
+  // Returns a const iterator to the end of the `btree_set`.
+  using Base::cend;
+
+  // btree_set::empty()
+  //
+  // Returns whether or not the `btree_set` is empty.
+  using Base::empty;
+
+  // btree_set::max_size()
+  //
+  // Returns the largest theoretical possible number of elements within a
+  // `btree_set` under current memory constraints. This value can be thought
+  // of as the largest value of `std::distance(begin(), end())` for a
+  // `btree_set<Key>`.
+  using Base::max_size;
+
+  // btree_set::size()
+  //
+  // Returns the number of elements currently within the `btree_set`.
+  using Base::size;
+
+  // btree_set::clear()
+  //
+  // Removes all elements from the `btree_set`. Invalidates any references,
+  // pointers, or iterators referring to contained elements.
+  using Base::clear;
+
+  // btree_set::erase()
+  //
+  // Erases elements within the `btree_set`. Overloads are listed below.
+  //
+  // iterator erase(iterator position):
+  // iterator erase(const_iterator position):
+  //
+  //   Erases the element at `position` of the `btree_set`, returning
+  //   the iterator pointing to the element after the one that was erased
+  //   (or end() if none exists).
+  //
+  // iterator erase(const_iterator first, const_iterator last):
+  //
+  //   Erases the elements in the open interval [`first`, `last`), returning
+  //   the iterator pointing to the element after the interval that was erased
+  //   (or end() if none exists).
+  //
+  // template <typename K> size_type erase(const K& key):
+  //
+  //   Erases the element with the matching key, if it exists, returning the
+  //   number of elements erased (0 or 1).
+  using Base::erase;
+
+  // btree_set::insert()
+  //
+  // Inserts an element of the specified value into the `btree_set`,
+  // returning an iterator pointing to the newly inserted element, provided that
+  // an element with the given key does not already exist. If an insertion
+  // occurs, any references, pointers, or iterators are invalidated.
+  // Overloads are listed below.
+  //
+  // std::pair<iterator,bool> insert(const value_type& value):
+  //
+  //   Inserts a value into the `btree_set`. Returns a pair consisting of an
+  //   iterator to the inserted element (or to the element that prevented the
+  //   insertion) and a bool denoting whether the insertion took place.
+  //
+  // std::pair<iterator,bool> insert(value_type&& value):
+  //
+  //   Inserts a moveable value into the `btree_set`. Returns a pair
+  //   consisting of an iterator to the inserted element (or to the element that
+  //   prevented the insertion) and a bool denoting whether the insertion took
+  //   place.
+  //
+  // iterator insert(const_iterator hint, const value_type& value):
+  // iterator insert(const_iterator hint, value_type&& value):
+  //
+  //   Inserts a value, using the position of `hint` as a non-binding suggestion
+  //   for where to begin the insertion search. Returns an iterator to the
+  //   inserted element, or to the existing element that prevented the
+  //   insertion.
+  //
+  // void insert(InputIterator first, InputIterator last):
+  //
+  //   Inserts a range of values [`first`, `last`).
+  //
+  // void insert(std::initializer_list<init_type> ilist):
+  //
+  //   Inserts the elements within the initializer list `ilist`.
+  using Base::insert;
+
+  // btree_set::emplace()
+  //
+  // Inserts an element of the specified value by constructing it in-place
+  // within the `btree_set`, provided that no element with the given key
+  // already exists.
+  //
+  // The element may be constructed even if there already is an element with the
+  // key in the container, in which case the newly constructed element will be
+  // destroyed immediately.
+  //
+  // If an insertion occurs, any references, pointers, or iterators are
+  // invalidated.
+  using Base::emplace;
+
+  // btree_set::emplace_hint()
+  //
+  // Inserts an element of the specified value by constructing it in-place
+  // within the `btree_set`, using the position of `hint` as a non-binding
+  // suggestion for where to begin the insertion search, and only inserts
+  // provided that no element with the given key already exists.
+  //
+  // The element may be constructed even if there already is an element with the
+  // key in the container, in which case the newly constructed element will be
+  // destroyed immediately.
+  //
+  // If an insertion occurs, any references, pointers, or iterators are
+  // invalidated.
+  using Base::emplace_hint;
+
+  // btree_set::extract()
+  //
+  // Extracts the indicated element, erasing it in the process, and returns it
+  // as a C++17-compatible node handle. Overloads are listed below.
+  //
+  // node_type extract(const_iterator position):
+  //
+  //   Extracts the element at the indicated position and returns a node handle
+  //   owning that extracted data.
+  //
+  // template <typename K> node_type extract(const K& k):
+  //
+  //   Extracts the element with the key matching the passed key value and
+  //   returns a node handle owning that extracted data. If the `btree_set`
+  //   does not contain an element with a matching key, this function returns an
+  //   empty node handle.
+  //
+  // NOTE: In this context, `node_type` refers to the C++17 concept of a
+  // move-only type that owns and provides access to the elements in associative
+  // containers (https://en.cppreference.com/w/cpp/container/node_handle).
+  // It does NOT refer to the data layout of the underlying btree.
+  using Base::extract;
+
+  // btree_set::merge()
+  //
+  // Extracts elements from a given `source` btree_set into this
+  // `btree_set`. If the destination `btree_set` already contains an
+  // element with an equivalent key, that element is not extracted.
+  using Base::merge;
+
+  // btree_set::swap(btree_set& other)
+  //
+  // Exchanges the contents of this `btree_set` with those of the `other`
+  // btree_set, avoiding invocation of any move, copy, or swap operations on
+  // individual elements.
+  //
+  // All iterators and references on the `btree_set` remain valid, excepting
+  // for the past-the-end iterator, which is invalidated.
+  using Base::swap;
+
+  // btree_set::contains()
+  //
+  // template <typename K> bool contains(const K& key) const:
+  //
+  // Determines whether an element comparing equal to the given `key` exists
+  // within the `btree_set`, returning `true` if so or `false` otherwise.
+  //
+  // Supports heterogeneous lookup, provided that the set is provided a
+  // compatible heterogeneous comparator.
+  using Base::contains;
+
+  // btree_set::count()
+  //
+  // template <typename K> size_type count(const K& key) const:
+  //
+  // Returns the number of elements comparing equal to the given `key` within
+  // the `btree_set`. Note that this function will return either `1` or `0`
+  // since duplicate elements are not allowed within a `btree_set`.
+  //
+  // Supports heterogeneous lookup, provided that the set is provided a
+  // compatible heterogeneous comparator.
+  using Base::count;
+
+  // btree_set::equal_range()
+  //
+  // Returns a closed range [first, last], defined by a `std::pair` of two
+  // iterators, containing all elements with the passed key in the
+  // `btree_set`.
+  using Base::equal_range;
+
+  // btree_set::find()
+  //
+  // template <typename K> iterator find(const K& key):
+  // template <typename K> const_iterator find(const K& key) const:
+  //
+  // Finds an element with the passed `key` within the `btree_set`.
+  //
+  // Supports heterogeneous lookup, provided that the set is provided a
+  // compatible heterogeneous comparator.
+  using Base::find;
+
+  // btree_set::get_allocator()
+  //
+  // Returns the allocator function associated with this `btree_set`.
+  using Base::get_allocator;
+
+  // btree_set::key_comp();
+  //
+  // Returns the key comparator associated with this `btree_set`.
+  using Base::key_comp;
+
+  // btree_set::value_comp();
+  //
+  // Returns the value comparator associated with this `btree_set`. The keys to
+  // sort the elements are the values themselves, therefore `value_comp` and its
+  // sibling member function `key_comp` are equivalent.
+  using Base::value_comp;
+};
+
+// absl::swap(absl::btree_set<>, absl::btree_set<>)
+//
+// Swaps the contents of two `absl::btree_set` containers.
+template <typename K, typename C, typename A>
+void swap(btree_set<K, C, A> &x, btree_set<K, C, A> &y) {
+  return x.swap(y);
+}
+
+// absl::erase_if(absl::btree_set<>, Pred)
+//
+// Erases all elements that satisfy the predicate pred from the container.
+template <typename K, typename C, typename A, typename Pred>
+void erase_if(btree_set<K, C, A> &set, Pred pred) {
+  for (auto it = set.begin(); it != set.end();) {
+    if (pred(*it)) {
+      it = set.erase(it);
+    } else {
+      ++it;
+    }
+  }
+}
+
+// absl::btree_multiset<>
+//
+// An `absl::btree_multiset<K>` is an ordered associative container of
+// keys and associated values designed to be a more efficient replacement
+// for `std::multiset` (in most cases). Unlike `absl::btree_set`, a B-tree
+// multiset allows equivalent elements.
+//
+// Keys are sorted using an (optional) comparison function, which defaults to
+// `std::less<K>`.
+//
+// An `absl::btree_multiset<K>` uses a default allocator of `std::allocator<K>`
+// to allocate (and deallocate) nodes, and construct and destruct values within
+// those nodes. You may instead specify a custom allocator `A` (which in turn
+// requires specifying a custom comparator `C`) as in
+// `absl::btree_multiset<K, C, A>`.
+//
+template <typename Key, typename Compare = std::less<Key>,
+          typename Alloc = std::allocator<Key>>
+class btree_multiset
+    : public container_internal::btree_multiset_container<
+          container_internal::btree<container_internal::set_params<
+              Key, Compare, Alloc, /*TargetNodeSize=*/256,
+              /*Multi=*/true>>> {
+  using Base = typename btree_multiset::btree_multiset_container;
+
+ public:
+  // Constructors and Assignment Operators
+  //
+  // A `btree_multiset` supports the same overload set as `std::set`
+  // for construction and assignment:
+  //
+  // * Default constructor
+  //
+  //   absl::btree_multiset<std::string> set1;
+  //
+  // * Initializer List constructor
+  //
+  //   absl::btree_multiset<std::string> set2 =
+  //       {{"huey"}, {"dewey"}, {"louie"},};
+  //
+  // * Copy constructor
+  //
+  //   absl::btree_multiset<std::string> set3(set2);
+  //
+  // * Copy assignment operator
+  //
+  //  absl::btree_multiset<std::string> set4;
+  //  set4 = set3;
+  //
+  // * Move constructor
+  //
+  //   // Move is guaranteed efficient
+  //   absl::btree_multiset<std::string> set5(std::move(set4));
+  //
+  // * Move assignment operator
+  //
+  //   // May be efficient if allocators are compatible
+  //   absl::btree_multiset<std::string> set6;
+  //   set6 = std::move(set5);
+  //
+  // * Range constructor
+  //
+  //   std::vector<std::string> v = {"a", "b"};
+  //   absl::btree_multiset<std::string> set7(v.begin(), v.end());
+  btree_multiset() {}
+  using Base::Base;
+
+  // btree_multiset::begin()
+  //
+  // Returns an iterator to the beginning of the `btree_multiset`.
+  using Base::begin;
+
+  // btree_multiset::cbegin()
+  //
+  // Returns a const iterator to the beginning of the `btree_multiset`.
+  using Base::cbegin;
+
+  // btree_multiset::end()
+  //
+  // Returns an iterator to the end of the `btree_multiset`.
+  using Base::end;
+
+  // btree_multiset::cend()
+  //
+  // Returns a const iterator to the end of the `btree_multiset`.
+  using Base::cend;
+
+  // btree_multiset::empty()
+  //
+  // Returns whether or not the `btree_multiset` is empty.
+  using Base::empty;
+
+  // btree_multiset::max_size()
+  //
+  // Returns the largest theoretical possible number of elements within a
+  // `btree_multiset` under current memory constraints. This value can be
+  // thought of as the largest value of `std::distance(begin(), end())` for a
+  // `btree_multiset<Key>`.
+  using Base::max_size;
+
+  // btree_multiset::size()
+  //
+  // Returns the number of elements currently within the `btree_multiset`.
+  using Base::size;
+
+  // btree_multiset::clear()
+  //
+  // Removes all elements from the `btree_multiset`. Invalidates any references,
+  // pointers, or iterators referring to contained elements.
+  using Base::clear;
+
+  // btree_multiset::erase()
+  //
+  // Erases elements within the `btree_multiset`. Overloads are listed below.
+  //
+  // iterator erase(iterator position):
+  // iterator erase(const_iterator position):
+  //
+  //   Erases the element at `position` of the `btree_multiset`, returning
+  //   the iterator pointing to the element after the one that was erased
+  //   (or end() if none exists).
+  //
+  // iterator erase(const_iterator first, const_iterator last):
+  //
+  //   Erases the elements in the open interval [`first`, `last`), returning
+  //   the iterator pointing to the element after the interval that was erased
+  //   (or end() if none exists).
+  //
+  // template <typename K> size_type erase(const K& key):
+  //
+  //   Erases the elements matching the key, if any exist, returning the
+  //   number of elements erased.
+  using Base::erase;
+
+  // btree_multiset::insert()
+  //
+  // Inserts an element of the specified value into the `btree_multiset`,
+  // returning an iterator pointing to the newly inserted element.
+  // Any references, pointers, or iterators are invalidated.  Overloads are
+  // listed below.
+  //
+  // iterator insert(const value_type& value):
+  //
+  //   Inserts a value into the `btree_multiset`, returning an iterator to the
+  //   inserted element.
+  //
+  // iterator insert(value_type&& value):
+  //
+  //   Inserts a moveable value into the `btree_multiset`, returning an iterator
+  //   to the inserted element.
+  //
+  // iterator insert(const_iterator hint, const value_type& value):
+  // iterator insert(const_iterator hint, value_type&& value):
+  //
+  //   Inserts a value, using the position of `hint` as a non-binding suggestion
+  //   for where to begin the insertion search. Returns an iterator to the
+  //   inserted element.
+  //
+  // void insert(InputIterator first, InputIterator last):
+  //
+  //   Inserts a range of values [`first`, `last`).
+  //
+  // void insert(std::initializer_list<init_type> ilist):
+  //
+  //   Inserts the elements within the initializer list `ilist`.
+  using Base::insert;
+
+  // btree_multiset::emplace()
+  //
+  // Inserts an element of the specified value by constructing it in-place
+  // within the `btree_multiset`. Any references, pointers, or iterators are
+  // invalidated.
+  using Base::emplace;
+
+  // btree_multiset::emplace_hint()
+  //
+  // Inserts an element of the specified value by constructing it in-place
+  // within the `btree_multiset`, using the position of `hint` as a non-binding
+  // suggestion for where to begin the insertion search.
+  //
+  // Any references, pointers, or iterators are invalidated.
+  using Base::emplace_hint;
+
+  // btree_multiset::extract()
+  //
+  // Extracts the indicated element, erasing it in the process, and returns it
+  // as a C++17-compatible node handle. Overloads are listed below.
+  //
+  // node_type extract(const_iterator position):
+  //
+  //   Extracts the element at the indicated position and returns a node handle
+  //   owning that extracted data.
+  //
+  // template <typename K> node_type extract(const K& k):
+  //
+  //   Extracts the element with the key matching the passed key value and
+  //   returns a node handle owning that extracted data. If the `btree_multiset`
+  //   does not contain an element with a matching key, this function returns an
+  //   empty node handle.
+  //
+  // NOTE: In this context, `node_type` refers to the C++17 concept of a
+  // move-only type that owns and provides access to the elements in associative
+  // containers (https://en.cppreference.com/w/cpp/container/node_handle).
+  // It does NOT refer to the data layout of the underlying btree.
+  using Base::extract;
+
+  // btree_multiset::merge()
+  //
+  // Extracts elements from a given `source` btree_multiset into this
+  // `btree_multiset`. If the destination `btree_multiset` already contains an
+  // element with an equivalent key, that element is not extracted.
+  using Base::merge;
+
+  // btree_multiset::swap(btree_multiset& other)
+  //
+  // Exchanges the contents of this `btree_multiset` with those of the `other`
+  // btree_multiset, avoiding invocation of any move, copy, or swap operations
+  // on individual elements.
+  //
+  // All iterators and references on the `btree_multiset` remain valid,
+  // excepting for the past-the-end iterator, which is invalidated.
+  using Base::swap;
+
+  // btree_multiset::contains()
+  //
+  // template <typename K> bool contains(const K& key) const:
+  //
+  // Determines whether an element comparing equal to the given `key` exists
+  // within the `btree_multiset`, returning `true` if so or `false` otherwise.
+  //
+  // Supports heterogeneous lookup, provided that the set is provided a
+  // compatible heterogeneous comparator.
+  using Base::contains;
+
+  // btree_multiset::count()
+  //
+  // template <typename K> size_type count(const K& key) const:
+  //
+  // Returns the number of elements comparing equal to the given `key` within
+  // the `btree_multiset`.
+  //
+  // Supports heterogeneous lookup, provided that the set is provided a
+  // compatible heterogeneous comparator.
+  using Base::count;
+
+  // btree_multiset::equal_range()
+  //
+  // Returns a closed range [first, last], defined by a `std::pair` of two
+  // iterators, containing all elements with the passed key in the
+  // `btree_multiset`.
+  using Base::equal_range;
+
+  // btree_multiset::find()
+  //
+  // template <typename K> iterator find(const K& key):
+  // template <typename K> const_iterator find(const K& key) const:
+  //
+  // Finds an element with the passed `key` within the `btree_multiset`.
+  //
+  // Supports heterogeneous lookup, provided that the set is provided a
+  // compatible heterogeneous comparator.
+  using Base::find;
+
+  // btree_multiset::get_allocator()
+  //
+  // Returns the allocator function associated with this `btree_multiset`.
+  using Base::get_allocator;
+
+  // btree_multiset::key_comp();
+  //
+  // Returns the key comparator associated with this `btree_multiset`.
+  using Base::key_comp;
+
+  // btree_multiset::value_comp();
+  //
+  // Returns the value comparator associated with this `btree_multiset`. The
+  // keys to sort the elements are the values themselves, therefore `value_comp`
+  // and its sibling member function `key_comp` are equivalent.
+  using Base::value_comp;
+};
+
+// absl::swap(absl::btree_multiset<>, absl::btree_multiset<>)
+//
+// Swaps the contents of two `absl::btree_multiset` containers.
+template <typename K, typename C, typename A>
+void swap(btree_multiset<K, C, A> &x, btree_multiset<K, C, A> &y) {
+  return x.swap(y);
+}
+
+// absl::erase_if(absl::btree_multiset<>, Pred)
+//
+// Erases all elements that satisfy the predicate pred from the container.
+template <typename K, typename C, typename A, typename Pred>
+void erase_if(btree_multiset<K, C, A> &set, Pred pred) {
+  for (auto it = set.begin(); it != set.end();) {
+    if (pred(*it)) {
+      it = set.erase(it);
+    } else {
+      ++it;
+    }
+  }
+}
+
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#endif  // ABSL_CONTAINER_BTREE_SET_H_
diff --git a/src/absl/container/fixed_array.h b/src/absl/container/fixed_array.h
new file mode 100644 (file)
index 0000000..fcb3e54
--- /dev/null
@@ -0,0 +1,532 @@
+// Copyright 2018 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// -----------------------------------------------------------------------------
+// File: fixed_array.h
+// -----------------------------------------------------------------------------
+//
+// A `FixedArray<T>` represents a non-resizable array of `T` where the length of
+// the array can be determined at run-time. It is a good replacement for
+// non-standard and deprecated uses of `alloca()` and variable length arrays
+// within the GCC extension. (See
+// https://gcc.gnu.org/onlinedocs/gcc/Variable-Length.html).
+//
+// `FixedArray` allocates small arrays inline, keeping performance fast by
+// avoiding heap operations. It also helps reduce the chances of
+// accidentally overflowing your stack if large input is passed to
+// your function.
+
+#ifndef ABSL_CONTAINER_FIXED_ARRAY_H_
+#define ABSL_CONTAINER_FIXED_ARRAY_H_
+
+#include <algorithm>
+#include <cassert>
+#include <cstddef>
+#include <initializer_list>
+#include <iterator>
+#include <limits>
+#include <memory>
+#include <new>
+#include <type_traits>
+
+#include "absl/algorithm/algorithm.h"
+#include "absl/base/config.h"
+#include "absl/base/dynamic_annotations.h"
+#include "absl/base/internal/throw_delegate.h"
+#include "absl/base/macros.h"
+#include "absl/base/optimization.h"
+#include "absl/base/port.h"
+#include "absl/container/internal/compressed_tuple.h"
+#include "absl/memory/memory.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+
+constexpr static auto kFixedArrayUseDefault = static_cast<size_t>(-1);
+
+// -----------------------------------------------------------------------------
+// FixedArray
+// -----------------------------------------------------------------------------
+//
+// A `FixedArray` provides a run-time fixed-size array, allocating a small array
+// inline for efficiency.
+//
+// Most users should not specify an `inline_elements` argument and let
+// `FixedArray` automatically determine the number of elements
+// to store inline based on `sizeof(T)`. If `inline_elements` is specified, the
+// `FixedArray` implementation will use inline storage for arrays with a
+// length <= `inline_elements`.
+//
+// Note that a `FixedArray` constructed with a `size_type` argument will
+// default-initialize its values by leaving trivially constructible types
+// uninitialized (e.g. int, int[4], double), and others default-constructed.
+// This matches the behavior of c-style arrays and `std::array`, but not
+// `std::vector`.
+//
+// Note that `FixedArray` does not provide a public allocator; if it requires a
+// heap allocation, it will do so with global `::operator new[]()` and
+// `::operator delete[]()`, even if T provides class-scope overrides for these
+// operators.
+template <typename T, size_t N = kFixedArrayUseDefault,
+          typename A = std::allocator<T>>
+class FixedArray {
+  static_assert(!std::is_array<T>::value || std::extent<T>::value > 0,
+                "Arrays with unknown bounds cannot be used with FixedArray.");
+
+  static constexpr size_t kInlineBytesDefault = 256;
+
+  using AllocatorTraits = std::allocator_traits<A>;
+  // std::iterator_traits isn't guaranteed to be SFINAE-friendly until C++17,
+  // but this seems to be mostly pedantic.
+  template <typename Iterator>
+  using EnableIfForwardIterator = absl::enable_if_t<std::is_convertible<
+      typename std::iterator_traits<Iterator>::iterator_category,
+      std::forward_iterator_tag>::value>;
+  static constexpr bool NoexceptCopyable() {
+    return std::is_nothrow_copy_constructible<StorageElement>::value &&
+           absl::allocator_is_nothrow<allocator_type>::value;
+  }
+  static constexpr bool NoexceptMovable() {
+    return std::is_nothrow_move_constructible<StorageElement>::value &&
+           absl::allocator_is_nothrow<allocator_type>::value;
+  }
+  static constexpr bool DefaultConstructorIsNonTrivial() {
+    return !absl::is_trivially_default_constructible<StorageElement>::value;
+  }
+
+ public:
+  using allocator_type = typename AllocatorTraits::allocator_type;
+  using value_type = typename AllocatorTraits::value_type;
+  using pointer = typename AllocatorTraits::pointer;
+  using const_pointer = typename AllocatorTraits::const_pointer;
+  using reference = value_type&;
+  using const_reference = const value_type&;
+  using size_type = typename AllocatorTraits::size_type;
+  using difference_type = typename AllocatorTraits::difference_type;
+  using iterator = pointer;
+  using const_iterator = const_pointer;
+  using reverse_iterator = std::reverse_iterator<iterator>;
+  using const_reverse_iterator = std::reverse_iterator<const_iterator>;
+
+  static constexpr size_type inline_elements =
+      (N == kFixedArrayUseDefault ? kInlineBytesDefault / sizeof(value_type)
+                                  : static_cast<size_type>(N));
+
+  FixedArray(
+      const FixedArray& other,
+      const allocator_type& a = allocator_type()) noexcept(NoexceptCopyable())
+      : FixedArray(other.begin(), other.end(), a) {}
+
+  FixedArray(
+      FixedArray&& other,
+      const allocator_type& a = allocator_type()) noexcept(NoexceptMovable())
+      : FixedArray(std::make_move_iterator(other.begin()),
+                   std::make_move_iterator(other.end()), a) {}
+
+  // Creates an array object that can store `n` elements.
+  // Note that trivially constructible elements will be uninitialized.
+  explicit FixedArray(size_type n, const allocator_type& a = allocator_type())
+      : storage_(n, a) {
+    if (DefaultConstructorIsNonTrivial()) {
+      memory_internal::ConstructRange(storage_.alloc(), storage_.begin(),
+                                      storage_.end());
+    }
+  }
+
+  // Creates an array initialized with `n` copies of `val`.
+  FixedArray(size_type n, const value_type& val,
+             const allocator_type& a = allocator_type())
+      : storage_(n, a) {
+    memory_internal::ConstructRange(storage_.alloc(), storage_.begin(),
+                                    storage_.end(), val);
+  }
+
+  // Creates an array initialized with the size and contents of `init_list`.
+  FixedArray(std::initializer_list<value_type> init_list,
+             const allocator_type& a = allocator_type())
+      : FixedArray(init_list.begin(), init_list.end(), a) {}
+
+  // Creates an array initialized with the elements from the input
+  // range. The array's size will always be `std::distance(first, last)`.
+  // REQUIRES: Iterator must be a forward_iterator or better.
+  template <typename Iterator, EnableIfForwardIterator<Iterator>* = nullptr>
+  FixedArray(Iterator first, Iterator last,
+             const allocator_type& a = allocator_type())
+      : storage_(std::distance(first, last), a) {
+    memory_internal::CopyRange(storage_.alloc(), storage_.begin(), first, last);
+  }
+
+  ~FixedArray() noexcept {
+    for (auto* cur = storage_.begin(); cur != storage_.end(); ++cur) {
+      AllocatorTraits::destroy(storage_.alloc(), cur);
+    }
+  }
+
+  // Assignments are deleted because they break the invariant that the size of a
+  // `FixedArray` never changes.
+  void operator=(FixedArray&&) = delete;
+  void operator=(const FixedArray&) = delete;
+
+  // FixedArray::size()
+  //
+  // Returns the length of the fixed array.
+  size_type size() const { return storage_.size(); }
+
+  // FixedArray::max_size()
+  //
+  // Returns the largest possible value of `std::distance(begin(), end())` for a
+  // `FixedArray<T>`. This is equivalent to the most possible addressable bytes
+  // over the number of bytes taken by T.
+  constexpr size_type max_size() const {
+    return (std::numeric_limits<difference_type>::max)() / sizeof(value_type);
+  }
+
+  // FixedArray::empty()
+  //
+  // Returns whether or not the fixed array is empty.
+  bool empty() const { return size() == 0; }
+
+  // FixedArray::memsize()
+  //
+  // Returns the memory size of the fixed array in bytes.
+  size_t memsize() const { return size() * sizeof(value_type); }
+
+  // FixedArray::data()
+  //
+  // Returns a const T* pointer to elements of the `FixedArray`. This pointer
+  // can be used to access (but not modify) the contained elements.
+  const_pointer data() const { return AsValueType(storage_.begin()); }
+
+  // Overload of FixedArray::data() to return a T* pointer to elements of the
+  // fixed array. This pointer can be used to access and modify the contained
+  // elements.
+  pointer data() { return AsValueType(storage_.begin()); }
+
+  // FixedArray::operator[]
+  //
+  // Returns a reference the ith element of the fixed array.
+  // REQUIRES: 0 <= i < size()
+  reference operator[](size_type i) {
+    ABSL_HARDENING_ASSERT(i < size());
+    return data()[i];
+  }
+
+  // Overload of FixedArray::operator()[] to return a const reference to the
+  // ith element of the fixed array.
+  // REQUIRES: 0 <= i < size()
+  const_reference operator[](size_type i) const {
+    ABSL_HARDENING_ASSERT(i < size());
+    return data()[i];
+  }
+
+  // FixedArray::at
+  //
+  // Bounds-checked access.  Returns a reference to the ith element of the fixed
+  // array, or throws std::out_of_range
+  reference at(size_type i) {
+    if (ABSL_PREDICT_FALSE(i >= size())) {
+      base_internal::ThrowStdOutOfRange("FixedArray::at failed bounds check");
+    }
+    return data()[i];
+  }
+
+  // Overload of FixedArray::at() to return a const reference to the ith element
+  // of the fixed array.
+  const_reference at(size_type i) const {
+    if (ABSL_PREDICT_FALSE(i >= size())) {
+      base_internal::ThrowStdOutOfRange("FixedArray::at failed bounds check");
+    }
+    return data()[i];
+  }
+
+  // FixedArray::front()
+  //
+  // Returns a reference to the first element of the fixed array.
+  reference front() {
+    ABSL_HARDENING_ASSERT(!empty());
+    return data()[0];
+  }
+
+  // Overload of FixedArray::front() to return a reference to the first element
+  // of a fixed array of const values.
+  const_reference front() const {
+    ABSL_HARDENING_ASSERT(!empty());
+    return data()[0];
+  }
+
+  // FixedArray::back()
+  //
+  // Returns a reference to the last element of the fixed array.
+  reference back() {
+    ABSL_HARDENING_ASSERT(!empty());
+    return data()[size() - 1];
+  }
+
+  // Overload of FixedArray::back() to return a reference to the last element
+  // of a fixed array of const values.
+  const_reference back() const {
+    ABSL_HARDENING_ASSERT(!empty());
+    return data()[size() - 1];
+  }
+
+  // FixedArray::begin()
+  //
+  // Returns an iterator to the beginning of the fixed array.
+  iterator begin() { return data(); }
+
+  // Overload of FixedArray::begin() to return a const iterator to the
+  // beginning of the fixed array.
+  const_iterator begin() const { return data(); }
+
+  // FixedArray::cbegin()
+  //
+  // Returns a const iterator to the beginning of the fixed array.
+  const_iterator cbegin() const { return begin(); }
+
+  // FixedArray::end()
+  //
+  // Returns an iterator to the end of the fixed array.
+  iterator end() { return data() + size(); }
+
+  // Overload of FixedArray::end() to return a const iterator to the end of the
+  // fixed array.
+  const_iterator end() const { return data() + size(); }
+
+  // FixedArray::cend()
+  //
+  // Returns a const iterator to the end of the fixed array.
+  const_iterator cend() const { return end(); }
+
+  // FixedArray::rbegin()
+  //
+  // Returns a reverse iterator from the end of the fixed array.
+  reverse_iterator rbegin() { return reverse_iterator(end()); }
+
+  // Overload of FixedArray::rbegin() to return a const reverse iterator from
+  // the end of the fixed array.
+  const_reverse_iterator rbegin() const {
+    return const_reverse_iterator(end());
+  }
+
+  // FixedArray::crbegin()
+  //
+  // Returns a const reverse iterator from the end of the fixed array.
+  const_reverse_iterator crbegin() const { return rbegin(); }
+
+  // FixedArray::rend()
+  //
+  // Returns a reverse iterator from the beginning of the fixed array.
+  reverse_iterator rend() { return reverse_iterator(begin()); }
+
+  // Overload of FixedArray::rend() for returning a const reverse iterator
+  // from the beginning of the fixed array.
+  const_reverse_iterator rend() const {
+    return const_reverse_iterator(begin());
+  }
+
+  // FixedArray::crend()
+  //
+  // Returns a reverse iterator from the beginning of the fixed array.
+  const_reverse_iterator crend() const { return rend(); }
+
+  // FixedArray::fill()
+  //
+  // Assigns the given `value` to all elements in the fixed array.
+  void fill(const value_type& val) { std::fill(begin(), end(), val); }
+
+  // Relational operators. Equality operators are elementwise using
+  // `operator==`, while order operators order FixedArrays lexicographically.
+  friend bool operator==(const FixedArray& lhs, const FixedArray& rhs) {
+    return absl::equal(lhs.begin(), lhs.end(), rhs.begin(), rhs.end());
+  }
+
+  friend bool operator!=(const FixedArray& lhs, const FixedArray& rhs) {
+    return !(lhs == rhs);
+  }
+
+  friend bool operator<(const FixedArray& lhs, const FixedArray& rhs) {
+    return std::lexicographical_compare(lhs.begin(), lhs.end(), rhs.begin(),
+                                        rhs.end());
+  }
+
+  friend bool operator>(const FixedArray& lhs, const FixedArray& rhs) {
+    return rhs < lhs;
+  }
+
+  friend bool operator<=(const FixedArray& lhs, const FixedArray& rhs) {
+    return !(rhs < lhs);
+  }
+
+  friend bool operator>=(const FixedArray& lhs, const FixedArray& rhs) {
+    return !(lhs < rhs);
+  }
+
+  template <typename H>
+  friend H AbslHashValue(H h, const FixedArray& v) {
+    return H::combine(H::combine_contiguous(std::move(h), v.data(), v.size()),
+                      v.size());
+  }
+
+ private:
+  // StorageElement
+  //
+  // For FixedArrays with a C-style-array value_type, StorageElement is a POD
+  // wrapper struct called StorageElementWrapper that holds the value_type
+  // instance inside. This is needed for construction and destruction of the
+  // entire array regardless of how many dimensions it has. For all other cases,
+  // StorageElement is just an alias of value_type.
+  //
+  // Maintainer's Note: The simpler solution would be to simply wrap value_type
+  // in a struct whether it's an array or not. That causes some paranoid
+  // diagnostics to misfire, believing that 'data()' returns a pointer to a
+  // single element, rather than the packed array that it really is.
+  // e.g.:
+  //
+  //     FixedArray<char> buf(1);
+  //     sprintf(buf.data(), "foo");
+  //
+  //     error: call to int __builtin___sprintf_chk(etc...)
+  //     will always overflow destination buffer [-Werror]
+  //
+  template <typename OuterT, typename InnerT = absl::remove_extent_t<OuterT>,
+            size_t InnerN = std::extent<OuterT>::value>
+  struct StorageElementWrapper {
+    InnerT array[InnerN];
+  };
+
+  using StorageElement =
+      absl::conditional_t<std::is_array<value_type>::value,
+                          StorageElementWrapper<value_type>, value_type>;
+
+  static pointer AsValueType(pointer ptr) { return ptr; }
+  static pointer AsValueType(StorageElementWrapper<value_type>* ptr) {
+    return std::addressof(ptr->array);
+  }
+
+  static_assert(sizeof(StorageElement) == sizeof(value_type), "");
+  static_assert(alignof(StorageElement) == alignof(value_type), "");
+
+  class NonEmptyInlinedStorage {
+   public:
+    StorageElement* data() { return reinterpret_cast<StorageElement*>(buff_); }
+    void AnnotateConstruct(size_type n);
+    void AnnotateDestruct(size_type n);
+
+#ifdef ABSL_HAVE_ADDRESS_SANITIZER
+    void* RedzoneBegin() { return &redzone_begin_; }
+    void* RedzoneEnd() { return &redzone_end_ + 1; }
+#endif  // ABSL_HAVE_ADDRESS_SANITIZER
+
+   private:
+    ABSL_ADDRESS_SANITIZER_REDZONE(redzone_begin_);
+    alignas(StorageElement) char buff_[sizeof(StorageElement[inline_elements])];
+    ABSL_ADDRESS_SANITIZER_REDZONE(redzone_end_);
+  };
+
+  class EmptyInlinedStorage {
+   public:
+    StorageElement* data() { return nullptr; }
+    void AnnotateConstruct(size_type) {}
+    void AnnotateDestruct(size_type) {}
+  };
+
+  using InlinedStorage =
+      absl::conditional_t<inline_elements == 0, EmptyInlinedStorage,
+                          NonEmptyInlinedStorage>;
+
+  // Storage
+  //
+  // An instance of Storage manages the inline and out-of-line memory for
+  // instances of FixedArray. This guarantees that even when construction of
+  // individual elements fails in the FixedArray constructor body, the
+  // destructor for Storage will still be called and out-of-line memory will be
+  // properly deallocated.
+  //
+  class Storage : public InlinedStorage {
+   public:
+    Storage(size_type n, const allocator_type& a)
+        : size_alloc_(n, a), data_(InitializeData()) {}
+
+    ~Storage() noexcept {
+      if (UsingInlinedStorage(size())) {
+        InlinedStorage::AnnotateDestruct(size());
+      } else {
+        AllocatorTraits::deallocate(alloc(), AsValueType(begin()), size());
+      }
+    }
+
+    size_type size() const { return size_alloc_.template get<0>(); }
+    StorageElement* begin() const { return data_; }
+    StorageElement* end() const { return begin() + size(); }
+    allocator_type& alloc() { return size_alloc_.template get<1>(); }
+
+   private:
+    static bool UsingInlinedStorage(size_type n) {
+      return n <= inline_elements;
+    }
+
+    StorageElement* InitializeData() {
+      if (UsingInlinedStorage(size())) {
+        InlinedStorage::AnnotateConstruct(size());
+        return InlinedStorage::data();
+      } else {
+        return reinterpret_cast<StorageElement*>(
+            AllocatorTraits::allocate(alloc(), size()));
+      }
+    }
+
+    // `CompressedTuple` takes advantage of EBCO for stateless `allocator_type`s
+    container_internal::CompressedTuple<size_type, allocator_type> size_alloc_;
+    StorageElement* data_;
+  };
+
+  Storage storage_;
+};
+
+template <typename T, size_t N, typename A>
+constexpr size_t FixedArray<T, N, A>::kInlineBytesDefault;
+
+template <typename T, size_t N, typename A>
+constexpr typename FixedArray<T, N, A>::size_type
+    FixedArray<T, N, A>::inline_elements;
+
+template <typename T, size_t N, typename A>
+void FixedArray<T, N, A>::NonEmptyInlinedStorage::AnnotateConstruct(
+    typename FixedArray<T, N, A>::size_type n) {
+#ifdef ABSL_HAVE_ADDRESS_SANITIZER
+  if (!n) return;
+  ABSL_ANNOTATE_CONTIGUOUS_CONTAINER(data(), RedzoneEnd(), RedzoneEnd(),
+                                     data() + n);
+  ABSL_ANNOTATE_CONTIGUOUS_CONTAINER(RedzoneBegin(), data(), data(),
+                                     RedzoneBegin());
+#endif  // ABSL_HAVE_ADDRESS_SANITIZER
+  static_cast<void>(n);  // Mark used when not in asan mode
+}
+
+template <typename T, size_t N, typename A>
+void FixedArray<T, N, A>::NonEmptyInlinedStorage::AnnotateDestruct(
+    typename FixedArray<T, N, A>::size_type n) {
+#ifdef ABSL_HAVE_ADDRESS_SANITIZER
+  if (!n) return;
+  ABSL_ANNOTATE_CONTIGUOUS_CONTAINER(data(), RedzoneEnd(), data() + n,
+                                     RedzoneEnd());
+  ABSL_ANNOTATE_CONTIGUOUS_CONTAINER(RedzoneBegin(), data(), RedzoneBegin(),
+                                     data());
+#endif  // ABSL_HAVE_ADDRESS_SANITIZER
+  static_cast<void>(n);  // Mark used when not in asan mode
+}
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#endif  // ABSL_CONTAINER_FIXED_ARRAY_H_
diff --git a/src/absl/container/flat_hash_map.h b/src/absl/container/flat_hash_map.h
new file mode 100644 (file)
index 0000000..74def0d
--- /dev/null
@@ -0,0 +1,606 @@
+// Copyright 2018 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// -----------------------------------------------------------------------------
+// File: flat_hash_map.h
+// -----------------------------------------------------------------------------
+//
+// An `absl::flat_hash_map<K, V>` is an unordered associative container of
+// unique keys and associated values designed to be a more efficient replacement
+// for `std::unordered_map`. Like `unordered_map`, search, insertion, and
+// deletion of map elements can be done as an `O(1)` operation. However,
+// `flat_hash_map` (and other unordered associative containers known as the
+// collection of Abseil "Swiss tables") contain other optimizations that result
+// in both memory and computation advantages.
+//
+// In most cases, your default choice for a hash map should be a map of type
+// `flat_hash_map`.
+
+#ifndef ABSL_CONTAINER_FLAT_HASH_MAP_H_
+#define ABSL_CONTAINER_FLAT_HASH_MAP_H_
+
+#include <cstddef>
+#include <new>
+#include <type_traits>
+#include <utility>
+
+#include "absl/algorithm/container.h"
+#include "absl/container/internal/container_memory.h"
+#include "absl/container/internal/hash_function_defaults.h"  // IWYU pragma: export
+#include "absl/container/internal/raw_hash_map.h"  // IWYU pragma: export
+#include "absl/memory/memory.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace container_internal {
+template <class K, class V>
+struct FlatHashMapPolicy;
+}  // namespace container_internal
+
+// -----------------------------------------------------------------------------
+// absl::flat_hash_map
+// -----------------------------------------------------------------------------
+//
+// An `absl::flat_hash_map<K, V>` is an unordered associative container which
+// has been optimized for both speed and memory footprint in most common use
+// cases. Its interface is similar to that of `std::unordered_map<K, V>` with
+// the following notable differences:
+//
+// * Requires keys that are CopyConstructible
+// * Requires values that are MoveConstructible
+// * Supports heterogeneous lookup, through `find()`, `operator[]()` and
+//   `insert()`, provided that the map is provided a compatible heterogeneous
+//   hashing function and equality operator.
+// * Invalidates any references and pointers to elements within the table after
+//   `rehash()`.
+// * Contains a `capacity()` member function indicating the number of element
+//   slots (open, deleted, and empty) within the hash map.
+// * Returns `void` from the `erase(iterator)` overload.
+//
+// By default, `flat_hash_map` uses the `absl::Hash` hashing framework.
+// All fundamental and Abseil types that support the `absl::Hash` framework have
+// a compatible equality operator for comparing insertions into `flat_hash_map`.
+// If your type is not yet supported by the `absl::Hash` framework, see
+// absl/hash/hash.h for information on extending Abseil hashing to user-defined
+// types.
+//
+// NOTE: A `flat_hash_map` stores its value types directly inside its
+// implementation array to avoid memory indirection. Because a `flat_hash_map`
+// is designed to move data when rehashed, map values will not retain pointer
+// stability. If you require pointer stability, or if your values are large,
+// consider using `absl::flat_hash_map<Key, std::unique_ptr<Value>>` instead.
+// If your types are not moveable or you require pointer stability for keys,
+// consider `absl::node_hash_map`.
+//
+// Example:
+//
+//   // Create a flat hash map of three strings (that map to strings)
+//   absl::flat_hash_map<std::string, std::string> ducks =
+//     {{"a", "huey"}, {"b", "dewey"}, {"c", "louie"}};
+//
+//  // Insert a new element into the flat hash map
+//  ducks.insert({"d", "donald"});
+//
+//  // Force a rehash of the flat hash map
+//  ducks.rehash(0);
+//
+//  // Find the element with the key "b"
+//  std::string search_key = "b";
+//  auto result = ducks.find(search_key);
+//  if (result != ducks.end()) {
+//    std::cout << "Result: " << result->second << std::endl;
+//  }
+template <class K, class V,
+          class Hash = absl::container_internal::hash_default_hash<K>,
+          class Eq = absl::container_internal::hash_default_eq<K>,
+          class Allocator = std::allocator<std::pair<const K, V>>>
+class flat_hash_map : public absl::container_internal::raw_hash_map<
+                          absl::container_internal::FlatHashMapPolicy<K, V>,
+                          Hash, Eq, Allocator> {
+  using Base = typename flat_hash_map::raw_hash_map;
+
+ public:
+  // Constructors and Assignment Operators
+  //
+  // A flat_hash_map supports the same overload set as `std::unordered_map`
+  // for construction and assignment:
+  //
+  // *  Default constructor
+  //
+  //    // No allocation for the table's elements is made.
+  //    absl::flat_hash_map<int, std::string> map1;
+  //
+  // * Initializer List constructor
+  //
+  //   absl::flat_hash_map<int, std::string> map2 =
+  //       {{1, "huey"}, {2, "dewey"}, {3, "louie"},};
+  //
+  // * Copy constructor
+  //
+  //   absl::flat_hash_map<int, std::string> map3(map2);
+  //
+  // * Copy assignment operator
+  //
+  //  // Hash functor and Comparator are copied as well
+  //  absl::flat_hash_map<int, std::string> map4;
+  //  map4 = map3;
+  //
+  // * Move constructor
+  //
+  //   // Move is guaranteed efficient
+  //   absl::flat_hash_map<int, std::string> map5(std::move(map4));
+  //
+  // * Move assignment operator
+  //
+  //   // May be efficient if allocators are compatible
+  //   absl::flat_hash_map<int, std::string> map6;
+  //   map6 = std::move(map5);
+  //
+  // * Range constructor
+  //
+  //   std::vector<std::pair<int, std::string>> v = {{1, "a"}, {2, "b"}};
+  //   absl::flat_hash_map<int, std::string> map7(v.begin(), v.end());
+  flat_hash_map() {}
+  using Base::Base;
+
+  // flat_hash_map::begin()
+  //
+  // Returns an iterator to the beginning of the `flat_hash_map`.
+  using Base::begin;
+
+  // flat_hash_map::cbegin()
+  //
+  // Returns a const iterator to the beginning of the `flat_hash_map`.
+  using Base::cbegin;
+
+  // flat_hash_map::cend()
+  //
+  // Returns a const iterator to the end of the `flat_hash_map`.
+  using Base::cend;
+
+  // flat_hash_map::end()
+  //
+  // Returns an iterator to the end of the `flat_hash_map`.
+  using Base::end;
+
+  // flat_hash_map::capacity()
+  //
+  // Returns the number of element slots (assigned, deleted, and empty)
+  // available within the `flat_hash_map`.
+  //
+  // NOTE: this member function is particular to `absl::flat_hash_map` and is
+  // not provided in the `std::unordered_map` API.
+  using Base::capacity;
+
+  // flat_hash_map::empty()
+  //
+  // Returns whether or not the `flat_hash_map` is empty.
+  using Base::empty;
+
+  // flat_hash_map::max_size()
+  //
+  // Returns the largest theoretical possible number of elements within a
+  // `flat_hash_map` under current memory constraints. This value can be thought
+  // of the largest value of `std::distance(begin(), end())` for a
+  // `flat_hash_map<K, V>`.
+  using Base::max_size;
+
+  // flat_hash_map::size()
+  //
+  // Returns the number of elements currently within the `flat_hash_map`.
+  using Base::size;
+
+  // flat_hash_map::clear()
+  //
+  // Removes all elements from the `flat_hash_map`. Invalidates any references,
+  // pointers, or iterators referring to contained elements.
+  //
+  // NOTE: this operation may shrink the underlying buffer. To avoid shrinking
+  // the underlying buffer call `erase(begin(), end())`.
+  using Base::clear;
+
+  // flat_hash_map::erase()
+  //
+  // Erases elements within the `flat_hash_map`. Erasing does not trigger a
+  // rehash. Overloads are listed below.
+  //
+  // void erase(const_iterator pos):
+  //
+  //   Erases the element at `position` of the `flat_hash_map`, returning
+  //   `void`.
+  //
+  //   NOTE: returning `void` in this case is different than that of STL
+  //   containers in general and `std::unordered_map` in particular (which
+  //   return an iterator to the element following the erased element). If that
+  //   iterator is needed, simply post increment the iterator:
+  //
+  //     map.erase(it++);
+  //
+  // iterator erase(const_iterator first, const_iterator last):
+  //
+  //   Erases the elements in the open interval [`first`, `last`), returning an
+  //   iterator pointing to `last`.
+  //
+  // size_type erase(const key_type& key):
+  //
+  //   Erases the element with the matching key, if it exists, returning the
+  //   number of elements erased (0 or 1).
+  using Base::erase;
+
+  // flat_hash_map::insert()
+  //
+  // Inserts an element of the specified value into the `flat_hash_map`,
+  // returning an iterator pointing to the newly inserted element, provided that
+  // an element with the given key does not already exist. If rehashing occurs
+  // due to the insertion, all iterators are invalidated. Overloads are listed
+  // below.
+  //
+  // std::pair<iterator,bool> insert(const init_type& value):
+  //
+  //   Inserts a value into the `flat_hash_map`. Returns a pair consisting of an
+  //   iterator to the inserted element (or to the element that prevented the
+  //   insertion) and a bool denoting whether the insertion took place.
+  //
+  // std::pair<iterator,bool> insert(T&& value):
+  // std::pair<iterator,bool> insert(init_type&& value):
+  //
+  //   Inserts a moveable value into the `flat_hash_map`. Returns a pair
+  //   consisting of an iterator to the inserted element (or to the element that
+  //   prevented the insertion) and a bool denoting whether the insertion took
+  //   place.
+  //
+  // iterator insert(const_iterator hint, const init_type& value):
+  // iterator insert(const_iterator hint, T&& value):
+  // iterator insert(const_iterator hint, init_type&& value);
+  //
+  //   Inserts a value, using the position of `hint` as a non-binding suggestion
+  //   for where to begin the insertion search. Returns an iterator to the
+  //   inserted element, or to the existing element that prevented the
+  //   insertion.
+  //
+  // void insert(InputIterator first, InputIterator last):
+  //
+  //   Inserts a range of values [`first`, `last`).
+  //
+  //   NOTE: Although the STL does not specify which element may be inserted if
+  //   multiple keys compare equivalently, for `flat_hash_map` we guarantee the
+  //   first match is inserted.
+  //
+  // void insert(std::initializer_list<init_type> ilist):
+  //
+  //   Inserts the elements within the initializer list `ilist`.
+  //
+  //   NOTE: Although the STL does not specify which element may be inserted if
+  //   multiple keys compare equivalently within the initializer list, for
+  //   `flat_hash_map` we guarantee the first match is inserted.
+  using Base::insert;
+
+  // flat_hash_map::insert_or_assign()
+  //
+  // Inserts an element of the specified value into the `flat_hash_map` provided
+  // that a value with the given key does not already exist, or replaces it with
+  // the element value if a key for that value already exists, returning an
+  // iterator pointing to the newly inserted element.  If rehashing occurs due
+  // to the insertion, all existing iterators are invalidated. Overloads are
+  // listed below.
+  //
+  // pair<iterator, bool> insert_or_assign(const init_type& k, T&& obj):
+  // pair<iterator, bool> insert_or_assign(init_type&& k, T&& obj):
+  //
+  //   Inserts/Assigns (or moves) the element of the specified key into the
+  //   `flat_hash_map`.
+  //
+  // iterator insert_or_assign(const_iterator hint,
+  //                           const init_type& k, T&& obj):
+  // iterator insert_or_assign(const_iterator hint, init_type&& k, T&& obj):
+  //
+  //   Inserts/Assigns (or moves) the element of the specified key into the
+  //   `flat_hash_map` using the position of `hint` as a non-binding suggestion
+  //   for where to begin the insertion search.
+  using Base::insert_or_assign;
+
+  // flat_hash_map::emplace()
+  //
+  // Inserts an element of the specified value by constructing it in-place
+  // within the `flat_hash_map`, provided that no element with the given key
+  // already exists.
+  //
+  // The element may be constructed even if there already is an element with the
+  // key in the container, in which case the newly constructed element will be
+  // destroyed immediately. Prefer `try_emplace()` unless your key is not
+  // copyable or moveable.
+  //
+  // If rehashing occurs due to the insertion, all iterators are invalidated.
+  using Base::emplace;
+
+  // flat_hash_map::emplace_hint()
+  //
+  // Inserts an element of the specified value by constructing it in-place
+  // within the `flat_hash_map`, using the position of `hint` as a non-binding
+  // suggestion for where to begin the insertion search, and only inserts
+  // provided that no element with the given key already exists.
+  //
+  // The element may be constructed even if there already is an element with the
+  // key in the container, in which case the newly constructed element will be
+  // destroyed immediately. Prefer `try_emplace()` unless your key is not
+  // copyable or moveable.
+  //
+  // If rehashing occurs due to the insertion, all iterators are invalidated.
+  using Base::emplace_hint;
+
+  // flat_hash_map::try_emplace()
+  //
+  // Inserts an element of the specified value by constructing it in-place
+  // within the `flat_hash_map`, provided that no element with the given key
+  // already exists. Unlike `emplace()`, if an element with the given key
+  // already exists, we guarantee that no element is constructed.
+  //
+  // If rehashing occurs due to the insertion, all iterators are invalidated.
+  // Overloads are listed below.
+  //
+  //   pair<iterator, bool> try_emplace(const key_type& k, Args&&... args):
+  //   pair<iterator, bool> try_emplace(key_type&& k, Args&&... args):
+  //
+  // Inserts (via copy or move) the element of the specified key into the
+  // `flat_hash_map`.
+  //
+  //   iterator try_emplace(const_iterator hint,
+  //                        const init_type& k, Args&&... args):
+  //   iterator try_emplace(const_iterator hint, init_type&& k, Args&&... args):
+  //
+  // Inserts (via copy or move) the element of the specified key into the
+  // `flat_hash_map` using the position of `hint` as a non-binding suggestion
+  // for where to begin the insertion search.
+  //
+  // All `try_emplace()` overloads make the same guarantees regarding rvalue
+  // arguments as `std::unordered_map::try_emplace()`, namely that these
+  // functions will not move from rvalue arguments if insertions do not happen.
+  using Base::try_emplace;
+
+  // flat_hash_map::extract()
+  //
+  // Extracts the indicated element, erasing it in the process, and returns it
+  // as a C++17-compatible node handle. Overloads are listed below.
+  //
+  // node_type extract(const_iterator position):
+  //
+  //   Extracts the key,value pair of the element at the indicated position and
+  //   returns a node handle owning that extracted data.
+  //
+  // node_type extract(const key_type& x):
+  //
+  //   Extracts the key,value pair of the element with a key matching the passed
+  //   key value and returns a node handle owning that extracted data. If the
+  //   `flat_hash_map` does not contain an element with a matching key, this
+  //   function returns an empty node handle.
+  //
+  // NOTE: when compiled in an earlier version of C++ than C++17,
+  // `node_type::key()` returns a const reference to the key instead of a
+  // mutable reference. We cannot safely return a mutable reference without
+  // std::launder (which is not available before C++17).
+  using Base::extract;
+
+  // flat_hash_map::merge()
+  //
+  // Extracts elements from a given `source` flat hash map into this
+  // `flat_hash_map`. If the destination `flat_hash_map` already contains an
+  // element with an equivalent key, that element is not extracted.
+  using Base::merge;
+
+  // flat_hash_map::swap(flat_hash_map& other)
+  //
+  // Exchanges the contents of this `flat_hash_map` with those of the `other`
+  // flat hash map, avoiding invocation of any move, copy, or swap operations on
+  // individual elements.
+  //
+  // All iterators and references on the `flat_hash_map` remain valid, excepting
+  // for the past-the-end iterator, which is invalidated.
+  //
+  // `swap()` requires that the flat hash map's hashing and key equivalence
+  // functions be Swappable, and are exchanged using unqualified calls to
+  // non-member `swap()`. If the map's allocator has
+  // `std::allocator_traits<allocator_type>::propagate_on_container_swap::value`
+  // set to `true`, the allocators are also exchanged using an unqualified call
+  // to non-member `swap()`; otherwise, the allocators are not swapped.
+  using Base::swap;
+
+  // flat_hash_map::rehash(count)
+  //
+  // Rehashes the `flat_hash_map`, setting the number of slots to be at least
+  // the passed value. If the new number of slots increases the load factor more
+  // than the current maximum load factor
+  // (`count` < `size()` / `max_load_factor()`), then the new number of slots
+  // will be at least `size()` / `max_load_factor()`.
+  //
+  // To force a rehash, pass rehash(0).
+  //
+  // NOTE: unlike behavior in `std::unordered_map`, references are also
+  // invalidated upon a `rehash()`.
+  using Base::rehash;
+
+  // flat_hash_map::reserve(count)
+  //
+  // Sets the number of slots in the `flat_hash_map` to the number needed to
+  // accommodate at least `count` total elements without exceeding the current
+  // maximum load factor, and may rehash the container if needed.
+  using Base::reserve;
+
+  // flat_hash_map::at()
+  //
+  // Returns a reference to the mapped value of the element with key equivalent
+  // to the passed key.
+  using Base::at;
+
+  // flat_hash_map::contains()
+  //
+  // Determines whether an element with a key comparing equal to the given `key`
+  // exists within the `flat_hash_map`, returning `true` if so or `false`
+  // otherwise.
+  using Base::contains;
+
+  // flat_hash_map::count(const Key& key) const
+  //
+  // Returns the number of elements with a key comparing equal to the given
+  // `key` within the `flat_hash_map`. note that this function will return
+  // either `1` or `0` since duplicate keys are not allowed within a
+  // `flat_hash_map`.
+  using Base::count;
+
+  // flat_hash_map::equal_range()
+  //
+  // Returns a closed range [first, last], defined by a `std::pair` of two
+  // iterators, containing all elements with the passed key in the
+  // `flat_hash_map`.
+  using Base::equal_range;
+
+  // flat_hash_map::find()
+  //
+  // Finds an element with the passed `key` within the `flat_hash_map`.
+  using Base::find;
+
+  // flat_hash_map::operator[]()
+  //
+  // Returns a reference to the value mapped to the passed key within the
+  // `flat_hash_map`, performing an `insert()` if the key does not already
+  // exist.
+  //
+  // If an insertion occurs and results in a rehashing of the container, all
+  // iterators are invalidated. Otherwise iterators are not affected and
+  // references are not invalidated. Overloads are listed below.
+  //
+  // T& operator[](const Key& key):
+  //
+  //   Inserts an init_type object constructed in-place if the element with the
+  //   given key does not exist.
+  //
+  // T& operator[](Key&& key):
+  //
+  //   Inserts an init_type object constructed in-place provided that an element
+  //   with the given key does not exist.
+  using Base::operator[];
+
+  // flat_hash_map::bucket_count()
+  //
+  // Returns the number of "buckets" within the `flat_hash_map`. Note that
+  // because a flat hash map contains all elements within its internal storage,
+  // this value simply equals the current capacity of the `flat_hash_map`.
+  using Base::bucket_count;
+
+  // flat_hash_map::load_factor()
+  //
+  // Returns the current load factor of the `flat_hash_map` (the average number
+  // of slots occupied with a value within the hash map).
+  using Base::load_factor;
+
+  // flat_hash_map::max_load_factor()
+  //
+  // Manages the maximum load factor of the `flat_hash_map`. Overloads are
+  // listed below.
+  //
+  // float flat_hash_map::max_load_factor()
+  //
+  //   Returns the current maximum load factor of the `flat_hash_map`.
+  //
+  // void flat_hash_map::max_load_factor(float ml)
+  //
+  //   Sets the maximum load factor of the `flat_hash_map` to the passed value.
+  //
+  //   NOTE: This overload is provided only for API compatibility with the STL;
+  //   `flat_hash_map` will ignore any set load factor and manage its rehashing
+  //   internally as an implementation detail.
+  using Base::max_load_factor;
+
+  // flat_hash_map::get_allocator()
+  //
+  // Returns the allocator function associated with this `flat_hash_map`.
+  using Base::get_allocator;
+
+  // flat_hash_map::hash_function()
+  //
+  // Returns the hashing function used to hash the keys within this
+  // `flat_hash_map`.
+  using Base::hash_function;
+
+  // flat_hash_map::key_eq()
+  //
+  // Returns the function used for comparing keys equality.
+  using Base::key_eq;
+};
+
+// erase_if(flat_hash_map<>, Pred)
+//
+// Erases all elements that satisfy the predicate `pred` from the container `c`.
+template <typename K, typename V, typename H, typename E, typename A,
+          typename Predicate>
+void erase_if(flat_hash_map<K, V, H, E, A>& c, Predicate pred) {
+  container_internal::EraseIf(pred, &c);
+}
+
+namespace container_internal {
+
+template <class K, class V>
+struct FlatHashMapPolicy {
+  using slot_policy = container_internal::map_slot_policy<K, V>;
+  using slot_type = typename slot_policy::slot_type;
+  using key_type = K;
+  using mapped_type = V;
+  using init_type = std::pair</*non const*/ key_type, mapped_type>;
+
+  template <class Allocator, class... Args>
+  static void construct(Allocator* alloc, slot_type* slot, Args&&... args) {
+    slot_policy::construct(alloc, slot, std::forward<Args>(args)...);
+  }
+
+  template <class Allocator>
+  static void destroy(Allocator* alloc, slot_type* slot) {
+    slot_policy::destroy(alloc, slot);
+  }
+
+  template <class Allocator>
+  static void transfer(Allocator* alloc, slot_type* new_slot,
+                       slot_type* old_slot) {
+    slot_policy::transfer(alloc, new_slot, old_slot);
+  }
+
+  template <class F, class... Args>
+  static decltype(absl::container_internal::DecomposePair(
+      std::declval<F>(), std::declval<Args>()...))
+  apply(F&& f, Args&&... args) {
+    return absl::container_internal::DecomposePair(std::forward<F>(f),
+                                                   std::forward<Args>(args)...);
+  }
+
+  static size_t space_used(const slot_type*) { return 0; }
+
+  static std::pair<const K, V>& element(slot_type* slot) { return slot->value; }
+
+  static V& value(std::pair<const K, V>* kv) { return kv->second; }
+  static const V& value(const std::pair<const K, V>* kv) { return kv->second; }
+};
+
+}  // namespace container_internal
+
+namespace container_algorithm_internal {
+
+// Specialization of trait in absl/algorithm/container.h
+template <class Key, class T, class Hash, class KeyEqual, class Allocator>
+struct IsUnorderedContainer<
+    absl::flat_hash_map<Key, T, Hash, KeyEqual, Allocator>> : std::true_type {};
+
+}  // namespace container_algorithm_internal
+
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#endif  // ABSL_CONTAINER_FLAT_HASH_MAP_H_
diff --git a/src/absl/container/flat_hash_set.h b/src/absl/container/flat_hash_set.h
new file mode 100644 (file)
index 0000000..6b89da6
--- /dev/null
@@ -0,0 +1,504 @@
+// Copyright 2018 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// -----------------------------------------------------------------------------
+// File: flat_hash_set.h
+// -----------------------------------------------------------------------------
+//
+// An `absl::flat_hash_set<T>` is an unordered associative container designed to
+// be a more efficient replacement for `std::unordered_set`. Like
+// `unordered_set`, search, insertion, and deletion of set elements can be done
+// as an `O(1)` operation. However, `flat_hash_set` (and other unordered
+// associative containers known as the collection of Abseil "Swiss tables")
+// contain other optimizations that result in both memory and computation
+// advantages.
+//
+// In most cases, your default choice for a hash set should be a set of type
+// `flat_hash_set`.
+#ifndef ABSL_CONTAINER_FLAT_HASH_SET_H_
+#define ABSL_CONTAINER_FLAT_HASH_SET_H_
+
+#include <type_traits>
+#include <utility>
+
+#include "absl/algorithm/container.h"
+#include "absl/base/macros.h"
+#include "absl/container/internal/container_memory.h"
+#include "absl/container/internal/hash_function_defaults.h"  // IWYU pragma: export
+#include "absl/container/internal/raw_hash_set.h"  // IWYU pragma: export
+#include "absl/memory/memory.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace container_internal {
+template <typename T>
+struct FlatHashSetPolicy;
+}  // namespace container_internal
+
+// -----------------------------------------------------------------------------
+// absl::flat_hash_set
+// -----------------------------------------------------------------------------
+//
+// An `absl::flat_hash_set<T>` is an unordered associative container which has
+// been optimized for both speed and memory footprint in most common use cases.
+// Its interface is similar to that of `std::unordered_set<T>` with the
+// following notable differences:
+//
+// * Requires keys that are CopyConstructible
+// * Supports heterogeneous lookup, through `find()` and `insert()`, provided
+//   that the set is provided a compatible heterogeneous hashing function and
+//   equality operator.
+// * Invalidates any references and pointers to elements within the table after
+//   `rehash()`.
+// * Contains a `capacity()` member function indicating the number of element
+//   slots (open, deleted, and empty) within the hash set.
+// * Returns `void` from the `erase(iterator)` overload.
+//
+// By default, `flat_hash_set` uses the `absl::Hash` hashing framework. All
+// fundamental and Abseil types that support the `absl::Hash` framework have a
+// compatible equality operator for comparing insertions into `flat_hash_map`.
+// If your type is not yet supported by the `absl::Hash` framework, see
+// absl/hash/hash.h for information on extending Abseil hashing to user-defined
+// types.
+//
+// NOTE: A `flat_hash_set` stores its keys directly inside its implementation
+// array to avoid memory indirection. Because a `flat_hash_set` is designed to
+// move data when rehashed, set keys will not retain pointer stability. If you
+// require pointer stability, consider using
+// `absl::flat_hash_set<std::unique_ptr<T>>`. If your type is not moveable and
+// you require pointer stability, consider `absl::node_hash_set` instead.
+//
+// Example:
+//
+//   // Create a flat hash set of three strings
+//   absl::flat_hash_set<std::string> ducks =
+//     {"huey", "dewey", "louie"};
+//
+//  // Insert a new element into the flat hash set
+//  ducks.insert("donald");
+//
+//  // Force a rehash of the flat hash set
+//  ducks.rehash(0);
+//
+//  // See if "dewey" is present
+//  if (ducks.contains("dewey")) {
+//    std::cout << "We found dewey!" << std::endl;
+//  }
+template <class T, class Hash = absl::container_internal::hash_default_hash<T>,
+          class Eq = absl::container_internal::hash_default_eq<T>,
+          class Allocator = std::allocator<T>>
+class flat_hash_set
+    : public absl::container_internal::raw_hash_set<
+          absl::container_internal::FlatHashSetPolicy<T>, Hash, Eq, Allocator> {
+  using Base = typename flat_hash_set::raw_hash_set;
+
+ public:
+  // Constructors and Assignment Operators
+  //
+  // A flat_hash_set supports the same overload set as `std::unordered_map`
+  // for construction and assignment:
+  //
+  // *  Default constructor
+  //
+  //    // No allocation for the table's elements is made.
+  //    absl::flat_hash_set<std::string> set1;
+  //
+  // * Initializer List constructor
+  //
+  //   absl::flat_hash_set<std::string> set2 =
+  //       {{"huey"}, {"dewey"}, {"louie"},};
+  //
+  // * Copy constructor
+  //
+  //   absl::flat_hash_set<std::string> set3(set2);
+  //
+  // * Copy assignment operator
+  //
+  //  // Hash functor and Comparator are copied as well
+  //  absl::flat_hash_set<std::string> set4;
+  //  set4 = set3;
+  //
+  // * Move constructor
+  //
+  //   // Move is guaranteed efficient
+  //   absl::flat_hash_set<std::string> set5(std::move(set4));
+  //
+  // * Move assignment operator
+  //
+  //   // May be efficient if allocators are compatible
+  //   absl::flat_hash_set<std::string> set6;
+  //   set6 = std::move(set5);
+  //
+  // * Range constructor
+  //
+  //   std::vector<std::string> v = {"a", "b"};
+  //   absl::flat_hash_set<std::string> set7(v.begin(), v.end());
+  flat_hash_set() {}
+  using Base::Base;
+
+  // flat_hash_set::begin()
+  //
+  // Returns an iterator to the beginning of the `flat_hash_set`.
+  using Base::begin;
+
+  // flat_hash_set::cbegin()
+  //
+  // Returns a const iterator to the beginning of the `flat_hash_set`.
+  using Base::cbegin;
+
+  // flat_hash_set::cend()
+  //
+  // Returns a const iterator to the end of the `flat_hash_set`.
+  using Base::cend;
+
+  // flat_hash_set::end()
+  //
+  // Returns an iterator to the end of the `flat_hash_set`.
+  using Base::end;
+
+  // flat_hash_set::capacity()
+  //
+  // Returns the number of element slots (assigned, deleted, and empty)
+  // available within the `flat_hash_set`.
+  //
+  // NOTE: this member function is particular to `absl::flat_hash_set` and is
+  // not provided in the `std::unordered_map` API.
+  using Base::capacity;
+
+  // flat_hash_set::empty()
+  //
+  // Returns whether or not the `flat_hash_set` is empty.
+  using Base::empty;
+
+  // flat_hash_set::max_size()
+  //
+  // Returns the largest theoretical possible number of elements within a
+  // `flat_hash_set` under current memory constraints. This value can be thought
+  // of the largest value of `std::distance(begin(), end())` for a
+  // `flat_hash_set<T>`.
+  using Base::max_size;
+
+  // flat_hash_set::size()
+  //
+  // Returns the number of elements currently within the `flat_hash_set`.
+  using Base::size;
+
+  // flat_hash_set::clear()
+  //
+  // Removes all elements from the `flat_hash_set`. Invalidates any references,
+  // pointers, or iterators referring to contained elements.
+  //
+  // NOTE: this operation may shrink the underlying buffer. To avoid shrinking
+  // the underlying buffer call `erase(begin(), end())`.
+  using Base::clear;
+
+  // flat_hash_set::erase()
+  //
+  // Erases elements within the `flat_hash_set`. Erasing does not trigger a
+  // rehash. Overloads are listed below.
+  //
+  // void erase(const_iterator pos):
+  //
+  //   Erases the element at `position` of the `flat_hash_set`, returning
+  //   `void`.
+  //
+  //   NOTE: returning `void` in this case is different than that of STL
+  //   containers in general and `std::unordered_set` in particular (which
+  //   return an iterator to the element following the erased element). If that
+  //   iterator is needed, simply post increment the iterator:
+  //
+  //     set.erase(it++);
+  //
+  // iterator erase(const_iterator first, const_iterator last):
+  //
+  //   Erases the elements in the open interval [`first`, `last`), returning an
+  //   iterator pointing to `last`.
+  //
+  // size_type erase(const key_type& key):
+  //
+  //   Erases the element with the matching key, if it exists, returning the
+  //   number of elements erased (0 or 1).
+  using Base::erase;
+
+  // flat_hash_set::insert()
+  //
+  // Inserts an element of the specified value into the `flat_hash_set`,
+  // returning an iterator pointing to the newly inserted element, provided that
+  // an element with the given key does not already exist. If rehashing occurs
+  // due to the insertion, all iterators are invalidated. Overloads are listed
+  // below.
+  //
+  // std::pair<iterator,bool> insert(const T& value):
+  //
+  //   Inserts a value into the `flat_hash_set`. Returns a pair consisting of an
+  //   iterator to the inserted element (or to the element that prevented the
+  //   insertion) and a bool denoting whether the insertion took place.
+  //
+  // std::pair<iterator,bool> insert(T&& value):
+  //
+  //   Inserts a moveable value into the `flat_hash_set`. Returns a pair
+  //   consisting of an iterator to the inserted element (or to the element that
+  //   prevented the insertion) and a bool denoting whether the insertion took
+  //   place.
+  //
+  // iterator insert(const_iterator hint, const T& value):
+  // iterator insert(const_iterator hint, T&& value):
+  //
+  //   Inserts a value, using the position of `hint` as a non-binding suggestion
+  //   for where to begin the insertion search. Returns an iterator to the
+  //   inserted element, or to the existing element that prevented the
+  //   insertion.
+  //
+  // void insert(InputIterator first, InputIterator last):
+  //
+  //   Inserts a range of values [`first`, `last`).
+  //
+  //   NOTE: Although the STL does not specify which element may be inserted if
+  //   multiple keys compare equivalently, for `flat_hash_set` we guarantee the
+  //   first match is inserted.
+  //
+  // void insert(std::initializer_list<T> ilist):
+  //
+  //   Inserts the elements within the initializer list `ilist`.
+  //
+  //   NOTE: Although the STL does not specify which element may be inserted if
+  //   multiple keys compare equivalently within the initializer list, for
+  //   `flat_hash_set` we guarantee the first match is inserted.
+  using Base::insert;
+
+  // flat_hash_set::emplace()
+  //
+  // Inserts an element of the specified value by constructing it in-place
+  // within the `flat_hash_set`, provided that no element with the given key
+  // already exists.
+  //
+  // The element may be constructed even if there already is an element with the
+  // key in the container, in which case the newly constructed element will be
+  // destroyed immediately.
+  //
+  // If rehashing occurs due to the insertion, all iterators are invalidated.
+  using Base::emplace;
+
+  // flat_hash_set::emplace_hint()
+  //
+  // Inserts an element of the specified value by constructing it in-place
+  // within the `flat_hash_set`, using the position of `hint` as a non-binding
+  // suggestion for where to begin the insertion search, and only inserts
+  // provided that no element with the given key already exists.
+  //
+  // The element may be constructed even if there already is an element with the
+  // key in the container, in which case the newly constructed element will be
+  // destroyed immediately.
+  //
+  // If rehashing occurs due to the insertion, all iterators are invalidated.
+  using Base::emplace_hint;
+
+  // flat_hash_set::extract()
+  //
+  // Extracts the indicated element, erasing it in the process, and returns it
+  // as a C++17-compatible node handle. Overloads are listed below.
+  //
+  // node_type extract(const_iterator position):
+  //
+  //   Extracts the element at the indicated position and returns a node handle
+  //   owning that extracted data.
+  //
+  // node_type extract(const key_type& x):
+  //
+  //   Extracts the element with the key matching the passed key value and
+  //   returns a node handle owning that extracted data. If the `flat_hash_set`
+  //   does not contain an element with a matching key, this function returns an
+  //   empty node handle.
+  using Base::extract;
+
+  // flat_hash_set::merge()
+  //
+  // Extracts elements from a given `source` flat hash set into this
+  // `flat_hash_set`. If the destination `flat_hash_set` already contains an
+  // element with an equivalent key, that element is not extracted.
+  using Base::merge;
+
+  // flat_hash_set::swap(flat_hash_set& other)
+  //
+  // Exchanges the contents of this `flat_hash_set` with those of the `other`
+  // flat hash map, avoiding invocation of any move, copy, or swap operations on
+  // individual elements.
+  //
+  // All iterators and references on the `flat_hash_set` remain valid, excepting
+  // for the past-the-end iterator, which is invalidated.
+  //
+  // `swap()` requires that the flat hash set's hashing and key equivalence
+  // functions be Swappable, and are exchaged using unqualified calls to
+  // non-member `swap()`. If the map's allocator has
+  // `std::allocator_traits<allocator_type>::propagate_on_container_swap::value`
+  // set to `true`, the allocators are also exchanged using an unqualified call
+  // to non-member `swap()`; otherwise, the allocators are not swapped.
+  using Base::swap;
+
+  // flat_hash_set::rehash(count)
+  //
+  // Rehashes the `flat_hash_set`, setting the number of slots to be at least
+  // the passed value. If the new number of slots increases the load factor more
+  // than the current maximum load factor
+  // (`count` < `size()` / `max_load_factor()`), then the new number of slots
+  // will be at least `size()` / `max_load_factor()`.
+  //
+  // To force a rehash, pass rehash(0).
+  //
+  // NOTE: unlike behavior in `std::unordered_set`, references are also
+  // invalidated upon a `rehash()`.
+  using Base::rehash;
+
+  // flat_hash_set::reserve(count)
+  //
+  // Sets the number of slots in the `flat_hash_set` to the number needed to
+  // accommodate at least `count` total elements without exceeding the current
+  // maximum load factor, and may rehash the container if needed.
+  using Base::reserve;
+
+  // flat_hash_set::contains()
+  //
+  // Determines whether an element comparing equal to the given `key` exists
+  // within the `flat_hash_set`, returning `true` if so or `false` otherwise.
+  using Base::contains;
+
+  // flat_hash_set::count(const Key& key) const
+  //
+  // Returns the number of elements comparing equal to the given `key` within
+  // the `flat_hash_set`. note that this function will return either `1` or `0`
+  // since duplicate elements are not allowed within a `flat_hash_set`.
+  using Base::count;
+
+  // flat_hash_set::equal_range()
+  //
+  // Returns a closed range [first, last], defined by a `std::pair` of two
+  // iterators, containing all elements with the passed key in the
+  // `flat_hash_set`.
+  using Base::equal_range;
+
+  // flat_hash_set::find()
+  //
+  // Finds an element with the passed `key` within the `flat_hash_set`.
+  using Base::find;
+
+  // flat_hash_set::bucket_count()
+  //
+  // Returns the number of "buckets" within the `flat_hash_set`. Note that
+  // because a flat hash map contains all elements within its internal storage,
+  // this value simply equals the current capacity of the `flat_hash_set`.
+  using Base::bucket_count;
+
+  // flat_hash_set::load_factor()
+  //
+  // Returns the current load factor of the `flat_hash_set` (the average number
+  // of slots occupied with a value within the hash map).
+  using Base::load_factor;
+
+  // flat_hash_set::max_load_factor()
+  //
+  // Manages the maximum load factor of the `flat_hash_set`. Overloads are
+  // listed below.
+  //
+  // float flat_hash_set::max_load_factor()
+  //
+  //   Returns the current maximum load factor of the `flat_hash_set`.
+  //
+  // void flat_hash_set::max_load_factor(float ml)
+  //
+  //   Sets the maximum load factor of the `flat_hash_set` to the passed value.
+  //
+  //   NOTE: This overload is provided only for API compatibility with the STL;
+  //   `flat_hash_set` will ignore any set load factor and manage its rehashing
+  //   internally as an implementation detail.
+  using Base::max_load_factor;
+
+  // flat_hash_set::get_allocator()
+  //
+  // Returns the allocator function associated with this `flat_hash_set`.
+  using Base::get_allocator;
+
+  // flat_hash_set::hash_function()
+  //
+  // Returns the hashing function used to hash the keys within this
+  // `flat_hash_set`.
+  using Base::hash_function;
+
+  // flat_hash_set::key_eq()
+  //
+  // Returns the function used for comparing keys equality.
+  using Base::key_eq;
+};
+
+// erase_if(flat_hash_set<>, Pred)
+//
+// Erases all elements that satisfy the predicate `pred` from the container `c`.
+template <typename T, typename H, typename E, typename A, typename Predicate>
+void erase_if(flat_hash_set<T, H, E, A>& c, Predicate pred) {
+  container_internal::EraseIf(pred, &c);
+}
+
+namespace container_internal {
+
+template <class T>
+struct FlatHashSetPolicy {
+  using slot_type = T;
+  using key_type = T;
+  using init_type = T;
+  using constant_iterators = std::true_type;
+
+  template <class Allocator, class... Args>
+  static void construct(Allocator* alloc, slot_type* slot, Args&&... args) {
+    absl::allocator_traits<Allocator>::construct(*alloc, slot,
+                                                 std::forward<Args>(args)...);
+  }
+
+  template <class Allocator>
+  static void destroy(Allocator* alloc, slot_type* slot) {
+    absl::allocator_traits<Allocator>::destroy(*alloc, slot);
+  }
+
+  template <class Allocator>
+  static void transfer(Allocator* alloc, slot_type* new_slot,
+                       slot_type* old_slot) {
+    construct(alloc, new_slot, std::move(*old_slot));
+    destroy(alloc, old_slot);
+  }
+
+  static T& element(slot_type* slot) { return *slot; }
+
+  template <class F, class... Args>
+  static decltype(absl::container_internal::DecomposeValue(
+      std::declval<F>(), std::declval<Args>()...))
+  apply(F&& f, Args&&... args) {
+    return absl::container_internal::DecomposeValue(
+        std::forward<F>(f), std::forward<Args>(args)...);
+  }
+
+  static size_t space_used(const T*) { return 0; }
+};
+}  // namespace container_internal
+
+namespace container_algorithm_internal {
+
+// Specialization of trait in absl/algorithm/container.h
+template <class Key, class Hash, class KeyEqual, class Allocator>
+struct IsUnorderedContainer<absl::flat_hash_set<Key, Hash, KeyEqual, Allocator>>
+    : std::true_type {};
+
+}  // namespace container_algorithm_internal
+
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#endif  // ABSL_CONTAINER_FLAT_HASH_SET_H_
diff --git a/src/absl/container/inlined_vector.h b/src/absl/container/inlined_vector.h
new file mode 100644 (file)
index 0000000..7c18234
--- /dev/null
@@ -0,0 +1,847 @@
+// Copyright 2019 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// -----------------------------------------------------------------------------
+// File: inlined_vector.h
+// -----------------------------------------------------------------------------
+//
+// This header file contains the declaration and definition of an "inlined
+// vector" which behaves in an equivalent fashion to a `std::vector`, except
+// that storage for small sequences of the vector are provided inline without
+// requiring any heap allocation.
+//
+// An `absl::InlinedVector<T, N>` specifies the default capacity `N` as one of
+// its template parameters. Instances where `size() <= N` hold contained
+// elements in inline space. Typically `N` is very small so that sequences that
+// are expected to be short do not require allocations.
+//
+// An `absl::InlinedVector` does not usually require a specific allocator. If
+// the inlined vector grows beyond its initial constraints, it will need to
+// allocate (as any normal `std::vector` would). This is usually performed with
+// the default allocator (defined as `std::allocator<T>`). Optionally, a custom
+// allocator type may be specified as `A` in `absl::InlinedVector<T, N, A>`.
+
+#ifndef ABSL_CONTAINER_INLINED_VECTOR_H_
+#define ABSL_CONTAINER_INLINED_VECTOR_H_
+
+#include <algorithm>
+#include <cassert>
+#include <cstddef>
+#include <cstdlib>
+#include <cstring>
+#include <initializer_list>
+#include <iterator>
+#include <memory>
+#include <type_traits>
+#include <utility>
+
+#include "absl/algorithm/algorithm.h"
+#include "absl/base/internal/throw_delegate.h"
+#include "absl/base/macros.h"
+#include "absl/base/optimization.h"
+#include "absl/base/port.h"
+#include "absl/container/internal/inlined_vector.h"
+#include "absl/memory/memory.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+// -----------------------------------------------------------------------------
+// InlinedVector
+// -----------------------------------------------------------------------------
+//
+// An `absl::InlinedVector` is designed to be a drop-in replacement for
+// `std::vector` for use cases where the vector's size is sufficiently small
+// that it can be inlined. If the inlined vector does grow beyond its estimated
+// capacity, it will trigger an initial allocation on the heap, and will behave
+// as a `std::vector`. The API of the `absl::InlinedVector` within this file is
+// designed to cover the same API footprint as covered by `std::vector`.
+template <typename T, size_t N, typename A = std::allocator<T>>
+class InlinedVector {
+  static_assert(N > 0, "`absl::InlinedVector` requires an inlined capacity.");
+
+  using Storage = inlined_vector_internal::Storage<T, N, A>;
+
+  using AllocatorTraits = typename Storage::AllocatorTraits;
+  using RValueReference = typename Storage::RValueReference;
+  using MoveIterator = typename Storage::MoveIterator;
+  using IsMemcpyOk = typename Storage::IsMemcpyOk;
+
+  template <typename Iterator>
+  using IteratorValueAdapter =
+      typename Storage::template IteratorValueAdapter<Iterator>;
+  using CopyValueAdapter = typename Storage::CopyValueAdapter;
+  using DefaultValueAdapter = typename Storage::DefaultValueAdapter;
+
+  template <typename Iterator>
+  using EnableIfAtLeastForwardIterator = absl::enable_if_t<
+      inlined_vector_internal::IsAtLeastForwardIterator<Iterator>::value>;
+  template <typename Iterator>
+  using DisableIfAtLeastForwardIterator = absl::enable_if_t<
+      !inlined_vector_internal::IsAtLeastForwardIterator<Iterator>::value>;
+
+ public:
+  using allocator_type = typename Storage::allocator_type;
+  using value_type = typename Storage::value_type;
+  using pointer = typename Storage::pointer;
+  using const_pointer = typename Storage::const_pointer;
+  using size_type = typename Storage::size_type;
+  using difference_type = typename Storage::difference_type;
+  using reference = typename Storage::reference;
+  using const_reference = typename Storage::const_reference;
+  using iterator = typename Storage::iterator;
+  using const_iterator = typename Storage::const_iterator;
+  using reverse_iterator = typename Storage::reverse_iterator;
+  using const_reverse_iterator = typename Storage::const_reverse_iterator;
+
+  // ---------------------------------------------------------------------------
+  // InlinedVector Constructors and Destructor
+  // ---------------------------------------------------------------------------
+
+  // Creates an empty inlined vector with a value-initialized allocator.
+  InlinedVector() noexcept(noexcept(allocator_type())) : storage_() {}
+
+  // Creates an empty inlined vector with a copy of `alloc`.
+  explicit InlinedVector(const allocator_type& alloc) noexcept
+      : storage_(alloc) {}
+
+  // Creates an inlined vector with `n` copies of `value_type()`.
+  explicit InlinedVector(size_type n,
+                         const allocator_type& alloc = allocator_type())
+      : storage_(alloc) {
+    storage_.Initialize(DefaultValueAdapter(), n);
+  }
+
+  // Creates an inlined vector with `n` copies of `v`.
+  InlinedVector(size_type n, const_reference v,
+                const allocator_type& alloc = allocator_type())
+      : storage_(alloc) {
+    storage_.Initialize(CopyValueAdapter(v), n);
+  }
+
+  // Creates an inlined vector with copies of the elements of `list`.
+  InlinedVector(std::initializer_list<value_type> list,
+                const allocator_type& alloc = allocator_type())
+      : InlinedVector(list.begin(), list.end(), alloc) {}
+
+  // Creates an inlined vector with elements constructed from the provided
+  // forward iterator range [`first`, `last`).
+  //
+  // NOTE: the `enable_if` prevents ambiguous interpretation between a call to
+  // this constructor with two integral arguments and a call to the above
+  // `InlinedVector(size_type, const_reference)` constructor.
+  template <typename ForwardIterator,
+            EnableIfAtLeastForwardIterator<ForwardIterator>* = nullptr>
+  InlinedVector(ForwardIterator first, ForwardIterator last,
+                const allocator_type& alloc = allocator_type())
+      : storage_(alloc) {
+    storage_.Initialize(IteratorValueAdapter<ForwardIterator>(first),
+                        std::distance(first, last));
+  }
+
+  // Creates an inlined vector with elements constructed from the provided input
+  // iterator range [`first`, `last`).
+  template <typename InputIterator,
+            DisableIfAtLeastForwardIterator<InputIterator>* = nullptr>
+  InlinedVector(InputIterator first, InputIterator last,
+                const allocator_type& alloc = allocator_type())
+      : storage_(alloc) {
+    std::copy(first, last, std::back_inserter(*this));
+  }
+
+  // Creates an inlined vector by copying the contents of `other` using
+  // `other`'s allocator.
+  InlinedVector(const InlinedVector& other)
+      : InlinedVector(other, *other.storage_.GetAllocPtr()) {}
+
+  // Creates an inlined vector by copying the contents of `other` using `alloc`.
+  InlinedVector(const InlinedVector& other, const allocator_type& alloc)
+      : storage_(alloc) {
+    if (other.empty()) {
+      // Empty; nothing to do.
+    } else if (IsMemcpyOk::value && !other.storage_.GetIsAllocated()) {
+      // Memcpy-able and do not need allocation.
+      storage_.MemcpyFrom(other.storage_);
+    } else {
+      storage_.InitFrom(other.storage_);
+    }
+  }
+
+  // Creates an inlined vector by moving in the contents of `other` without
+  // allocating. If `other` contains allocated memory, the newly-created inlined
+  // vector will take ownership of that memory. However, if `other` does not
+  // contain allocated memory, the newly-created inlined vector will perform
+  // element-wise move construction of the contents of `other`.
+  //
+  // NOTE: since no allocation is performed for the inlined vector in either
+  // case, the `noexcept(...)` specification depends on whether moving the
+  // underlying objects can throw. It is assumed assumed that...
+  //  a) move constructors should only throw due to allocation failure.
+  //  b) if `value_type`'s move constructor allocates, it uses the same
+  //     allocation function as the inlined vector's allocator.
+  // Thus, the move constructor is non-throwing if the allocator is non-throwing
+  // or `value_type`'s move constructor is specified as `noexcept`.
+  InlinedVector(InlinedVector&& other) noexcept(
+      absl::allocator_is_nothrow<allocator_type>::value ||
+      std::is_nothrow_move_constructible<value_type>::value)
+      : storage_(*other.storage_.GetAllocPtr()) {
+    if (IsMemcpyOk::value) {
+      storage_.MemcpyFrom(other.storage_);
+
+      other.storage_.SetInlinedSize(0);
+    } else if (other.storage_.GetIsAllocated()) {
+      storage_.SetAllocatedData(other.storage_.GetAllocatedData(),
+                                other.storage_.GetAllocatedCapacity());
+      storage_.SetAllocatedSize(other.storage_.GetSize());
+
+      other.storage_.SetInlinedSize(0);
+    } else {
+      IteratorValueAdapter<MoveIterator> other_values(
+          MoveIterator(other.storage_.GetInlinedData()));
+
+      inlined_vector_internal::ConstructElements(
+          storage_.GetAllocPtr(), storage_.GetInlinedData(), &other_values,
+          other.storage_.GetSize());
+
+      storage_.SetInlinedSize(other.storage_.GetSize());
+    }
+  }
+
+  // Creates an inlined vector by moving in the contents of `other` with a copy
+  // of `alloc`.
+  //
+  // NOTE: if `other`'s allocator is not equal to `alloc`, even if `other`
+  // contains allocated memory, this move constructor will still allocate. Since
+  // allocation is performed, this constructor can only be `noexcept` if the
+  // specified allocator is also `noexcept`.
+  InlinedVector(InlinedVector&& other, const allocator_type& alloc) noexcept(
+      absl::allocator_is_nothrow<allocator_type>::value)
+      : storage_(alloc) {
+    if (IsMemcpyOk::value) {
+      storage_.MemcpyFrom(other.storage_);
+
+      other.storage_.SetInlinedSize(0);
+    } else if ((*storage_.GetAllocPtr() == *other.storage_.GetAllocPtr()) &&
+               other.storage_.GetIsAllocated()) {
+      storage_.SetAllocatedData(other.storage_.GetAllocatedData(),
+                                other.storage_.GetAllocatedCapacity());
+      storage_.SetAllocatedSize(other.storage_.GetSize());
+
+      other.storage_.SetInlinedSize(0);
+    } else {
+      storage_.Initialize(
+          IteratorValueAdapter<MoveIterator>(MoveIterator(other.data())),
+          other.size());
+    }
+  }
+
+  ~InlinedVector() {}
+
+  // ---------------------------------------------------------------------------
+  // InlinedVector Member Accessors
+  // ---------------------------------------------------------------------------
+
+  // `InlinedVector::empty()`
+  //
+  // Returns whether the inlined vector contains no elements.
+  bool empty() const noexcept { return !size(); }
+
+  // `InlinedVector::size()`
+  //
+  // Returns the number of elements in the inlined vector.
+  size_type size() const noexcept { return storage_.GetSize(); }
+
+  // `InlinedVector::max_size()`
+  //
+  // Returns the maximum number of elements the inlined vector can hold.
+  size_type max_size() const noexcept {
+    // One bit of the size storage is used to indicate whether the inlined
+    // vector contains allocated memory. As a result, the maximum size that the
+    // inlined vector can express is half of the max for `size_type`.
+    return (std::numeric_limits<size_type>::max)() / 2;
+  }
+
+  // `InlinedVector::capacity()`
+  //
+  // Returns the number of elements that could be stored in the inlined vector
+  // without requiring a reallocation.
+  //
+  // NOTE: for most inlined vectors, `capacity()` should be equal to the
+  // template parameter `N`. For inlined vectors which exceed this capacity,
+  // they will no longer be inlined and `capacity()` will equal the capactity of
+  // the allocated memory.
+  size_type capacity() const noexcept {
+    return storage_.GetIsAllocated() ? storage_.GetAllocatedCapacity()
+                                     : storage_.GetInlinedCapacity();
+  }
+
+  // `InlinedVector::data()`
+  //
+  // Returns a `pointer` to the elements of the inlined vector. This pointer
+  // can be used to access and modify the contained elements.
+  //
+  // NOTE: only elements within [`data()`, `data() + size()`) are valid.
+  pointer data() noexcept {
+    return storage_.GetIsAllocated() ? storage_.GetAllocatedData()
+                                     : storage_.GetInlinedData();
+  }
+
+  // Overload of `InlinedVector::data()` that returns a `const_pointer` to the
+  // elements of the inlined vector. This pointer can be used to access but not
+  // modify the contained elements.
+  //
+  // NOTE: only elements within [`data()`, `data() + size()`) are valid.
+  const_pointer data() const noexcept {
+    return storage_.GetIsAllocated() ? storage_.GetAllocatedData()
+                                     : storage_.GetInlinedData();
+  }
+
+  // `InlinedVector::operator[](...)`
+  //
+  // Returns a `reference` to the `i`th element of the inlined vector.
+  reference operator[](size_type i) {
+    ABSL_HARDENING_ASSERT(i < size());
+    return data()[i];
+  }
+
+  // Overload of `InlinedVector::operator[](...)` that returns a
+  // `const_reference` to the `i`th element of the inlined vector.
+  const_reference operator[](size_type i) const {
+    ABSL_HARDENING_ASSERT(i < size());
+    return data()[i];
+  }
+
+  // `InlinedVector::at(...)`
+  //
+  // Returns a `reference` to the `i`th element of the inlined vector.
+  //
+  // NOTE: if `i` is not within the required range of `InlinedVector::at(...)`,
+  // in both debug and non-debug builds, `std::out_of_range` will be thrown.
+  reference at(size_type i) {
+    if (ABSL_PREDICT_FALSE(i >= size())) {
+      base_internal::ThrowStdOutOfRange(
+          "`InlinedVector::at(size_type)` failed bounds check");
+    }
+    return data()[i];
+  }
+
+  // Overload of `InlinedVector::at(...)` that returns a `const_reference` to
+  // the `i`th element of the inlined vector.
+  //
+  // NOTE: if `i` is not within the required range of `InlinedVector::at(...)`,
+  // in both debug and non-debug builds, `std::out_of_range` will be thrown.
+  const_reference at(size_type i) const {
+    if (ABSL_PREDICT_FALSE(i >= size())) {
+      base_internal::ThrowStdOutOfRange(
+          "`InlinedVector::at(size_type) const` failed bounds check");
+    }
+    return data()[i];
+  }
+
+  // `InlinedVector::front()`
+  //
+  // Returns a `reference` to the first element of the inlined vector.
+  reference front() {
+    ABSL_HARDENING_ASSERT(!empty());
+    return data()[0];
+  }
+
+  // Overload of `InlinedVector::front()` that returns a `const_reference` to
+  // the first element of the inlined vector.
+  const_reference front() const {
+    ABSL_HARDENING_ASSERT(!empty());
+    return data()[0];
+  }
+
+  // `InlinedVector::back()`
+  //
+  // Returns a `reference` to the last element of the inlined vector.
+  reference back() {
+    ABSL_HARDENING_ASSERT(!empty());
+    return data()[size() - 1];
+  }
+
+  // Overload of `InlinedVector::back()` that returns a `const_reference` to the
+  // last element of the inlined vector.
+  const_reference back() const {
+    ABSL_HARDENING_ASSERT(!empty());
+    return data()[size() - 1];
+  }
+
+  // `InlinedVector::begin()`
+  //
+  // Returns an `iterator` to the beginning of the inlined vector.
+  iterator begin() noexcept { return data(); }
+
+  // Overload of `InlinedVector::begin()` that returns a `const_iterator` to
+  // the beginning of the inlined vector.
+  const_iterator begin() const noexcept { return data(); }
+
+  // `InlinedVector::end()`
+  //
+  // Returns an `iterator` to the end of the inlined vector.
+  iterator end() noexcept { return data() + size(); }
+
+  // Overload of `InlinedVector::end()` that returns a `const_iterator` to the
+  // end of the inlined vector.
+  const_iterator end() const noexcept { return data() + size(); }
+
+  // `InlinedVector::cbegin()`
+  //
+  // Returns a `const_iterator` to the beginning of the inlined vector.
+  const_iterator cbegin() const noexcept { return begin(); }
+
+  // `InlinedVector::cend()`
+  //
+  // Returns a `const_iterator` to the end of the inlined vector.
+  const_iterator cend() const noexcept { return end(); }
+
+  // `InlinedVector::rbegin()`
+  //
+  // Returns a `reverse_iterator` from the end of the inlined vector.
+  reverse_iterator rbegin() noexcept { return reverse_iterator(end()); }
+
+  // Overload of `InlinedVector::rbegin()` that returns a
+  // `const_reverse_iterator` from the end of the inlined vector.
+  const_reverse_iterator rbegin() const noexcept {
+    return const_reverse_iterator(end());
+  }
+
+  // `InlinedVector::rend()`
+  //
+  // Returns a `reverse_iterator` from the beginning of the inlined vector.
+  reverse_iterator rend() noexcept { return reverse_iterator(begin()); }
+
+  // Overload of `InlinedVector::rend()` that returns a `const_reverse_iterator`
+  // from the beginning of the inlined vector.
+  const_reverse_iterator rend() const noexcept {
+    return const_reverse_iterator(begin());
+  }
+
+  // `InlinedVector::crbegin()`
+  //
+  // Returns a `const_reverse_iterator` from the end of the inlined vector.
+  const_reverse_iterator crbegin() const noexcept { return rbegin(); }
+
+  // `InlinedVector::crend()`
+  //
+  // Returns a `const_reverse_iterator` from the beginning of the inlined
+  // vector.
+  const_reverse_iterator crend() const noexcept { return rend(); }
+
+  // `InlinedVector::get_allocator()`
+  //
+  // Returns a copy of the inlined vector's allocator.
+  allocator_type get_allocator() const { return *storage_.GetAllocPtr(); }
+
+  // ---------------------------------------------------------------------------
+  // InlinedVector Member Mutators
+  // ---------------------------------------------------------------------------
+
+  // `InlinedVector::operator=(...)`
+  //
+  // Replaces the elements of the inlined vector with copies of the elements of
+  // `list`.
+  InlinedVector& operator=(std::initializer_list<value_type> list) {
+    assign(list.begin(), list.end());
+
+    return *this;
+  }
+
+  // Overload of `InlinedVector::operator=(...)` that replaces the elements of
+  // the inlined vector with copies of the elements of `other`.
+  InlinedVector& operator=(const InlinedVector& other) {
+    if (ABSL_PREDICT_TRUE(this != std::addressof(other))) {
+      const_pointer other_data = other.data();
+      assign(other_data, other_data + other.size());
+    }
+
+    return *this;
+  }
+
+  // Overload of `InlinedVector::operator=(...)` that moves the elements of
+  // `other` into the inlined vector.
+  //
+  // NOTE: as a result of calling this overload, `other` is left in a valid but
+  // unspecified state.
+  InlinedVector& operator=(InlinedVector&& other) {
+    if (ABSL_PREDICT_TRUE(this != std::addressof(other))) {
+      if (IsMemcpyOk::value || other.storage_.GetIsAllocated()) {
+        inlined_vector_internal::DestroyElements(storage_.GetAllocPtr(), data(),
+                                                 size());
+        storage_.DeallocateIfAllocated();
+        storage_.MemcpyFrom(other.storage_);
+
+        other.storage_.SetInlinedSize(0);
+      } else {
+        storage_.Assign(IteratorValueAdapter<MoveIterator>(
+                            MoveIterator(other.storage_.GetInlinedData())),
+                        other.size());
+      }
+    }
+
+    return *this;
+  }
+
+  // `InlinedVector::assign(...)`
+  //
+  // Replaces the contents of the inlined vector with `n` copies of `v`.
+  void assign(size_type n, const_reference v) {
+    storage_.Assign(CopyValueAdapter(v), n);
+  }
+
+  // Overload of `InlinedVector::assign(...)` that replaces the contents of the
+  // inlined vector with copies of the elements of `list`.
+  void assign(std::initializer_list<value_type> list) {
+    assign(list.begin(), list.end());
+  }
+
+  // Overload of `InlinedVector::assign(...)` to replace the contents of the
+  // inlined vector with the range [`first`, `last`).
+  //
+  // NOTE: this overload is for iterators that are "forward" category or better.
+  template <typename ForwardIterator,
+            EnableIfAtLeastForwardIterator<ForwardIterator>* = nullptr>
+  void assign(ForwardIterator first, ForwardIterator last) {
+    storage_.Assign(IteratorValueAdapter<ForwardIterator>(first),
+                    std::distance(first, last));
+  }
+
+  // Overload of `InlinedVector::assign(...)` to replace the contents of the
+  // inlined vector with the range [`first`, `last`).
+  //
+  // NOTE: this overload is for iterators that are "input" category.
+  template <typename InputIterator,
+            DisableIfAtLeastForwardIterator<InputIterator>* = nullptr>
+  void assign(InputIterator first, InputIterator last) {
+    size_type i = 0;
+    for (; i < size() && first != last; ++i, static_cast<void>(++first)) {
+      data()[i] = *first;
+    }
+
+    erase(data() + i, data() + size());
+    std::copy(first, last, std::back_inserter(*this));
+  }
+
+  // `InlinedVector::resize(...)`
+  //
+  // Resizes the inlined vector to contain `n` elements.
+  //
+  // NOTE: If `n` is smaller than `size()`, extra elements are destroyed. If `n`
+  // is larger than `size()`, new elements are value-initialized.
+  void resize(size_type n) {
+    ABSL_HARDENING_ASSERT(n <= max_size());
+    storage_.Resize(DefaultValueAdapter(), n);
+  }
+
+  // Overload of `InlinedVector::resize(...)` that resizes the inlined vector to
+  // contain `n` elements.
+  //
+  // NOTE: if `n` is smaller than `size()`, extra elements are destroyed. If `n`
+  // is larger than `size()`, new elements are copied-constructed from `v`.
+  void resize(size_type n, const_reference v) {
+    ABSL_HARDENING_ASSERT(n <= max_size());
+    storage_.Resize(CopyValueAdapter(v), n);
+  }
+
+  // `InlinedVector::insert(...)`
+  //
+  // Inserts a copy of `v` at `pos`, returning an `iterator` to the newly
+  // inserted element.
+  iterator insert(const_iterator pos, const_reference v) {
+    return emplace(pos, v);
+  }
+
+  // Overload of `InlinedVector::insert(...)` that inserts `v` at `pos` using
+  // move semantics, returning an `iterator` to the newly inserted element.
+  iterator insert(const_iterator pos, RValueReference v) {
+    return emplace(pos, std::move(v));
+  }
+
+  // Overload of `InlinedVector::insert(...)` that inserts `n` contiguous copies
+  // of `v` starting at `pos`, returning an `iterator` pointing to the first of
+  // the newly inserted elements.
+  iterator insert(const_iterator pos, size_type n, const_reference v) {
+    ABSL_HARDENING_ASSERT(pos >= begin());
+    ABSL_HARDENING_ASSERT(pos <= end());
+
+    if (ABSL_PREDICT_TRUE(n != 0)) {
+      value_type dealias = v;
+      return storage_.Insert(pos, CopyValueAdapter(dealias), n);
+    } else {
+      return const_cast<iterator>(pos);
+    }
+  }
+
+  // Overload of `InlinedVector::insert(...)` that inserts copies of the
+  // elements of `list` starting at `pos`, returning an `iterator` pointing to
+  // the first of the newly inserted elements.
+  iterator insert(const_iterator pos, std::initializer_list<value_type> list) {
+    return insert(pos, list.begin(), list.end());
+  }
+
+  // Overload of `InlinedVector::insert(...)` that inserts the range [`first`,
+  // `last`) starting at `pos`, returning an `iterator` pointing to the first
+  // of the newly inserted elements.
+  //
+  // NOTE: this overload is for iterators that are "forward" category or better.
+  template <typename ForwardIterator,
+            EnableIfAtLeastForwardIterator<ForwardIterator>* = nullptr>
+  iterator insert(const_iterator pos, ForwardIterator first,
+                  ForwardIterator last) {
+    ABSL_HARDENING_ASSERT(pos >= begin());
+    ABSL_HARDENING_ASSERT(pos <= end());
+
+    if (ABSL_PREDICT_TRUE(first != last)) {
+      return storage_.Insert(pos, IteratorValueAdapter<ForwardIterator>(first),
+                             std::distance(first, last));
+    } else {
+      return const_cast<iterator>(pos);
+    }
+  }
+
+  // Overload of `InlinedVector::insert(...)` that inserts the range [`first`,
+  // `last`) starting at `pos`, returning an `iterator` pointing to the first
+  // of the newly inserted elements.
+  //
+  // NOTE: this overload is for iterators that are "input" category.
+  template <typename InputIterator,
+            DisableIfAtLeastForwardIterator<InputIterator>* = nullptr>
+  iterator insert(const_iterator pos, InputIterator first, InputIterator last) {
+    ABSL_HARDENING_ASSERT(pos >= begin());
+    ABSL_HARDENING_ASSERT(pos <= end());
+
+    size_type index = std::distance(cbegin(), pos);
+    for (size_type i = index; first != last; ++i, static_cast<void>(++first)) {
+      insert(data() + i, *first);
+    }
+
+    return iterator(data() + index);
+  }
+
+  // `InlinedVector::emplace(...)`
+  //
+  // Constructs and inserts an element using `args...` in the inlined vector at
+  // `pos`, returning an `iterator` pointing to the newly emplaced element.
+  template <typename... Args>
+  iterator emplace(const_iterator pos, Args&&... args) {
+    ABSL_HARDENING_ASSERT(pos >= begin());
+    ABSL_HARDENING_ASSERT(pos <= end());
+
+    value_type dealias(std::forward<Args>(args)...);
+    return storage_.Insert(pos,
+                           IteratorValueAdapter<MoveIterator>(
+                               MoveIterator(std::addressof(dealias))),
+                           1);
+  }
+
+  // `InlinedVector::emplace_back(...)`
+  //
+  // Constructs and inserts an element using `args...` in the inlined vector at
+  // `end()`, returning a `reference` to the newly emplaced element.
+  template <typename... Args>
+  reference emplace_back(Args&&... args) {
+    return storage_.EmplaceBack(std::forward<Args>(args)...);
+  }
+
+  // `InlinedVector::push_back(...)`
+  //
+  // Inserts a copy of `v` in the inlined vector at `end()`.
+  void push_back(const_reference v) { static_cast<void>(emplace_back(v)); }
+
+  // Overload of `InlinedVector::push_back(...)` for inserting `v` at `end()`
+  // using move semantics.
+  void push_back(RValueReference v) {
+    static_cast<void>(emplace_back(std::move(v)));
+  }
+
+  // `InlinedVector::pop_back()`
+  //
+  // Destroys the element at `back()`, reducing the size by `1`.
+  void pop_back() noexcept {
+    ABSL_HARDENING_ASSERT(!empty());
+
+    AllocatorTraits::destroy(*storage_.GetAllocPtr(), data() + (size() - 1));
+    storage_.SubtractSize(1);
+  }
+
+  // `InlinedVector::erase(...)`
+  //
+  // Erases the element at `pos`, returning an `iterator` pointing to where the
+  // erased element was located.
+  //
+  // NOTE: may return `end()`, which is not dereferencable.
+  iterator erase(const_iterator pos) {
+    ABSL_HARDENING_ASSERT(pos >= begin());
+    ABSL_HARDENING_ASSERT(pos < end());
+
+    return storage_.Erase(pos, pos + 1);
+  }
+
+  // Overload of `InlinedVector::erase(...)` that erases every element in the
+  // range [`from`, `to`), returning an `iterator` pointing to where the first
+  // erased element was located.
+  //
+  // NOTE: may return `end()`, which is not dereferencable.
+  iterator erase(const_iterator from, const_iterator to) {
+    ABSL_HARDENING_ASSERT(from >= begin());
+    ABSL_HARDENING_ASSERT(from <= to);
+    ABSL_HARDENING_ASSERT(to <= end());
+
+    if (ABSL_PREDICT_TRUE(from != to)) {
+      return storage_.Erase(from, to);
+    } else {
+      return const_cast<iterator>(from);
+    }
+  }
+
+  // `InlinedVector::clear()`
+  //
+  // Destroys all elements in the inlined vector, setting the size to `0` and
+  // deallocating any held memory.
+  void clear() noexcept {
+    inlined_vector_internal::DestroyElements(storage_.GetAllocPtr(), data(),
+                                             size());
+    storage_.DeallocateIfAllocated();
+
+    storage_.SetInlinedSize(0);
+  }
+
+  // `InlinedVector::reserve(...)`
+  //
+  // Ensures that there is enough room for at least `n` elements.
+  void reserve(size_type n) { storage_.Reserve(n); }
+
+  // `InlinedVector::shrink_to_fit()`
+  //
+  // Reduces memory usage by freeing unused memory. After being called, calls to
+  // `capacity()` will be equal to `max(N, size())`.
+  //
+  // If `size() <= N` and the inlined vector contains allocated memory, the
+  // elements will all be moved to the inlined space and the allocated memory
+  // will be deallocated.
+  //
+  // If `size() > N` and `size() < capacity()`, the elements will be moved to a
+  // smaller allocation.
+  void shrink_to_fit() {
+    if (storage_.GetIsAllocated()) {
+      storage_.ShrinkToFit();
+    }
+  }
+
+  // `InlinedVector::swap(...)`
+  //
+  // Swaps the contents of the inlined vector with `other`.
+  void swap(InlinedVector& other) {
+    if (ABSL_PREDICT_TRUE(this != std::addressof(other))) {
+      storage_.Swap(std::addressof(other.storage_));
+    }
+  }
+
+ private:
+  template <typename H, typename TheT, size_t TheN, typename TheA>
+  friend H AbslHashValue(H h, const absl::InlinedVector<TheT, TheN, TheA>& a);
+
+  Storage storage_;
+};
+
+// -----------------------------------------------------------------------------
+// InlinedVector Non-Member Functions
+// -----------------------------------------------------------------------------
+
+// `swap(...)`
+//
+// Swaps the contents of two inlined vectors.
+template <typename T, size_t N, typename A>
+void swap(absl::InlinedVector<T, N, A>& a,
+          absl::InlinedVector<T, N, A>& b) noexcept(noexcept(a.swap(b))) {
+  a.swap(b);
+}
+
+// `operator==(...)`
+//
+// Tests for value-equality of two inlined vectors.
+template <typename T, size_t N, typename A>
+bool operator==(const absl::InlinedVector<T, N, A>& a,
+                const absl::InlinedVector<T, N, A>& b) {
+  auto a_data = a.data();
+  auto b_data = b.data();
+  return absl::equal(a_data, a_data + a.size(), b_data, b_data + b.size());
+}
+
+// `operator!=(...)`
+//
+// Tests for value-inequality of two inlined vectors.
+template <typename T, size_t N, typename A>
+bool operator!=(const absl::InlinedVector<T, N, A>& a,
+                const absl::InlinedVector<T, N, A>& b) {
+  return !(a == b);
+}
+
+// `operator<(...)`
+//
+// Tests whether the value of an inlined vector is less than the value of
+// another inlined vector using a lexicographical comparison algorithm.
+template <typename T, size_t N, typename A>
+bool operator<(const absl::InlinedVector<T, N, A>& a,
+               const absl::InlinedVector<T, N, A>& b) {
+  auto a_data = a.data();
+  auto b_data = b.data();
+  return std::lexicographical_compare(a_data, a_data + a.size(), b_data,
+                                      b_data + b.size());
+}
+
+// `operator>(...)`
+//
+// Tests whether the value of an inlined vector is greater than the value of
+// another inlined vector using a lexicographical comparison algorithm.
+template <typename T, size_t N, typename A>
+bool operator>(const absl::InlinedVector<T, N, A>& a,
+               const absl::InlinedVector<T, N, A>& b) {
+  return b < a;
+}
+
+// `operator<=(...)`
+//
+// Tests whether the value of an inlined vector is less than or equal to the
+// value of another inlined vector using a lexicographical comparison algorithm.
+template <typename T, size_t N, typename A>
+bool operator<=(const absl::InlinedVector<T, N, A>& a,
+                const absl::InlinedVector<T, N, A>& b) {
+  return !(b < a);
+}
+
+// `operator>=(...)`
+//
+// Tests whether the value of an inlined vector is greater than or equal to the
+// value of another inlined vector using a lexicographical comparison algorithm.
+template <typename T, size_t N, typename A>
+bool operator>=(const absl::InlinedVector<T, N, A>& a,
+                const absl::InlinedVector<T, N, A>& b) {
+  return !(a < b);
+}
+
+// `AbslHashValue(...)`
+//
+// Provides `absl::Hash` support for `absl::InlinedVector`. It is uncommon to
+// call this directly.
+template <typename H, typename T, size_t N, typename A>
+H AbslHashValue(H h, const absl::InlinedVector<T, N, A>& a) {
+  auto size = a.size();
+  return H::combine(H::combine_contiguous(std::move(h), a.data(), size), size);
+}
+
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#endif  // ABSL_CONTAINER_INLINED_VECTOR_H_
diff --git a/src/absl/container/internal/btree.h b/src/absl/container/internal/btree.h
new file mode 100644 (file)
index 0000000..0bb3836
--- /dev/null
@@ -0,0 +1,2620 @@
+// Copyright 2018 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// A btree implementation of the STL set and map interfaces. A btree is smaller
+// and generally also faster than STL set/map (refer to the benchmarks below).
+// The red-black tree implementation of STL set/map has an overhead of 3
+// pointers (left, right and parent) plus the node color information for each
+// stored value. So a set<int32_t> consumes 40 bytes for each value stored in
+// 64-bit mode. This btree implementation stores multiple values on fixed
+// size nodes (usually 256 bytes) and doesn't store child pointers for leaf
+// nodes. The result is that a btree_set<int32_t> may use much less memory per
+// stored value. For the random insertion benchmark in btree_bench.cc, a
+// btree_set<int32_t> with node-size of 256 uses 5.1 bytes per stored value.
+//
+// The packing of multiple values on to each node of a btree has another effect
+// besides better space utilization: better cache locality due to fewer cache
+// lines being accessed. Better cache locality translates into faster
+// operations.
+//
+// CAVEATS
+//
+// Insertions and deletions on a btree can cause splitting, merging or
+// rebalancing of btree nodes. And even without these operations, insertions
+// and deletions on a btree will move values around within a node. In both
+// cases, the result is that insertions and deletions can invalidate iterators
+// pointing to values other than the one being inserted/deleted. Therefore, this
+// container does not provide pointer stability. This is notably different from
+// STL set/map which takes care to not invalidate iterators on insert/erase
+// except, of course, for iterators pointing to the value being erased.  A
+// partial workaround when erasing is available: erase() returns an iterator
+// pointing to the item just after the one that was erased (or end() if none
+// exists).
+
+#ifndef ABSL_CONTAINER_INTERNAL_BTREE_H_
+#define ABSL_CONTAINER_INTERNAL_BTREE_H_
+
+#include <algorithm>
+#include <cassert>
+#include <cstddef>
+#include <cstdint>
+#include <cstring>
+#include <functional>
+#include <iterator>
+#include <limits>
+#include <new>
+#include <string>
+#include <type_traits>
+#include <utility>
+
+#include "absl/base/macros.h"
+#include "absl/container/internal/common.h"
+#include "absl/container/internal/compressed_tuple.h"
+#include "absl/container/internal/container_memory.h"
+#include "absl/container/internal/layout.h"
+#include "absl/memory/memory.h"
+#include "absl/meta/type_traits.h"
+#include "absl/strings/cord.h"
+#include "absl/strings/string_view.h"
+#include "absl/types/compare.h"
+#include "absl/utility/utility.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace container_internal {
+
+// A helper class that indicates if the Compare parameter is a key-compare-to
+// comparator.
+template <typename Compare, typename T>
+using btree_is_key_compare_to =
+    std::is_convertible<absl::result_of_t<Compare(const T &, const T &)>,
+                        absl::weak_ordering>;
+
+struct StringBtreeDefaultLess {
+  using is_transparent = void;
+
+  StringBtreeDefaultLess() = default;
+
+  // Compatibility constructor.
+  StringBtreeDefaultLess(std::less<std::string>) {}  // NOLINT
+  StringBtreeDefaultLess(std::less<string_view>) {}  // NOLINT
+
+  absl::weak_ordering operator()(absl::string_view lhs,
+                                 absl::string_view rhs) const {
+    return compare_internal::compare_result_as_ordering(lhs.compare(rhs));
+  }
+  StringBtreeDefaultLess(std::less<absl::Cord>) {}  // NOLINT
+  absl::weak_ordering operator()(const absl::Cord &lhs,
+                                 const absl::Cord &rhs) const {
+    return compare_internal::compare_result_as_ordering(lhs.Compare(rhs));
+  }
+  absl::weak_ordering operator()(const absl::Cord &lhs,
+                                 absl::string_view rhs) const {
+    return compare_internal::compare_result_as_ordering(lhs.Compare(rhs));
+  }
+  absl::weak_ordering operator()(absl::string_view lhs,
+                                 const absl::Cord &rhs) const {
+    return compare_internal::compare_result_as_ordering(-rhs.Compare(lhs));
+  }
+};
+
+struct StringBtreeDefaultGreater {
+  using is_transparent = void;
+
+  StringBtreeDefaultGreater() = default;
+
+  StringBtreeDefaultGreater(std::greater<std::string>) {}  // NOLINT
+  StringBtreeDefaultGreater(std::greater<string_view>) {}  // NOLINT
+
+  absl::weak_ordering operator()(absl::string_view lhs,
+                                 absl::string_view rhs) const {
+    return compare_internal::compare_result_as_ordering(rhs.compare(lhs));
+  }
+  StringBtreeDefaultGreater(std::greater<absl::Cord>) {}  // NOLINT
+  absl::weak_ordering operator()(const absl::Cord &lhs,
+                                 const absl::Cord &rhs) const {
+    return compare_internal::compare_result_as_ordering(rhs.Compare(lhs));
+  }
+  absl::weak_ordering operator()(const absl::Cord &lhs,
+                                 absl::string_view rhs) const {
+    return compare_internal::compare_result_as_ordering(-lhs.Compare(rhs));
+  }
+  absl::weak_ordering operator()(absl::string_view lhs,
+                                 const absl::Cord &rhs) const {
+    return compare_internal::compare_result_as_ordering(rhs.Compare(lhs));
+  }
+};
+
+// A helper class to convert a boolean comparison into a three-way "compare-to"
+// comparison that returns an `absl::weak_ordering`. This helper
+// class is specialized for less<std::string>, greater<std::string>,
+// less<string_view>, greater<string_view>, less<absl::Cord>, and
+// greater<absl::Cord>.
+//
+// key_compare_to_adapter is provided so that btree users
+// automatically get the more efficient compare-to code when using common
+// Abseil string types with common comparison functors.
+// These string-like specializations also turn on heterogeneous lookup by
+// default.
+template <typename Compare>
+struct key_compare_to_adapter {
+  using type = Compare;
+};
+
+template <>
+struct key_compare_to_adapter<std::less<std::string>> {
+  using type = StringBtreeDefaultLess;
+};
+
+template <>
+struct key_compare_to_adapter<std::greater<std::string>> {
+  using type = StringBtreeDefaultGreater;
+};
+
+template <>
+struct key_compare_to_adapter<std::less<absl::string_view>> {
+  using type = StringBtreeDefaultLess;
+};
+
+template <>
+struct key_compare_to_adapter<std::greater<absl::string_view>> {
+  using type = StringBtreeDefaultGreater;
+};
+
+template <>
+struct key_compare_to_adapter<std::less<absl::Cord>> {
+  using type = StringBtreeDefaultLess;
+};
+
+template <>
+struct key_compare_to_adapter<std::greater<absl::Cord>> {
+  using type = StringBtreeDefaultGreater;
+};
+
+// Detects an 'absl_btree_prefer_linear_node_search' member. This is
+// a protocol used as an opt-in or opt-out of linear search.
+//
+//  For example, this would be useful for key types that wrap an integer
+//  and define their own cheap operator<(). For example:
+//
+//   class K {
+//    public:
+//     using absl_btree_prefer_linear_node_search = std::true_type;
+//     ...
+//    private:
+//     friend bool operator<(K a, K b) { return a.k_ < b.k_; }
+//     int k_;
+//   };
+//
+//   btree_map<K, V> m;  // Uses linear search
+//
+// If T has the preference tag, then it has a preference.
+// Btree will use the tag's truth value.
+template <typename T, typename = void>
+struct has_linear_node_search_preference : std::false_type {};
+template <typename T, typename = void>
+struct prefers_linear_node_search : std::false_type {};
+template <typename T>
+struct has_linear_node_search_preference<
+    T, absl::void_t<typename T::absl_btree_prefer_linear_node_search>>
+    : std::true_type {};
+template <typename T>
+struct prefers_linear_node_search<
+    T, absl::void_t<typename T::absl_btree_prefer_linear_node_search>>
+    : T::absl_btree_prefer_linear_node_search {};
+
+template <typename Key, typename Compare, typename Alloc, int TargetNodeSize,
+          bool Multi, typename SlotPolicy>
+struct common_params {
+  // If Compare is a common comparator for a string-like type, then we adapt it
+  // to use heterogeneous lookup and to be a key-compare-to comparator.
+  using key_compare = typename key_compare_to_adapter<Compare>::type;
+  // A type which indicates if we have a key-compare-to functor or a plain old
+  // key-compare functor.
+  using is_key_compare_to = btree_is_key_compare_to<key_compare, Key>;
+
+  using allocator_type = Alloc;
+  using key_type = Key;
+  using size_type = std::make_signed<size_t>::type;
+  using difference_type = ptrdiff_t;
+
+  using slot_policy = SlotPolicy;
+  using slot_type = typename slot_policy::slot_type;
+  using value_type = typename slot_policy::value_type;
+  using init_type = typename slot_policy::mutable_value_type;
+  using pointer = value_type *;
+  using const_pointer = const value_type *;
+  using reference = value_type &;
+  using const_reference = const value_type &;
+
+  // For the given lookup key type, returns whether we can have multiple
+  // equivalent keys in the btree. If this is a multi-container, then we can.
+  // Otherwise, we can have multiple equivalent keys only if all of the
+  // following conditions are met:
+  // - The comparator is transparent.
+  // - The lookup key type is not the same as key_type.
+  // - The comparator is not a StringBtreeDefault{Less,Greater} comparator
+  //   that we know has the same equivalence classes for all lookup types.
+  template <typename LookupKey>
+  constexpr static bool can_have_multiple_equivalent_keys() {
+    return Multi ||
+           (IsTransparent<key_compare>::value &&
+            !std::is_same<LookupKey, Key>::value &&
+            !std::is_same<key_compare, StringBtreeDefaultLess>::value &&
+            !std::is_same<key_compare, StringBtreeDefaultGreater>::value);
+  }
+
+  enum {
+    kTargetNodeSize = TargetNodeSize,
+
+    // Upper bound for the available space for values. This is largest for leaf
+    // nodes, which have overhead of at least a pointer + 4 bytes (for storing
+    // 3 field_types and an enum).
+    kNodeValueSpace =
+        TargetNodeSize - /*minimum overhead=*/(sizeof(void *) + 4),
+  };
+
+  // This is an integral type large enough to hold as many
+  // ValueSize-values as will fit a node of TargetNodeSize bytes.
+  using node_count_type =
+      absl::conditional_t<(kNodeValueSpace / sizeof(value_type) >
+                           (std::numeric_limits<uint8_t>::max)()),
+                          uint16_t, uint8_t>;  // NOLINT
+
+  // The following methods are necessary for passing this struct as PolicyTraits
+  // for node_handle and/or are used within btree.
+  static value_type &element(slot_type *slot) {
+    return slot_policy::element(slot);
+  }
+  static const value_type &element(const slot_type *slot) {
+    return slot_policy::element(slot);
+  }
+  template <class... Args>
+  static void construct(Alloc *alloc, slot_type *slot, Args &&... args) {
+    slot_policy::construct(alloc, slot, std::forward<Args>(args)...);
+  }
+  static void construct(Alloc *alloc, slot_type *slot, slot_type *other) {
+    slot_policy::construct(alloc, slot, other);
+  }
+  static void destroy(Alloc *alloc, slot_type *slot) {
+    slot_policy::destroy(alloc, slot);
+  }
+  static void transfer(Alloc *alloc, slot_type *new_slot, slot_type *old_slot) {
+    construct(alloc, new_slot, old_slot);
+    destroy(alloc, old_slot);
+  }
+  static void swap(Alloc *alloc, slot_type *a, slot_type *b) {
+    slot_policy::swap(alloc, a, b);
+  }
+  static void move(Alloc *alloc, slot_type *src, slot_type *dest) {
+    slot_policy::move(alloc, src, dest);
+  }
+};
+
+// A parameters structure for holding the type parameters for a btree_map.
+// Compare and Alloc should be nothrow copy-constructible.
+template <typename Key, typename Data, typename Compare, typename Alloc,
+          int TargetNodeSize, bool Multi>
+struct map_params : common_params<Key, Compare, Alloc, TargetNodeSize, Multi,
+                                  map_slot_policy<Key, Data>> {
+  using super_type = typename map_params::common_params;
+  using mapped_type = Data;
+  // This type allows us to move keys when it is safe to do so. It is safe
+  // for maps in which value_type and mutable_value_type are layout compatible.
+  using slot_policy = typename super_type::slot_policy;
+  using slot_type = typename super_type::slot_type;
+  using value_type = typename super_type::value_type;
+  using init_type = typename super_type::init_type;
+
+  using key_compare = typename super_type::key_compare;
+  // Inherit from key_compare for empty base class optimization.
+  struct value_compare : private key_compare {
+    value_compare() = default;
+    explicit value_compare(const key_compare &cmp) : key_compare(cmp) {}
+
+    template <typename T, typename U>
+    auto operator()(const T &left, const U &right) const
+        -> decltype(std::declval<key_compare>()(left.first, right.first)) {
+      return key_compare::operator()(left.first, right.first);
+    }
+  };
+  using is_map_container = std::true_type;
+
+  template <typename V>
+  static auto key(const V &value) -> decltype(value.first) {
+    return value.first;
+  }
+  static const Key &key(const slot_type *s) { return slot_policy::key(s); }
+  static const Key &key(slot_type *s) { return slot_policy::key(s); }
+  // For use in node handle.
+  static auto mutable_key(slot_type *s)
+      -> decltype(slot_policy::mutable_key(s)) {
+    return slot_policy::mutable_key(s);
+  }
+  static mapped_type &value(value_type *value) { return value->second; }
+};
+
+// This type implements the necessary functions from the
+// absl::container_internal::slot_type interface.
+template <typename Key>
+struct set_slot_policy {
+  using slot_type = Key;
+  using value_type = Key;
+  using mutable_value_type = Key;
+
+  static value_type &element(slot_type *slot) { return *slot; }
+  static const value_type &element(const slot_type *slot) { return *slot; }
+
+  template <typename Alloc, class... Args>
+  static void construct(Alloc *alloc, slot_type *slot, Args &&... args) {
+    absl::allocator_traits<Alloc>::construct(*alloc, slot,
+                                             std::forward<Args>(args)...);
+  }
+
+  template <typename Alloc>
+  static void construct(Alloc *alloc, slot_type *slot, slot_type *other) {
+    absl::allocator_traits<Alloc>::construct(*alloc, slot, std::move(*other));
+  }
+
+  template <typename Alloc>
+  static void destroy(Alloc *alloc, slot_type *slot) {
+    absl::allocator_traits<Alloc>::destroy(*alloc, slot);
+  }
+
+  template <typename Alloc>
+  static void swap(Alloc * /*alloc*/, slot_type *a, slot_type *b) {
+    using std::swap;
+    swap(*a, *b);
+  }
+
+  template <typename Alloc>
+  static void move(Alloc * /*alloc*/, slot_type *src, slot_type *dest) {
+    *dest = std::move(*src);
+  }
+};
+
+// A parameters structure for holding the type parameters for a btree_set.
+// Compare and Alloc should be nothrow copy-constructible.
+template <typename Key, typename Compare, typename Alloc, int TargetNodeSize,
+          bool Multi>
+struct set_params : common_params<Key, Compare, Alloc, TargetNodeSize, Multi,
+                                  set_slot_policy<Key>> {
+  using value_type = Key;
+  using slot_type = typename set_params::common_params::slot_type;
+  using value_compare = typename set_params::common_params::key_compare;
+  using is_map_container = std::false_type;
+
+  template <typename V>
+  static const V &key(const V &value) { return value; }
+  static const Key &key(const slot_type *slot) { return *slot; }
+  static const Key &key(slot_type *slot) { return *slot; }
+};
+
+// An adapter class that converts a lower-bound compare into an upper-bound
+// compare. Note: there is no need to make a version of this adapter specialized
+// for key-compare-to functors because the upper-bound (the first value greater
+// than the input) is never an exact match.
+template <typename Compare>
+struct upper_bound_adapter {
+  explicit upper_bound_adapter(const Compare &c) : comp(c) {}
+  template <typename K1, typename K2>
+  bool operator()(const K1 &a, const K2 &b) const {
+    // Returns true when a is not greater than b.
+    return !compare_internal::compare_result_as_less_than(comp(b, a));
+  }
+
+ private:
+  Compare comp;
+};
+
+enum class MatchKind : uint8_t { kEq, kNe };
+
+template <typename V, bool IsCompareTo>
+struct SearchResult {
+  V value;
+  MatchKind match;
+
+  static constexpr bool HasMatch() { return true; }
+  bool IsEq() const { return match == MatchKind::kEq; }
+};
+
+// When we don't use CompareTo, `match` is not present.
+// This ensures that callers can't use it accidentally when it provides no
+// useful information.
+template <typename V>
+struct SearchResult<V, false> {
+  SearchResult() {}
+  explicit SearchResult(V value) : value(value) {}
+  SearchResult(V value, MatchKind /*match*/) : value(value) {}
+
+  V value;
+
+  static constexpr bool HasMatch() { return false; }
+  static constexpr bool IsEq() { return false; }
+};
+
+// A node in the btree holding. The same node type is used for both internal
+// and leaf nodes in the btree, though the nodes are allocated in such a way
+// that the children array is only valid in internal nodes.
+template <typename Params>
+class btree_node {
+  using is_key_compare_to = typename Params::is_key_compare_to;
+  using field_type = typename Params::node_count_type;
+  using allocator_type = typename Params::allocator_type;
+  using slot_type = typename Params::slot_type;
+
+ public:
+  using params_type = Params;
+  using key_type = typename Params::key_type;
+  using value_type = typename Params::value_type;
+  using pointer = typename Params::pointer;
+  using const_pointer = typename Params::const_pointer;
+  using reference = typename Params::reference;
+  using const_reference = typename Params::const_reference;
+  using key_compare = typename Params::key_compare;
+  using size_type = typename Params::size_type;
+  using difference_type = typename Params::difference_type;
+
+  // Btree decides whether to use linear node search as follows:
+  //   - If the comparator expresses a preference, use that.
+  //   - If the key expresses a preference, use that.
+  //   - If the key is arithmetic and the comparator is std::less or
+  //     std::greater, choose linear.
+  //   - Otherwise, choose binary.
+  // TODO(ezb): Might make sense to add condition(s) based on node-size.
+  using use_linear_search = std::integral_constant<
+      bool,
+      has_linear_node_search_preference<key_compare>::value
+          ? prefers_linear_node_search<key_compare>::value
+          : has_linear_node_search_preference<key_type>::value
+                ? prefers_linear_node_search<key_type>::value
+                : std::is_arithmetic<key_type>::value &&
+                      (std::is_same<std::less<key_type>, key_compare>::value ||
+                       std::is_same<std::greater<key_type>,
+                                    key_compare>::value)>;
+
+  // This class is organized by gtl::Layout as if it had the following
+  // structure:
+  //   // A pointer to the node's parent.
+  //   btree_node *parent;
+  //
+  //   // The position of the node in the node's parent.
+  //   field_type position;
+  //   // The index of the first populated value in `values`.
+  //   // TODO(ezb): right now, `start` is always 0. Update insertion/merge
+  //   // logic to allow for floating storage within nodes.
+  //   field_type start;
+  //   // The index after the last populated value in `values`. Currently, this
+  //   // is the same as the count of values.
+  //   field_type finish;
+  //   // The maximum number of values the node can hold. This is an integer in
+  //   // [1, kNodeSlots] for root leaf nodes, kNodeSlots for non-root leaf
+  //   // nodes, and kInternalNodeMaxCount (as a sentinel value) for internal
+  //   // nodes (even though there are still kNodeSlots values in the node).
+  //   // TODO(ezb): make max_count use only 4 bits and record log2(capacity)
+  //   // to free extra bits for is_root, etc.
+  //   field_type max_count;
+  //
+  //   // The array of values. The capacity is `max_count` for leaf nodes and
+  //   // kNodeSlots for internal nodes. Only the values in
+  //   // [start, finish) have been initialized and are valid.
+  //   slot_type values[max_count];
+  //
+  //   // The array of child pointers. The keys in children[i] are all less
+  //   // than key(i). The keys in children[i + 1] are all greater than key(i).
+  //   // There are 0 children for leaf nodes and kNodeSlots + 1 children for
+  //   // internal nodes.
+  //   btree_node *children[kNodeSlots + 1];
+  //
+  // This class is only constructed by EmptyNodeType. Normally, pointers to the
+  // layout above are allocated, cast to btree_node*, and de-allocated within
+  // the btree implementation.
+  ~btree_node() = default;
+  btree_node(btree_node const &) = delete;
+  btree_node &operator=(btree_node const &) = delete;
+
+  // Public for EmptyNodeType.
+  constexpr static size_type Alignment() {
+    static_assert(LeafLayout(1).Alignment() == InternalLayout().Alignment(),
+                  "Alignment of all nodes must be equal.");
+    return InternalLayout().Alignment();
+  }
+
+ protected:
+  btree_node() = default;
+
+ private:
+  using layout_type = absl::container_internal::Layout<btree_node *, field_type,
+                                                       slot_type, btree_node *>;
+  constexpr static size_type SizeWithNSlots(size_type n) {
+    return layout_type(/*parent*/ 1,
+                       /*position, start, finish, max_count*/ 4,
+                       /*slots*/ n,
+                       /*children*/ 0)
+        .AllocSize();
+  }
+  // A lower bound for the overhead of fields other than values in a leaf node.
+  constexpr static size_type MinimumOverhead() {
+    return SizeWithNSlots(1) - sizeof(value_type);
+  }
+
+  // Compute how many values we can fit onto a leaf node taking into account
+  // padding.
+  constexpr static size_type NodeTargetSlots(const int begin, const int end) {
+    return begin == end ? begin
+                        : SizeWithNSlots((begin + end) / 2 + 1) >
+                                  params_type::kTargetNodeSize
+                              ? NodeTargetSlots(begin, (begin + end) / 2)
+                              : NodeTargetSlots((begin + end) / 2 + 1, end);
+  }
+
+  enum {
+    kTargetNodeSize = params_type::kTargetNodeSize,
+    kNodeTargetSlots = NodeTargetSlots(0, params_type::kTargetNodeSize),
+
+    // We need a minimum of 3 slots per internal node in order to perform
+    // splitting (1 value for the two nodes involved in the split and 1 value
+    // propagated to the parent as the delimiter for the split). For performance
+    // reasons, we don't allow 3 slots-per-node due to bad worst case occupancy
+    // of 1/3 (for a node, not a b-tree).
+    kMinNodeSlots = 4,
+
+    kNodeSlots =
+        kNodeTargetSlots >= kMinNodeSlots ? kNodeTargetSlots : kMinNodeSlots,
+
+    // The node is internal (i.e. is not a leaf node) if and only if `max_count`
+    // has this value.
+    kInternalNodeMaxCount = 0,
+  };
+
+  // Leaves can have less than kNodeSlots values.
+  constexpr static layout_type LeafLayout(const int slot_count = kNodeSlots) {
+    return layout_type(/*parent*/ 1,
+                       /*position, start, finish, max_count*/ 4,
+                       /*slots*/ slot_count,
+                       /*children*/ 0);
+  }
+  constexpr static layout_type InternalLayout() {
+    return layout_type(/*parent*/ 1,
+                       /*position, start, finish, max_count*/ 4,
+                       /*slots*/ kNodeSlots,
+                       /*children*/ kNodeSlots + 1);
+  }
+  constexpr static size_type LeafSize(const int slot_count = kNodeSlots) {
+    return LeafLayout(slot_count).AllocSize();
+  }
+  constexpr static size_type InternalSize() {
+    return InternalLayout().AllocSize();
+  }
+
+  // N is the index of the type in the Layout definition.
+  // ElementType<N> is the Nth type in the Layout definition.
+  template <size_type N>
+  inline typename layout_type::template ElementType<N> *GetField() {
+    // We assert that we don't read from values that aren't there.
+    assert(N < 3 || !leaf());
+    return InternalLayout().template Pointer<N>(reinterpret_cast<char *>(this));
+  }
+  template <size_type N>
+  inline const typename layout_type::template ElementType<N> *GetField() const {
+    assert(N < 3 || !leaf());
+    return InternalLayout().template Pointer<N>(
+        reinterpret_cast<const char *>(this));
+  }
+  void set_parent(btree_node *p) { *GetField<0>() = p; }
+  field_type &mutable_finish() { return GetField<1>()[2]; }
+  slot_type *slot(int i) { return &GetField<2>()[i]; }
+  slot_type *start_slot() { return slot(start()); }
+  slot_type *finish_slot() { return slot(finish()); }
+  const slot_type *slot(int i) const { return &GetField<2>()[i]; }
+  void set_position(field_type v) { GetField<1>()[0] = v; }
+  void set_start(field_type v) { GetField<1>()[1] = v; }
+  void set_finish(field_type v) { GetField<1>()[2] = v; }
+  // This method is only called by the node init methods.
+  void set_max_count(field_type v) { GetField<1>()[3] = v; }
+
+ public:
+  // Whether this is a leaf node or not. This value doesn't change after the
+  // node is created.
+  bool leaf() const { return GetField<1>()[3] != kInternalNodeMaxCount; }
+
+  // Getter for the position of this node in its parent.
+  field_type position() const { return GetField<1>()[0]; }
+
+  // Getter for the offset of the first value in the `values` array.
+  field_type start() const {
+    // TODO(ezb): when floating storage is implemented, return GetField<1>()[1];
+    assert(GetField<1>()[1] == 0);
+    return 0;
+  }
+
+  // Getter for the offset after the last value in the `values` array.
+  field_type finish() const { return GetField<1>()[2]; }
+
+  // Getters for the number of values stored in this node.
+  field_type count() const {
+    assert(finish() >= start());
+    return finish() - start();
+  }
+  field_type max_count() const {
+    // Internal nodes have max_count==kInternalNodeMaxCount.
+    // Leaf nodes have max_count in [1, kNodeSlots].
+    const field_type max_count = GetField<1>()[3];
+    return max_count == field_type{kInternalNodeMaxCount}
+               ? field_type{kNodeSlots}
+               : max_count;
+  }
+
+  // Getter for the parent of this node.
+  btree_node *parent() const { return *GetField<0>(); }
+  // Getter for whether the node is the root of the tree. The parent of the
+  // root of the tree is the leftmost node in the tree which is guaranteed to
+  // be a leaf.
+  bool is_root() const { return parent()->leaf(); }
+  void make_root() {
+    assert(parent()->is_root());
+    set_parent(parent()->parent());
+  }
+
+  // Getters for the key/value at position i in the node.
+  const key_type &key(int i) const { return params_type::key(slot(i)); }
+  reference value(int i) { return params_type::element(slot(i)); }
+  const_reference value(int i) const { return params_type::element(slot(i)); }
+
+  // Getters/setter for the child at position i in the node.
+  btree_node *child(int i) const { return GetField<3>()[i]; }
+  btree_node *start_child() const { return child(start()); }
+  btree_node *&mutable_child(int i) { return GetField<3>()[i]; }
+  void clear_child(int i) {
+    absl::container_internal::SanitizerPoisonObject(&mutable_child(i));
+  }
+  void set_child(int i, btree_node *c) {
+    absl::container_internal::SanitizerUnpoisonObject(&mutable_child(i));
+    mutable_child(i) = c;
+    c->set_position(i);
+  }
+  void init_child(int i, btree_node *c) {
+    set_child(i, c);
+    c->set_parent(this);
+  }
+
+  // Returns the position of the first value whose key is not less than k.
+  template <typename K>
+  SearchResult<int, is_key_compare_to::value> lower_bound(
+      const K &k, const key_compare &comp) const {
+    return use_linear_search::value ? linear_search(k, comp)
+                                    : binary_search(k, comp);
+  }
+  // Returns the position of the first value whose key is greater than k.
+  template <typename K>
+  int upper_bound(const K &k, const key_compare &comp) const {
+    auto upper_compare = upper_bound_adapter<key_compare>(comp);
+    return use_linear_search::value ? linear_search(k, upper_compare).value
+                                    : binary_search(k, upper_compare).value;
+  }
+
+  template <typename K, typename Compare>
+  SearchResult<int, btree_is_key_compare_to<Compare, key_type>::value>
+  linear_search(const K &k, const Compare &comp) const {
+    return linear_search_impl(k, start(), finish(), comp,
+                              btree_is_key_compare_to<Compare, key_type>());
+  }
+
+  template <typename K, typename Compare>
+  SearchResult<int, btree_is_key_compare_to<Compare, key_type>::value>
+  binary_search(const K &k, const Compare &comp) const {
+    return binary_search_impl(k, start(), finish(), comp,
+                              btree_is_key_compare_to<Compare, key_type>());
+  }
+
+  // Returns the position of the first value whose key is not less than k using
+  // linear search performed using plain compare.
+  template <typename K, typename Compare>
+  SearchResult<int, false> linear_search_impl(
+      const K &k, int s, const int e, const Compare &comp,
+      std::false_type /* IsCompareTo */) const {
+    while (s < e) {
+      if (!comp(key(s), k)) {
+        break;
+      }
+      ++s;
+    }
+    return SearchResult<int, false>{s};
+  }
+
+  // Returns the position of the first value whose key is not less than k using
+  // linear search performed using compare-to.
+  template <typename K, typename Compare>
+  SearchResult<int, true> linear_search_impl(
+      const K &k, int s, const int e, const Compare &comp,
+      std::true_type /* IsCompareTo */) const {
+    while (s < e) {
+      const absl::weak_ordering c = comp(key(s), k);
+      if (c == 0) {
+        return {s, MatchKind::kEq};
+      } else if (c > 0) {
+        break;
+      }
+      ++s;
+    }
+    return {s, MatchKind::kNe};
+  }
+
+  // Returns the position of the first value whose key is not less than k using
+  // binary search performed using plain compare.
+  template <typename K, typename Compare>
+  SearchResult<int, false> binary_search_impl(
+      const K &k, int s, int e, const Compare &comp,
+      std::false_type /* IsCompareTo */) const {
+    while (s != e) {
+      const int mid = (s + e) >> 1;
+      if (comp(key(mid), k)) {
+        s = mid + 1;
+      } else {
+        e = mid;
+      }
+    }
+    return SearchResult<int, false>{s};
+  }
+
+  // Returns the position of the first value whose key is not less than k using
+  // binary search performed using compare-to.
+  template <typename K, typename CompareTo>
+  SearchResult<int, true> binary_search_impl(
+      const K &k, int s, int e, const CompareTo &comp,
+      std::true_type /* IsCompareTo */) const {
+    if (params_type::template can_have_multiple_equivalent_keys<K>()) {
+      MatchKind exact_match = MatchKind::kNe;
+      while (s != e) {
+        const int mid = (s + e) >> 1;
+        const absl::weak_ordering c = comp(key(mid), k);
+        if (c < 0) {
+          s = mid + 1;
+        } else {
+          e = mid;
+          if (c == 0) {
+            // Need to return the first value whose key is not less than k,
+            // which requires continuing the binary search if there could be
+            // multiple equivalent keys.
+            exact_match = MatchKind::kEq;
+          }
+        }
+      }
+      return {s, exact_match};
+    } else {  // Can't have multiple equivalent keys.
+      while (s != e) {
+        const int mid = (s + e) >> 1;
+        const absl::weak_ordering c = comp(key(mid), k);
+        if (c < 0) {
+          s = mid + 1;
+        } else if (c > 0) {
+          e = mid;
+        } else {
+          return {mid, MatchKind::kEq};
+        }
+      }
+      return {s, MatchKind::kNe};
+    }
+  }
+
+  // Emplaces a value at position i, shifting all existing values and
+  // children at positions >= i to the right by 1.
+  template <typename... Args>
+  void emplace_value(size_type i, allocator_type *alloc, Args &&... args);
+
+  // Removes the values at positions [i, i + to_erase), shifting all existing
+  // values and children after that range to the left by to_erase. Clears all
+  // children between [i, i + to_erase).
+  void remove_values(field_type i, field_type to_erase, allocator_type *alloc);
+
+  // Rebalances a node with its right sibling.
+  void rebalance_right_to_left(int to_move, btree_node *right,
+                               allocator_type *alloc);
+  void rebalance_left_to_right(int to_move, btree_node *right,
+                               allocator_type *alloc);
+
+  // Splits a node, moving a portion of the node's values to its right sibling.
+  void split(int insert_position, btree_node *dest, allocator_type *alloc);
+
+  // Merges a node with its right sibling, moving all of the values and the
+  // delimiting key in the parent node onto itself, and deleting the src node.
+  void merge(btree_node *src, allocator_type *alloc);
+
+  // Node allocation/deletion routines.
+  void init_leaf(btree_node *parent, int max_count) {
+    set_parent(parent);
+    set_position(0);
+    set_start(0);
+    set_finish(0);
+    set_max_count(max_count);
+    absl::container_internal::SanitizerPoisonMemoryRegion(
+        start_slot(), max_count * sizeof(slot_type));
+  }
+  void init_internal(btree_node *parent) {
+    init_leaf(parent, kNodeSlots);
+    // Set `max_count` to a sentinel value to indicate that this node is
+    // internal.
+    set_max_count(kInternalNodeMaxCount);
+    absl::container_internal::SanitizerPoisonMemoryRegion(
+        &mutable_child(start()), (kNodeSlots + 1) * sizeof(btree_node *));
+  }
+
+  static void deallocate(const size_type size, btree_node *node,
+                         allocator_type *alloc) {
+    absl::container_internal::Deallocate<Alignment()>(alloc, node, size);
+  }
+
+  // Deletes a node and all of its children.
+  static void clear_and_delete(btree_node *node, allocator_type *alloc);
+
+ private:
+  template <typename... Args>
+  void value_init(const field_type i, allocator_type *alloc, Args &&... args) {
+    absl::container_internal::SanitizerUnpoisonObject(slot(i));
+    params_type::construct(alloc, slot(i), std::forward<Args>(args)...);
+  }
+  void value_destroy(const field_type i, allocator_type *alloc) {
+    params_type::destroy(alloc, slot(i));
+    absl::container_internal::SanitizerPoisonObject(slot(i));
+  }
+  void value_destroy_n(const field_type i, const field_type n,
+                       allocator_type *alloc) {
+    for (slot_type *s = slot(i), *end = slot(i + n); s != end; ++s) {
+      params_type::destroy(alloc, s);
+      absl::container_internal::SanitizerPoisonObject(s);
+    }
+  }
+
+  static void transfer(slot_type *dest, slot_type *src, allocator_type *alloc) {
+    absl::container_internal::SanitizerUnpoisonObject(dest);
+    params_type::transfer(alloc, dest, src);
+    absl::container_internal::SanitizerPoisonObject(src);
+  }
+
+  // Transfers value from slot `src_i` in `src_node` to slot `dest_i` in `this`.
+  void transfer(const size_type dest_i, const size_type src_i,
+                btree_node *src_node, allocator_type *alloc) {
+    transfer(slot(dest_i), src_node->slot(src_i), alloc);
+  }
+
+  // Transfers `n` values starting at value `src_i` in `src_node` into the
+  // values starting at value `dest_i` in `this`.
+  void transfer_n(const size_type n, const size_type dest_i,
+                  const size_type src_i, btree_node *src_node,
+                  allocator_type *alloc) {
+    for (slot_type *src = src_node->slot(src_i), *end = src + n,
+                   *dest = slot(dest_i);
+         src != end; ++src, ++dest) {
+      transfer(dest, src, alloc);
+    }
+  }
+
+  // Same as above, except that we start at the end and work our way to the
+  // beginning.
+  void transfer_n_backward(const size_type n, const size_type dest_i,
+                           const size_type src_i, btree_node *src_node,
+                           allocator_type *alloc) {
+    for (slot_type *src = src_node->slot(src_i + n - 1), *end = src - n,
+                   *dest = slot(dest_i + n - 1);
+         src != end; --src, --dest) {
+      transfer(dest, src, alloc);
+    }
+  }
+
+  template <typename P>
+  friend class btree;
+  template <typename N, typename R, typename P>
+  friend struct btree_iterator;
+  friend class BtreeNodePeer;
+};
+
+template <typename Node, typename Reference, typename Pointer>
+struct btree_iterator {
+ private:
+  using key_type = typename Node::key_type;
+  using size_type = typename Node::size_type;
+  using params_type = typename Node::params_type;
+  using is_map_container = typename params_type::is_map_container;
+
+  using node_type = Node;
+  using normal_node = typename std::remove_const<Node>::type;
+  using const_node = const Node;
+  using normal_pointer = typename params_type::pointer;
+  using normal_reference = typename params_type::reference;
+  using const_pointer = typename params_type::const_pointer;
+  using const_reference = typename params_type::const_reference;
+  using slot_type = typename params_type::slot_type;
+
+  using iterator =
+     btree_iterator<normal_node, normal_reference, normal_pointer>;
+  using const_iterator =
+      btree_iterator<const_node, const_reference, const_pointer>;
+
+ public:
+  // These aliases are public for std::iterator_traits.
+  using difference_type = typename Node::difference_type;
+  using value_type = typename params_type::value_type;
+  using pointer = Pointer;
+  using reference = Reference;
+  using iterator_category = std::bidirectional_iterator_tag;
+
+  btree_iterator() : node(nullptr), position(-1) {}
+  explicit btree_iterator(Node *n) : node(n), position(n->start()) {}
+  btree_iterator(Node *n, int p) : node(n), position(p) {}
+
+  // NOTE: this SFINAE allows for implicit conversions from iterator to
+  // const_iterator, but it specifically avoids hiding the copy constructor so
+  // that the trivial one will be used when possible.
+  template <typename N, typename R, typename P,
+            absl::enable_if_t<
+                std::is_same<btree_iterator<N, R, P>, iterator>::value &&
+                    std::is_same<btree_iterator, const_iterator>::value,
+                int> = 0>
+  btree_iterator(const btree_iterator<N, R, P> other)  // NOLINT
+      : node(other.node), position(other.position) {}
+
+ private:
+  // This SFINAE allows explicit conversions from const_iterator to
+  // iterator, but also avoids hiding the copy constructor.
+  // NOTE: the const_cast is safe because this constructor is only called by
+  // non-const methods and the container owns the nodes.
+  template <typename N, typename R, typename P,
+            absl::enable_if_t<
+                std::is_same<btree_iterator<N, R, P>, const_iterator>::value &&
+                    std::is_same<btree_iterator, iterator>::value,
+                int> = 0>
+  explicit btree_iterator(const btree_iterator<N, R, P> other)
+      : node(const_cast<node_type *>(other.node)), position(other.position) {}
+
+  // Increment/decrement the iterator.
+  void increment() {
+    if (node->leaf() && ++position < node->finish()) {
+      return;
+    }
+    increment_slow();
+  }
+  void increment_slow();
+
+  void decrement() {
+    if (node->leaf() && --position >= node->start()) {
+      return;
+    }
+    decrement_slow();
+  }
+  void decrement_slow();
+
+ public:
+  bool operator==(const iterator &other) const {
+    return node == other.node && position == other.position;
+  }
+  bool operator==(const const_iterator &other) const {
+    return node == other.node && position == other.position;
+  }
+  bool operator!=(const iterator &other) const {
+    return node != other.node || position != other.position;
+  }
+  bool operator!=(const const_iterator &other) const {
+    return node != other.node || position != other.position;
+  }
+
+  // Accessors for the key/value the iterator is pointing at.
+  reference operator*() const {
+    ABSL_HARDENING_ASSERT(node != nullptr);
+    ABSL_HARDENING_ASSERT(node->start() <= position);
+    ABSL_HARDENING_ASSERT(node->finish() > position);
+    return node->value(position);
+  }
+  pointer operator->() const { return &operator*(); }
+
+  btree_iterator &operator++() {
+    increment();
+    return *this;
+  }
+  btree_iterator &operator--() {
+    decrement();
+    return *this;
+  }
+  btree_iterator operator++(int) {
+    btree_iterator tmp = *this;
+    ++*this;
+    return tmp;
+  }
+  btree_iterator operator--(int) {
+    btree_iterator tmp = *this;
+    --*this;
+    return tmp;
+  }
+
+ private:
+  friend iterator;
+  friend const_iterator;
+  template <typename Params>
+  friend class btree;
+  template <typename Tree>
+  friend class btree_container;
+  template <typename Tree>
+  friend class btree_set_container;
+  template <typename Tree>
+  friend class btree_map_container;
+  template <typename Tree>
+  friend class btree_multiset_container;
+  template <typename TreeType, typename CheckerType>
+  friend class base_checker;
+
+  const key_type &key() const { return node->key(position); }
+  slot_type *slot() { return node->slot(position); }
+
+  // The node in the tree the iterator is pointing at.
+  Node *node;
+  // The position within the node of the tree the iterator is pointing at.
+  // NOTE: this is an int rather than a field_type because iterators can point
+  // to invalid positions (such as -1) in certain circumstances.
+  int position;
+};
+
+template <typename Params>
+class btree {
+  using node_type = btree_node<Params>;
+  using is_key_compare_to = typename Params::is_key_compare_to;
+  using init_type = typename Params::init_type;
+  using field_type = typename node_type::field_type;
+
+  // We use a static empty node for the root/leftmost/rightmost of empty btrees
+  // in order to avoid branching in begin()/end().
+  struct alignas(node_type::Alignment()) EmptyNodeType : node_type {
+    using field_type = typename node_type::field_type;
+    node_type *parent;
+    field_type position = 0;
+    field_type start = 0;
+    field_type finish = 0;
+    // max_count must be != kInternalNodeMaxCount (so that this node is regarded
+    // as a leaf node). max_count() is never called when the tree is empty.
+    field_type max_count = node_type::kInternalNodeMaxCount + 1;
+
+#ifdef _MSC_VER
+    // MSVC has constexpr code generations bugs here.
+    EmptyNodeType() : parent(this) {}
+#else
+    constexpr EmptyNodeType(node_type *p) : parent(p) {}
+#endif
+  };
+
+  static node_type *EmptyNode() {
+#ifdef _MSC_VER
+    static EmptyNodeType *empty_node = new EmptyNodeType;
+    // This assert fails on some other construction methods.
+    assert(empty_node->parent == empty_node);
+    return empty_node;
+#else
+    static constexpr EmptyNodeType empty_node(
+        const_cast<EmptyNodeType *>(&empty_node));
+    return const_cast<EmptyNodeType *>(&empty_node);
+#endif
+  }
+
+  enum : uint32_t {
+    kNodeSlots = node_type::kNodeSlots,
+    kMinNodeValues = kNodeSlots / 2,
+  };
+
+  struct node_stats {
+    using size_type = typename Params::size_type;
+
+    node_stats(size_type l, size_type i) : leaf_nodes(l), internal_nodes(i) {}
+
+    node_stats &operator+=(const node_stats &other) {
+      leaf_nodes += other.leaf_nodes;
+      internal_nodes += other.internal_nodes;
+      return *this;
+    }
+
+    size_type leaf_nodes;
+    size_type internal_nodes;
+  };
+
+ public:
+  using key_type = typename Params::key_type;
+  using value_type = typename Params::value_type;
+  using size_type = typename Params::size_type;
+  using difference_type = typename Params::difference_type;
+  using key_compare = typename Params::key_compare;
+  using value_compare = typename Params::value_compare;
+  using allocator_type = typename Params::allocator_type;
+  using reference = typename Params::reference;
+  using const_reference = typename Params::const_reference;
+  using pointer = typename Params::pointer;
+  using const_pointer = typename Params::const_pointer;
+  using iterator =
+      typename btree_iterator<node_type, reference, pointer>::iterator;
+  using const_iterator = typename iterator::const_iterator;
+  using reverse_iterator = std::reverse_iterator<iterator>;
+  using const_reverse_iterator = std::reverse_iterator<const_iterator>;
+  using node_handle_type = node_handle<Params, Params, allocator_type>;
+
+  // Internal types made public for use by btree_container types.
+  using params_type = Params;
+  using slot_type = typename Params::slot_type;
+
+ private:
+  // For use in copy_or_move_values_in_order.
+  const value_type &maybe_move_from_iterator(const_iterator it) { return *it; }
+  value_type &&maybe_move_from_iterator(iterator it) {
+    // This is a destructive operation on the other container so it's safe for
+    // us to const_cast and move from the keys here even if it's a set.
+    return std::move(const_cast<value_type &>(*it));
+  }
+
+  // Copies or moves (depending on the template parameter) the values in
+  // other into this btree in their order in other. This btree must be empty
+  // before this method is called. This method is used in copy construction,
+  // copy assignment, and move assignment.
+  template <typename Btree>
+  void copy_or_move_values_in_order(Btree &other);
+
+  // Validates that various assumptions/requirements are true at compile time.
+  constexpr static bool static_assert_validation();
+
+ public:
+  btree(const key_compare &comp, const allocator_type &alloc)
+      : root_(comp, alloc, EmptyNode()), rightmost_(EmptyNode()), size_(0) {}
+
+  btree(const btree &other) : btree(other, other.allocator()) {}
+  btree(const btree &other, const allocator_type &alloc)
+      : btree(other.key_comp(), alloc) {
+    copy_or_move_values_in_order(other);
+  }
+  btree(btree &&other) noexcept
+      : root_(std::move(other.root_)),
+        rightmost_(absl::exchange(other.rightmost_, EmptyNode())),
+        size_(absl::exchange(other.size_, 0)) {
+    other.mutable_root() = EmptyNode();
+  }
+  btree(btree &&other, const allocator_type &alloc)
+      : btree(other.key_comp(), alloc) {
+    if (alloc == other.allocator()) {
+      swap(other);
+    } else {
+      // Move values from `other` one at a time when allocators are different.
+      copy_or_move_values_in_order(other);
+    }
+  }
+
+  ~btree() {
+    // Put static_asserts in destructor to avoid triggering them before the type
+    // is complete.
+    static_assert(static_assert_validation(), "This call must be elided.");
+    clear();
+  }
+
+  // Assign the contents of other to *this.
+  btree &operator=(const btree &other);
+  btree &operator=(btree &&other) noexcept;
+
+  iterator begin() { return iterator(leftmost()); }
+  const_iterator begin() const { return const_iterator(leftmost()); }
+  iterator end() { return iterator(rightmost_, rightmost_->finish()); }
+  const_iterator end() const {
+    return const_iterator(rightmost_, rightmost_->finish());
+  }
+  reverse_iterator rbegin() { return reverse_iterator(end()); }
+  const_reverse_iterator rbegin() const {
+    return const_reverse_iterator(end());
+  }
+  reverse_iterator rend() { return reverse_iterator(begin()); }
+  const_reverse_iterator rend() const {
+    return const_reverse_iterator(begin());
+  }
+
+  // Finds the first element whose key is not less than `key`.
+  template <typename K>
+  iterator lower_bound(const K &key) {
+    return internal_end(internal_lower_bound(key).value);
+  }
+  template <typename K>
+  const_iterator lower_bound(const K &key) const {
+    return internal_end(internal_lower_bound(key).value);
+  }
+
+  // Finds the first element whose key is not less than `key` and also returns
+  // whether that element is equal to `key`.
+  template <typename K>
+  std::pair<iterator, bool> lower_bound_equal(const K &key) const;
+
+  // Finds the first element whose key is greater than `key`.
+  template <typename K>
+  iterator upper_bound(const K &key) {
+    return internal_end(internal_upper_bound(key));
+  }
+  template <typename K>
+  const_iterator upper_bound(const K &key) const {
+    return internal_end(internal_upper_bound(key));
+  }
+
+  // Finds the range of values which compare equal to key. The first member of
+  // the returned pair is equal to lower_bound(key). The second member of the
+  // pair is equal to upper_bound(key).
+  template <typename K>
+  std::pair<iterator, iterator> equal_range(const K &key);
+  template <typename K>
+  std::pair<const_iterator, const_iterator> equal_range(const K &key) const {
+    return const_cast<btree *>(this)->equal_range(key);
+  }
+
+  // Inserts a value into the btree only if it does not already exist. The
+  // boolean return value indicates whether insertion succeeded or failed.
+  // Requirement: if `key` already exists in the btree, does not consume `args`.
+  // Requirement: `key` is never referenced after consuming `args`.
+  template <typename K, typename... Args>
+  std::pair<iterator, bool> insert_unique(const K &key, Args &&... args);
+
+  // Inserts with hint. Checks to see if the value should be placed immediately
+  // before `position` in the tree. If so, then the insertion will take
+  // amortized constant time. If not, the insertion will take amortized
+  // logarithmic time as if a call to insert_unique() were made.
+  // Requirement: if `key` already exists in the btree, does not consume `args`.
+  // Requirement: `key` is never referenced after consuming `args`.
+  template <typename K, typename... Args>
+  std::pair<iterator, bool> insert_hint_unique(iterator position,
+                                               const K &key,
+                                               Args &&... args);
+
+  // Insert a range of values into the btree.
+  // Note: the first overload avoids constructing a value_type if the key
+  // already exists in the btree.
+  template <typename InputIterator,
+            typename = decltype(std::declval<const key_compare &>()(
+                params_type::key(*std::declval<InputIterator>()),
+                std::declval<const key_type &>()))>
+  void insert_iterator_unique(InputIterator b, InputIterator e, int);
+  // We need the second overload for cases in which we need to construct a
+  // value_type in order to compare it with the keys already in the btree.
+  template <typename InputIterator>
+  void insert_iterator_unique(InputIterator b, InputIterator e, char);
+
+  // Inserts a value into the btree.
+  template <typename ValueType>
+  iterator insert_multi(const key_type &key, ValueType &&v);
+
+  // Inserts a value into the btree.
+  template <typename ValueType>
+  iterator insert_multi(ValueType &&v) {
+    return insert_multi(params_type::key(v), std::forward<ValueType>(v));
+  }
+
+  // Insert with hint. Check to see if the value should be placed immediately
+  // before position in the tree. If it does, then the insertion will take
+  // amortized constant time. If not, the insertion will take amortized
+  // logarithmic time as if a call to insert_multi(v) were made.
+  template <typename ValueType>
+  iterator insert_hint_multi(iterator position, ValueType &&v);
+
+  // Insert a range of values into the btree.
+  template <typename InputIterator>
+  void insert_iterator_multi(InputIterator b, InputIterator e);
+
+  // Erase the specified iterator from the btree. The iterator must be valid
+  // (i.e. not equal to end()).  Return an iterator pointing to the node after
+  // the one that was erased (or end() if none exists).
+  // Requirement: does not read the value at `*iter`.
+  iterator erase(iterator iter);
+
+  // Erases range. Returns the number of keys erased and an iterator pointing
+  // to the element after the last erased element.
+  std::pair<size_type, iterator> erase_range(iterator begin, iterator end);
+
+  // Finds an element with key equivalent to `key` or returns `end()` if `key`
+  // is not present.
+  template <typename K>
+  iterator find(const K &key) {
+    return internal_end(internal_find(key));
+  }
+  template <typename K>
+  const_iterator find(const K &key) const {
+    return internal_end(internal_find(key));
+  }
+
+  // Clear the btree, deleting all of the values it contains.
+  void clear();
+
+  // Swaps the contents of `this` and `other`.
+  void swap(btree &other);
+
+  const key_compare &key_comp() const noexcept {
+    return root_.template get<0>();
+  }
+  template <typename K1, typename K2>
+  bool compare_keys(const K1 &a, const K2 &b) const {
+    return compare_internal::compare_result_as_less_than(key_comp()(a, b));
+  }
+
+  value_compare value_comp() const { return value_compare(key_comp()); }
+
+  // Verifies the structure of the btree.
+  void verify() const;
+
+  // Size routines.
+  size_type size() const { return size_; }
+  size_type max_size() const { return (std::numeric_limits<size_type>::max)(); }
+  bool empty() const { return size_ == 0; }
+
+  // The height of the btree. An empty tree will have height 0.
+  size_type height() const {
+    size_type h = 0;
+    if (!empty()) {
+      // Count the length of the chain from the leftmost node up to the
+      // root. We actually count from the root back around to the level below
+      // the root, but the calculation is the same because of the circularity
+      // of that traversal.
+      const node_type *n = root();
+      do {
+        ++h;
+        n = n->parent();
+      } while (n != root());
+    }
+    return h;
+  }
+
+  // The number of internal, leaf and total nodes used by the btree.
+  size_type leaf_nodes() const { return internal_stats(root()).leaf_nodes; }
+  size_type internal_nodes() const {
+    return internal_stats(root()).internal_nodes;
+  }
+  size_type nodes() const {
+    node_stats stats = internal_stats(root());
+    return stats.leaf_nodes + stats.internal_nodes;
+  }
+
+  // The total number of bytes used by the btree.
+  size_type bytes_used() const {
+    node_stats stats = internal_stats(root());
+    if (stats.leaf_nodes == 1 && stats.internal_nodes == 0) {
+      return sizeof(*this) + node_type::LeafSize(root()->max_count());
+    } else {
+      return sizeof(*this) + stats.leaf_nodes * node_type::LeafSize() +
+             stats.internal_nodes * node_type::InternalSize();
+    }
+  }
+
+  // The average number of bytes used per value stored in the btree assuming
+  // random insertion order.
+  static double average_bytes_per_value() {
+    // The expected number of values per node with random insertion order is the
+    // average of the maximum and minimum numbers of values per node.
+    const double expected_values_per_node =
+        (kNodeSlots + kMinNodeValues) / 2.0;
+    return node_type::LeafSize() / expected_values_per_node;
+  }
+
+  // The fullness of the btree. Computed as the number of elements in the btree
+  // divided by the maximum number of elements a tree with the current number
+  // of nodes could hold. A value of 1 indicates perfect space
+  // utilization. Smaller values indicate space wastage.
+  // Returns 0 for empty trees.
+  double fullness() const {
+    if (empty()) return 0.0;
+    return static_cast<double>(size()) / (nodes() * kNodeSlots);
+  }
+  // The overhead of the btree structure in bytes per node. Computed as the
+  // total number of bytes used by the btree minus the number of bytes used for
+  // storing elements divided by the number of elements.
+  // Returns 0 for empty trees.
+  double overhead() const {
+    if (empty()) return 0.0;
+    return (bytes_used() - size() * sizeof(value_type)) /
+           static_cast<double>(size());
+  }
+
+  // The allocator used by the btree.
+  allocator_type get_allocator() const { return allocator(); }
+
+ private:
+  // Internal accessor routines.
+  node_type *root() { return root_.template get<2>(); }
+  const node_type *root() const { return root_.template get<2>(); }
+  node_type *&mutable_root() noexcept { return root_.template get<2>(); }
+  key_compare *mutable_key_comp() noexcept { return &root_.template get<0>(); }
+
+  // The leftmost node is stored as the parent of the root node.
+  node_type *leftmost() { return root()->parent(); }
+  const node_type *leftmost() const { return root()->parent(); }
+
+  // Allocator routines.
+  allocator_type *mutable_allocator() noexcept {
+    return &root_.template get<1>();
+  }
+  const allocator_type &allocator() const noexcept {
+    return root_.template get<1>();
+  }
+
+  // Allocates a correctly aligned node of at least size bytes using the
+  // allocator.
+  node_type *allocate(const size_type size) {
+    return reinterpret_cast<node_type *>(
+        absl::container_internal::Allocate<node_type::Alignment()>(
+            mutable_allocator(), size));
+  }
+
+  // Node creation/deletion routines.
+  node_type *new_internal_node(node_type *parent) {
+    node_type *n = allocate(node_type::InternalSize());
+    n->init_internal(parent);
+    return n;
+  }
+  node_type *new_leaf_node(node_type *parent) {
+    node_type *n = allocate(node_type::LeafSize());
+    n->init_leaf(parent, kNodeSlots);
+    return n;
+  }
+  node_type *new_leaf_root_node(const int max_count) {
+    node_type *n = allocate(node_type::LeafSize(max_count));
+    n->init_leaf(/*parent=*/n, max_count);
+    return n;
+  }
+
+  // Deletion helper routines.
+  iterator rebalance_after_delete(iterator iter);
+
+  // Rebalances or splits the node iter points to.
+  void rebalance_or_split(iterator *iter);
+
+  // Merges the values of left, right and the delimiting key on their parent
+  // onto left, removing the delimiting key and deleting right.
+  void merge_nodes(node_type *left, node_type *right);
+
+  // Tries to merge node with its left or right sibling, and failing that,
+  // rebalance with its left or right sibling. Returns true if a merge
+  // occurred, at which point it is no longer valid to access node. Returns
+  // false if no merging took place.
+  bool try_merge_or_rebalance(iterator *iter);
+
+  // Tries to shrink the height of the tree by 1.
+  void try_shrink();
+
+  iterator internal_end(iterator iter) {
+    return iter.node != nullptr ? iter : end();
+  }
+  const_iterator internal_end(const_iterator iter) const {
+    return iter.node != nullptr ? iter : end();
+  }
+
+  // Emplaces a value into the btree immediately before iter. Requires that
+  // key(v) <= iter.key() and (--iter).key() <= key(v).
+  template <typename... Args>
+  iterator internal_emplace(iterator iter, Args &&... args);
+
+  // Returns an iterator pointing to the first value >= the value "iter" is
+  // pointing at. Note that "iter" might be pointing to an invalid location such
+  // as iter.position == iter.node->finish(). This routine simply moves iter up
+  // in the tree to a valid location.
+  // Requires: iter.node is non-null.
+  template <typename IterType>
+  static IterType internal_last(IterType iter);
+
+  // Returns an iterator pointing to the leaf position at which key would
+  // reside in the tree, unless there is an exact match - in which case, the
+  // result may not be on a leaf. When there's a three-way comparator, we can
+  // return whether there was an exact match. This allows the caller to avoid a
+  // subsequent comparison to determine if an exact match was made, which is
+  // important for keys with expensive comparison, such as strings.
+  template <typename K>
+  SearchResult<iterator, is_key_compare_to::value> internal_locate(
+      const K &key) const;
+
+  // Internal routine which implements lower_bound().
+  template <typename K>
+  SearchResult<iterator, is_key_compare_to::value> internal_lower_bound(
+      const K &key) const;
+
+  // Internal routine which implements upper_bound().
+  template <typename K>
+  iterator internal_upper_bound(const K &key) const;
+
+  // Internal routine which implements find().
+  template <typename K>
+  iterator internal_find(const K &key) const;
+
+  // Verifies the tree structure of node.
+  int internal_verify(const node_type *node, const key_type *lo,
+                      const key_type *hi) const;
+
+  node_stats internal_stats(const node_type *node) const {
+    // The root can be a static empty node.
+    if (node == nullptr || (node == root() && empty())) {
+      return node_stats(0, 0);
+    }
+    if (node->leaf()) {
+      return node_stats(1, 0);
+    }
+    node_stats res(0, 1);
+    for (int i = node->start(); i <= node->finish(); ++i) {
+      res += internal_stats(node->child(i));
+    }
+    return res;
+  }
+
+  // We use compressed tuple in order to save space because key_compare and
+  // allocator_type are usually empty.
+  absl::container_internal::CompressedTuple<key_compare, allocator_type,
+                                            node_type *>
+      root_;
+
+  // A pointer to the rightmost node. Note that the leftmost node is stored as
+  // the root's parent.
+  node_type *rightmost_;
+
+  // Number of values.
+  size_type size_;
+};
+
+////
+// btree_node methods
+template <typename P>
+template <typename... Args>
+inline void btree_node<P>::emplace_value(const size_type i,
+                                         allocator_type *alloc,
+                                         Args &&... args) {
+  assert(i >= start());
+  assert(i <= finish());
+  // Shift old values to create space for new value and then construct it in
+  // place.
+  if (i < finish()) {
+    transfer_n_backward(finish() - i, /*dest_i=*/i + 1, /*src_i=*/i, this,
+                        alloc);
+  }
+  value_init(i, alloc, std::forward<Args>(args)...);
+  set_finish(finish() + 1);
+
+  if (!leaf() && finish() > i + 1) {
+    for (int j = finish(); j > i + 1; --j) {
+      set_child(j, child(j - 1));
+    }
+    clear_child(i + 1);
+  }
+}
+
+template <typename P>
+inline void btree_node<P>::remove_values(const field_type i,
+                                         const field_type to_erase,
+                                         allocator_type *alloc) {
+  // Transfer values after the removed range into their new places.
+  value_destroy_n(i, to_erase, alloc);
+  const field_type orig_finish = finish();
+  const field_type src_i = i + to_erase;
+  transfer_n(orig_finish - src_i, i, src_i, this, alloc);
+
+  if (!leaf()) {
+    // Delete all children between begin and end.
+    for (int j = 0; j < to_erase; ++j) {
+      clear_and_delete(child(i + j + 1), alloc);
+    }
+    // Rotate children after end into new positions.
+    for (int j = i + to_erase + 1; j <= orig_finish; ++j) {
+      set_child(j - to_erase, child(j));
+      clear_child(j);
+    }
+  }
+  set_finish(orig_finish - to_erase);
+}
+
+template <typename P>
+void btree_node<P>::rebalance_right_to_left(const int to_move,
+                                            btree_node *right,
+                                            allocator_type *alloc) {
+  assert(parent() == right->parent());
+  assert(position() + 1 == right->position());
+  assert(right->count() >= count());
+  assert(to_move >= 1);
+  assert(to_move <= right->count());
+
+  // 1) Move the delimiting value in the parent to the left node.
+  transfer(finish(), position(), parent(), alloc);
+
+  // 2) Move the (to_move - 1) values from the right node to the left node.
+  transfer_n(to_move - 1, finish() + 1, right->start(), right, alloc);
+
+  // 3) Move the new delimiting value to the parent from the right node.
+  parent()->transfer(position(), right->start() + to_move - 1, right, alloc);
+
+  // 4) Shift the values in the right node to their correct positions.
+  right->transfer_n(right->count() - to_move, right->start(),
+                    right->start() + to_move, right, alloc);
+
+  if (!leaf()) {
+    // Move the child pointers from the right to the left node.
+    for (int i = 0; i < to_move; ++i) {
+      init_child(finish() + i + 1, right->child(i));
+    }
+    for (int i = right->start(); i <= right->finish() - to_move; ++i) {
+      assert(i + to_move <= right->max_count());
+      right->init_child(i, right->child(i + to_move));
+      right->clear_child(i + to_move);
+    }
+  }
+
+  // Fixup `finish` on the left and right nodes.
+  set_finish(finish() + to_move);
+  right->set_finish(right->finish() - to_move);
+}
+
+template <typename P>
+void btree_node<P>::rebalance_left_to_right(const int to_move,
+                                            btree_node *right,
+                                            allocator_type *alloc) {
+  assert(parent() == right->parent());
+  assert(position() + 1 == right->position());
+  assert(count() >= right->count());
+  assert(to_move >= 1);
+  assert(to_move <= count());
+
+  // Values in the right node are shifted to the right to make room for the
+  // new to_move values. Then, the delimiting value in the parent and the
+  // other (to_move - 1) values in the left node are moved into the right node.
+  // Lastly, a new delimiting value is moved from the left node into the
+  // parent, and the remaining empty left node entries are destroyed.
+
+  // 1) Shift existing values in the right node to their correct positions.
+  right->transfer_n_backward(right->count(), right->start() + to_move,
+                             right->start(), right, alloc);
+
+  // 2) Move the delimiting value in the parent to the right node.
+  right->transfer(right->start() + to_move - 1, position(), parent(), alloc);
+
+  // 3) Move the (to_move - 1) values from the left node to the right node.
+  right->transfer_n(to_move - 1, right->start(), finish() - (to_move - 1), this,
+                    alloc);
+
+  // 4) Move the new delimiting value to the parent from the left node.
+  parent()->transfer(position(), finish() - to_move, this, alloc);
+
+  if (!leaf()) {
+    // Move the child pointers from the left to the right node.
+    for (int i = right->finish(); i >= right->start(); --i) {
+      right->init_child(i + to_move, right->child(i));
+      right->clear_child(i);
+    }
+    for (int i = 1; i <= to_move; ++i) {
+      right->init_child(i - 1, child(finish() - to_move + i));
+      clear_child(finish() - to_move + i);
+    }
+  }
+
+  // Fixup the counts on the left and right nodes.
+  set_finish(finish() - to_move);
+  right->set_finish(right->finish() + to_move);
+}
+
+template <typename P>
+void btree_node<P>::split(const int insert_position, btree_node *dest,
+                          allocator_type *alloc) {
+  assert(dest->count() == 0);
+  assert(max_count() == kNodeSlots);
+
+  // We bias the split based on the position being inserted. If we're
+  // inserting at the beginning of the left node then bias the split to put
+  // more values on the right node. If we're inserting at the end of the
+  // right node then bias the split to put more values on the left node.
+  if (insert_position == start()) {
+    dest->set_finish(dest->start() + finish() - 1);
+  } else if (insert_position == kNodeSlots) {
+    dest->set_finish(dest->start());
+  } else {
+    dest->set_finish(dest->start() + count() / 2);
+  }
+  set_finish(finish() - dest->count());
+  assert(count() >= 1);
+
+  // Move values from the left sibling to the right sibling.
+  dest->transfer_n(dest->count(), dest->start(), finish(), this, alloc);
+
+  // The split key is the largest value in the left sibling.
+  --mutable_finish();
+  parent()->emplace_value(position(), alloc, finish_slot());
+  value_destroy(finish(), alloc);
+  parent()->init_child(position() + 1, dest);
+
+  if (!leaf()) {
+    for (int i = dest->start(), j = finish() + 1; i <= dest->finish();
+         ++i, ++j) {
+      assert(child(j) != nullptr);
+      dest->init_child(i, child(j));
+      clear_child(j);
+    }
+  }
+}
+
+template <typename P>
+void btree_node<P>::merge(btree_node *src, allocator_type *alloc) {
+  assert(parent() == src->parent());
+  assert(position() + 1 == src->position());
+
+  // Move the delimiting value to the left node.
+  value_init(finish(), alloc, parent()->slot(position()));
+
+  // Move the values from the right to the left node.
+  transfer_n(src->count(), finish() + 1, src->start(), src, alloc);
+
+  if (!leaf()) {
+    // Move the child pointers from the right to the left node.
+    for (int i = src->start(), j = finish() + 1; i <= src->finish(); ++i, ++j) {
+      init_child(j, src->child(i));
+      src->clear_child(i);
+    }
+  }
+
+  // Fixup `finish` on the src and dest nodes.
+  set_finish(start() + 1 + count() + src->count());
+  src->set_finish(src->start());
+
+  // Remove the value on the parent node and delete the src node.
+  parent()->remove_values(position(), /*to_erase=*/1, alloc);
+}
+
+template <typename P>
+void btree_node<P>::clear_and_delete(btree_node *node, allocator_type *alloc) {
+  if (node->leaf()) {
+    node->value_destroy_n(node->start(), node->count(), alloc);
+    deallocate(LeafSize(node->max_count()), node, alloc);
+    return;
+  }
+  if (node->count() == 0) {
+    deallocate(InternalSize(), node, alloc);
+    return;
+  }
+
+  // The parent of the root of the subtree we are deleting.
+  btree_node *delete_root_parent = node->parent();
+
+  // Navigate to the leftmost leaf under node, and then delete upwards.
+  while (!node->leaf()) node = node->start_child();
+  // Use `int` because `pos` needs to be able to hold `kNodeSlots+1`, which
+  // isn't guaranteed to be a valid `field_type`.
+  int pos = node->position();
+  btree_node *parent = node->parent();
+  for (;;) {
+    // In each iteration of the next loop, we delete one leaf node and go right.
+    assert(pos <= parent->finish());
+    do {
+      node = parent->child(pos);
+      if (!node->leaf()) {
+        // Navigate to the leftmost leaf under node.
+        while (!node->leaf()) node = node->start_child();
+        pos = node->position();
+        parent = node->parent();
+      }
+      node->value_destroy_n(node->start(), node->count(), alloc);
+      deallocate(LeafSize(node->max_count()), node, alloc);
+      ++pos;
+    } while (pos <= parent->finish());
+
+    // Once we've deleted all children of parent, delete parent and go up/right.
+    assert(pos > parent->finish());
+    do {
+      node = parent;
+      pos = node->position();
+      parent = node->parent();
+      node->value_destroy_n(node->start(), node->count(), alloc);
+      deallocate(InternalSize(), node, alloc);
+      if (parent == delete_root_parent) return;
+      ++pos;
+    } while (pos > parent->finish());
+  }
+}
+
+////
+// btree_iterator methods
+template <typename N, typename R, typename P>
+void btree_iterator<N, R, P>::increment_slow() {
+  if (node->leaf()) {
+    assert(position >= node->finish());
+    btree_iterator save(*this);
+    while (position == node->finish() && !node->is_root()) {
+      assert(node->parent()->child(node->position()) == node);
+      position = node->position();
+      node = node->parent();
+    }
+    // TODO(ezb): assert we aren't incrementing end() instead of handling.
+    if (position == node->finish()) {
+      *this = save;
+    }
+  } else {
+    assert(position < node->finish());
+    node = node->child(position + 1);
+    while (!node->leaf()) {
+      node = node->start_child();
+    }
+    position = node->start();
+  }
+}
+
+template <typename N, typename R, typename P>
+void btree_iterator<N, R, P>::decrement_slow() {
+  if (node->leaf()) {
+    assert(position <= -1);
+    btree_iterator save(*this);
+    while (position < node->start() && !node->is_root()) {
+      assert(node->parent()->child(node->position()) == node);
+      position = node->position() - 1;
+      node = node->parent();
+    }
+    // TODO(ezb): assert we aren't decrementing begin() instead of handling.
+    if (position < node->start()) {
+      *this = save;
+    }
+  } else {
+    assert(position >= node->start());
+    node = node->child(position);
+    while (!node->leaf()) {
+      node = node->child(node->finish());
+    }
+    position = node->finish() - 1;
+  }
+}
+
+////
+// btree methods
+template <typename P>
+template <typename Btree>
+void btree<P>::copy_or_move_values_in_order(Btree &other) {
+  static_assert(std::is_same<btree, Btree>::value ||
+                    std::is_same<const btree, Btree>::value,
+                "Btree type must be same or const.");
+  assert(empty());
+
+  // We can avoid key comparisons because we know the order of the
+  // values is the same order we'll store them in.
+  auto iter = other.begin();
+  if (iter == other.end()) return;
+  insert_multi(maybe_move_from_iterator(iter));
+  ++iter;
+  for (; iter != other.end(); ++iter) {
+    // If the btree is not empty, we can just insert the new value at the end
+    // of the tree.
+    internal_emplace(end(), maybe_move_from_iterator(iter));
+  }
+}
+
+template <typename P>
+constexpr bool btree<P>::static_assert_validation() {
+  static_assert(std::is_nothrow_copy_constructible<key_compare>::value,
+                "Key comparison must be nothrow copy constructible");
+  static_assert(std::is_nothrow_copy_constructible<allocator_type>::value,
+                "Allocator must be nothrow copy constructible");
+  static_assert(type_traits_internal::is_trivially_copyable<iterator>::value,
+                "iterator not trivially copyable.");
+
+  // Note: We assert that kTargetValues, which is computed from
+  // Params::kTargetNodeSize, must fit the node_type::field_type.
+  static_assert(
+      kNodeSlots < (1 << (8 * sizeof(typename node_type::field_type))),
+      "target node size too large");
+
+  // Verify that key_compare returns an absl::{weak,strong}_ordering or bool.
+  using compare_result_type =
+      absl::result_of_t<key_compare(key_type, key_type)>;
+  static_assert(
+      std::is_same<compare_result_type, bool>::value ||
+          std::is_convertible<compare_result_type, absl::weak_ordering>::value,
+      "key comparison function must return absl::{weak,strong}_ordering or "
+      "bool.");
+
+  // Test the assumption made in setting kNodeValueSpace.
+  static_assert(node_type::MinimumOverhead() >= sizeof(void *) + 4,
+                "node space assumption incorrect");
+
+  return true;
+}
+
+template <typename P>
+template <typename K>
+auto btree<P>::lower_bound_equal(const K &key) const
+    -> std::pair<iterator, bool> {
+  const SearchResult<iterator, is_key_compare_to::value> res =
+      internal_lower_bound(key);
+  const iterator lower = iterator(internal_end(res.value));
+  const bool equal = res.HasMatch()
+                         ? res.IsEq()
+                         : lower != end() && !compare_keys(key, lower.key());
+  return {lower, equal};
+}
+
+template <typename P>
+template <typename K>
+auto btree<P>::equal_range(const K &key) -> std::pair<iterator, iterator> {
+  const std::pair<iterator, bool> lower_and_equal = lower_bound_equal(key);
+  const iterator lower = lower_and_equal.first;
+  if (!lower_and_equal.second) {
+    return {lower, lower};
+  }
+
+  const iterator next = std::next(lower);
+  if (!params_type::template can_have_multiple_equivalent_keys<K>()) {
+    // The next iterator after lower must point to a key greater than `key`.
+    // Note: if this assert fails, then it may indicate that the comparator does
+    // not meet the equivalence requirements for Compare
+    // (see https://en.cppreference.com/w/cpp/named_req/Compare).
+    assert(next == end() || compare_keys(key, next.key()));
+    return {lower, next};
+  }
+  // Try once more to avoid the call to upper_bound() if there's only one
+  // equivalent key. This should prevent all calls to upper_bound() in cases of
+  // unique-containers with heterogeneous comparators in which all comparison
+  // operators have the same equivalence classes.
+  if (next == end() || compare_keys(key, next.key())) return {lower, next};
+
+  // In this case, we need to call upper_bound() to avoid worst case O(N)
+  // behavior if we were to iterate over equal keys.
+  return {lower, upper_bound(key)};
+}
+
+template <typename P>
+template <typename K, typename... Args>
+auto btree<P>::insert_unique(const K &key, Args &&... args)
+    -> std::pair<iterator, bool> {
+  if (empty()) {
+    mutable_root() = rightmost_ = new_leaf_root_node(1);
+  }
+
+  SearchResult<iterator, is_key_compare_to::value> res = internal_locate(key);
+  iterator iter = res.value;
+
+  if (res.HasMatch()) {
+    if (res.IsEq()) {
+      // The key already exists in the tree, do nothing.
+      return {iter, false};
+    }
+  } else {
+    iterator last = internal_last(iter);
+    if (last.node && !compare_keys(key, last.key())) {
+      // The key already exists in the tree, do nothing.
+      return {last, false};
+    }
+  }
+  return {internal_emplace(iter, std::forward<Args>(args)...), true};
+}
+
+template <typename P>
+template <typename K, typename... Args>
+inline auto btree<P>::insert_hint_unique(iterator position, const K &key,
+                                         Args &&... args)
+    -> std::pair<iterator, bool> {
+  if (!empty()) {
+    if (position == end() || compare_keys(key, position.key())) {
+      if (position == begin() || compare_keys(std::prev(position).key(), key)) {
+        // prev.key() < key < position.key()
+        return {internal_emplace(position, std::forward<Args>(args)...), true};
+      }
+    } else if (compare_keys(position.key(), key)) {
+      ++position;
+      if (position == end() || compare_keys(key, position.key())) {
+        // {original `position`}.key() < key < {current `position`}.key()
+        return {internal_emplace(position, std::forward<Args>(args)...), true};
+      }
+    } else {
+      // position.key() == key
+      return {position, false};
+    }
+  }
+  return insert_unique(key, std::forward<Args>(args)...);
+}
+
+template <typename P>
+template <typename InputIterator, typename>
+void btree<P>::insert_iterator_unique(InputIterator b, InputIterator e, int) {
+  for (; b != e; ++b) {
+    insert_hint_unique(end(), params_type::key(*b), *b);
+  }
+}
+
+template <typename P>
+template <typename InputIterator>
+void btree<P>::insert_iterator_unique(InputIterator b, InputIterator e, char) {
+  for (; b != e; ++b) {
+    init_type value(*b);
+    insert_hint_unique(end(), params_type::key(value), std::move(value));
+  }
+}
+
+template <typename P>
+template <typename ValueType>
+auto btree<P>::insert_multi(const key_type &key, ValueType &&v) -> iterator {
+  if (empty()) {
+    mutable_root() = rightmost_ = new_leaf_root_node(1);
+  }
+
+  iterator iter = internal_upper_bound(key);
+  if (iter.node == nullptr) {
+    iter = end();
+  }
+  return internal_emplace(iter, std::forward<ValueType>(v));
+}
+
+template <typename P>
+template <typename ValueType>
+auto btree<P>::insert_hint_multi(iterator position, ValueType &&v) -> iterator {
+  if (!empty()) {
+    const key_type &key = params_type::key(v);
+    if (position == end() || !compare_keys(position.key(), key)) {
+      if (position == begin() ||
+          !compare_keys(key, std::prev(position).key())) {
+        // prev.key() <= key <= position.key()
+        return internal_emplace(position, std::forward<ValueType>(v));
+      }
+    } else {
+      ++position;
+      if (position == end() || !compare_keys(position.key(), key)) {
+        // {original `position`}.key() < key < {current `position`}.key()
+        return internal_emplace(position, std::forward<ValueType>(v));
+      }
+    }
+  }
+  return insert_multi(std::forward<ValueType>(v));
+}
+
+template <typename P>
+template <typename InputIterator>
+void btree<P>::insert_iterator_multi(InputIterator b, InputIterator e) {
+  for (; b != e; ++b) {
+    insert_hint_multi(end(), *b);
+  }
+}
+
+template <typename P>
+auto btree<P>::operator=(const btree &other) -> btree & {
+  if (this != &other) {
+    clear();
+
+    *mutable_key_comp() = other.key_comp();
+    if (absl::allocator_traits<
+            allocator_type>::propagate_on_container_copy_assignment::value) {
+      *mutable_allocator() = other.allocator();
+    }
+
+    copy_or_move_values_in_order(other);
+  }
+  return *this;
+}
+
+template <typename P>
+auto btree<P>::operator=(btree &&other) noexcept -> btree & {
+  if (this != &other) {
+    clear();
+
+    using std::swap;
+    if (absl::allocator_traits<
+            allocator_type>::propagate_on_container_copy_assignment::value) {
+      // Note: `root_` also contains the allocator and the key comparator.
+      swap(root_, other.root_);
+      swap(rightmost_, other.rightmost_);
+      swap(size_, other.size_);
+    } else {
+      if (allocator() == other.allocator()) {
+        swap(mutable_root(), other.mutable_root());
+        swap(*mutable_key_comp(), *other.mutable_key_comp());
+        swap(rightmost_, other.rightmost_);
+        swap(size_, other.size_);
+      } else {
+        // We aren't allowed to propagate the allocator and the allocator is
+        // different so we can't take over its memory. We must move each element
+        // individually. We need both `other` and `this` to have `other`s key
+        // comparator while moving the values so we can't swap the key
+        // comparators.
+        *mutable_key_comp() = other.key_comp();
+        copy_or_move_values_in_order(other);
+      }
+    }
+  }
+  return *this;
+}
+
+template <typename P>
+auto btree<P>::erase(iterator iter) -> iterator {
+  bool internal_delete = false;
+  if (!iter.node->leaf()) {
+    // Deletion of a value on an internal node. First, move the largest value
+    // from our left child here, then delete that position (in remove_values()
+    // below). We can get to the largest value from our left child by
+    // decrementing iter.
+    iterator internal_iter(iter);
+    --iter;
+    assert(iter.node->leaf());
+    params_type::move(mutable_allocator(), iter.node->slot(iter.position),
+                      internal_iter.node->slot(internal_iter.position));
+    internal_delete = true;
+  }
+
+  // Delete the key from the leaf.
+  iter.node->remove_values(iter.position, /*to_erase=*/1, mutable_allocator());
+  --size_;
+
+  // We want to return the next value after the one we just erased. If we
+  // erased from an internal node (internal_delete == true), then the next
+  // value is ++(++iter). If we erased from a leaf node (internal_delete ==
+  // false) then the next value is ++iter. Note that ++iter may point to an
+  // internal node and the value in the internal node may move to a leaf node
+  // (iter.node) when rebalancing is performed at the leaf level.
+
+  iterator res = rebalance_after_delete(iter);
+
+  // If we erased from an internal node, advance the iterator.
+  if (internal_delete) {
+    ++res;
+  }
+  return res;
+}
+
+template <typename P>
+auto btree<P>::rebalance_after_delete(iterator iter) -> iterator {
+  // Merge/rebalance as we walk back up the tree.
+  iterator res(iter);
+  bool first_iteration = true;
+  for (;;) {
+    if (iter.node == root()) {
+      try_shrink();
+      if (empty()) {
+        return end();
+      }
+      break;
+    }
+    if (iter.node->count() >= kMinNodeValues) {
+      break;
+    }
+    bool merged = try_merge_or_rebalance(&iter);
+    // On the first iteration, we should update `res` with `iter` because `res`
+    // may have been invalidated.
+    if (first_iteration) {
+      res = iter;
+      first_iteration = false;
+    }
+    if (!merged) {
+      break;
+    }
+    iter.position = iter.node->position();
+    iter.node = iter.node->parent();
+  }
+
+  // Adjust our return value. If we're pointing at the end of a node, advance
+  // the iterator.
+  if (res.position == res.node->finish()) {
+    res.position = res.node->finish() - 1;
+    ++res;
+  }
+
+  return res;
+}
+
+template <typename P>
+auto btree<P>::erase_range(iterator begin, iterator end)
+    -> std::pair<size_type, iterator> {
+  difference_type count = std::distance(begin, end);
+  assert(count >= 0);
+
+  if (count == 0) {
+    return {0, begin};
+  }
+
+  if (count == size_) {
+    clear();
+    return {count, this->end()};
+  }
+
+  if (begin.node == end.node) {
+    assert(end.position > begin.position);
+    begin.node->remove_values(begin.position, end.position - begin.position,
+                              mutable_allocator());
+    size_ -= count;
+    return {count, rebalance_after_delete(begin)};
+  }
+
+  const size_type target_size = size_ - count;
+  while (size_ > target_size) {
+    if (begin.node->leaf()) {
+      const size_type remaining_to_erase = size_ - target_size;
+      const size_type remaining_in_node = begin.node->finish() - begin.position;
+      const size_type to_erase =
+          (std::min)(remaining_to_erase, remaining_in_node);
+      begin.node->remove_values(begin.position, to_erase, mutable_allocator());
+      size_ -= to_erase;
+      begin = rebalance_after_delete(begin);
+    } else {
+      begin = erase(begin);
+    }
+  }
+  return {count, begin};
+}
+
+template <typename P>
+void btree<P>::clear() {
+  if (!empty()) {
+    node_type::clear_and_delete(root(), mutable_allocator());
+  }
+  mutable_root() = EmptyNode();
+  rightmost_ = EmptyNode();
+  size_ = 0;
+}
+
+template <typename P>
+void btree<P>::swap(btree &other) {
+  using std::swap;
+  if (absl::allocator_traits<
+          allocator_type>::propagate_on_container_swap::value) {
+    // Note: `root_` also contains the allocator and the key comparator.
+    swap(root_, other.root_);
+  } else {
+    // It's undefined behavior if the allocators are unequal here.
+    assert(allocator() == other.allocator());
+    swap(mutable_root(), other.mutable_root());
+    swap(*mutable_key_comp(), *other.mutable_key_comp());
+  }
+  swap(rightmost_, other.rightmost_);
+  swap(size_, other.size_);
+}
+
+template <typename P>
+void btree<P>::verify() const {
+  assert(root() != nullptr);
+  assert(leftmost() != nullptr);
+  assert(rightmost_ != nullptr);
+  assert(empty() || size() == internal_verify(root(), nullptr, nullptr));
+  assert(leftmost() == (++const_iterator(root(), -1)).node);
+  assert(rightmost_ == (--const_iterator(root(), root()->finish())).node);
+  assert(leftmost()->leaf());
+  assert(rightmost_->leaf());
+}
+
+template <typename P>
+void btree<P>::rebalance_or_split(iterator *iter) {
+  node_type *&node = iter->node;
+  int &insert_position = iter->position;
+  assert(node->count() == node->max_count());
+  assert(kNodeSlots == node->max_count());
+
+  // First try to make room on the node by rebalancing.
+  node_type *parent = node->parent();
+  if (node != root()) {
+    if (node->position() > parent->start()) {
+      // Try rebalancing with our left sibling.
+      node_type *left = parent->child(node->position() - 1);
+      assert(left->max_count() == kNodeSlots);
+      if (left->count() < kNodeSlots) {
+        // We bias rebalancing based on the position being inserted. If we're
+        // inserting at the end of the right node then we bias rebalancing to
+        // fill up the left node.
+        int to_move = (kNodeSlots - left->count()) /
+                      (1 + (insert_position < static_cast<int>(kNodeSlots)));
+        to_move = (std::max)(1, to_move);
+
+        if (insert_position - to_move >= node->start() ||
+            left->count() + to_move < static_cast<int>(kNodeSlots)) {
+          left->rebalance_right_to_left(to_move, node, mutable_allocator());
+
+          assert(node->max_count() - node->count() == to_move);
+          insert_position = insert_position - to_move;
+          if (insert_position < node->start()) {
+            insert_position = insert_position + left->count() + 1;
+            node = left;
+          }
+
+          assert(node->count() < node->max_count());
+          return;
+        }
+      }
+    }
+
+    if (node->position() < parent->finish()) {
+      // Try rebalancing with our right sibling.
+      node_type *right = parent->child(node->position() + 1);
+      assert(right->max_count() == kNodeSlots);
+      if (right->count() < kNodeSlots) {
+        // We bias rebalancing based on the position being inserted. If we're
+        // inserting at the beginning of the left node then we bias rebalancing
+        // to fill up the right node.
+        int to_move = (static_cast<int>(kNodeSlots) - right->count()) /
+                      (1 + (insert_position > node->start()));
+        to_move = (std::max)(1, to_move);
+
+        if (insert_position <= node->finish() - to_move ||
+            right->count() + to_move < static_cast<int>(kNodeSlots)) {
+          node->rebalance_left_to_right(to_move, right, mutable_allocator());
+
+          if (insert_position > node->finish()) {
+            insert_position = insert_position - node->count() - 1;
+            node = right;
+          }
+
+          assert(node->count() < node->max_count());
+          return;
+        }
+      }
+    }
+
+    // Rebalancing failed, make sure there is room on the parent node for a new
+    // value.
+    assert(parent->max_count() == kNodeSlots);
+    if (parent->count() == kNodeSlots) {
+      iterator parent_iter(node->parent(), node->position());
+      rebalance_or_split(&parent_iter);
+    }
+  } else {
+    // Rebalancing not possible because this is the root node.
+    // Create a new root node and set the current root node as the child of the
+    // new root.
+    parent = new_internal_node(parent);
+    parent->init_child(parent->start(), root());
+    mutable_root() = parent;
+    // If the former root was a leaf node, then it's now the rightmost node.
+    assert(!parent->start_child()->leaf() ||
+           parent->start_child() == rightmost_);
+  }
+
+  // Split the node.
+  node_type *split_node;
+  if (node->leaf()) {
+    split_node = new_leaf_node(parent);
+    node->split(insert_position, split_node, mutable_allocator());
+    if (rightmost_ == node) rightmost_ = split_node;
+  } else {
+    split_node = new_internal_node(parent);
+    node->split(insert_position, split_node, mutable_allocator());
+  }
+
+  if (insert_position > node->finish()) {
+    insert_position = insert_position - node->count() - 1;
+    node = split_node;
+  }
+}
+
+template <typename P>
+void btree<P>::merge_nodes(node_type *left, node_type *right) {
+  left->merge(right, mutable_allocator());
+  if (rightmost_ == right) rightmost_ = left;
+}
+
+template <typename P>
+bool btree<P>::try_merge_or_rebalance(iterator *iter) {
+  node_type *parent = iter->node->parent();
+  if (iter->node->position() > parent->start()) {
+    // Try merging with our left sibling.
+    node_type *left = parent->child(iter->node->position() - 1);
+    assert(left->max_count() == kNodeSlots);
+    if (1U + left->count() + iter->node->count() <= kNodeSlots) {
+      iter->position += 1 + left->count();
+      merge_nodes(left, iter->node);
+      iter->node = left;
+      return true;
+    }
+  }
+  if (iter->node->position() < parent->finish()) {
+    // Try merging with our right sibling.
+    node_type *right = parent->child(iter->node->position() + 1);
+    assert(right->max_count() == kNodeSlots);
+    if (1U + iter->node->count() + right->count() <= kNodeSlots) {
+      merge_nodes(iter->node, right);
+      return true;
+    }
+    // Try rebalancing with our right sibling. We don't perform rebalancing if
+    // we deleted the first element from iter->node and the node is not
+    // empty. This is a small optimization for the common pattern of deleting
+    // from the front of the tree.
+    if (right->count() > kMinNodeValues &&
+        (iter->node->count() == 0 || iter->position > iter->node->start())) {
+      int to_move = (right->count() - iter->node->count()) / 2;
+      to_move = (std::min)(to_move, right->count() - 1);
+      iter->node->rebalance_right_to_left(to_move, right, mutable_allocator());
+      return false;
+    }
+  }
+  if (iter->node->position() > parent->start()) {
+    // Try rebalancing with our left sibling. We don't perform rebalancing if
+    // we deleted the last element from iter->node and the node is not
+    // empty. This is a small optimization for the common pattern of deleting
+    // from the back of the tree.
+    node_type *left = parent->child(iter->node->position() - 1);
+    if (left->count() > kMinNodeValues &&
+        (iter->node->count() == 0 || iter->position < iter->node->finish())) {
+      int to_move = (left->count() - iter->node->count()) / 2;
+      to_move = (std::min)(to_move, left->count() - 1);
+      left->rebalance_left_to_right(to_move, iter->node, mutable_allocator());
+      iter->position += to_move;
+      return false;
+    }
+  }
+  return false;
+}
+
+template <typename P>
+void btree<P>::try_shrink() {
+  node_type *orig_root = root();
+  if (orig_root->count() > 0) {
+    return;
+  }
+  // Deleted the last item on the root node, shrink the height of the tree.
+  if (orig_root->leaf()) {
+    assert(size() == 0);
+    mutable_root() = rightmost_ = EmptyNode();
+  } else {
+    node_type *child = orig_root->start_child();
+    child->make_root();
+    mutable_root() = child;
+  }
+  node_type::clear_and_delete(orig_root, mutable_allocator());
+}
+
+template <typename P>
+template <typename IterType>
+inline IterType btree<P>::internal_last(IterType iter) {
+  assert(iter.node != nullptr);
+  while (iter.position == iter.node->finish()) {
+    iter.position = iter.node->position();
+    iter.node = iter.node->parent();
+    if (iter.node->leaf()) {
+      iter.node = nullptr;
+      break;
+    }
+  }
+  return iter;
+}
+
+template <typename P>
+template <typename... Args>
+inline auto btree<P>::internal_emplace(iterator iter, Args &&... args)
+    -> iterator {
+  if (!iter.node->leaf()) {
+    // We can't insert on an internal node. Instead, we'll insert after the
+    // previous value which is guaranteed to be on a leaf node.
+    --iter;
+    ++iter.position;
+  }
+  const field_type max_count = iter.node->max_count();
+  allocator_type *alloc = mutable_allocator();
+  if (iter.node->count() == max_count) {
+    // Make room in the leaf for the new item.
+    if (max_count < kNodeSlots) {
+      // Insertion into the root where the root is smaller than the full node
+      // size. Simply grow the size of the root node.
+      assert(iter.node == root());
+      iter.node =
+          new_leaf_root_node((std::min<int>)(kNodeSlots, 2 * max_count));
+      // Transfer the values from the old root to the new root.
+      node_type *old_root = root();
+      node_type *new_root = iter.node;
+      new_root->transfer_n(old_root->count(), new_root->start(),
+                           old_root->start(), old_root, alloc);
+      new_root->set_finish(old_root->finish());
+      old_root->set_finish(old_root->start());
+      node_type::clear_and_delete(old_root, alloc);
+      mutable_root() = rightmost_ = new_root;
+    } else {
+      rebalance_or_split(&iter);
+    }
+  }
+  iter.node->emplace_value(iter.position, alloc, std::forward<Args>(args)...);
+  ++size_;
+  return iter;
+}
+
+template <typename P>
+template <typename K>
+inline auto btree<P>::internal_locate(const K &key) const
+    -> SearchResult<iterator, is_key_compare_to::value> {
+  iterator iter(const_cast<node_type *>(root()));
+  for (;;) {
+    SearchResult<int, is_key_compare_to::value> res =
+        iter.node->lower_bound(key, key_comp());
+    iter.position = res.value;
+    if (res.IsEq()) {
+      return {iter, MatchKind::kEq};
+    }
+    // Note: in the non-key-compare-to case, we don't need to walk all the way
+    // down the tree if the keys are equal, but determining equality would
+    // require doing an extra comparison on each node on the way down, and we
+    // will need to go all the way to the leaf node in the expected case.
+    if (iter.node->leaf()) {
+      break;
+    }
+    iter.node = iter.node->child(iter.position);
+  }
+  // Note: in the non-key-compare-to case, the key may actually be equivalent
+  // here (and the MatchKind::kNe is ignored).
+  return {iter, MatchKind::kNe};
+}
+
+template <typename P>
+template <typename K>
+auto btree<P>::internal_lower_bound(const K &key) const
+    -> SearchResult<iterator, is_key_compare_to::value> {
+  if (!params_type::template can_have_multiple_equivalent_keys<K>()) {
+    SearchResult<iterator, is_key_compare_to::value> ret = internal_locate(key);
+    ret.value = internal_last(ret.value);
+    return ret;
+  }
+  iterator iter(const_cast<node_type *>(root()));
+  SearchResult<int, is_key_compare_to::value> res;
+  bool seen_eq = false;
+  for (;;) {
+    res = iter.node->lower_bound(key, key_comp());
+    iter.position = res.value;
+    if (iter.node->leaf()) {
+      break;
+    }
+    seen_eq = seen_eq || res.IsEq();
+    iter.node = iter.node->child(iter.position);
+  }
+  if (res.IsEq()) return {iter, MatchKind::kEq};
+  return {internal_last(iter), seen_eq ? MatchKind::kEq : MatchKind::kNe};
+}
+
+template <typename P>
+template <typename K>
+auto btree<P>::internal_upper_bound(const K &key) const -> iterator {
+  iterator iter(const_cast<node_type *>(root()));
+  for (;;) {
+    iter.position = iter.node->upper_bound(key, key_comp());
+    if (iter.node->leaf()) {
+      break;
+    }
+    iter.node = iter.node->child(iter.position);
+  }
+  return internal_last(iter);
+}
+
+template <typename P>
+template <typename K>
+auto btree<P>::internal_find(const K &key) const -> iterator {
+  SearchResult<iterator, is_key_compare_to::value> res = internal_locate(key);
+  if (res.HasMatch()) {
+    if (res.IsEq()) {
+      return res.value;
+    }
+  } else {
+    const iterator iter = internal_last(res.value);
+    if (iter.node != nullptr && !compare_keys(key, iter.key())) {
+      return iter;
+    }
+  }
+  return {nullptr, 0};
+}
+
+template <typename P>
+int btree<P>::internal_verify(const node_type *node, const key_type *lo,
+                              const key_type *hi) const {
+  assert(node->count() > 0);
+  assert(node->count() <= node->max_count());
+  if (lo) {
+    assert(!compare_keys(node->key(node->start()), *lo));
+  }
+  if (hi) {
+    assert(!compare_keys(*hi, node->key(node->finish() - 1)));
+  }
+  for (int i = node->start() + 1; i < node->finish(); ++i) {
+    assert(!compare_keys(node->key(i), node->key(i - 1)));
+  }
+  int count = node->count();
+  if (!node->leaf()) {
+    for (int i = node->start(); i <= node->finish(); ++i) {
+      assert(node->child(i) != nullptr);
+      assert(node->child(i)->parent() == node);
+      assert(node->child(i)->position() == i);
+      count += internal_verify(node->child(i),
+                               i == node->start() ? lo : &node->key(i - 1),
+                               i == node->finish() ? hi : &node->key(i));
+    }
+  }
+  return count;
+}
+
+}  // namespace container_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#endif  // ABSL_CONTAINER_INTERNAL_BTREE_H_
diff --git a/src/absl/container/internal/btree_container.h b/src/absl/container/internal/btree_container.h
new file mode 100644 (file)
index 0000000..03be708
--- /dev/null
@@ -0,0 +1,682 @@
+// Copyright 2018 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef ABSL_CONTAINER_INTERNAL_BTREE_CONTAINER_H_
+#define ABSL_CONTAINER_INTERNAL_BTREE_CONTAINER_H_
+
+#include <algorithm>
+#include <initializer_list>
+#include <iterator>
+#include <utility>
+
+#include "absl/base/internal/throw_delegate.h"
+#include "absl/container/internal/btree.h"  // IWYU pragma: export
+#include "absl/container/internal/common.h"
+#include "absl/memory/memory.h"
+#include "absl/meta/type_traits.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace container_internal {
+
+// A common base class for btree_set, btree_map, btree_multiset, and
+// btree_multimap.
+template <typename Tree>
+class btree_container {
+  using params_type = typename Tree::params_type;
+
+ protected:
+  // Alias used for heterogeneous lookup functions.
+  // `key_arg<K>` evaluates to `K` when the functors are transparent and to
+  // `key_type` otherwise. It permits template argument deduction on `K` for the
+  // transparent case.
+  template <class K>
+  using key_arg =
+      typename KeyArg<IsTransparent<typename Tree::key_compare>::value>::
+          template type<K, typename Tree::key_type>;
+
+ public:
+  using key_type = typename Tree::key_type;
+  using value_type = typename Tree::value_type;
+  using size_type = typename Tree::size_type;
+  using difference_type = typename Tree::difference_type;
+  using key_compare = typename Tree::key_compare;
+  using value_compare = typename Tree::value_compare;
+  using allocator_type = typename Tree::allocator_type;
+  using reference = typename Tree::reference;
+  using const_reference = typename Tree::const_reference;
+  using pointer = typename Tree::pointer;
+  using const_pointer = typename Tree::const_pointer;
+  using iterator = typename Tree::iterator;
+  using const_iterator = typename Tree::const_iterator;
+  using reverse_iterator = typename Tree::reverse_iterator;
+  using const_reverse_iterator = typename Tree::const_reverse_iterator;
+  using node_type = typename Tree::node_handle_type;
+
+  // Constructors/assignments.
+  btree_container() : tree_(key_compare(), allocator_type()) {}
+  explicit btree_container(const key_compare &comp,
+                           const allocator_type &alloc = allocator_type())
+      : tree_(comp, alloc) {}
+  explicit btree_container(const allocator_type &alloc)
+      : tree_(key_compare(), alloc) {}
+
+  btree_container(const btree_container &other)
+      : btree_container(other, absl::allocator_traits<allocator_type>::
+                                   select_on_container_copy_construction(
+                                       other.get_allocator())) {}
+  btree_container(const btree_container &other, const allocator_type &alloc)
+      : tree_(other.tree_, alloc) {}
+
+  btree_container(btree_container &&other) noexcept(
+      std::is_nothrow_move_constructible<Tree>::value) = default;
+  btree_container(btree_container &&other, const allocator_type &alloc)
+      : tree_(std::move(other.tree_), alloc) {}
+
+  btree_container &operator=(const btree_container &other) = default;
+  btree_container &operator=(btree_container &&other) noexcept(
+      std::is_nothrow_move_assignable<Tree>::value) = default;
+
+  // Iterator routines.
+  iterator begin() { return tree_.begin(); }
+  const_iterator begin() const { return tree_.begin(); }
+  const_iterator cbegin() const { return tree_.begin(); }
+  iterator end() { return tree_.end(); }
+  const_iterator end() const { return tree_.end(); }
+  const_iterator cend() const { return tree_.end(); }
+  reverse_iterator rbegin() { return tree_.rbegin(); }
+  const_reverse_iterator rbegin() const { return tree_.rbegin(); }
+  const_reverse_iterator crbegin() const { return tree_.rbegin(); }
+  reverse_iterator rend() { return tree_.rend(); }
+  const_reverse_iterator rend() const { return tree_.rend(); }
+  const_reverse_iterator crend() const { return tree_.rend(); }
+
+  // Lookup routines.
+  template <typename K = key_type>
+  size_type count(const key_arg<K> &key) const {
+    auto equal_range = this->equal_range(key);
+    return std::distance(equal_range.first, equal_range.second);
+  }
+  template <typename K = key_type>
+  iterator find(const key_arg<K> &key) {
+    return tree_.find(key);
+  }
+  template <typename K = key_type>
+  const_iterator find(const key_arg<K> &key) const {
+    return tree_.find(key);
+  }
+  template <typename K = key_type>
+  bool contains(const key_arg<K> &key) const {
+    return find(key) != end();
+  }
+  template <typename K = key_type>
+  iterator lower_bound(const key_arg<K> &key) {
+    return tree_.lower_bound(key);
+  }
+  template <typename K = key_type>
+  const_iterator lower_bound(const key_arg<K> &key) const {
+    return tree_.lower_bound(key);
+  }
+  template <typename K = key_type>
+  iterator upper_bound(const key_arg<K> &key) {
+    return tree_.upper_bound(key);
+  }
+  template <typename K = key_type>
+  const_iterator upper_bound(const key_arg<K> &key) const {
+    return tree_.upper_bound(key);
+  }
+  template <typename K = key_type>
+  std::pair<iterator, iterator> equal_range(const key_arg<K> &key) {
+    return tree_.equal_range(key);
+  }
+  template <typename K = key_type>
+  std::pair<const_iterator, const_iterator> equal_range(
+      const key_arg<K> &key) const {
+    return tree_.equal_range(key);
+  }
+
+  // Deletion routines. Note that there is also a deletion routine that is
+  // specific to btree_set_container/btree_multiset_container.
+
+  // Erase the specified iterator from the btree. The iterator must be valid
+  // (i.e. not equal to end()).  Return an iterator pointing to the node after
+  // the one that was erased (or end() if none exists).
+  iterator erase(const_iterator iter) { return tree_.erase(iterator(iter)); }
+  iterator erase(iterator iter) { return tree_.erase(iter); }
+  iterator erase(const_iterator first, const_iterator last) {
+    return tree_.erase_range(iterator(first), iterator(last)).second;
+  }
+  template <typename K = key_type>
+  size_type erase(const key_arg<K> &key) {
+    auto equal_range = this->equal_range(key);
+    return tree_.erase_range(equal_range.first, equal_range.second).first;
+  }
+
+  // Extract routines.
+  node_type extract(iterator position) {
+    // Use Move instead of Transfer, because the rebalancing code expects to
+    // have a valid object to scribble metadata bits on top of.
+    auto node = CommonAccess::Move<node_type>(get_allocator(), position.slot());
+    erase(position);
+    return node;
+  }
+  node_type extract(const_iterator position) {
+    return extract(iterator(position));
+  }
+
+  // Utility routines.
+  void clear() { tree_.clear(); }
+  void swap(btree_container &other) { tree_.swap(other.tree_); }
+  void verify() const { tree_.verify(); }
+
+  // Size routines.
+  size_type size() const { return tree_.size(); }
+  size_type max_size() const { return tree_.max_size(); }
+  bool empty() const { return tree_.empty(); }
+
+  friend bool operator==(const btree_container &x, const btree_container &y) {
+    if (x.size() != y.size()) return false;
+    return std::equal(x.begin(), x.end(), y.begin());
+  }
+
+  friend bool operator!=(const btree_container &x, const btree_container &y) {
+    return !(x == y);
+  }
+
+  friend bool operator<(const btree_container &x, const btree_container &y) {
+    return std::lexicographical_compare(x.begin(), x.end(), y.begin(), y.end());
+  }
+
+  friend bool operator>(const btree_container &x, const btree_container &y) {
+    return y < x;
+  }
+
+  friend bool operator<=(const btree_container &x, const btree_container &y) {
+    return !(y < x);
+  }
+
+  friend bool operator>=(const btree_container &x, const btree_container &y) {
+    return !(x < y);
+  }
+
+  // The allocator used by the btree.
+  allocator_type get_allocator() const { return tree_.get_allocator(); }
+
+  // The key comparator used by the btree.
+  key_compare key_comp() const { return tree_.key_comp(); }
+  value_compare value_comp() const { return tree_.value_comp(); }
+
+  // Support absl::Hash.
+  template <typename State>
+  friend State AbslHashValue(State h, const btree_container &b) {
+    for (const auto &v : b) {
+      h = State::combine(std::move(h), v);
+    }
+    return State::combine(std::move(h), b.size());
+  }
+
+ protected:
+  Tree tree_;
+};
+
+// A common base class for btree_set and btree_map.
+template <typename Tree>
+class btree_set_container : public btree_container<Tree> {
+  using super_type = btree_container<Tree>;
+  using params_type = typename Tree::params_type;
+  using init_type = typename params_type::init_type;
+  using is_key_compare_to = typename params_type::is_key_compare_to;
+  friend class BtreeNodePeer;
+
+ protected:
+  template <class K>
+  using key_arg = typename super_type::template key_arg<K>;
+
+ public:
+  using key_type = typename Tree::key_type;
+  using value_type = typename Tree::value_type;
+  using size_type = typename Tree::size_type;
+  using key_compare = typename Tree::key_compare;
+  using allocator_type = typename Tree::allocator_type;
+  using iterator = typename Tree::iterator;
+  using const_iterator = typename Tree::const_iterator;
+  using node_type = typename super_type::node_type;
+  using insert_return_type = InsertReturnType<iterator, node_type>;
+
+  // Inherit constructors.
+  using super_type::super_type;
+  btree_set_container() {}
+
+  // Range constructors.
+  template <class InputIterator>
+  btree_set_container(InputIterator b, InputIterator e,
+                      const key_compare &comp = key_compare(),
+                      const allocator_type &alloc = allocator_type())
+      : super_type(comp, alloc) {
+    insert(b, e);
+  }
+  template <class InputIterator>
+  btree_set_container(InputIterator b, InputIterator e,
+                      const allocator_type &alloc)
+      : btree_set_container(b, e, key_compare(), alloc) {}
+
+  // Initializer list constructors.
+  btree_set_container(std::initializer_list<init_type> init,
+                      const key_compare &comp = key_compare(),
+                      const allocator_type &alloc = allocator_type())
+      : btree_set_container(init.begin(), init.end(), comp, alloc) {}
+  btree_set_container(std::initializer_list<init_type> init,
+                      const allocator_type &alloc)
+      : btree_set_container(init.begin(), init.end(), alloc) {}
+
+  // Insertion routines.
+  std::pair<iterator, bool> insert(const value_type &v) {
+    return this->tree_.insert_unique(params_type::key(v), v);
+  }
+  std::pair<iterator, bool> insert(value_type &&v) {
+    return this->tree_.insert_unique(params_type::key(v), std::move(v));
+  }
+  template <typename... Args>
+  std::pair<iterator, bool> emplace(Args &&... args) {
+    init_type v(std::forward<Args>(args)...);
+    return this->tree_.insert_unique(params_type::key(v), std::move(v));
+  }
+  iterator insert(const_iterator hint, const value_type &v) {
+    return this->tree_
+        .insert_hint_unique(iterator(hint), params_type::key(v), v)
+        .first;
+  }
+  iterator insert(const_iterator hint, value_type &&v) {
+    return this->tree_
+        .insert_hint_unique(iterator(hint), params_type::key(v), std::move(v))
+        .first;
+  }
+  template <typename... Args>
+  iterator emplace_hint(const_iterator hint, Args &&... args) {
+    init_type v(std::forward<Args>(args)...);
+    return this->tree_
+        .insert_hint_unique(iterator(hint), params_type::key(v), std::move(v))
+        .first;
+  }
+  template <typename InputIterator>
+  void insert(InputIterator b, InputIterator e) {
+    this->tree_.insert_iterator_unique(b, e, 0);
+  }
+  void insert(std::initializer_list<init_type> init) {
+    this->tree_.insert_iterator_unique(init.begin(), init.end(), 0);
+  }
+  insert_return_type insert(node_type &&node) {
+    if (!node) return {this->end(), false, node_type()};
+    std::pair<iterator, bool> res =
+        this->tree_.insert_unique(params_type::key(CommonAccess::GetSlot(node)),
+                                  CommonAccess::GetSlot(node));
+    if (res.second) {
+      CommonAccess::Destroy(&node);
+      return {res.first, true, node_type()};
+    } else {
+      return {res.first, false, std::move(node)};
+    }
+  }
+  iterator insert(const_iterator hint, node_type &&node) {
+    if (!node) return this->end();
+    std::pair<iterator, bool> res = this->tree_.insert_hint_unique(
+        iterator(hint), params_type::key(CommonAccess::GetSlot(node)),
+        CommonAccess::GetSlot(node));
+    if (res.second) CommonAccess::Destroy(&node);
+    return res.first;
+  }
+
+  // Node extraction routines.
+  template <typename K = key_type>
+  node_type extract(const key_arg<K> &key) {
+    const std::pair<iterator, bool> lower_and_equal =
+        this->tree_.lower_bound_equal(key);
+    return lower_and_equal.second ? extract(lower_and_equal.first)
+                                  : node_type();
+  }
+  using super_type::extract;
+
+  // Merge routines.
+  // Moves elements from `src` into `this`. If the element already exists in
+  // `this`, it is left unmodified in `src`.
+  template <
+      typename T,
+      typename absl::enable_if_t<
+          absl::conjunction<
+              std::is_same<value_type, typename T::value_type>,
+              std::is_same<allocator_type, typename T::allocator_type>,
+              std::is_same<typename params_type::is_map_container,
+                           typename T::params_type::is_map_container>>::value,
+          int> = 0>
+  void merge(btree_container<T> &src) {  // NOLINT
+    for (auto src_it = src.begin(); src_it != src.end();) {
+      if (insert(std::move(params_type::element(src_it.slot()))).second) {
+        src_it = src.erase(src_it);
+      } else {
+        ++src_it;
+      }
+    }
+  }
+
+  template <
+      typename T,
+      typename absl::enable_if_t<
+          absl::conjunction<
+              std::is_same<value_type, typename T::value_type>,
+              std::is_same<allocator_type, typename T::allocator_type>,
+              std::is_same<typename params_type::is_map_container,
+                           typename T::params_type::is_map_container>>::value,
+          int> = 0>
+  void merge(btree_container<T> &&src) {
+    merge(src);
+  }
+};
+
+// Base class for btree_map.
+template <typename Tree>
+class btree_map_container : public btree_set_container<Tree> {
+  using super_type = btree_set_container<Tree>;
+  using params_type = typename Tree::params_type;
+  friend class BtreeNodePeer;
+
+ private:
+  template <class K>
+  using key_arg = typename super_type::template key_arg<K>;
+
+ public:
+  using key_type = typename Tree::key_type;
+  using mapped_type = typename params_type::mapped_type;
+  using value_type = typename Tree::value_type;
+  using key_compare = typename Tree::key_compare;
+  using allocator_type = typename Tree::allocator_type;
+  using iterator = typename Tree::iterator;
+  using const_iterator = typename Tree::const_iterator;
+
+  // Inherit constructors.
+  using super_type::super_type;
+  btree_map_container() {}
+
+  // Insertion routines.
+  // Note: the nullptr template arguments and extra `const M&` overloads allow
+  // for supporting bitfield arguments.
+  template <typename K = key_type, class M>
+  std::pair<iterator, bool> insert_or_assign(const key_arg<K> &k,
+                                             const M &obj) {
+    return insert_or_assign_impl(k, obj);
+  }
+  template <typename K = key_type, class M, K * = nullptr>
+  std::pair<iterator, bool> insert_or_assign(key_arg<K> &&k, const M &obj) {
+    return insert_or_assign_impl(std::forward<K>(k), obj);
+  }
+  template <typename K = key_type, class M, M * = nullptr>
+  std::pair<iterator, bool> insert_or_assign(const key_arg<K> &k, M &&obj) {
+    return insert_or_assign_impl(k, std::forward<M>(obj));
+  }
+  template <typename K = key_type, class M, K * = nullptr, M * = nullptr>
+  std::pair<iterator, bool> insert_or_assign(key_arg<K> &&k, M &&obj) {
+    return insert_or_assign_impl(std::forward<K>(k), std::forward<M>(obj));
+  }
+  template <typename K = key_type, class M>
+  iterator insert_or_assign(const_iterator hint, const key_arg<K> &k,
+                            const M &obj) {
+    return insert_or_assign_hint_impl(hint, k, obj);
+  }
+  template <typename K = key_type, class M, K * = nullptr>
+  iterator insert_or_assign(const_iterator hint, key_arg<K> &&k, const M &obj) {
+    return insert_or_assign_hint_impl(hint, std::forward<K>(k), obj);
+  }
+  template <typename K = key_type, class M, M * = nullptr>
+  iterator insert_or_assign(const_iterator hint, const key_arg<K> &k, M &&obj) {
+    return insert_or_assign_hint_impl(hint, k, std::forward<M>(obj));
+  }
+  template <typename K = key_type, class M, K * = nullptr, M * = nullptr>
+  iterator insert_or_assign(const_iterator hint, key_arg<K> &&k, M &&obj) {
+    return insert_or_assign_hint_impl(hint, std::forward<K>(k),
+                                      std::forward<M>(obj));
+  }
+
+  template <typename K = key_type, typename... Args,
+            typename absl::enable_if_t<
+                !std::is_convertible<K, const_iterator>::value, int> = 0>
+  std::pair<iterator, bool> try_emplace(const key_arg<K> &k, Args &&... args) {
+    return try_emplace_impl(k, std::forward<Args>(args)...);
+  }
+  template <typename K = key_type, typename... Args,
+            typename absl::enable_if_t<
+                !std::is_convertible<K, const_iterator>::value, int> = 0>
+  std::pair<iterator, bool> try_emplace(key_arg<K> &&k, Args &&... args) {
+    return try_emplace_impl(std::forward<K>(k), std::forward<Args>(args)...);
+  }
+  template <typename K = key_type, typename... Args>
+  iterator try_emplace(const_iterator hint, const key_arg<K> &k,
+                       Args &&... args) {
+    return try_emplace_hint_impl(hint, k, std::forward<Args>(args)...);
+  }
+  template <typename K = key_type, typename... Args>
+  iterator try_emplace(const_iterator hint, key_arg<K> &&k, Args &&... args) {
+    return try_emplace_hint_impl(hint, std::forward<K>(k),
+                                 std::forward<Args>(args)...);
+  }
+
+  template <typename K = key_type>
+  mapped_type &operator[](const key_arg<K> &k) {
+    return try_emplace(k).first->second;
+  }
+  template <typename K = key_type>
+  mapped_type &operator[](key_arg<K> &&k) {
+    return try_emplace(std::forward<K>(k)).first->second;
+  }
+
+  template <typename K = key_type>
+  mapped_type &at(const key_arg<K> &key) {
+    auto it = this->find(key);
+    if (it == this->end())
+      base_internal::ThrowStdOutOfRange("absl::btree_map::at");
+    return it->second;
+  }
+  template <typename K = key_type>
+  const mapped_type &at(const key_arg<K> &key) const {
+    auto it = this->find(key);
+    if (it == this->end())
+      base_internal::ThrowStdOutOfRange("absl::btree_map::at");
+    return it->second;
+  }
+
+ private:
+  // Note: when we call `std::forward<M>(obj)` twice, it's safe because
+  // insert_unique/insert_hint_unique are guaranteed to not consume `obj` when
+  // `ret.second` is false.
+  template <class K, class M>
+  std::pair<iterator, bool> insert_or_assign_impl(K &&k, M &&obj) {
+    const std::pair<iterator, bool> ret =
+        this->tree_.insert_unique(k, std::forward<K>(k), std::forward<M>(obj));
+    if (!ret.second) ret.first->second = std::forward<M>(obj);
+    return ret;
+  }
+  template <class K, class M>
+  iterator insert_or_assign_hint_impl(const_iterator hint, K &&k, M &&obj) {
+    const std::pair<iterator, bool> ret = this->tree_.insert_hint_unique(
+        iterator(hint), k, std::forward<K>(k), std::forward<M>(obj));
+    if (!ret.second) ret.first->second = std::forward<M>(obj);
+    return ret.first;
+  }
+
+  template <class K, class... Args>
+  std::pair<iterator, bool> try_emplace_impl(K &&k, Args &&... args) {
+    return this->tree_.insert_unique(
+        k, std::piecewise_construct, std::forward_as_tuple(std::forward<K>(k)),
+        std::forward_as_tuple(std::forward<Args>(args)...));
+  }
+  template <class K, class... Args>
+  iterator try_emplace_hint_impl(const_iterator hint, K &&k, Args &&... args) {
+    return this->tree_
+        .insert_hint_unique(iterator(hint), k, std::piecewise_construct,
+                            std::forward_as_tuple(std::forward<K>(k)),
+                            std::forward_as_tuple(std::forward<Args>(args)...))
+        .first;
+  }
+};
+
+// A common base class for btree_multiset and btree_multimap.
+template <typename Tree>
+class btree_multiset_container : public btree_container<Tree> {
+  using super_type = btree_container<Tree>;
+  using params_type = typename Tree::params_type;
+  using init_type = typename params_type::init_type;
+  using is_key_compare_to = typename params_type::is_key_compare_to;
+
+  template <class K>
+  using key_arg = typename super_type::template key_arg<K>;
+
+ public:
+  using key_type = typename Tree::key_type;
+  using value_type = typename Tree::value_type;
+  using size_type = typename Tree::size_type;
+  using key_compare = typename Tree::key_compare;
+  using allocator_type = typename Tree::allocator_type;
+  using iterator = typename Tree::iterator;
+  using const_iterator = typename Tree::const_iterator;
+  using node_type = typename super_type::node_type;
+
+  // Inherit constructors.
+  using super_type::super_type;
+  btree_multiset_container() {}
+
+  // Range constructors.
+  template <class InputIterator>
+  btree_multiset_container(InputIterator b, InputIterator e,
+                           const key_compare &comp = key_compare(),
+                           const allocator_type &alloc = allocator_type())
+      : super_type(comp, alloc) {
+    insert(b, e);
+  }
+  template <class InputIterator>
+  btree_multiset_container(InputIterator b, InputIterator e,
+                           const allocator_type &alloc)
+      : btree_multiset_container(b, e, key_compare(), alloc) {}
+
+  // Initializer list constructors.
+  btree_multiset_container(std::initializer_list<init_type> init,
+                           const key_compare &comp = key_compare(),
+                           const allocator_type &alloc = allocator_type())
+      : btree_multiset_container(init.begin(), init.end(), comp, alloc) {}
+  btree_multiset_container(std::initializer_list<init_type> init,
+                           const allocator_type &alloc)
+      : btree_multiset_container(init.begin(), init.end(), alloc) {}
+
+  // Insertion routines.
+  iterator insert(const value_type &v) { return this->tree_.insert_multi(v); }
+  iterator insert(value_type &&v) {
+    return this->tree_.insert_multi(std::move(v));
+  }
+  iterator insert(const_iterator hint, const value_type &v) {
+    return this->tree_.insert_hint_multi(iterator(hint), v);
+  }
+  iterator insert(const_iterator hint, value_type &&v) {
+    return this->tree_.insert_hint_multi(iterator(hint), std::move(v));
+  }
+  template <typename InputIterator>
+  void insert(InputIterator b, InputIterator e) {
+    this->tree_.insert_iterator_multi(b, e);
+  }
+  void insert(std::initializer_list<init_type> init) {
+    this->tree_.insert_iterator_multi(init.begin(), init.end());
+  }
+  template <typename... Args>
+  iterator emplace(Args &&... args) {
+    return this->tree_.insert_multi(init_type(std::forward<Args>(args)...));
+  }
+  template <typename... Args>
+  iterator emplace_hint(const_iterator hint, Args &&... args) {
+    return this->tree_.insert_hint_multi(
+        iterator(hint), init_type(std::forward<Args>(args)...));
+  }
+  iterator insert(node_type &&node) {
+    if (!node) return this->end();
+    iterator res =
+        this->tree_.insert_multi(params_type::key(CommonAccess::GetSlot(node)),
+                                 CommonAccess::GetSlot(node));
+    CommonAccess::Destroy(&node);
+    return res;
+  }
+  iterator insert(const_iterator hint, node_type &&node) {
+    if (!node) return this->end();
+    iterator res = this->tree_.insert_hint_multi(
+        iterator(hint),
+        std::move(params_type::element(CommonAccess::GetSlot(node))));
+    CommonAccess::Destroy(&node);
+    return res;
+  }
+
+  // Node extraction routines.
+  template <typename K = key_type>
+  node_type extract(const key_arg<K> &key) {
+    const std::pair<iterator, bool> lower_and_equal =
+        this->tree_.lower_bound_equal(key);
+    return lower_and_equal.second ? extract(lower_and_equal.first)
+                                  : node_type();
+  }
+  using super_type::extract;
+
+  // Merge routines.
+  // Moves all elements from `src` into `this`.
+  template <
+      typename T,
+      typename absl::enable_if_t<
+          absl::conjunction<
+              std::is_same<value_type, typename T::value_type>,
+              std::is_same<allocator_type, typename T::allocator_type>,
+              std::is_same<typename params_type::is_map_container,
+                           typename T::params_type::is_map_container>>::value,
+          int> = 0>
+  void merge(btree_container<T> &src) {  // NOLINT
+    for (auto src_it = src.begin(), end = src.end(); src_it != end; ++src_it) {
+      insert(std::move(params_type::element(src_it.slot())));
+    }
+    src.clear();
+  }
+
+  template <
+      typename T,
+      typename absl::enable_if_t<
+          absl::conjunction<
+              std::is_same<value_type, typename T::value_type>,
+              std::is_same<allocator_type, typename T::allocator_type>,
+              std::is_same<typename params_type::is_map_container,
+                           typename T::params_type::is_map_container>>::value,
+          int> = 0>
+  void merge(btree_container<T> &&src) {
+    merge(src);
+  }
+};
+
+// A base class for btree_multimap.
+template <typename Tree>
+class btree_multimap_container : public btree_multiset_container<Tree> {
+  using super_type = btree_multiset_container<Tree>;
+  using params_type = typename Tree::params_type;
+
+ public:
+  using mapped_type = typename params_type::mapped_type;
+
+  // Inherit constructors.
+  using super_type::super_type;
+  btree_multimap_container() {}
+};
+
+}  // namespace container_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#endif  // ABSL_CONTAINER_INTERNAL_BTREE_CONTAINER_H_
diff --git a/src/absl/container/internal/common.h b/src/absl/container/internal/common.h
new file mode 100644 (file)
index 0000000..030e9d4
--- /dev/null
@@ -0,0 +1,206 @@
+// Copyright 2018 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef ABSL_CONTAINER_INTERNAL_CONTAINER_H_
+#define ABSL_CONTAINER_INTERNAL_CONTAINER_H_
+
+#include <cassert>
+#include <type_traits>
+
+#include "absl/meta/type_traits.h"
+#include "absl/types/optional.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace container_internal {
+
+template <class, class = void>
+struct IsTransparent : std::false_type {};
+template <class T>
+struct IsTransparent<T, absl::void_t<typename T::is_transparent>>
+    : std::true_type {};
+
+template <bool is_transparent>
+struct KeyArg {
+  // Transparent. Forward `K`.
+  template <typename K, typename key_type>
+  using type = K;
+};
+
+template <>
+struct KeyArg<false> {
+  // Not transparent. Always use `key_type`.
+  template <typename K, typename key_type>
+  using type = key_type;
+};
+
+// The node_handle concept from C++17.
+// We specialize node_handle for sets and maps. node_handle_base holds the
+// common API of both.
+template <typename PolicyTraits, typename Alloc>
+class node_handle_base {
+ protected:
+  using slot_type = typename PolicyTraits::slot_type;
+
+ public:
+  using allocator_type = Alloc;
+
+  constexpr node_handle_base() = default;
+  node_handle_base(node_handle_base&& other) noexcept {
+    *this = std::move(other);
+  }
+  ~node_handle_base() { destroy(); }
+  node_handle_base& operator=(node_handle_base&& other) noexcept {
+    destroy();
+    if (!other.empty()) {
+      alloc_ = other.alloc_;
+      PolicyTraits::transfer(alloc(), slot(), other.slot());
+      other.reset();
+    }
+    return *this;
+  }
+
+  bool empty() const noexcept { return !alloc_; }
+  explicit operator bool() const noexcept { return !empty(); }
+  allocator_type get_allocator() const { return *alloc_; }
+
+ protected:
+  friend struct CommonAccess;
+
+  struct transfer_tag_t {};
+  node_handle_base(transfer_tag_t, const allocator_type& a, slot_type* s)
+      : alloc_(a) {
+    PolicyTraits::transfer(alloc(), slot(), s);
+  }
+
+  struct move_tag_t {};
+  node_handle_base(move_tag_t, const allocator_type& a, slot_type* s)
+      : alloc_(a) {
+    PolicyTraits::construct(alloc(), slot(), s);
+  }
+
+  void destroy() {
+    if (!empty()) {
+      PolicyTraits::destroy(alloc(), slot());
+      reset();
+    }
+  }
+
+  void reset() {
+    assert(alloc_.has_value());
+    alloc_ = absl::nullopt;
+  }
+
+  slot_type* slot() const {
+    assert(!empty());
+    return reinterpret_cast<slot_type*>(std::addressof(slot_space_));
+  }
+  allocator_type* alloc() { return std::addressof(*alloc_); }
+
+ private:
+  absl::optional<allocator_type> alloc_ = {};
+  alignas(slot_type) mutable unsigned char slot_space_[sizeof(slot_type)] = {};
+};
+
+// For sets.
+template <typename Policy, typename PolicyTraits, typename Alloc,
+          typename = void>
+class node_handle : public node_handle_base<PolicyTraits, Alloc> {
+  using Base = node_handle_base<PolicyTraits, Alloc>;
+
+ public:
+  using value_type = typename PolicyTraits::value_type;
+
+  constexpr node_handle() {}
+
+  value_type& value() const { return PolicyTraits::element(this->slot()); }
+
+ private:
+  friend struct CommonAccess;
+
+  using Base::Base;
+};
+
+// For maps.
+template <typename Policy, typename PolicyTraits, typename Alloc>
+class node_handle<Policy, PolicyTraits, Alloc,
+                  absl::void_t<typename Policy::mapped_type>>
+    : public node_handle_base<PolicyTraits, Alloc> {
+  using Base = node_handle_base<PolicyTraits, Alloc>;
+  using slot_type = typename PolicyTraits::slot_type;
+
+ public:
+  using key_type = typename Policy::key_type;
+  using mapped_type = typename Policy::mapped_type;
+
+  constexpr node_handle() {}
+
+  // When C++17 is available, we can use std::launder to provide mutable
+  // access to the key. Otherwise, we provide const access.
+  auto key() const
+      -> decltype(PolicyTraits::mutable_key(std::declval<slot_type*>())) {
+    return PolicyTraits::mutable_key(this->slot());
+  }
+
+  mapped_type& mapped() const {
+    return PolicyTraits::value(&PolicyTraits::element(this->slot()));
+  }
+
+ private:
+  friend struct CommonAccess;
+
+  using Base::Base;
+};
+
+// Provide access to non-public node-handle functions.
+struct CommonAccess {
+  template <typename Node>
+  static auto GetSlot(const Node& node) -> decltype(node.slot()) {
+    return node.slot();
+  }
+
+  template <typename Node>
+  static void Destroy(Node* node) {
+    node->destroy();
+  }
+
+  template <typename Node>
+  static void Reset(Node* node) {
+    node->reset();
+  }
+
+  template <typename T, typename... Args>
+  static T Transfer(Args&&... args) {
+    return T(typename T::transfer_tag_t{}, std::forward<Args>(args)...);
+  }
+
+  template <typename T, typename... Args>
+  static T Move(Args&&... args) {
+    return T(typename T::move_tag_t{}, std::forward<Args>(args)...);
+  }
+};
+
+// Implement the insert_return_type<> concept of C++17.
+template <class Iterator, class NodeType>
+struct InsertReturnType {
+  Iterator position;
+  bool inserted;
+  NodeType node;
+};
+
+}  // namespace container_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#endif  // ABSL_CONTAINER_INTERNAL_CONTAINER_H_
diff --git a/src/absl/container/internal/compressed_tuple.h b/src/absl/container/internal/compressed_tuple.h
new file mode 100644 (file)
index 0000000..5ebe164
--- /dev/null
@@ -0,0 +1,290 @@
+// Copyright 2018 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// Helper class to perform the Empty Base Optimization.
+// Ts can contain classes and non-classes, empty or not. For the ones that
+// are empty classes, we perform the optimization. If all types in Ts are empty
+// classes, then CompressedTuple<Ts...> is itself an empty class.
+//
+// To access the members, use member get<N>() function.
+//
+// Eg:
+//   absl::container_internal::CompressedTuple<int, T1, T2, T3> value(7, t1, t2,
+//                                                                    t3);
+//   assert(value.get<0>() == 7);
+//   T1& t1 = value.get<1>();
+//   const T2& t2 = value.get<2>();
+//   ...
+//
+// https://en.cppreference.com/w/cpp/language/ebo
+
+#ifndef ABSL_CONTAINER_INTERNAL_COMPRESSED_TUPLE_H_
+#define ABSL_CONTAINER_INTERNAL_COMPRESSED_TUPLE_H_
+
+#include <initializer_list>
+#include <tuple>
+#include <type_traits>
+#include <utility>
+
+#include "absl/utility/utility.h"
+
+#if defined(_MSC_VER) && !defined(__NVCC__)
+// We need to mark these classes with this declspec to ensure that
+// CompressedTuple happens.
+#define ABSL_INTERNAL_COMPRESSED_TUPLE_DECLSPEC __declspec(empty_bases)
+#else
+#define ABSL_INTERNAL_COMPRESSED_TUPLE_DECLSPEC
+#endif
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace container_internal {
+
+template <typename... Ts>
+class CompressedTuple;
+
+namespace internal_compressed_tuple {
+
+template <typename D, size_t I>
+struct Elem;
+template <typename... B, size_t I>
+struct Elem<CompressedTuple<B...>, I>
+    : std::tuple_element<I, std::tuple<B...>> {};
+template <typename D, size_t I>
+using ElemT = typename Elem<D, I>::type;
+
+// Use the __is_final intrinsic if available. Where it's not available, classes
+// declared with the 'final' specifier cannot be used as CompressedTuple
+// elements.
+// TODO(sbenza): Replace this with std::is_final in C++14.
+template <typename T>
+constexpr bool IsFinal() {
+#if defined(__clang__) || defined(__GNUC__)
+  return __is_final(T);
+#else
+  return false;
+#endif
+}
+
+// We can't use EBCO on other CompressedTuples because that would mean that we
+// derive from multiple Storage<> instantiations with the same I parameter,
+// and potentially from multiple identical Storage<> instantiations.  So anytime
+// we use type inheritance rather than encapsulation, we mark
+// CompressedTupleImpl, to make this easy to detect.
+struct uses_inheritance {};
+
+template <typename T>
+constexpr bool ShouldUseBase() {
+  return std::is_class<T>::value && std::is_empty<T>::value && !IsFinal<T>() &&
+         !std::is_base_of<uses_inheritance, T>::value;
+}
+
+// The storage class provides two specializations:
+//  - For empty classes, it stores T as a base class.
+//  - For everything else, it stores T as a member.
+template <typename T, size_t I,
+#if defined(_MSC_VER)
+          bool UseBase =
+              ShouldUseBase<typename std::enable_if<true, T>::type>()>
+#else
+          bool UseBase = ShouldUseBase<T>()>
+#endif
+struct Storage {
+  T value;
+  constexpr Storage() = default;
+  template <typename V>
+  explicit constexpr Storage(absl::in_place_t, V&& v)
+      : value(absl::forward<V>(v)) {}
+  constexpr const T& get() const& { return value; }
+  T& get() & { return value; }
+  constexpr const T&& get() const&& { return absl::move(*this).value; }
+  T&& get() && { return std::move(*this).value; }
+};
+
+template <typename T, size_t I>
+struct ABSL_INTERNAL_COMPRESSED_TUPLE_DECLSPEC Storage<T, I, true> : T {
+  constexpr Storage() = default;
+
+  template <typename V>
+  explicit constexpr Storage(absl::in_place_t, V&& v)
+      : T(absl::forward<V>(v)) {}
+
+  constexpr const T& get() const& { return *this; }
+  T& get() & { return *this; }
+  constexpr const T&& get() const&& { return absl::move(*this); }
+  T&& get() && { return std::move(*this); }
+};
+
+template <typename D, typename I, bool ShouldAnyUseBase>
+struct ABSL_INTERNAL_COMPRESSED_TUPLE_DECLSPEC CompressedTupleImpl;
+
+template <typename... Ts, size_t... I, bool ShouldAnyUseBase>
+struct ABSL_INTERNAL_COMPRESSED_TUPLE_DECLSPEC CompressedTupleImpl<
+    CompressedTuple<Ts...>, absl::index_sequence<I...>, ShouldAnyUseBase>
+    // We use the dummy identity function through std::integral_constant to
+    // convince MSVC of accepting and expanding I in that context. Without it
+    // you would get:
+    //   error C3548: 'I': parameter pack cannot be used in this context
+    : uses_inheritance,
+      Storage<Ts, std::integral_constant<size_t, I>::value>... {
+  constexpr CompressedTupleImpl() = default;
+  template <typename... Vs>
+  explicit constexpr CompressedTupleImpl(absl::in_place_t, Vs&&... args)
+      : Storage<Ts, I>(absl::in_place, absl::forward<Vs>(args))... {}
+  friend CompressedTuple<Ts...>;
+};
+
+template <typename... Ts, size_t... I>
+struct ABSL_INTERNAL_COMPRESSED_TUPLE_DECLSPEC CompressedTupleImpl<
+    CompressedTuple<Ts...>, absl::index_sequence<I...>, false>
+    // We use the dummy identity function as above...
+    : Storage<Ts, std::integral_constant<size_t, I>::value, false>... {
+  constexpr CompressedTupleImpl() = default;
+  template <typename... Vs>
+  explicit constexpr CompressedTupleImpl(absl::in_place_t, Vs&&... args)
+      : Storage<Ts, I, false>(absl::in_place, absl::forward<Vs>(args))... {}
+  friend CompressedTuple<Ts...>;
+};
+
+std::false_type Or(std::initializer_list<std::false_type>);
+std::true_type Or(std::initializer_list<bool>);
+
+// MSVC requires this to be done separately rather than within the declaration
+// of CompressedTuple below.
+template <typename... Ts>
+constexpr bool ShouldAnyUseBase() {
+  return decltype(
+      Or({std::integral_constant<bool, ShouldUseBase<Ts>()>()...})){};
+}
+
+template <typename T, typename V>
+using TupleElementMoveConstructible =
+    typename std::conditional<std::is_reference<T>::value,
+                              std::is_convertible<V, T>,
+                              std::is_constructible<T, V&&>>::type;
+
+template <bool SizeMatches, class T, class... Vs>
+struct TupleMoveConstructible : std::false_type {};
+
+template <class... Ts, class... Vs>
+struct TupleMoveConstructible<true, CompressedTuple<Ts...>, Vs...>
+    : std::integral_constant<
+          bool, absl::conjunction<
+                    TupleElementMoveConstructible<Ts, Vs&&>...>::value> {};
+
+template <typename T>
+struct compressed_tuple_size;
+
+template <typename... Es>
+struct compressed_tuple_size<CompressedTuple<Es...>>
+    : public std::integral_constant<std::size_t, sizeof...(Es)> {};
+
+template <class T, class... Vs>
+struct TupleItemsMoveConstructible
+    : std::integral_constant<
+          bool, TupleMoveConstructible<compressed_tuple_size<T>::value ==
+                                           sizeof...(Vs),
+                                       T, Vs...>::value> {};
+
+}  // namespace internal_compressed_tuple
+
+// Helper class to perform the Empty Base Class Optimization.
+// Ts can contain classes and non-classes, empty or not. For the ones that
+// are empty classes, we perform the CompressedTuple. If all types in Ts are
+// empty classes, then CompressedTuple<Ts...> is itself an empty class.  (This
+// does not apply when one or more of those empty classes is itself an empty
+// CompressedTuple.)
+//
+// To access the members, use member .get<N>() function.
+//
+// Eg:
+//   absl::container_internal::CompressedTuple<int, T1, T2, T3> value(7, t1, t2,
+//                                                                    t3);
+//   assert(value.get<0>() == 7);
+//   T1& t1 = value.get<1>();
+//   const T2& t2 = value.get<2>();
+//   ...
+//
+// https://en.cppreference.com/w/cpp/language/ebo
+template <typename... Ts>
+class ABSL_INTERNAL_COMPRESSED_TUPLE_DECLSPEC CompressedTuple
+    : private internal_compressed_tuple::CompressedTupleImpl<
+          CompressedTuple<Ts...>, absl::index_sequence_for<Ts...>,
+          internal_compressed_tuple::ShouldAnyUseBase<Ts...>()> {
+ private:
+  template <int I>
+  using ElemT = internal_compressed_tuple::ElemT<CompressedTuple, I>;
+
+  template <int I>
+  using StorageT = internal_compressed_tuple::Storage<ElemT<I>, I>;
+
+ public:
+  // There seems to be a bug in MSVC dealing in which using '=default' here will
+  // cause the compiler to ignore the body of other constructors. The work-
+  // around is to explicitly implement the default constructor.
+#if defined(_MSC_VER)
+  constexpr CompressedTuple() : CompressedTuple::CompressedTupleImpl() {}
+#else
+  constexpr CompressedTuple() = default;
+#endif
+  explicit constexpr CompressedTuple(const Ts&... base)
+      : CompressedTuple::CompressedTupleImpl(absl::in_place, base...) {}
+
+  template <typename First, typename... Vs,
+            absl::enable_if_t<
+                absl::conjunction<
+                    // Ensure we are not hiding default copy/move constructors.
+                    absl::negation<std::is_same<void(CompressedTuple),
+                                                void(absl::decay_t<First>)>>,
+                    internal_compressed_tuple::TupleItemsMoveConstructible<
+                        CompressedTuple<Ts...>, First, Vs...>>::value,
+                bool> = true>
+  explicit constexpr CompressedTuple(First&& first, Vs&&... base)
+      : CompressedTuple::CompressedTupleImpl(absl::in_place,
+                                             absl::forward<First>(first),
+                                             absl::forward<Vs>(base)...) {}
+
+  template <int I>
+  ElemT<I>& get() & {
+    return StorageT<I>::get();
+  }
+
+  template <int I>
+  constexpr const ElemT<I>& get() const& {
+    return StorageT<I>::get();
+  }
+
+  template <int I>
+  ElemT<I>&& get() && {
+    return std::move(*this).StorageT<I>::get();
+  }
+
+  template <int I>
+  constexpr const ElemT<I>&& get() const&& {
+    return absl::move(*this).StorageT<I>::get();
+  }
+};
+
+// Explicit specialization for a zero-element tuple
+// (needed to avoid ambiguous overloads for the default constructor).
+template <>
+class ABSL_INTERNAL_COMPRESSED_TUPLE_DECLSPEC CompressedTuple<> {};
+
+}  // namespace container_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#undef ABSL_INTERNAL_COMPRESSED_TUPLE_DECLSPEC
+
+#endif  // ABSL_CONTAINER_INTERNAL_COMPRESSED_TUPLE_H_
diff --git a/src/absl/container/internal/container_memory.h b/src/absl/container/internal/container_memory.h
new file mode 100644 (file)
index 0000000..e67529e
--- /dev/null
@@ -0,0 +1,460 @@
+// Copyright 2018 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef ABSL_CONTAINER_INTERNAL_CONTAINER_MEMORY_H_
+#define ABSL_CONTAINER_INTERNAL_CONTAINER_MEMORY_H_
+
+#include <cassert>
+#include <cstddef>
+#include <memory>
+#include <new>
+#include <tuple>
+#include <type_traits>
+#include <utility>
+
+#include "absl/base/config.h"
+#include "absl/memory/memory.h"
+#include "absl/meta/type_traits.h"
+#include "absl/utility/utility.h"
+
+#ifdef ABSL_HAVE_ADDRESS_SANITIZER
+#include <sanitizer/asan_interface.h>
+#endif
+
+#ifdef ABSL_HAVE_MEMORY_SANITIZER
+#include <sanitizer/msan_interface.h>
+#endif
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace container_internal {
+
+template <size_t Alignment>
+struct alignas(Alignment) AlignedType {};
+
+// Allocates at least n bytes aligned to the specified alignment.
+// Alignment must be a power of 2. It must be positive.
+//
+// Note that many allocators don't honor alignment requirements above certain
+// threshold (usually either alignof(std::max_align_t) or alignof(void*)).
+// Allocate() doesn't apply alignment corrections. If the underlying allocator
+// returns insufficiently alignment pointer, that's what you are going to get.
+template <size_t Alignment, class Alloc>
+void* Allocate(Alloc* alloc, size_t n) {
+  static_assert(Alignment > 0, "");
+  assert(n && "n must be positive");
+  using M = AlignedType<Alignment>;
+  using A = typename absl::allocator_traits<Alloc>::template rebind_alloc<M>;
+  using AT = typename absl::allocator_traits<Alloc>::template rebind_traits<M>;
+  // On macOS, "mem_alloc" is a #define with one argument defined in
+  // rpc/types.h, so we can't name the variable "mem_alloc" and initialize it
+  // with the "foo(bar)" syntax.
+  A my_mem_alloc(*alloc);
+  void* p = AT::allocate(my_mem_alloc, (n + sizeof(M) - 1) / sizeof(M));
+  assert(reinterpret_cast<uintptr_t>(p) % Alignment == 0 &&
+         "allocator does not respect alignment");
+  return p;
+}
+
+// The pointer must have been previously obtained by calling
+// Allocate<Alignment>(alloc, n).
+template <size_t Alignment, class Alloc>
+void Deallocate(Alloc* alloc, void* p, size_t n) {
+  static_assert(Alignment > 0, "");
+  assert(n && "n must be positive");
+  using M = AlignedType<Alignment>;
+  using A = typename absl::allocator_traits<Alloc>::template rebind_alloc<M>;
+  using AT = typename absl::allocator_traits<Alloc>::template rebind_traits<M>;
+  // On macOS, "mem_alloc" is a #define with one argument defined in
+  // rpc/types.h, so we can't name the variable "mem_alloc" and initialize it
+  // with the "foo(bar)" syntax.
+  A my_mem_alloc(*alloc);
+  AT::deallocate(my_mem_alloc, static_cast<M*>(p),
+                 (n + sizeof(M) - 1) / sizeof(M));
+}
+
+namespace memory_internal {
+
+// Constructs T into uninitialized storage pointed by `ptr` using the args
+// specified in the tuple.
+template <class Alloc, class T, class Tuple, size_t... I>
+void ConstructFromTupleImpl(Alloc* alloc, T* ptr, Tuple&& t,
+                            absl::index_sequence<I...>) {
+  absl::allocator_traits<Alloc>::construct(
+      *alloc, ptr, std::get<I>(std::forward<Tuple>(t))...);
+}
+
+template <class T, class F>
+struct WithConstructedImplF {
+  template <class... Args>
+  decltype(std::declval<F>()(std::declval<T>())) operator()(
+      Args&&... args) const {
+    return std::forward<F>(f)(T(std::forward<Args>(args)...));
+  }
+  F&& f;
+};
+
+template <class T, class Tuple, size_t... Is, class F>
+decltype(std::declval<F>()(std::declval<T>())) WithConstructedImpl(
+    Tuple&& t, absl::index_sequence<Is...>, F&& f) {
+  return WithConstructedImplF<T, F>{std::forward<F>(f)}(
+      std::get<Is>(std::forward<Tuple>(t))...);
+}
+
+template <class T, size_t... Is>
+auto TupleRefImpl(T&& t, absl::index_sequence<Is...>)
+    -> decltype(std::forward_as_tuple(std::get<Is>(std::forward<T>(t))...)) {
+  return std::forward_as_tuple(std::get<Is>(std::forward<T>(t))...);
+}
+
+// Returns a tuple of references to the elements of the input tuple. T must be a
+// tuple.
+template <class T>
+auto TupleRef(T&& t) -> decltype(
+    TupleRefImpl(std::forward<T>(t),
+                 absl::make_index_sequence<
+                     std::tuple_size<typename std::decay<T>::type>::value>())) {
+  return TupleRefImpl(
+      std::forward<T>(t),
+      absl::make_index_sequence<
+          std::tuple_size<typename std::decay<T>::type>::value>());
+}
+
+template <class F, class K, class V>
+decltype(std::declval<F>()(std::declval<const K&>(), std::piecewise_construct,
+                           std::declval<std::tuple<K>>(), std::declval<V>()))
+DecomposePairImpl(F&& f, std::pair<std::tuple<K>, V> p) {
+  const auto& key = std::get<0>(p.first);
+  return std::forward<F>(f)(key, std::piecewise_construct, std::move(p.first),
+                            std::move(p.second));
+}
+
+}  // namespace memory_internal
+
+// Constructs T into uninitialized storage pointed by `ptr` using the args
+// specified in the tuple.
+template <class Alloc, class T, class Tuple>
+void ConstructFromTuple(Alloc* alloc, T* ptr, Tuple&& t) {
+  memory_internal::ConstructFromTupleImpl(
+      alloc, ptr, std::forward<Tuple>(t),
+      absl::make_index_sequence<
+          std::tuple_size<typename std::decay<Tuple>::type>::value>());
+}
+
+// Constructs T using the args specified in the tuple and calls F with the
+// constructed value.
+template <class T, class Tuple, class F>
+decltype(std::declval<F>()(std::declval<T>())) WithConstructed(
+    Tuple&& t, F&& f) {
+  return memory_internal::WithConstructedImpl<T>(
+      std::forward<Tuple>(t),
+      absl::make_index_sequence<
+          std::tuple_size<typename std::decay<Tuple>::type>::value>(),
+      std::forward<F>(f));
+}
+
+// Given arguments of an std::pair's consructor, PairArgs() returns a pair of
+// tuples with references to the passed arguments. The tuples contain
+// constructor arguments for the first and the second elements of the pair.
+//
+// The following two snippets are equivalent.
+//
+// 1. std::pair<F, S> p(args...);
+//
+// 2. auto a = PairArgs(args...);
+//    std::pair<F, S> p(std::piecewise_construct,
+//                      std::move(p.first), std::move(p.second));
+inline std::pair<std::tuple<>, std::tuple<>> PairArgs() { return {}; }
+template <class F, class S>
+std::pair<std::tuple<F&&>, std::tuple<S&&>> PairArgs(F&& f, S&& s) {
+  return {std::piecewise_construct, std::forward_as_tuple(std::forward<F>(f)),
+          std::forward_as_tuple(std::forward<S>(s))};
+}
+template <class F, class S>
+std::pair<std::tuple<const F&>, std::tuple<const S&>> PairArgs(
+    const std::pair<F, S>& p) {
+  return PairArgs(p.first, p.second);
+}
+template <class F, class S>
+std::pair<std::tuple<F&&>, std::tuple<S&&>> PairArgs(std::pair<F, S>&& p) {
+  return PairArgs(std::forward<F>(p.first), std::forward<S>(p.second));
+}
+template <class F, class S>
+auto PairArgs(std::piecewise_construct_t, F&& f, S&& s)
+    -> decltype(std::make_pair(memory_internal::TupleRef(std::forward<F>(f)),
+                               memory_internal::TupleRef(std::forward<S>(s)))) {
+  return std::make_pair(memory_internal::TupleRef(std::forward<F>(f)),
+                        memory_internal::TupleRef(std::forward<S>(s)));
+}
+
+// A helper function for implementing apply() in map policies.
+template <class F, class... Args>
+auto DecomposePair(F&& f, Args&&... args)
+    -> decltype(memory_internal::DecomposePairImpl(
+        std::forward<F>(f), PairArgs(std::forward<Args>(args)...))) {
+  return memory_internal::DecomposePairImpl(
+      std::forward<F>(f), PairArgs(std::forward<Args>(args)...));
+}
+
+// A helper function for implementing apply() in set policies.
+template <class F, class Arg>
+decltype(std::declval<F>()(std::declval<const Arg&>(), std::declval<Arg>()))
+DecomposeValue(F&& f, Arg&& arg) {
+  const auto& key = arg;
+  return std::forward<F>(f)(key, std::forward<Arg>(arg));
+}
+
+// Helper functions for asan and msan.
+inline void SanitizerPoisonMemoryRegion(const void* m, size_t s) {
+#ifdef ABSL_HAVE_ADDRESS_SANITIZER
+  ASAN_POISON_MEMORY_REGION(m, s);
+#endif
+#ifdef ABSL_HAVE_MEMORY_SANITIZER
+  __msan_poison(m, s);
+#endif
+  (void)m;
+  (void)s;
+}
+
+inline void SanitizerUnpoisonMemoryRegion(const void* m, size_t s) {
+#ifdef ABSL_HAVE_ADDRESS_SANITIZER
+  ASAN_UNPOISON_MEMORY_REGION(m, s);
+#endif
+#ifdef ABSL_HAVE_MEMORY_SANITIZER
+  __msan_unpoison(m, s);
+#endif
+  (void)m;
+  (void)s;
+}
+
+template <typename T>
+inline void SanitizerPoisonObject(const T* object) {
+  SanitizerPoisonMemoryRegion(object, sizeof(T));
+}
+
+template <typename T>
+inline void SanitizerUnpoisonObject(const T* object) {
+  SanitizerUnpoisonMemoryRegion(object, sizeof(T));
+}
+
+namespace memory_internal {
+
+// If Pair is a standard-layout type, OffsetOf<Pair>::kFirst and
+// OffsetOf<Pair>::kSecond are equivalent to offsetof(Pair, first) and
+// offsetof(Pair, second) respectively. Otherwise they are -1.
+//
+// The purpose of OffsetOf is to avoid calling offsetof() on non-standard-layout
+// type, which is non-portable.
+template <class Pair, class = std::true_type>
+struct OffsetOf {
+  static constexpr size_t kFirst = static_cast<size_t>(-1);
+  static constexpr size_t kSecond = static_cast<size_t>(-1);
+};
+
+template <class Pair>
+struct OffsetOf<Pair, typename std::is_standard_layout<Pair>::type> {
+  static constexpr size_t kFirst = offsetof(Pair, first);
+  static constexpr size_t kSecond = offsetof(Pair, second);
+};
+
+template <class K, class V>
+struct IsLayoutCompatible {
+ private:
+  struct Pair {
+    K first;
+    V second;
+  };
+
+  // Is P layout-compatible with Pair?
+  template <class P>
+  static constexpr bool LayoutCompatible() {
+    return std::is_standard_layout<P>() && sizeof(P) == sizeof(Pair) &&
+           alignof(P) == alignof(Pair) &&
+           memory_internal::OffsetOf<P>::kFirst ==
+               memory_internal::OffsetOf<Pair>::kFirst &&
+           memory_internal::OffsetOf<P>::kSecond ==
+               memory_internal::OffsetOf<Pair>::kSecond;
+  }
+
+ public:
+  // Whether pair<const K, V> and pair<K, V> are layout-compatible. If they are,
+  // then it is safe to store them in a union and read from either.
+  static constexpr bool value = std::is_standard_layout<K>() &&
+                                std::is_standard_layout<Pair>() &&
+                                memory_internal::OffsetOf<Pair>::kFirst == 0 &&
+                                LayoutCompatible<std::pair<K, V>>() &&
+                                LayoutCompatible<std::pair<const K, V>>();
+};
+
+}  // namespace memory_internal
+
+// The internal storage type for key-value containers like flat_hash_map.
+//
+// It is convenient for the value_type of a flat_hash_map<K, V> to be
+// pair<const K, V>; the "const K" prevents accidental modification of the key
+// when dealing with the reference returned from find() and similar methods.
+// However, this creates other problems; we want to be able to emplace(K, V)
+// efficiently with move operations, and similarly be able to move a
+// pair<K, V> in insert().
+//
+// The solution is this union, which aliases the const and non-const versions
+// of the pair. This also allows flat_hash_map<const K, V> to work, even though
+// that has the same efficiency issues with move in emplace() and insert() -
+// but people do it anyway.
+//
+// If kMutableKeys is false, only the value member can be accessed.
+//
+// If kMutableKeys is true, key can be accessed through all slots while value
+// and mutable_value must be accessed only via INITIALIZED slots. Slots are
+// created and destroyed via mutable_value so that the key can be moved later.
+//
+// Accessing one of the union fields while the other is active is safe as
+// long as they are layout-compatible, which is guaranteed by the definition of
+// kMutableKeys. For C++11, the relevant section of the standard is
+// https://timsong-cpp.github.io/cppwp/n3337/class.mem#19 (9.2.19)
+template <class K, class V>
+union map_slot_type {
+  map_slot_type() {}
+  ~map_slot_type() = delete;
+  using value_type = std::pair<const K, V>;
+  using mutable_value_type =
+      std::pair<absl::remove_const_t<K>, absl::remove_const_t<V>>;
+
+  value_type value;
+  mutable_value_type mutable_value;
+  absl::remove_const_t<K> key;
+};
+
+template <class K, class V>
+struct map_slot_policy {
+  using slot_type = map_slot_type<K, V>;
+  using value_type = std::pair<const K, V>;
+  using mutable_value_type = std::pair<K, V>;
+
+ private:
+  static void emplace(slot_type* slot) {
+    // The construction of union doesn't do anything at runtime but it allows us
+    // to access its members without violating aliasing rules.
+    new (slot) slot_type;
+  }
+  // If pair<const K, V> and pair<K, V> are layout-compatible, we can accept one
+  // or the other via slot_type. We are also free to access the key via
+  // slot_type::key in this case.
+  using kMutableKeys = memory_internal::IsLayoutCompatible<K, V>;
+
+ public:
+  static value_type& element(slot_type* slot) { return slot->value; }
+  static const value_type& element(const slot_type* slot) {
+    return slot->value;
+  }
+
+  // When C++17 is available, we can use std::launder to provide mutable
+  // access to the key for use in node handle.
+#if defined(__cpp_lib_launder) && __cpp_lib_launder >= 201606
+  static K& mutable_key(slot_type* slot) {
+    // Still check for kMutableKeys so that we can avoid calling std::launder
+    // unless necessary because it can interfere with optimizations.
+    return kMutableKeys::value ? slot->key
+                               : *std::launder(const_cast<K*>(
+                                     std::addressof(slot->value.first)));
+  }
+#else  // !(defined(__cpp_lib_launder) && __cpp_lib_launder >= 201606)
+  static const K& mutable_key(slot_type* slot) { return key(slot); }
+#endif
+
+  static const K& key(const slot_type* slot) {
+    return kMutableKeys::value ? slot->key : slot->value.first;
+  }
+
+  template <class Allocator, class... Args>
+  static void construct(Allocator* alloc, slot_type* slot, Args&&... args) {
+    emplace(slot);
+    if (kMutableKeys::value) {
+      absl::allocator_traits<Allocator>::construct(*alloc, &slot->mutable_value,
+                                                   std::forward<Args>(args)...);
+    } else {
+      absl::allocator_traits<Allocator>::construct(*alloc, &slot->value,
+                                                   std::forward<Args>(args)...);
+    }
+  }
+
+  // Construct this slot by moving from another slot.
+  template <class Allocator>
+  static void construct(Allocator* alloc, slot_type* slot, slot_type* other) {
+    emplace(slot);
+    if (kMutableKeys::value) {
+      absl::allocator_traits<Allocator>::construct(
+          *alloc, &slot->mutable_value, std::move(other->mutable_value));
+    } else {
+      absl::allocator_traits<Allocator>::construct(*alloc, &slot->value,
+                                                   std::move(other->value));
+    }
+  }
+
+  template <class Allocator>
+  static void destroy(Allocator* alloc, slot_type* slot) {
+    if (kMutableKeys::value) {
+      absl::allocator_traits<Allocator>::destroy(*alloc, &slot->mutable_value);
+    } else {
+      absl::allocator_traits<Allocator>::destroy(*alloc, &slot->value);
+    }
+  }
+
+  template <class Allocator>
+  static void transfer(Allocator* alloc, slot_type* new_slot,
+                       slot_type* old_slot) {
+    emplace(new_slot);
+    if (kMutableKeys::value) {
+      absl::allocator_traits<Allocator>::construct(
+          *alloc, &new_slot->mutable_value, std::move(old_slot->mutable_value));
+    } else {
+      absl::allocator_traits<Allocator>::construct(*alloc, &new_slot->value,
+                                                   std::move(old_slot->value));
+    }
+    destroy(alloc, old_slot);
+  }
+
+  template <class Allocator>
+  static void swap(Allocator* alloc, slot_type* a, slot_type* b) {
+    if (kMutableKeys::value) {
+      using std::swap;
+      swap(a->mutable_value, b->mutable_value);
+    } else {
+      value_type tmp = std::move(a->value);
+      absl::allocator_traits<Allocator>::destroy(*alloc, &a->value);
+      absl::allocator_traits<Allocator>::construct(*alloc, &a->value,
+                                                   std::move(b->value));
+      absl::allocator_traits<Allocator>::destroy(*alloc, &b->value);
+      absl::allocator_traits<Allocator>::construct(*alloc, &b->value,
+                                                   std::move(tmp));
+    }
+  }
+
+  template <class Allocator>
+  static void move(Allocator* alloc, slot_type* src, slot_type* dest) {
+    if (kMutableKeys::value) {
+      dest->mutable_value = std::move(src->mutable_value);
+    } else {
+      absl::allocator_traits<Allocator>::destroy(*alloc, &dest->value);
+      absl::allocator_traits<Allocator>::construct(*alloc, &dest->value,
+                                                   std::move(src->value));
+    }
+  }
+};
+
+}  // namespace container_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#endif  // ABSL_CONTAINER_INTERNAL_CONTAINER_MEMORY_H_
diff --git a/src/absl/container/internal/counting_allocator.h b/src/absl/container/internal/counting_allocator.h
new file mode 100644 (file)
index 0000000..927cf08
--- /dev/null
@@ -0,0 +1,114 @@
+// Copyright 2018 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef ABSL_CONTAINER_INTERNAL_COUNTING_ALLOCATOR_H_
+#define ABSL_CONTAINER_INTERNAL_COUNTING_ALLOCATOR_H_
+
+#include <cstdint>
+#include <memory>
+
+#include "absl/base/config.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace container_internal {
+
+// This is a stateful allocator, but the state lives outside of the
+// allocator (in whatever test is using the allocator). This is odd
+// but helps in tests where the allocator is propagated into nested
+// containers - that chain of allocators uses the same state and is
+// thus easier to query for aggregate allocation information.
+template <typename T>
+class CountingAllocator {
+ public:
+  using Allocator = std::allocator<T>;
+  using AllocatorTraits = std::allocator_traits<Allocator>;
+  using value_type = typename AllocatorTraits::value_type;
+  using pointer = typename AllocatorTraits::pointer;
+  using const_pointer = typename AllocatorTraits::const_pointer;
+  using size_type = typename AllocatorTraits::size_type;
+  using difference_type = typename AllocatorTraits::difference_type;
+
+  CountingAllocator() = default;
+  explicit CountingAllocator(int64_t* bytes_used) : bytes_used_(bytes_used) {}
+  CountingAllocator(int64_t* bytes_used, int64_t* instance_count)
+      : bytes_used_(bytes_used), instance_count_(instance_count) {}
+
+  template <typename U>
+  CountingAllocator(const CountingAllocator<U>& x)
+      : bytes_used_(x.bytes_used_), instance_count_(x.instance_count_) {}
+
+  pointer allocate(
+      size_type n,
+      typename AllocatorTraits::const_void_pointer hint = nullptr) {
+    Allocator allocator;
+    pointer ptr = AllocatorTraits::allocate(allocator, n, hint);
+    if (bytes_used_ != nullptr) {
+      *bytes_used_ += n * sizeof(T);
+    }
+    return ptr;
+  }
+
+  void deallocate(pointer p, size_type n) {
+    Allocator allocator;
+    AllocatorTraits::deallocate(allocator, p, n);
+    if (bytes_used_ != nullptr) {
+      *bytes_used_ -= n * sizeof(T);
+    }
+  }
+
+  template <typename U, typename... Args>
+  void construct(U* p, Args&&... args) {
+    Allocator allocator;
+    AllocatorTraits::construct(allocator, p, std::forward<Args>(args)...);
+    if (instance_count_ != nullptr) {
+      *instance_count_ += 1;
+    }
+  }
+
+  template <typename U>
+  void destroy(U* p) {
+    Allocator allocator;
+    AllocatorTraits::destroy(allocator, p);
+    if (instance_count_ != nullptr) {
+      *instance_count_ -= 1;
+    }
+  }
+
+  template <typename U>
+  class rebind {
+   public:
+    using other = CountingAllocator<U>;
+  };
+
+  friend bool operator==(const CountingAllocator& a,
+                         const CountingAllocator& b) {
+    return a.bytes_used_ == b.bytes_used_ &&
+           a.instance_count_ == b.instance_count_;
+  }
+
+  friend bool operator!=(const CountingAllocator& a,
+                         const CountingAllocator& b) {
+    return !(a == b);
+  }
+
+  int64_t* bytes_used_ = nullptr;
+  int64_t* instance_count_ = nullptr;
+};
+
+}  // namespace container_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#endif  // ABSL_CONTAINER_INTERNAL_COUNTING_ALLOCATOR_H_
diff --git a/src/absl/container/internal/hash_function_defaults.h b/src/absl/container/internal/hash_function_defaults.h
new file mode 100644 (file)
index 0000000..0683422
--- /dev/null
@@ -0,0 +1,161 @@
+// Copyright 2018 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// Define the default Hash and Eq functions for SwissTable containers.
+//
+// std::hash<T> and std::equal_to<T> are not appropriate hash and equal
+// functions for SwissTable containers. There are two reasons for this.
+//
+// SwissTable containers are power of 2 sized containers:
+//
+// This means they use the lower bits of the hash value to find the slot for
+// each entry. The typical hash function for integral types is the identity.
+// This is a very weak hash function for SwissTable and any power of 2 sized
+// hashtable implementation which will lead to excessive collisions. For
+// SwissTable we use murmur3 style mixing to reduce collisions to a minimum.
+//
+// SwissTable containers support heterogeneous lookup:
+//
+// In order to make heterogeneous lookup work, hash and equal functions must be
+// polymorphic. At the same time they have to satisfy the same requirements the
+// C++ standard imposes on hash functions and equality operators. That is:
+//
+//   if hash_default_eq<T>(a, b) returns true for any a and b of type T, then
+//   hash_default_hash<T>(a) must equal hash_default_hash<T>(b)
+//
+// For SwissTable containers this requirement is relaxed to allow a and b of
+// any and possibly different types. Note that like the standard the hash and
+// equal functions are still bound to T. This is important because some type U
+// can be hashed by/tested for equality differently depending on T. A notable
+// example is `const char*`. `const char*` is treated as a c-style string when
+// the hash function is hash<std::string> but as a pointer when the hash
+// function is hash<void*>.
+//
+#ifndef ABSL_CONTAINER_INTERNAL_HASH_FUNCTION_DEFAULTS_H_
+#define ABSL_CONTAINER_INTERNAL_HASH_FUNCTION_DEFAULTS_H_
+
+#include <stdint.h>
+#include <cstddef>
+#include <memory>
+#include <string>
+#include <type_traits>
+
+#include "absl/base/config.h"
+#include "absl/hash/hash.h"
+#include "absl/strings/cord.h"
+#include "absl/strings/string_view.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace container_internal {
+
+// The hash of an object of type T is computed by using absl::Hash.
+template <class T, class E = void>
+struct HashEq {
+  using Hash = absl::Hash<T>;
+  using Eq = std::equal_to<T>;
+};
+
+struct StringHash {
+  using is_transparent = void;
+
+  size_t operator()(absl::string_view v) const {
+    return absl::Hash<absl::string_view>{}(v);
+  }
+  size_t operator()(const absl::Cord& v) const {
+    return absl::Hash<absl::Cord>{}(v);
+  }
+};
+
+// Supports heterogeneous lookup for string-like elements.
+struct StringHashEq {
+  using Hash = StringHash;
+  struct Eq {
+    using is_transparent = void;
+    bool operator()(absl::string_view lhs, absl::string_view rhs) const {
+      return lhs == rhs;
+    }
+    bool operator()(const absl::Cord& lhs, const absl::Cord& rhs) const {
+      return lhs == rhs;
+    }
+    bool operator()(const absl::Cord& lhs, absl::string_view rhs) const {
+      return lhs == rhs;
+    }
+    bool operator()(absl::string_view lhs, const absl::Cord& rhs) const {
+      return lhs == rhs;
+    }
+  };
+};
+
+template <>
+struct HashEq<std::string> : StringHashEq {};
+template <>
+struct HashEq<absl::string_view> : StringHashEq {};
+template <>
+struct HashEq<absl::Cord> : StringHashEq {};
+
+// Supports heterogeneous lookup for pointers and smart pointers.
+template <class T>
+struct HashEq<T*> {
+  struct Hash {
+    using is_transparent = void;
+    template <class U>
+    size_t operator()(const U& ptr) const {
+      return absl::Hash<const T*>{}(HashEq::ToPtr(ptr));
+    }
+  };
+  struct Eq {
+    using is_transparent = void;
+    template <class A, class B>
+    bool operator()(const A& a, const B& b) const {
+      return HashEq::ToPtr(a) == HashEq::ToPtr(b);
+    }
+  };
+
+ private:
+  static const T* ToPtr(const T* ptr) { return ptr; }
+  template <class U, class D>
+  static const T* ToPtr(const std::unique_ptr<U, D>& ptr) {
+    return ptr.get();
+  }
+  template <class U>
+  static const T* ToPtr(const std::shared_ptr<U>& ptr) {
+    return ptr.get();
+  }
+};
+
+template <class T, class D>
+struct HashEq<std::unique_ptr<T, D>> : HashEq<T*> {};
+template <class T>
+struct HashEq<std::shared_ptr<T>> : HashEq<T*> {};
+
+// This header's visibility is restricted.  If you need to access the default
+// hasher please use the container's ::hasher alias instead.
+//
+// Example: typename Hash = typename absl::flat_hash_map<K, V>::hasher
+template <class T>
+using hash_default_hash = typename container_internal::HashEq<T>::Hash;
+
+// This header's visibility is restricted.  If you need to access the default
+// key equal please use the container's ::key_equal alias instead.
+//
+// Example: typename Eq = typename absl::flat_hash_map<K, V, Hash>::key_equal
+template <class T>
+using hash_default_eq = typename container_internal::HashEq<T>::Eq;
+
+}  // namespace container_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#endif  // ABSL_CONTAINER_INTERNAL_HASH_FUNCTION_DEFAULTS_H_
diff --git a/src/absl/container/internal/hash_policy_traits.h b/src/absl/container/internal/hash_policy_traits.h
new file mode 100644 (file)
index 0000000..46c97b1
--- /dev/null
@@ -0,0 +1,208 @@
+// Copyright 2018 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef ABSL_CONTAINER_INTERNAL_HASH_POLICY_TRAITS_H_
+#define ABSL_CONTAINER_INTERNAL_HASH_POLICY_TRAITS_H_
+
+#include <cstddef>
+#include <memory>
+#include <new>
+#include <type_traits>
+#include <utility>
+
+#include "absl/meta/type_traits.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace container_internal {
+
+// Defines how slots are initialized/destroyed/moved.
+template <class Policy, class = void>
+struct hash_policy_traits {
+  // The type of the keys stored in the hashtable.
+  using key_type = typename Policy::key_type;
+
+ private:
+  struct ReturnKey {
+    // When C++17 is available, we can use std::launder to provide mutable
+    // access to the key for use in node handle.
+#if defined(__cpp_lib_launder) && __cpp_lib_launder >= 201606
+    template <class Key,
+              absl::enable_if_t<std::is_lvalue_reference<Key>::value, int> = 0>
+    static key_type& Impl(Key&& k, int) {
+      return *std::launder(
+          const_cast<key_type*>(std::addressof(std::forward<Key>(k))));
+    }
+#endif
+
+    template <class Key>
+    static Key Impl(Key&& k, char) {
+      return std::forward<Key>(k);
+    }
+
+    // When Key=T&, we forward the lvalue reference.
+    // When Key=T, we return by value to avoid a dangling reference.
+    // eg, for string_hash_map.
+    template <class Key, class... Args>
+    auto operator()(Key&& k, const Args&...) const
+        -> decltype(Impl(std::forward<Key>(k), 0)) {
+      return Impl(std::forward<Key>(k), 0);
+    }
+  };
+
+  template <class P = Policy, class = void>
+  struct ConstantIteratorsImpl : std::false_type {};
+
+  template <class P>
+  struct ConstantIteratorsImpl<P, absl::void_t<typename P::constant_iterators>>
+      : P::constant_iterators {};
+
+ public:
+  // The actual object stored in the hash table.
+  using slot_type = typename Policy::slot_type;
+
+  // The argument type for insertions into the hashtable. This is different
+  // from value_type for increased performance. See initializer_list constructor
+  // and insert() member functions for more details.
+  using init_type = typename Policy::init_type;
+
+  using reference = decltype(Policy::element(std::declval<slot_type*>()));
+  using pointer = typename std::remove_reference<reference>::type*;
+  using value_type = typename std::remove_reference<reference>::type;
+
+  // Policies can set this variable to tell raw_hash_set that all iterators
+  // should be constant, even `iterator`. This is useful for set-like
+  // containers.
+  // Defaults to false if not provided by the policy.
+  using constant_iterators = ConstantIteratorsImpl<>;
+
+  // PRECONDITION: `slot` is UNINITIALIZED
+  // POSTCONDITION: `slot` is INITIALIZED
+  template <class Alloc, class... Args>
+  static void construct(Alloc* alloc, slot_type* slot, Args&&... args) {
+    Policy::construct(alloc, slot, std::forward<Args>(args)...);
+  }
+
+  // PRECONDITION: `slot` is INITIALIZED
+  // POSTCONDITION: `slot` is UNINITIALIZED
+  template <class Alloc>
+  static void destroy(Alloc* alloc, slot_type* slot) {
+    Policy::destroy(alloc, slot);
+  }
+
+  // Transfers the `old_slot` to `new_slot`. Any memory allocated by the
+  // allocator inside `old_slot` to `new_slot` can be transferred.
+  //
+  // OPTIONAL: defaults to:
+  //
+  //     clone(new_slot, std::move(*old_slot));
+  //     destroy(old_slot);
+  //
+  // PRECONDITION: `new_slot` is UNINITIALIZED and `old_slot` is INITIALIZED
+  // POSTCONDITION: `new_slot` is INITIALIZED and `old_slot` is
+  //                UNINITIALIZED
+  template <class Alloc>
+  static void transfer(Alloc* alloc, slot_type* new_slot, slot_type* old_slot) {
+    transfer_impl(alloc, new_slot, old_slot, 0);
+  }
+
+  // PRECONDITION: `slot` is INITIALIZED
+  // POSTCONDITION: `slot` is INITIALIZED
+  template <class P = Policy>
+  static auto element(slot_type* slot) -> decltype(P::element(slot)) {
+    return P::element(slot);
+  }
+
+  // Returns the amount of memory owned by `slot`, exclusive of `sizeof(*slot)`.
+  //
+  // If `slot` is nullptr, returns the constant amount of memory owned by any
+  // full slot or -1 if slots own variable amounts of memory.
+  //
+  // PRECONDITION: `slot` is INITIALIZED or nullptr
+  template <class P = Policy>
+  static size_t space_used(const slot_type* slot) {
+    return P::space_used(slot);
+  }
+
+  // Provides generalized access to the key for elements, both for elements in
+  // the table and for elements that have not yet been inserted (or even
+  // constructed).  We would like an API that allows us to say: `key(args...)`
+  // but we cannot do that for all cases, so we use this more general API that
+  // can be used for many things, including the following:
+  //
+  //   - Given an element in a table, get its key.
+  //   - Given an element initializer, get its key.
+  //   - Given `emplace()` arguments, get the element key.
+  //
+  // Implementations of this must adhere to a very strict technical
+  // specification around aliasing and consuming arguments:
+  //
+  // Let `value_type` be the result type of `element()` without ref- and
+  // cv-qualifiers. The first argument is a functor, the rest are constructor
+  // arguments for `value_type`. Returns `std::forward<F>(f)(k, xs...)`, where
+  // `k` is the element key, and `xs...` are the new constructor arguments for
+  // `value_type`. It's allowed for `k` to alias `xs...`, and for both to alias
+  // `ts...`. The key won't be touched once `xs...` are used to construct an
+  // element; `ts...` won't be touched at all, which allows `apply()` to consume
+  // any rvalues among them.
+  //
+  // If `value_type` is constructible from `Ts&&...`, `Policy::apply()` must not
+  // trigger a hard compile error unless it originates from `f`. In other words,
+  // `Policy::apply()` must be SFINAE-friendly. If `value_type` is not
+  // constructible from `Ts&&...`, either SFINAE or a hard compile error is OK.
+  //
+  // If `Ts...` is `[cv] value_type[&]` or `[cv] init_type[&]`,
+  // `Policy::apply()` must work. A compile error is not allowed, SFINAE or not.
+  template <class F, class... Ts, class P = Policy>
+  static auto apply(F&& f, Ts&&... ts)
+      -> decltype(P::apply(std::forward<F>(f), std::forward<Ts>(ts)...)) {
+    return P::apply(std::forward<F>(f), std::forward<Ts>(ts)...);
+  }
+
+  // Returns the "key" portion of the slot.
+  // Used for node handle manipulation.
+  template <class P = Policy>
+  static auto mutable_key(slot_type* slot)
+      -> decltype(P::apply(ReturnKey(), element(slot))) {
+    return P::apply(ReturnKey(), element(slot));
+  }
+
+  // Returns the "value" (as opposed to the "key") portion of the element. Used
+  // by maps to implement `operator[]`, `at()` and `insert_or_assign()`.
+  template <class T, class P = Policy>
+  static auto value(T* elem) -> decltype(P::value(elem)) {
+    return P::value(elem);
+  }
+
+ private:
+  // Use auto -> decltype as an enabler.
+  template <class Alloc, class P = Policy>
+  static auto transfer_impl(Alloc* alloc, slot_type* new_slot,
+                            slot_type* old_slot, int)
+      -> decltype((void)P::transfer(alloc, new_slot, old_slot)) {
+    P::transfer(alloc, new_slot, old_slot);
+  }
+  template <class Alloc>
+  static void transfer_impl(Alloc* alloc, slot_type* new_slot,
+                            slot_type* old_slot, char) {
+    construct(alloc, new_slot, std::move(element(old_slot)));
+    destroy(alloc, old_slot);
+  }
+};
+
+}  // namespace container_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#endif  // ABSL_CONTAINER_INTERNAL_HASH_POLICY_TRAITS_H_
diff --git a/src/absl/container/internal/hashtable_debug.h b/src/absl/container/internal/hashtable_debug.h
new file mode 100644 (file)
index 0000000..19d5212
--- /dev/null
@@ -0,0 +1,110 @@
+// Copyright 2018 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// This library provides APIs to debug the probing behavior of hash tables.
+//
+// In general, the probing behavior is a black box for users and only the
+// side effects can be measured in the form of performance differences.
+// These APIs give a glimpse on the actual behavior of the probing algorithms in
+// these hashtables given a specified hash function and a set of elements.
+//
+// The probe count distribution can be used to assess the quality of the hash
+// function for that particular hash table. Note that a hash function that
+// performs well in one hash table implementation does not necessarily performs
+// well in a different one.
+//
+// This library supports std::unordered_{set,map}, dense_hash_{set,map} and
+// absl::{flat,node,string}_hash_{set,map}.
+
+#ifndef ABSL_CONTAINER_INTERNAL_HASHTABLE_DEBUG_H_
+#define ABSL_CONTAINER_INTERNAL_HASHTABLE_DEBUG_H_
+
+#include <cstddef>
+#include <algorithm>
+#include <type_traits>
+#include <vector>
+
+#include "absl/container/internal/hashtable_debug_hooks.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace container_internal {
+
+// Returns the number of probes required to lookup `key`.  Returns 0 for a
+// search with no collisions.  Higher values mean more hash collisions occurred;
+// however, the exact meaning of this number varies according to the container
+// type.
+template <typename C>
+size_t GetHashtableDebugNumProbes(
+    const C& c, const typename C::key_type& key) {
+  return absl::container_internal::hashtable_debug_internal::
+      HashtableDebugAccess<C>::GetNumProbes(c, key);
+}
+
+// Gets a histogram of the number of probes for each elements in the container.
+// The sum of all the values in the vector is equal to container.size().
+template <typename C>
+std::vector<size_t> GetHashtableDebugNumProbesHistogram(const C& container) {
+  std::vector<size_t> v;
+  for (auto it = container.begin(); it != container.end(); ++it) {
+    size_t num_probes = GetHashtableDebugNumProbes(
+        container,
+        absl::container_internal::hashtable_debug_internal::GetKey<C>(*it, 0));
+    v.resize((std::max)(v.size(), num_probes + 1));
+    v[num_probes]++;
+  }
+  return v;
+}
+
+struct HashtableDebugProbeSummary {
+  size_t total_elements;
+  size_t total_num_probes;
+  double mean;
+};
+
+// Gets a summary of the probe count distribution for the elements in the
+// container.
+template <typename C>
+HashtableDebugProbeSummary GetHashtableDebugProbeSummary(const C& container) {
+  auto probes = GetHashtableDebugNumProbesHistogram(container);
+  HashtableDebugProbeSummary summary = {};
+  for (size_t i = 0; i < probes.size(); ++i) {
+    summary.total_elements += probes[i];
+    summary.total_num_probes += probes[i] * i;
+  }
+  summary.mean = 1.0 * summary.total_num_probes / summary.total_elements;
+  return summary;
+}
+
+// Returns the number of bytes requested from the allocator by the container
+// and not freed.
+template <typename C>
+size_t AllocatedByteSize(const C& c) {
+  return absl::container_internal::hashtable_debug_internal::
+      HashtableDebugAccess<C>::AllocatedByteSize(c);
+}
+
+// Returns a tight lower bound for AllocatedByteSize(c) where `c` is of type `C`
+// and `c.size()` is equal to `num_elements`.
+template <typename C>
+size_t LowerBoundAllocatedByteSize(size_t num_elements) {
+  return absl::container_internal::hashtable_debug_internal::
+      HashtableDebugAccess<C>::LowerBoundAllocatedByteSize(num_elements);
+}
+
+}  // namespace container_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#endif  // ABSL_CONTAINER_INTERNAL_HASHTABLE_DEBUG_H_
diff --git a/src/absl/container/internal/hashtable_debug_hooks.h b/src/absl/container/internal/hashtable_debug_hooks.h
new file mode 100644 (file)
index 0000000..3e9ea59
--- /dev/null
@@ -0,0 +1,85 @@
+// Copyright 2018 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// Provides the internal API for hashtable_debug.h.
+
+#ifndef ABSL_CONTAINER_INTERNAL_HASHTABLE_DEBUG_HOOKS_H_
+#define ABSL_CONTAINER_INTERNAL_HASHTABLE_DEBUG_HOOKS_H_
+
+#include <cstddef>
+
+#include <algorithm>
+#include <type_traits>
+#include <vector>
+
+#include "absl/base/config.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace container_internal {
+namespace hashtable_debug_internal {
+
+// If it is a map, call get<0>().
+using std::get;
+template <typename T, typename = typename T::mapped_type>
+auto GetKey(const typename T::value_type& pair, int) -> decltype(get<0>(pair)) {
+  return get<0>(pair);
+}
+
+// If it is not a map, return the value directly.
+template <typename T>
+const typename T::key_type& GetKey(const typename T::key_type& key, char) {
+  return key;
+}
+
+// Containers should specialize this to provide debug information for that
+// container.
+template <class Container, typename Enabler = void>
+struct HashtableDebugAccess {
+  // Returns the number of probes required to find `key` in `c`.  The "number of
+  // probes" is a concept that can vary by container.  Implementations should
+  // return 0 when `key` was found in the minimum number of operations and
+  // should increment the result for each non-trivial operation required to find
+  // `key`.
+  //
+  // The default implementation uses the bucket api from the standard and thus
+  // works for `std::unordered_*` containers.
+  static size_t GetNumProbes(const Container& c,
+                             const typename Container::key_type& key) {
+    if (!c.bucket_count()) return {};
+    size_t num_probes = 0;
+    size_t bucket = c.bucket(key);
+    for (auto it = c.begin(bucket), e = c.end(bucket);; ++it, ++num_probes) {
+      if (it == e) return num_probes;
+      if (c.key_eq()(key, GetKey<Container>(*it, 0))) return num_probes;
+    }
+  }
+
+  // Returns the number of bytes requested from the allocator by the container
+  // and not freed.
+  //
+  // static size_t AllocatedByteSize(const Container& c);
+
+  // Returns a tight lower bound for AllocatedByteSize(c) where `c` is of type
+  // `Container` and `c.size()` is equal to `num_elements`.
+  //
+  // static size_t LowerBoundAllocatedByteSize(size_t num_elements);
+};
+
+}  // namespace hashtable_debug_internal
+}  // namespace container_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#endif  // ABSL_CONTAINER_INTERNAL_HASHTABLE_DEBUG_HOOKS_H_
diff --git a/src/absl/container/internal/hashtablez_sampler.cc b/src/absl/container/internal/hashtablez_sampler.cc
new file mode 100644 (file)
index 0000000..5a29bed
--- /dev/null
@@ -0,0 +1,274 @@
+// Copyright 2018 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "absl/container/internal/hashtablez_sampler.h"
+
+#include <atomic>
+#include <cassert>
+#include <cmath>
+#include <functional>
+#include <limits>
+
+#include "absl/base/attributes.h"
+#include "absl/base/internal/exponential_biased.h"
+#include "absl/container/internal/have_sse.h"
+#include "absl/debugging/stacktrace.h"
+#include "absl/memory/memory.h"
+#include "absl/synchronization/mutex.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace container_internal {
+constexpr int HashtablezInfo::kMaxStackDepth;
+
+namespace {
+ABSL_CONST_INIT std::atomic<bool> g_hashtablez_enabled{
+    false
+};
+ABSL_CONST_INIT std::atomic<int32_t> g_hashtablez_sample_parameter{1 << 10};
+ABSL_CONST_INIT std::atomic<int32_t> g_hashtablez_max_samples{1 << 20};
+
+#if defined(ABSL_INTERNAL_HASHTABLEZ_SAMPLE)
+ABSL_PER_THREAD_TLS_KEYWORD absl::base_internal::ExponentialBiased
+    g_exponential_biased_generator;
+#endif
+
+}  // namespace
+
+#if defined(ABSL_INTERNAL_HASHTABLEZ_SAMPLE)
+ABSL_PER_THREAD_TLS_KEYWORD int64_t global_next_sample = 0;
+#endif  // defined(ABSL_INTERNAL_HASHTABLEZ_SAMPLE)
+
+HashtablezSampler& HashtablezSampler::Global() {
+  static auto* sampler = new HashtablezSampler();
+  return *sampler;
+}
+
+HashtablezSampler::DisposeCallback HashtablezSampler::SetDisposeCallback(
+    DisposeCallback f) {
+  return dispose_.exchange(f, std::memory_order_relaxed);
+}
+
+HashtablezInfo::HashtablezInfo() { PrepareForSampling(); }
+HashtablezInfo::~HashtablezInfo() = default;
+
+void HashtablezInfo::PrepareForSampling() {
+  capacity.store(0, std::memory_order_relaxed);
+  size.store(0, std::memory_order_relaxed);
+  num_erases.store(0, std::memory_order_relaxed);
+  num_rehashes.store(0, std::memory_order_relaxed);
+  max_probe_length.store(0, std::memory_order_relaxed);
+  total_probe_length.store(0, std::memory_order_relaxed);
+  hashes_bitwise_or.store(0, std::memory_order_relaxed);
+  hashes_bitwise_and.store(~size_t{}, std::memory_order_relaxed);
+  hashes_bitwise_xor.store(0, std::memory_order_relaxed);
+
+  create_time = absl::Now();
+  // The inliner makes hardcoded skip_count difficult (especially when combined
+  // with LTO).  We use the ability to exclude stacks by regex when encoding
+  // instead.
+  depth = absl::GetStackTrace(stack, HashtablezInfo::kMaxStackDepth,
+                              /* skip_count= */ 0);
+  dead = nullptr;
+}
+
+HashtablezSampler::HashtablezSampler()
+    : dropped_samples_(0), size_estimate_(0), all_(nullptr), dispose_(nullptr) {
+  absl::MutexLock l(&graveyard_.init_mu);
+  graveyard_.dead = &graveyard_;
+}
+
+HashtablezSampler::~HashtablezSampler() {
+  HashtablezInfo* s = all_.load(std::memory_order_acquire);
+  while (s != nullptr) {
+    HashtablezInfo* next = s->next;
+    delete s;
+    s = next;
+  }
+}
+
+void HashtablezSampler::PushNew(HashtablezInfo* sample) {
+  sample->next = all_.load(std::memory_order_relaxed);
+  while (!all_.compare_exchange_weak(sample->next, sample,
+                                     std::memory_order_release,
+                                     std::memory_order_relaxed)) {
+  }
+}
+
+void HashtablezSampler::PushDead(HashtablezInfo* sample) {
+  if (auto* dispose = dispose_.load(std::memory_order_relaxed)) {
+    dispose(*sample);
+  }
+
+  absl::MutexLock graveyard_lock(&graveyard_.init_mu);
+  absl::MutexLock sample_lock(&sample->init_mu);
+  sample->dead = graveyard_.dead;
+  graveyard_.dead = sample;
+}
+
+HashtablezInfo* HashtablezSampler::PopDead() {
+  absl::MutexLock graveyard_lock(&graveyard_.init_mu);
+
+  // The list is circular, so eventually it collapses down to
+  //   graveyard_.dead == &graveyard_
+  // when it is empty.
+  HashtablezInfo* sample = graveyard_.dead;
+  if (sample == &graveyard_) return nullptr;
+
+  absl::MutexLock sample_lock(&sample->init_mu);
+  graveyard_.dead = sample->dead;
+  sample->PrepareForSampling();
+  return sample;
+}
+
+HashtablezInfo* HashtablezSampler::Register() {
+  int64_t size = size_estimate_.fetch_add(1, std::memory_order_relaxed);
+  if (size > g_hashtablez_max_samples.load(std::memory_order_relaxed)) {
+    size_estimate_.fetch_sub(1, std::memory_order_relaxed);
+    dropped_samples_.fetch_add(1, std::memory_order_relaxed);
+    return nullptr;
+  }
+
+  HashtablezInfo* sample = PopDead();
+  if (sample == nullptr) {
+    // Resurrection failed.  Hire a new warlock.
+    sample = new HashtablezInfo();
+    PushNew(sample);
+  }
+
+  return sample;
+}
+
+void HashtablezSampler::Unregister(HashtablezInfo* sample) {
+  PushDead(sample);
+  size_estimate_.fetch_sub(1, std::memory_order_relaxed);
+}
+
+int64_t HashtablezSampler::Iterate(
+    const std::function<void(const HashtablezInfo& stack)>& f) {
+  HashtablezInfo* s = all_.load(std::memory_order_acquire);
+  while (s != nullptr) {
+    absl::MutexLock l(&s->init_mu);
+    if (s->dead == nullptr) {
+      f(*s);
+    }
+    s = s->next;
+  }
+
+  return dropped_samples_.load(std::memory_order_relaxed);
+}
+
+static bool ShouldForceSampling() {
+  enum ForceState {
+    kDontForce,
+    kForce,
+    kUninitialized
+  };
+  ABSL_CONST_INIT static std::atomic<ForceState> global_state{
+      kUninitialized};
+  ForceState state = global_state.load(std::memory_order_relaxed);
+  if (ABSL_PREDICT_TRUE(state == kDontForce)) return false;
+
+  if (state == kUninitialized) {
+    state = ABSL_INTERNAL_C_SYMBOL(AbslContainerInternalSampleEverything)()
+                ? kForce
+                : kDontForce;
+    global_state.store(state, std::memory_order_relaxed);
+  }
+  return state == kForce;
+}
+
+HashtablezInfo* SampleSlow(int64_t* next_sample) {
+  if (ABSL_PREDICT_FALSE(ShouldForceSampling())) {
+    *next_sample = 1;
+    return HashtablezSampler::Global().Register();
+  }
+
+#if !defined(ABSL_INTERNAL_HASHTABLEZ_SAMPLE)
+  *next_sample = std::numeric_limits<int64_t>::max();
+  return nullptr;
+#else
+  bool first = *next_sample < 0;
+  *next_sample = g_exponential_biased_generator.GetStride(
+      g_hashtablez_sample_parameter.load(std::memory_order_relaxed));
+  // Small values of interval are equivalent to just sampling next time.
+  ABSL_ASSERT(*next_sample >= 1);
+
+  // g_hashtablez_enabled can be dynamically flipped, we need to set a threshold
+  // low enough that we will start sampling in a reasonable time, so we just use
+  // the default sampling rate.
+  if (!g_hashtablez_enabled.load(std::memory_order_relaxed)) return nullptr;
+
+  // We will only be negative on our first count, so we should just retry in
+  // that case.
+  if (first) {
+    if (ABSL_PREDICT_TRUE(--*next_sample > 0)) return nullptr;
+    return SampleSlow(next_sample);
+  }
+
+  return HashtablezSampler::Global().Register();
+#endif
+}
+
+void UnsampleSlow(HashtablezInfo* info) {
+  HashtablezSampler::Global().Unregister(info);
+}
+
+void RecordInsertSlow(HashtablezInfo* info, size_t hash,
+                      size_t distance_from_desired) {
+  // SwissTables probe in groups of 16, so scale this to count items probes and
+  // not offset from desired.
+  size_t probe_length = distance_from_desired;
+#if ABSL_INTERNAL_RAW_HASH_SET_HAVE_SSE2
+  probe_length /= 16;
+#else
+  probe_length /= 8;
+#endif
+
+  info->hashes_bitwise_and.fetch_and(hash, std::memory_order_relaxed);
+  info->hashes_bitwise_or.fetch_or(hash, std::memory_order_relaxed);
+  info->hashes_bitwise_xor.fetch_xor(hash, std::memory_order_relaxed);
+  info->max_probe_length.store(
+      std::max(info->max_probe_length.load(std::memory_order_relaxed),
+               probe_length),
+      std::memory_order_relaxed);
+  info->total_probe_length.fetch_add(probe_length, std::memory_order_relaxed);
+  info->size.fetch_add(1, std::memory_order_relaxed);
+}
+
+void SetHashtablezEnabled(bool enabled) {
+  g_hashtablez_enabled.store(enabled, std::memory_order_release);
+}
+
+void SetHashtablezSampleParameter(int32_t rate) {
+  if (rate > 0) {
+    g_hashtablez_sample_parameter.store(rate, std::memory_order_release);
+  } else {
+    ABSL_RAW_LOG(ERROR, "Invalid hashtablez sample rate: %lld",
+                 static_cast<long long>(rate));  // NOLINT(runtime/int)
+  }
+}
+
+void SetHashtablezMaxSamples(int32_t max) {
+  if (max > 0) {
+    g_hashtablez_max_samples.store(max, std::memory_order_release);
+  } else {
+    ABSL_RAW_LOG(ERROR, "Invalid hashtablez max samples: %lld",
+                 static_cast<long long>(max));  // NOLINT(runtime/int)
+  }
+}
+
+}  // namespace container_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
diff --git a/src/absl/container/internal/hashtablez_sampler.h b/src/absl/container/internal/hashtablez_sampler.h
new file mode 100644 (file)
index 0000000..85685f7
--- /dev/null
@@ -0,0 +1,322 @@
+// Copyright 2018 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// -----------------------------------------------------------------------------
+// File: hashtablez_sampler.h
+// -----------------------------------------------------------------------------
+//
+// This header file defines the API for a low level library to sample hashtables
+// and collect runtime statistics about them.
+//
+// `HashtablezSampler` controls the lifecycle of `HashtablezInfo` objects which
+// store information about a single sample.
+//
+// `Record*` methods store information into samples.
+// `Sample()` and `Unsample()` make use of a single global sampler with
+// properties controlled by the flags hashtablez_enabled,
+// hashtablez_sample_rate, and hashtablez_max_samples.
+//
+// WARNING
+//
+// Using this sampling API may cause sampled Swiss tables to use the global
+// allocator (operator `new`) in addition to any custom allocator.  If you
+// are using a table in an unusual circumstance where allocation or calling a
+// linux syscall is unacceptable, this could interfere.
+//
+// This utility is internal-only. Use at your own risk.
+
+#ifndef ABSL_CONTAINER_INTERNAL_HASHTABLEZ_SAMPLER_H_
+#define ABSL_CONTAINER_INTERNAL_HASHTABLEZ_SAMPLER_H_
+
+#include <atomic>
+#include <functional>
+#include <memory>
+#include <vector>
+
+#include "absl/base/internal/per_thread_tls.h"
+#include "absl/base/optimization.h"
+#include "absl/container/internal/have_sse.h"
+#include "absl/synchronization/mutex.h"
+#include "absl/utility/utility.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace container_internal {
+
+// Stores information about a sampled hashtable.  All mutations to this *must*
+// be made through `Record*` functions below.  All reads from this *must* only
+// occur in the callback to `HashtablezSampler::Iterate`.
+struct HashtablezInfo {
+  // Constructs the object but does not fill in any fields.
+  HashtablezInfo();
+  ~HashtablezInfo();
+  HashtablezInfo(const HashtablezInfo&) = delete;
+  HashtablezInfo& operator=(const HashtablezInfo&) = delete;
+
+  // Puts the object into a clean state, fills in the logically `const` members,
+  // blocking for any readers that are currently sampling the object.
+  void PrepareForSampling() ABSL_EXCLUSIVE_LOCKS_REQUIRED(init_mu);
+
+  // These fields are mutated by the various Record* APIs and need to be
+  // thread-safe.
+  std::atomic<size_t> capacity;
+  std::atomic<size_t> size;
+  std::atomic<size_t> num_erases;
+  std::atomic<size_t> num_rehashes;
+  std::atomic<size_t> max_probe_length;
+  std::atomic<size_t> total_probe_length;
+  std::atomic<size_t> hashes_bitwise_or;
+  std::atomic<size_t> hashes_bitwise_and;
+  std::atomic<size_t> hashes_bitwise_xor;
+
+  // `HashtablezSampler` maintains intrusive linked lists for all samples.  See
+  // comments on `HashtablezSampler::all_` for details on these.  `init_mu`
+  // guards the ability to restore the sample to a pristine state.  This
+  // prevents races with sampling and resurrecting an object.
+  absl::Mutex init_mu;
+  HashtablezInfo* next;
+  HashtablezInfo* dead ABSL_GUARDED_BY(init_mu);
+
+  // All of the fields below are set by `PrepareForSampling`, they must not be
+  // mutated in `Record*` functions.  They are logically `const` in that sense.
+  // These are guarded by init_mu, but that is not externalized to clients, who
+  // can only read them during `HashtablezSampler::Iterate` which will hold the
+  // lock.
+  static constexpr int kMaxStackDepth = 64;
+  absl::Time create_time;
+  int32_t depth;
+  void* stack[kMaxStackDepth];
+};
+
+inline void RecordRehashSlow(HashtablezInfo* info, size_t total_probe_length) {
+#if ABSL_INTERNAL_RAW_HASH_SET_HAVE_SSE2
+  total_probe_length /= 16;
+#else
+  total_probe_length /= 8;
+#endif
+  info->total_probe_length.store(total_probe_length, std::memory_order_relaxed);
+  info->num_erases.store(0, std::memory_order_relaxed);
+  // There is only one concurrent writer, so `load` then `store` is sufficient
+  // instead of using `fetch_add`.
+  info->num_rehashes.store(
+      1 + info->num_rehashes.load(std::memory_order_relaxed),
+      std::memory_order_relaxed);
+}
+
+inline void RecordStorageChangedSlow(HashtablezInfo* info, size_t size,
+                                     size_t capacity) {
+  info->size.store(size, std::memory_order_relaxed);
+  info->capacity.store(capacity, std::memory_order_relaxed);
+  if (size == 0) {
+    // This is a clear, reset the total/num_erases too.
+    info->total_probe_length.store(0, std::memory_order_relaxed);
+    info->num_erases.store(0, std::memory_order_relaxed);
+  }
+}
+
+void RecordInsertSlow(HashtablezInfo* info, size_t hash,
+                      size_t distance_from_desired);
+
+inline void RecordEraseSlow(HashtablezInfo* info) {
+  info->size.fetch_sub(1, std::memory_order_relaxed);
+  // There is only one concurrent writer, so `load` then `store` is sufficient
+  // instead of using `fetch_add`.
+  info->num_erases.store(
+      1 + info->num_erases.load(std::memory_order_relaxed),
+      std::memory_order_relaxed);
+}
+
+HashtablezInfo* SampleSlow(int64_t* next_sample);
+void UnsampleSlow(HashtablezInfo* info);
+
+#if defined(ABSL_INTERNAL_HASHTABLEZ_SAMPLE)
+#error ABSL_INTERNAL_HASHTABLEZ_SAMPLE cannot be directly set
+#endif  // defined(ABSL_INTERNAL_HASHTABLEZ_SAMPLE)
+
+#if defined(ABSL_INTERNAL_HASHTABLEZ_SAMPLE)
+class HashtablezInfoHandle {
+ public:
+  explicit HashtablezInfoHandle() : info_(nullptr) {}
+  explicit HashtablezInfoHandle(HashtablezInfo* info) : info_(info) {}
+  ~HashtablezInfoHandle() {
+    if (ABSL_PREDICT_TRUE(info_ == nullptr)) return;
+    UnsampleSlow(info_);
+  }
+
+  HashtablezInfoHandle(const HashtablezInfoHandle&) = delete;
+  HashtablezInfoHandle& operator=(const HashtablezInfoHandle&) = delete;
+
+  HashtablezInfoHandle(HashtablezInfoHandle&& o) noexcept
+      : info_(absl::exchange(o.info_, nullptr)) {}
+  HashtablezInfoHandle& operator=(HashtablezInfoHandle&& o) noexcept {
+    if (ABSL_PREDICT_FALSE(info_ != nullptr)) {
+      UnsampleSlow(info_);
+    }
+    info_ = absl::exchange(o.info_, nullptr);
+    return *this;
+  }
+
+  inline void RecordStorageChanged(size_t size, size_t capacity) {
+    if (ABSL_PREDICT_TRUE(info_ == nullptr)) return;
+    RecordStorageChangedSlow(info_, size, capacity);
+  }
+
+  inline void RecordRehash(size_t total_probe_length) {
+    if (ABSL_PREDICT_TRUE(info_ == nullptr)) return;
+    RecordRehashSlow(info_, total_probe_length);
+  }
+
+  inline void RecordInsert(size_t hash, size_t distance_from_desired) {
+    if (ABSL_PREDICT_TRUE(info_ == nullptr)) return;
+    RecordInsertSlow(info_, hash, distance_from_desired);
+  }
+
+  inline void RecordErase() {
+    if (ABSL_PREDICT_TRUE(info_ == nullptr)) return;
+    RecordEraseSlow(info_);
+  }
+
+  friend inline void swap(HashtablezInfoHandle& lhs,
+                          HashtablezInfoHandle& rhs) {
+    std::swap(lhs.info_, rhs.info_);
+  }
+
+ private:
+  friend class HashtablezInfoHandlePeer;
+  HashtablezInfo* info_;
+};
+#else
+// Ensure that when Hashtablez is turned off at compile time, HashtablezInfo can
+// be removed by the linker, in order to reduce the binary size.
+class HashtablezInfoHandle {
+ public:
+  explicit HashtablezInfoHandle() = default;
+  explicit HashtablezInfoHandle(std::nullptr_t) {}
+
+  inline void RecordStorageChanged(size_t /*size*/, size_t /*capacity*/) {}
+  inline void RecordRehash(size_t /*total_probe_length*/) {}
+  inline void RecordInsert(size_t /*hash*/, size_t /*distance_from_desired*/) {}
+  inline void RecordErase() {}
+
+  friend inline void swap(HashtablezInfoHandle& /*lhs*/,
+                          HashtablezInfoHandle& /*rhs*/) {}
+};
+#endif  // defined(ABSL_INTERNAL_HASHTABLEZ_SAMPLE)
+
+#if defined(ABSL_INTERNAL_HASHTABLEZ_SAMPLE)
+extern ABSL_PER_THREAD_TLS_KEYWORD int64_t global_next_sample;
+#endif  // defined(ABSL_INTERNAL_HASHTABLEZ_SAMPLE)
+
+// Returns an RAII sampling handle that manages registration and unregistation
+// with the global sampler.
+inline HashtablezInfoHandle Sample() {
+#if defined(ABSL_INTERNAL_HASHTABLEZ_SAMPLE)
+  if (ABSL_PREDICT_TRUE(--global_next_sample > 0)) {
+    return HashtablezInfoHandle(nullptr);
+  }
+  return HashtablezInfoHandle(SampleSlow(&global_next_sample));
+#else
+  return HashtablezInfoHandle(nullptr);
+#endif  // !ABSL_PER_THREAD_TLS
+}
+
+// Holds samples and their associated stack traces with a soft limit of
+// `SetHashtablezMaxSamples()`.
+//
+// Thread safe.
+class HashtablezSampler {
+ public:
+  // Returns a global Sampler.
+  static HashtablezSampler& Global();
+
+  HashtablezSampler();
+  ~HashtablezSampler();
+
+  // Registers for sampling.  Returns an opaque registration info.
+  HashtablezInfo* Register();
+
+  // Unregisters the sample.
+  void Unregister(HashtablezInfo* sample);
+
+  // The dispose callback will be called on all samples the moment they are
+  // being unregistered. Only affects samples that are unregistered after the
+  // callback has been set.
+  // Returns the previous callback.
+  using DisposeCallback = void (*)(const HashtablezInfo&);
+  DisposeCallback SetDisposeCallback(DisposeCallback f);
+
+  // Iterates over all the registered `StackInfo`s.  Returning the number of
+  // samples that have been dropped.
+  int64_t Iterate(const std::function<void(const HashtablezInfo& stack)>& f);
+
+ private:
+  void PushNew(HashtablezInfo* sample);
+  void PushDead(HashtablezInfo* sample);
+  HashtablezInfo* PopDead();
+
+  std::atomic<size_t> dropped_samples_;
+  std::atomic<size_t> size_estimate_;
+
+  // Intrusive lock free linked lists for tracking samples.
+  //
+  // `all_` records all samples (they are never removed from this list) and is
+  // terminated with a `nullptr`.
+  //
+  // `graveyard_.dead` is a circular linked list.  When it is empty,
+  // `graveyard_.dead == &graveyard`.  The list is circular so that
+  // every item on it (even the last) has a non-null dead pointer.  This allows
+  // `Iterate` to determine if a given sample is live or dead using only
+  // information on the sample itself.
+  //
+  // For example, nodes [A, B, C, D, E] with [A, C, E] alive and [B, D] dead
+  // looks like this (G is the Graveyard):
+  //
+  //           +---+    +---+    +---+    +---+    +---+
+  //    all -->| A |--->| B |--->| C |--->| D |--->| E |
+  //           |   |    |   |    |   |    |   |    |   |
+  //   +---+   |   | +->|   |-+  |   | +->|   |-+  |   |
+  //   | G |   +---+ |  +---+ |  +---+ |  +---+ |  +---+
+  //   |   |         |        |        |        |
+  //   |   | --------+        +--------+        |
+  //   +---+                                    |
+  //     ^                                      |
+  //     +--------------------------------------+
+  //
+  std::atomic<HashtablezInfo*> all_;
+  HashtablezInfo graveyard_;
+
+  std::atomic<DisposeCallback> dispose_;
+};
+
+// Enables or disables sampling for Swiss tables.
+void SetHashtablezEnabled(bool enabled);
+
+// Sets the rate at which Swiss tables will be sampled.
+void SetHashtablezSampleParameter(int32_t rate);
+
+// Sets a soft max for the number of samples that will be kept.
+void SetHashtablezMaxSamples(int32_t max);
+
+// Configuration override.
+// This allows process-wide sampling without depending on order of
+// initialization of static storage duration objects.
+// The definition of this constant is weak, which allows us to inject a
+// different value for it at link time.
+extern "C" bool ABSL_INTERNAL_C_SYMBOL(AbslContainerInternalSampleEverything)();
+
+}  // namespace container_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#endif  // ABSL_CONTAINER_INTERNAL_HASHTABLEZ_SAMPLER_H_
diff --git a/src/absl/container/internal/hashtablez_sampler_force_weak_definition.cc b/src/absl/container/internal/hashtablez_sampler_force_weak_definition.cc
new file mode 100644 (file)
index 0000000..ed35a7e
--- /dev/null
@@ -0,0 +1,31 @@
+// Copyright 2018 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "absl/container/internal/hashtablez_sampler.h"
+
+#include "absl/base/attributes.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace container_internal {
+
+// See hashtablez_sampler.h for details.
+extern "C" ABSL_ATTRIBUTE_WEAK bool ABSL_INTERNAL_C_SYMBOL(
+    AbslContainerInternalSampleEverything)() {
+  return false;
+}
+
+}  // namespace container_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
diff --git a/src/absl/container/internal/have_sse.h b/src/absl/container/internal/have_sse.h
new file mode 100644 (file)
index 0000000..e75e1a1
--- /dev/null
@@ -0,0 +1,50 @@
+// Copyright 2018 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// Shared config probing for SSE instructions used in Swiss tables.
+#ifndef ABSL_CONTAINER_INTERNAL_HAVE_SSE_H_
+#define ABSL_CONTAINER_INTERNAL_HAVE_SSE_H_
+
+#ifndef ABSL_INTERNAL_RAW_HASH_SET_HAVE_SSE2
+#if defined(__SSE2__) ||  \
+    (defined(_MSC_VER) && \
+     (defined(_M_X64) || (defined(_M_IX86) && _M_IX86_FP >= 2)))
+#define ABSL_INTERNAL_RAW_HASH_SET_HAVE_SSE2 1
+#else
+#define ABSL_INTERNAL_RAW_HASH_SET_HAVE_SSE2 0
+#endif
+#endif
+
+#ifndef ABSL_INTERNAL_RAW_HASH_SET_HAVE_SSSE3
+#ifdef __SSSE3__
+#define ABSL_INTERNAL_RAW_HASH_SET_HAVE_SSSE3 1
+#else
+#define ABSL_INTERNAL_RAW_HASH_SET_HAVE_SSSE3 0
+#endif
+#endif
+
+#if ABSL_INTERNAL_RAW_HASH_SET_HAVE_SSSE3 && \
+    !ABSL_INTERNAL_RAW_HASH_SET_HAVE_SSE2
+#error "Bad configuration!"
+#endif
+
+#if ABSL_INTERNAL_RAW_HASH_SET_HAVE_SSE2
+#include <emmintrin.h>
+#endif
+
+#if ABSL_INTERNAL_RAW_HASH_SET_HAVE_SSSE3
+#include <tmmintrin.h>
+#endif
+
+#endif  // ABSL_CONTAINER_INTERNAL_HAVE_SSE_H_
diff --git a/src/absl/container/internal/inlined_vector.h b/src/absl/container/internal/inlined_vector.h
new file mode 100644 (file)
index 0000000..b1b3649
--- /dev/null
@@ -0,0 +1,967 @@
+// Copyright 2019 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef ABSL_CONTAINER_INTERNAL_INLINED_VECTOR_INTERNAL_H_
+#define ABSL_CONTAINER_INTERNAL_INLINED_VECTOR_INTERNAL_H_
+
+#include <algorithm>
+#include <cstddef>
+#include <cstring>
+#include <iterator>
+#include <limits>
+#include <memory>
+#include <utility>
+
+#include "absl/base/macros.h"
+#include "absl/container/internal/compressed_tuple.h"
+#include "absl/memory/memory.h"
+#include "absl/meta/type_traits.h"
+#include "absl/types/span.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace inlined_vector_internal {
+
+// GCC does not deal very well with the below code
+// #if !defined(__clang__) && defined(__GNUC__)
+// #pragma GCC diagnostic push
+// #pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
+// #endif
+
+template <typename Iterator>
+using IsAtLeastForwardIterator = std::is_convertible<
+    typename std::iterator_traits<Iterator>::iterator_category,
+    std::forward_iterator_tag>;
+
+template <typename AllocatorType,
+          typename ValueType =
+              typename absl::allocator_traits<AllocatorType>::value_type>
+using IsMemcpyOk =
+    absl::conjunction<std::is_same<AllocatorType, std::allocator<ValueType>>,
+                      absl::is_trivially_copy_constructible<ValueType>,
+                      absl::is_trivially_copy_assignable<ValueType>,
+                      absl::is_trivially_destructible<ValueType>>;
+
+template <typename AllocatorType, typename Pointer, typename SizeType>
+void DestroyElements(AllocatorType* alloc_ptr, Pointer destroy_first,
+                     SizeType destroy_size) {
+  using AllocatorTraits = absl::allocator_traits<AllocatorType>;
+
+  if (destroy_first != nullptr) {
+    for (auto i = destroy_size; i != 0;) {
+      --i;
+      AllocatorTraits::destroy(*alloc_ptr, destroy_first + i);
+    }
+
+#if !defined(NDEBUG)
+    {
+      using ValueType = typename AllocatorTraits::value_type;
+
+      // Overwrite unused memory with `0xab` so we can catch uninitialized
+      // usage.
+      //
+      // Cast to `void*` to tell the compiler that we don't care that we might
+      // be scribbling on a vtable pointer.
+      void* memory_ptr = destroy_first;
+      auto memory_size = destroy_size * sizeof(ValueType);
+      std::memset(memory_ptr, 0xab, memory_size);
+    }
+#endif  // !defined(NDEBUG)
+  }
+}
+
+// If kUseMemcpy is true, memcpy(dst, src, n); else do nothing.
+// Useful to avoid compiler warnings when memcpy() is used for T values
+// that are not trivially copyable in non-reachable code.
+template <bool kUseMemcpy>
+inline void MemcpyIfAllowed(void* dst, const void* src, size_t n);
+
+// memcpy when allowed.
+template <>
+inline void MemcpyIfAllowed<true>(void* dst, const void* src, size_t n) {
+  memcpy(dst, src, n);
+}
+
+// Do nothing for types that are not memcpy-able. This function is only
+// called from non-reachable branches.
+template <>
+inline void MemcpyIfAllowed<false>(void*, const void*, size_t) {}
+
+template <typename AllocatorType, typename Pointer, typename ValueAdapter,
+          typename SizeType>
+void ConstructElements(AllocatorType* alloc_ptr, Pointer construct_first,
+                       ValueAdapter* values_ptr, SizeType construct_size) {
+  for (SizeType i = 0; i < construct_size; ++i) {
+    ABSL_INTERNAL_TRY {
+      values_ptr->ConstructNext(alloc_ptr, construct_first + i);
+    }
+    ABSL_INTERNAL_CATCH_ANY {
+      inlined_vector_internal::DestroyElements(alloc_ptr, construct_first, i);
+      ABSL_INTERNAL_RETHROW;
+    }
+  }
+}
+
+template <typename Pointer, typename ValueAdapter, typename SizeType>
+void AssignElements(Pointer assign_first, ValueAdapter* values_ptr,
+                    SizeType assign_size) {
+  for (SizeType i = 0; i < assign_size; ++i) {
+    values_ptr->AssignNext(assign_first + i);
+  }
+}
+
+template <typename AllocatorType>
+struct StorageView {
+  using AllocatorTraits = absl::allocator_traits<AllocatorType>;
+  using Pointer = typename AllocatorTraits::pointer;
+  using SizeType = typename AllocatorTraits::size_type;
+
+  Pointer data;
+  SizeType size;
+  SizeType capacity;
+};
+
+template <typename AllocatorType, typename Iterator>
+class IteratorValueAdapter {
+  using AllocatorTraits = absl::allocator_traits<AllocatorType>;
+  using Pointer = typename AllocatorTraits::pointer;
+
+ public:
+  explicit IteratorValueAdapter(const Iterator& it) : it_(it) {}
+
+  void ConstructNext(AllocatorType* alloc_ptr, Pointer construct_at) {
+    AllocatorTraits::construct(*alloc_ptr, construct_at, *it_);
+    ++it_;
+  }
+
+  void AssignNext(Pointer assign_at) {
+    *assign_at = *it_;
+    ++it_;
+  }
+
+ private:
+  Iterator it_;
+};
+
+template <typename AllocatorType>
+class CopyValueAdapter {
+  using AllocatorTraits = absl::allocator_traits<AllocatorType>;
+  using ValueType = typename AllocatorTraits::value_type;
+  using Pointer = typename AllocatorTraits::pointer;
+  using ConstPointer = typename AllocatorTraits::const_pointer;
+
+ public:
+  explicit CopyValueAdapter(const ValueType& v) : ptr_(std::addressof(v)) {}
+
+  void ConstructNext(AllocatorType* alloc_ptr, Pointer construct_at) {
+    AllocatorTraits::construct(*alloc_ptr, construct_at, *ptr_);
+  }
+
+  void AssignNext(Pointer assign_at) { *assign_at = *ptr_; }
+
+ private:
+  ConstPointer ptr_;
+};
+
+template <typename AllocatorType>
+class DefaultValueAdapter {
+  using AllocatorTraits = absl::allocator_traits<AllocatorType>;
+  using ValueType = typename AllocatorTraits::value_type;
+  using Pointer = typename AllocatorTraits::pointer;
+
+ public:
+  explicit DefaultValueAdapter() {}
+
+  void ConstructNext(AllocatorType* alloc_ptr, Pointer construct_at) {
+    AllocatorTraits::construct(*alloc_ptr, construct_at);
+  }
+
+  void AssignNext(Pointer assign_at) { *assign_at = ValueType(); }
+};
+
+template <typename AllocatorType>
+class AllocationTransaction {
+  using AllocatorTraits = absl::allocator_traits<AllocatorType>;
+  using Pointer = typename AllocatorTraits::pointer;
+  using SizeType = typename AllocatorTraits::size_type;
+
+ public:
+  explicit AllocationTransaction(AllocatorType* alloc_ptr)
+      : alloc_data_(*alloc_ptr, nullptr) {}
+
+  ~AllocationTransaction() {
+    if (DidAllocate()) {
+      AllocatorTraits::deallocate(GetAllocator(), GetData(), GetCapacity());
+    }
+  }
+
+  AllocationTransaction(const AllocationTransaction&) = delete;
+  void operator=(const AllocationTransaction&) = delete;
+
+  AllocatorType& GetAllocator() { return alloc_data_.template get<0>(); }
+  Pointer& GetData() { return alloc_data_.template get<1>(); }
+  SizeType& GetCapacity() { return capacity_; }
+
+  bool DidAllocate() { return GetData() != nullptr; }
+  Pointer Allocate(SizeType capacity) {
+    GetData() = AllocatorTraits::allocate(GetAllocator(), capacity);
+    GetCapacity() = capacity;
+    return GetData();
+  }
+
+  void Reset() {
+    GetData() = nullptr;
+    GetCapacity() = 0;
+  }
+
+ private:
+  container_internal::CompressedTuple<AllocatorType, Pointer> alloc_data_;
+  SizeType capacity_ = 0;
+};
+
+template <typename AllocatorType>
+class ConstructionTransaction {
+  using AllocatorTraits = absl::allocator_traits<AllocatorType>;
+  using Pointer = typename AllocatorTraits::pointer;
+  using SizeType = typename AllocatorTraits::size_type;
+
+ public:
+  explicit ConstructionTransaction(AllocatorType* alloc_ptr)
+      : alloc_data_(*alloc_ptr, nullptr) {}
+
+  ~ConstructionTransaction() {
+    if (DidConstruct()) {
+      inlined_vector_internal::DestroyElements(std::addressof(GetAllocator()),
+                                               GetData(), GetSize());
+    }
+  }
+
+  ConstructionTransaction(const ConstructionTransaction&) = delete;
+  void operator=(const ConstructionTransaction&) = delete;
+
+  AllocatorType& GetAllocator() { return alloc_data_.template get<0>(); }
+  Pointer& GetData() { return alloc_data_.template get<1>(); }
+  SizeType& GetSize() { return size_; }
+
+  bool DidConstruct() { return GetData() != nullptr; }
+  template <typename ValueAdapter>
+  void Construct(Pointer data, ValueAdapter* values_ptr, SizeType size) {
+    inlined_vector_internal::ConstructElements(std::addressof(GetAllocator()),
+                                               data, values_ptr, size);
+    GetData() = data;
+    GetSize() = size;
+  }
+  void Commit() {
+    GetData() = nullptr;
+    GetSize() = 0;
+  }
+
+ private:
+  container_internal::CompressedTuple<AllocatorType, Pointer> alloc_data_;
+  SizeType size_ = 0;
+};
+
+template <typename T, size_t N, typename A>
+class Storage {
+ public:
+  using AllocatorTraits = absl::allocator_traits<A>;
+  using allocator_type = typename AllocatorTraits::allocator_type;
+  using value_type = typename AllocatorTraits::value_type;
+  using pointer = typename AllocatorTraits::pointer;
+  using const_pointer = typename AllocatorTraits::const_pointer;
+  using size_type = typename AllocatorTraits::size_type;
+  using difference_type = typename AllocatorTraits::difference_type;
+
+  using reference = value_type&;
+  using const_reference = const value_type&;
+  using RValueReference = value_type&&;
+  using iterator = pointer;
+  using const_iterator = const_pointer;
+  using reverse_iterator = std::reverse_iterator<iterator>;
+  using const_reverse_iterator = std::reverse_iterator<const_iterator>;
+  using MoveIterator = std::move_iterator<iterator>;
+  using IsMemcpyOk = inlined_vector_internal::IsMemcpyOk<allocator_type>;
+
+  using StorageView = inlined_vector_internal::StorageView<allocator_type>;
+
+  template <typename Iterator>
+  using IteratorValueAdapter =
+      inlined_vector_internal::IteratorValueAdapter<allocator_type, Iterator>;
+  using CopyValueAdapter =
+      inlined_vector_internal::CopyValueAdapter<allocator_type>;
+  using DefaultValueAdapter =
+      inlined_vector_internal::DefaultValueAdapter<allocator_type>;
+
+  using AllocationTransaction =
+      inlined_vector_internal::AllocationTransaction<allocator_type>;
+  using ConstructionTransaction =
+      inlined_vector_internal::ConstructionTransaction<allocator_type>;
+
+  static size_type NextCapacity(size_type current_capacity) {
+    return current_capacity * 2;
+  }
+
+  static size_type ComputeCapacity(size_type current_capacity,
+                                   size_type requested_capacity) {
+    return (std::max)(NextCapacity(current_capacity), requested_capacity);
+  }
+
+  // ---------------------------------------------------------------------------
+  // Storage Constructors and Destructor
+  // ---------------------------------------------------------------------------
+
+  Storage() : metadata_(allocator_type(), /* size and is_allocated */ 0) {}
+
+  explicit Storage(const allocator_type& alloc)
+      : metadata_(alloc, /* size and is_allocated */ 0) {}
+
+  ~Storage() {
+    if (GetSizeAndIsAllocated() == 0) {
+      // Empty and not allocated; nothing to do.
+    } else if (IsMemcpyOk::value) {
+      // No destructors need to be run; just deallocate if necessary.
+      DeallocateIfAllocated();
+    } else {
+      DestroyContents();
+    }
+  }
+
+  // ---------------------------------------------------------------------------
+  // Storage Member Accessors
+  // ---------------------------------------------------------------------------
+
+  size_type& GetSizeAndIsAllocated() { return metadata_.template get<1>(); }
+
+  const size_type& GetSizeAndIsAllocated() const {
+    return metadata_.template get<1>();
+  }
+
+  size_type GetSize() const { return GetSizeAndIsAllocated() >> 1; }
+
+  bool GetIsAllocated() const { return GetSizeAndIsAllocated() & 1; }
+
+  pointer GetAllocatedData() { return data_.allocated.allocated_data; }
+
+  const_pointer GetAllocatedData() const {
+    return data_.allocated.allocated_data;
+  }
+
+  pointer GetInlinedData() {
+    return reinterpret_cast<pointer>(
+        std::addressof(data_.inlined.inlined_data[0]));
+  }
+
+  const_pointer GetInlinedData() const {
+    return reinterpret_cast<const_pointer>(
+        std::addressof(data_.inlined.inlined_data[0]));
+  }
+
+  size_type GetAllocatedCapacity() const {
+    return data_.allocated.allocated_capacity;
+  }
+
+  size_type GetInlinedCapacity() const { return static_cast<size_type>(N); }
+
+  StorageView MakeStorageView() {
+    return GetIsAllocated()
+               ? StorageView{GetAllocatedData(), GetSize(),
+                             GetAllocatedCapacity()}
+               : StorageView{GetInlinedData(), GetSize(), GetInlinedCapacity()};
+  }
+
+  allocator_type* GetAllocPtr() {
+    return std::addressof(metadata_.template get<0>());
+  }
+
+  const allocator_type* GetAllocPtr() const {
+    return std::addressof(metadata_.template get<0>());
+  }
+
+  // ---------------------------------------------------------------------------
+  // Storage Member Mutators
+  // ---------------------------------------------------------------------------
+
+  ABSL_ATTRIBUTE_NOINLINE void InitFrom(const Storage& other);
+
+  template <typename ValueAdapter>
+  void Initialize(ValueAdapter values, size_type new_size);
+
+  template <typename ValueAdapter>
+  void Assign(ValueAdapter values, size_type new_size);
+
+  template <typename ValueAdapter>
+  void Resize(ValueAdapter values, size_type new_size);
+
+  template <typename ValueAdapter>
+  iterator Insert(const_iterator pos, ValueAdapter values,
+                  size_type insert_count);
+
+  template <typename... Args>
+  reference EmplaceBack(Args&&... args);
+
+  iterator Erase(const_iterator from, const_iterator to);
+
+  void Reserve(size_type requested_capacity);
+
+  void ShrinkToFit();
+
+  void Swap(Storage* other_storage_ptr);
+
+  void SetIsAllocated() {
+    GetSizeAndIsAllocated() |= static_cast<size_type>(1);
+  }
+
+  void UnsetIsAllocated() {
+    GetSizeAndIsAllocated() &= ((std::numeric_limits<size_type>::max)() - 1);
+  }
+
+  void SetSize(size_type size) {
+    GetSizeAndIsAllocated() =
+        (size << 1) | static_cast<size_type>(GetIsAllocated());
+  }
+
+  void SetAllocatedSize(size_type size) {
+    GetSizeAndIsAllocated() = (size << 1) | static_cast<size_type>(1);
+  }
+
+  void SetInlinedSize(size_type size) {
+    GetSizeAndIsAllocated() = size << static_cast<size_type>(1);
+  }
+
+  void AddSize(size_type count) {
+    GetSizeAndIsAllocated() += count << static_cast<size_type>(1);
+  }
+
+  void SubtractSize(size_type count) {
+    assert(count <= GetSize());
+
+    GetSizeAndIsAllocated() -= count << static_cast<size_type>(1);
+  }
+
+  void SetAllocatedData(pointer data, size_type capacity) {
+    data_.allocated.allocated_data = data;
+    data_.allocated.allocated_capacity = capacity;
+  }
+
+  void AcquireAllocatedData(AllocationTransaction* allocation_tx_ptr) {
+    SetAllocatedData(allocation_tx_ptr->GetData(),
+                     allocation_tx_ptr->GetCapacity());
+
+    allocation_tx_ptr->Reset();
+  }
+
+  void MemcpyFrom(const Storage& other_storage) {
+    assert(IsMemcpyOk::value || other_storage.GetIsAllocated());
+
+    GetSizeAndIsAllocated() = other_storage.GetSizeAndIsAllocated();
+    data_ = other_storage.data_;
+  }
+
+  void DeallocateIfAllocated() {
+    if (GetIsAllocated()) {
+      AllocatorTraits::deallocate(*GetAllocPtr(), GetAllocatedData(),
+                                  GetAllocatedCapacity());
+    }
+  }
+
+ private:
+  ABSL_ATTRIBUTE_NOINLINE void DestroyContents();
+
+  using Metadata =
+      container_internal::CompressedTuple<allocator_type, size_type>;
+
+  struct Allocated {
+    pointer allocated_data;
+    size_type allocated_capacity;
+  };
+
+  struct Inlined {
+    alignas(value_type) char inlined_data[sizeof(value_type[N])];
+  };
+
+  union Data {
+    Allocated allocated;
+    Inlined inlined;
+  };
+
+  template <typename... Args>
+  ABSL_ATTRIBUTE_NOINLINE reference EmplaceBackSlow(Args&&... args);
+
+  Metadata metadata_;
+  Data data_;
+};
+
+template <typename T, size_t N, typename A>
+void Storage<T, N, A>::DestroyContents() {
+  pointer data = GetIsAllocated() ? GetAllocatedData() : GetInlinedData();
+  inlined_vector_internal::DestroyElements(GetAllocPtr(), data, GetSize());
+  DeallocateIfAllocated();
+}
+
+template <typename T, size_t N, typename A>
+void Storage<T, N, A>::InitFrom(const Storage& other) {
+  const auto n = other.GetSize();
+  assert(n > 0);  // Empty sources handled handled in caller.
+  const_pointer src;
+  pointer dst;
+  if (!other.GetIsAllocated()) {
+    dst = GetInlinedData();
+    src = other.GetInlinedData();
+  } else {
+    // Because this is only called from the `InlinedVector` constructors, it's
+    // safe to take on the allocation with size `0`. If `ConstructElements(...)`
+    // throws, deallocation will be automatically handled by `~Storage()`.
+    size_type new_capacity = ComputeCapacity(GetInlinedCapacity(), n);
+    dst = AllocatorTraits::allocate(*GetAllocPtr(), new_capacity);
+    SetAllocatedData(dst, new_capacity);
+    src = other.GetAllocatedData();
+  }
+  if (IsMemcpyOk::value) {
+    MemcpyIfAllowed<IsMemcpyOk::value>(dst, src, sizeof(dst[0]) * n);
+  } else {
+    auto values = IteratorValueAdapter<const_pointer>(src);
+    inlined_vector_internal::ConstructElements(GetAllocPtr(), dst, &values, n);
+  }
+  GetSizeAndIsAllocated() = other.GetSizeAndIsAllocated();
+}
+
+template <typename T, size_t N, typename A>
+template <typename ValueAdapter>
+auto Storage<T, N, A>::Initialize(ValueAdapter values, size_type new_size)
+    -> void {
+  // Only callable from constructors!
+  assert(!GetIsAllocated());
+  assert(GetSize() == 0);
+
+  pointer construct_data;
+  if (new_size > GetInlinedCapacity()) {
+    // Because this is only called from the `InlinedVector` constructors, it's
+    // safe to take on the allocation with size `0`. If `ConstructElements(...)`
+    // throws, deallocation will be automatically handled by `~Storage()`.
+    size_type new_capacity = ComputeCapacity(GetInlinedCapacity(), new_size);
+    construct_data = AllocatorTraits::allocate(*GetAllocPtr(), new_capacity);
+    SetAllocatedData(construct_data, new_capacity);
+    SetIsAllocated();
+  } else {
+    construct_data = GetInlinedData();
+  }
+
+  inlined_vector_internal::ConstructElements(GetAllocPtr(), construct_data,
+                                             &values, new_size);
+
+  // Since the initial size was guaranteed to be `0` and the allocated bit is
+  // already correct for either case, *adding* `new_size` gives us the correct
+  // result faster than setting it directly.
+  AddSize(new_size);
+}
+
+template <typename T, size_t N, typename A>
+template <typename ValueAdapter>
+auto Storage<T, N, A>::Assign(ValueAdapter values, size_type new_size) -> void {
+  StorageView storage_view = MakeStorageView();
+
+  AllocationTransaction allocation_tx(GetAllocPtr());
+
+  absl::Span<value_type> assign_loop;
+  absl::Span<value_type> construct_loop;
+  absl::Span<value_type> destroy_loop;
+
+  if (new_size > storage_view.capacity) {
+    size_type new_capacity = ComputeCapacity(storage_view.capacity, new_size);
+    construct_loop = {allocation_tx.Allocate(new_capacity), new_size};
+    destroy_loop = {storage_view.data, storage_view.size};
+  } else if (new_size > storage_view.size) {
+    assign_loop = {storage_view.data, storage_view.size};
+    construct_loop = {storage_view.data + storage_view.size,
+                      new_size - storage_view.size};
+  } else {
+    assign_loop = {storage_view.data, new_size};
+    destroy_loop = {storage_view.data + new_size, storage_view.size - new_size};
+  }
+
+  inlined_vector_internal::AssignElements(assign_loop.data(), &values,
+                                          assign_loop.size());
+
+  inlined_vector_internal::ConstructElements(
+      GetAllocPtr(), construct_loop.data(), &values, construct_loop.size());
+
+  inlined_vector_internal::DestroyElements(GetAllocPtr(), destroy_loop.data(),
+                                           destroy_loop.size());
+
+  if (allocation_tx.DidAllocate()) {
+    DeallocateIfAllocated();
+    AcquireAllocatedData(&allocation_tx);
+    SetIsAllocated();
+  }
+
+  SetSize(new_size);
+}
+
+template <typename T, size_t N, typename A>
+template <typename ValueAdapter>
+auto Storage<T, N, A>::Resize(ValueAdapter values, size_type new_size) -> void {
+  StorageView storage_view = MakeStorageView();
+  auto* const base = storage_view.data;
+  const size_type size = storage_view.size;
+  auto* alloc = GetAllocPtr();
+  if (new_size <= size) {
+    // Destroy extra old elements.
+    inlined_vector_internal::DestroyElements(alloc, base + new_size,
+                                             size - new_size);
+  } else if (new_size <= storage_view.capacity) {
+    // Construct new elements in place.
+    inlined_vector_internal::ConstructElements(alloc, base + size, &values,
+                                               new_size - size);
+  } else {
+    // Steps:
+    //  a. Allocate new backing store.
+    //  b. Construct new elements in new backing store.
+    //  c. Move existing elements from old backing store to now.
+    //  d. Destroy all elements in old backing store.
+    // Use transactional wrappers for the first two steps so we can roll
+    // back if necessary due to exceptions.
+    AllocationTransaction allocation_tx(alloc);
+    size_type new_capacity = ComputeCapacity(storage_view.capacity, new_size);
+    pointer new_data = allocation_tx.Allocate(new_capacity);
+
+    ConstructionTransaction construction_tx(alloc);
+    construction_tx.Construct(new_data + size, &values, new_size - size);
+
+    IteratorValueAdapter<MoveIterator> move_values((MoveIterator(base)));
+    inlined_vector_internal::ConstructElements(alloc, new_data, &move_values,
+                                               size);
+
+    inlined_vector_internal::DestroyElements(alloc, base, size);
+    construction_tx.Commit();
+    DeallocateIfAllocated();
+    AcquireAllocatedData(&allocation_tx);
+    SetIsAllocated();
+  }
+  SetSize(new_size);
+}
+
+template <typename T, size_t N, typename A>
+template <typename ValueAdapter>
+auto Storage<T, N, A>::Insert(const_iterator pos, ValueAdapter values,
+                              size_type insert_count) -> iterator {
+  StorageView storage_view = MakeStorageView();
+
+  size_type insert_index =
+      std::distance(const_iterator(storage_view.data), pos);
+  size_type insert_end_index = insert_index + insert_count;
+  size_type new_size = storage_view.size + insert_count;
+
+  if (new_size > storage_view.capacity) {
+    AllocationTransaction allocation_tx(GetAllocPtr());
+    ConstructionTransaction construction_tx(GetAllocPtr());
+    ConstructionTransaction move_construciton_tx(GetAllocPtr());
+
+    IteratorValueAdapter<MoveIterator> move_values(
+        MoveIterator(storage_view.data));
+
+    size_type new_capacity = ComputeCapacity(storage_view.capacity, new_size);
+    pointer new_data = allocation_tx.Allocate(new_capacity);
+
+    construction_tx.Construct(new_data + insert_index, &values, insert_count);
+
+    move_construciton_tx.Construct(new_data, &move_values, insert_index);
+
+    inlined_vector_internal::ConstructElements(
+        GetAllocPtr(), new_data + insert_end_index, &move_values,
+        storage_view.size - insert_index);
+
+    inlined_vector_internal::DestroyElements(GetAllocPtr(), storage_view.data,
+                                             storage_view.size);
+
+    construction_tx.Commit();
+    move_construciton_tx.Commit();
+    DeallocateIfAllocated();
+    AcquireAllocatedData(&allocation_tx);
+
+    SetAllocatedSize(new_size);
+    return iterator(new_data + insert_index);
+  } else {
+    size_type move_construction_destination_index =
+        (std::max)(insert_end_index, storage_view.size);
+
+    ConstructionTransaction move_construction_tx(GetAllocPtr());
+
+    IteratorValueAdapter<MoveIterator> move_construction_values(
+        MoveIterator(storage_view.data +
+                     (move_construction_destination_index - insert_count)));
+    absl::Span<value_type> move_construction = {
+        storage_view.data + move_construction_destination_index,
+        new_size - move_construction_destination_index};
+
+    pointer move_assignment_values = storage_view.data + insert_index;
+    absl::Span<value_type> move_assignment = {
+        storage_view.data + insert_end_index,
+        move_construction_destination_index - insert_end_index};
+
+    absl::Span<value_type> insert_assignment = {move_assignment_values,
+                                                move_construction.size()};
+
+    absl::Span<value_type> insert_construction = {
+        insert_assignment.data() + insert_assignment.size(),
+        insert_count - insert_assignment.size()};
+
+    move_construction_tx.Construct(move_construction.data(),
+                                   &move_construction_values,
+                                   move_construction.size());
+
+    for (pointer destination = move_assignment.data() + move_assignment.size(),
+                 last_destination = move_assignment.data(),
+                 source = move_assignment_values + move_assignment.size();
+         ;) {
+      --destination;
+      --source;
+      if (destination < last_destination) break;
+      *destination = std::move(*source);
+    }
+
+    inlined_vector_internal::AssignElements(insert_assignment.data(), &values,
+                                            insert_assignment.size());
+
+    inlined_vector_internal::ConstructElements(
+        GetAllocPtr(), insert_construction.data(), &values,
+        insert_construction.size());
+
+    move_construction_tx.Commit();
+
+    AddSize(insert_count);
+    return iterator(storage_view.data + insert_index);
+  }
+}
+
+template <typename T, size_t N, typename A>
+template <typename... Args>
+auto Storage<T, N, A>::EmplaceBack(Args&&... args) -> reference {
+  StorageView storage_view = MakeStorageView();
+  const auto n = storage_view.size;
+  if (ABSL_PREDICT_TRUE(n != storage_view.capacity)) {
+    // Fast path; new element fits.
+    pointer last_ptr = storage_view.data + n;
+    AllocatorTraits::construct(*GetAllocPtr(), last_ptr,
+                               std::forward<Args>(args)...);
+    AddSize(1);
+    return *last_ptr;
+  }
+  // TODO(b/173712035): Annotate with musttail attribute to prevent regression.
+  return EmplaceBackSlow(std::forward<Args>(args)...);
+}
+
+template <typename T, size_t N, typename A>
+template <typename... Args>
+auto Storage<T, N, A>::EmplaceBackSlow(Args&&... args) -> reference {
+  StorageView storage_view = MakeStorageView();
+  AllocationTransaction allocation_tx(GetAllocPtr());
+  IteratorValueAdapter<MoveIterator> move_values(
+      MoveIterator(storage_view.data));
+  size_type new_capacity = NextCapacity(storage_view.capacity);
+  pointer construct_data = allocation_tx.Allocate(new_capacity);
+  pointer last_ptr = construct_data + storage_view.size;
+
+  // Construct new element.
+  AllocatorTraits::construct(*GetAllocPtr(), last_ptr,
+                             std::forward<Args>(args)...);
+  // Move elements from old backing store to new backing store.
+  ABSL_INTERNAL_TRY {
+    inlined_vector_internal::ConstructElements(
+        GetAllocPtr(), allocation_tx.GetData(), &move_values,
+        storage_view.size);
+  }
+  ABSL_INTERNAL_CATCH_ANY {
+    AllocatorTraits::destroy(*GetAllocPtr(), last_ptr);
+    ABSL_INTERNAL_RETHROW;
+  }
+  // Destroy elements in old backing store.
+  inlined_vector_internal::DestroyElements(GetAllocPtr(), storage_view.data,
+                                           storage_view.size);
+
+  DeallocateIfAllocated();
+  AcquireAllocatedData(&allocation_tx);
+  SetIsAllocated();
+  AddSize(1);
+  return *last_ptr;
+}
+
+template <typename T, size_t N, typename A>
+auto Storage<T, N, A>::Erase(const_iterator from, const_iterator to)
+    -> iterator {
+  StorageView storage_view = MakeStorageView();
+
+  size_type erase_size = std::distance(from, to);
+  size_type erase_index =
+      std::distance(const_iterator(storage_view.data), from);
+  size_type erase_end_index = erase_index + erase_size;
+
+  IteratorValueAdapter<MoveIterator> move_values(
+      MoveIterator(storage_view.data + erase_end_index));
+
+  inlined_vector_internal::AssignElements(storage_view.data + erase_index,
+                                          &move_values,
+                                          storage_view.size - erase_end_index);
+
+  inlined_vector_internal::DestroyElements(
+      GetAllocPtr(), storage_view.data + (storage_view.size - erase_size),
+      erase_size);
+
+  SubtractSize(erase_size);
+  return iterator(storage_view.data + erase_index);
+}
+
+template <typename T, size_t N, typename A>
+auto Storage<T, N, A>::Reserve(size_type requested_capacity) -> void {
+  StorageView storage_view = MakeStorageView();
+
+  if (ABSL_PREDICT_FALSE(requested_capacity <= storage_view.capacity)) return;
+
+  AllocationTransaction allocation_tx(GetAllocPtr());
+
+  IteratorValueAdapter<MoveIterator> move_values(
+      MoveIterator(storage_view.data));
+
+  size_type new_capacity =
+      ComputeCapacity(storage_view.capacity, requested_capacity);
+  pointer new_data = allocation_tx.Allocate(new_capacity);
+
+  inlined_vector_internal::ConstructElements(GetAllocPtr(), new_data,
+                                             &move_values, storage_view.size);
+
+  inlined_vector_internal::DestroyElements(GetAllocPtr(), storage_view.data,
+                                           storage_view.size);
+
+  DeallocateIfAllocated();
+  AcquireAllocatedData(&allocation_tx);
+  SetIsAllocated();
+}
+
+template <typename T, size_t N, typename A>
+auto Storage<T, N, A>::ShrinkToFit() -> void {
+  // May only be called on allocated instances!
+  assert(GetIsAllocated());
+
+  StorageView storage_view{GetAllocatedData(), GetSize(),
+                           GetAllocatedCapacity()};
+
+  if (ABSL_PREDICT_FALSE(storage_view.size == storage_view.capacity)) return;
+
+  AllocationTransaction allocation_tx(GetAllocPtr());
+
+  IteratorValueAdapter<MoveIterator> move_values(
+      MoveIterator(storage_view.data));
+
+  pointer construct_data;
+  if (storage_view.size > GetInlinedCapacity()) {
+    size_type new_capacity = storage_view.size;
+    construct_data = allocation_tx.Allocate(new_capacity);
+  } else {
+    construct_data = GetInlinedData();
+  }
+
+  ABSL_INTERNAL_TRY {
+    inlined_vector_internal::ConstructElements(GetAllocPtr(), construct_data,
+                                               &move_values, storage_view.size);
+  }
+  ABSL_INTERNAL_CATCH_ANY {
+    SetAllocatedData(storage_view.data, storage_view.capacity);
+    ABSL_INTERNAL_RETHROW;
+  }
+
+  inlined_vector_internal::DestroyElements(GetAllocPtr(), storage_view.data,
+                                           storage_view.size);
+
+  AllocatorTraits::deallocate(*GetAllocPtr(), storage_view.data,
+                              storage_view.capacity);
+
+  if (allocation_tx.DidAllocate()) {
+    AcquireAllocatedData(&allocation_tx);
+  } else {
+    UnsetIsAllocated();
+  }
+}
+
+template <typename T, size_t N, typename A>
+auto Storage<T, N, A>::Swap(Storage* other_storage_ptr) -> void {
+  using std::swap;
+  assert(this != other_storage_ptr);
+
+  if (GetIsAllocated() && other_storage_ptr->GetIsAllocated()) {
+    swap(data_.allocated, other_storage_ptr->data_.allocated);
+  } else if (!GetIsAllocated() && !other_storage_ptr->GetIsAllocated()) {
+    Storage* small_ptr = this;
+    Storage* large_ptr = other_storage_ptr;
+    if (small_ptr->GetSize() > large_ptr->GetSize()) swap(small_ptr, large_ptr);
+
+    for (size_type i = 0; i < small_ptr->GetSize(); ++i) {
+      swap(small_ptr->GetInlinedData()[i], large_ptr->GetInlinedData()[i]);
+    }
+
+    IteratorValueAdapter<MoveIterator> move_values(
+        MoveIterator(large_ptr->GetInlinedData() + small_ptr->GetSize()));
+
+    inlined_vector_internal::ConstructElements(
+        large_ptr->GetAllocPtr(),
+        small_ptr->GetInlinedData() + small_ptr->GetSize(), &move_values,
+        large_ptr->GetSize() - small_ptr->GetSize());
+
+    inlined_vector_internal::DestroyElements(
+        large_ptr->GetAllocPtr(),
+        large_ptr->GetInlinedData() + small_ptr->GetSize(),
+        large_ptr->GetSize() - small_ptr->GetSize());
+  } else {
+    Storage* allocated_ptr = this;
+    Storage* inlined_ptr = other_storage_ptr;
+    if (!allocated_ptr->GetIsAllocated()) swap(allocated_ptr, inlined_ptr);
+
+    StorageView allocated_storage_view{allocated_ptr->GetAllocatedData(),
+                                       allocated_ptr->GetSize(),
+                                       allocated_ptr->GetAllocatedCapacity()};
+
+    IteratorValueAdapter<MoveIterator> move_values(
+        MoveIterator(inlined_ptr->GetInlinedData()));
+
+    ABSL_INTERNAL_TRY {
+      inlined_vector_internal::ConstructElements(
+          inlined_ptr->GetAllocPtr(), allocated_ptr->GetInlinedData(),
+          &move_values, inlined_ptr->GetSize());
+    }
+    ABSL_INTERNAL_CATCH_ANY {
+      allocated_ptr->SetAllocatedData(allocated_storage_view.data,
+                                      allocated_storage_view.capacity);
+      ABSL_INTERNAL_RETHROW;
+    }
+
+    inlined_vector_internal::DestroyElements(inlined_ptr->GetAllocPtr(),
+                                             inlined_ptr->GetInlinedData(),
+                                             inlined_ptr->GetSize());
+
+    inlined_ptr->SetAllocatedData(allocated_storage_view.data,
+                                  allocated_storage_view.capacity);
+  }
+
+  swap(GetSizeAndIsAllocated(), other_storage_ptr->GetSizeAndIsAllocated());
+  swap(*GetAllocPtr(), *other_storage_ptr->GetAllocPtr());
+}
+
+// End ignore "maybe-uninitialized"
+// #if !defined(__clang__) && defined(__GNUC__)
+// #pragma GCC diagnostic pop
+// #endif
+
+}  // namespace inlined_vector_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#endif  // ABSL_CONTAINER_INTERNAL_INLINED_VECTOR_INTERNAL_H_
diff --git a/src/absl/container/internal/layout.h b/src/absl/container/internal/layout.h
new file mode 100644 (file)
index 0000000..a59a243
--- /dev/null
@@ -0,0 +1,743 @@
+// Copyright 2018 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+//                           MOTIVATION AND TUTORIAL
+//
+// If you want to put in a single heap allocation N doubles followed by M ints,
+// it's easy if N and M are known at compile time.
+//
+//   struct S {
+//     double a[N];
+//     int b[M];
+//   };
+//
+//   S* p = new S;
+//
+// But what if N and M are known only in run time? Class template Layout to the
+// rescue! It's a portable generalization of the technique known as struct hack.
+//
+//   // This object will tell us everything we need to know about the memory
+//   // layout of double[N] followed by int[M]. It's structurally identical to
+//   // size_t[2] that stores N and M. It's very cheap to create.
+//   const Layout<double, int> layout(N, M);
+//
+//   // Allocate enough memory for both arrays. `AllocSize()` tells us how much
+//   // memory is needed. We are free to use any allocation function we want as
+//   // long as it returns aligned memory.
+//   std::unique_ptr<unsigned char[]> p(new unsigned char[layout.AllocSize()]);
+//
+//   // Obtain the pointer to the array of doubles.
+//   // Equivalent to `reinterpret_cast<double*>(p.get())`.
+//   //
+//   // We could have written layout.Pointer<0>(p) instead. If all the types are
+//   // unique you can use either form, but if some types are repeated you must
+//   // use the index form.
+//   double* a = layout.Pointer<double>(p.get());
+//
+//   // Obtain the pointer to the array of ints.
+//   // Equivalent to `reinterpret_cast<int*>(p.get() + N * 8)`.
+//   int* b = layout.Pointer<int>(p);
+//
+// If we are unable to specify sizes of all fields, we can pass as many sizes as
+// we can to `Partial()`. In return, it'll allow us to access the fields whose
+// locations and sizes can be computed from the provided information.
+// `Partial()` comes in handy when the array sizes are embedded into the
+// allocation.
+//
+//   // size_t[1] containing N, size_t[1] containing M, double[N], int[M].
+//   using L = Layout<size_t, size_t, double, int>;
+//
+//   unsigned char* Allocate(size_t n, size_t m) {
+//     const L layout(1, 1, n, m);
+//     unsigned char* p = new unsigned char[layout.AllocSize()];
+//     *layout.Pointer<0>(p) = n;
+//     *layout.Pointer<1>(p) = m;
+//     return p;
+//   }
+//
+//   void Use(unsigned char* p) {
+//     // First, extract N and M.
+//     // Specify that the first array has only one element. Using `prefix` we
+//     // can access the first two arrays but not more.
+//     constexpr auto prefix = L::Partial(1);
+//     size_t n = *prefix.Pointer<0>(p);
+//     size_t m = *prefix.Pointer<1>(p);
+//
+//     // Now we can get pointers to the payload.
+//     const L layout(1, 1, n, m);
+//     double* a = layout.Pointer<double>(p);
+//     int* b = layout.Pointer<int>(p);
+//   }
+//
+// The layout we used above combines fixed-size with dynamically-sized fields.
+// This is quite common. Layout is optimized for this use case and generates
+// optimal code. All computations that can be performed at compile time are
+// indeed performed at compile time.
+//
+// Efficiency tip: The order of fields matters. In `Layout<T1, ..., TN>` try to
+// ensure that `alignof(T1) >= ... >= alignof(TN)`. This way you'll have no
+// padding in between arrays.
+//
+// You can manually override the alignment of an array by wrapping the type in
+// `Aligned<T, N>`. `Layout<..., Aligned<T, N>, ...>` has exactly the same API
+// and behavior as `Layout<..., T, ...>` except that the first element of the
+// array of `T` is aligned to `N` (the rest of the elements follow without
+// padding). `N` cannot be less than `alignof(T)`.
+//
+// `AllocSize()` and `Pointer()` are the most basic methods for dealing with
+// memory layouts. Check out the reference or code below to discover more.
+//
+//                            EXAMPLE
+//
+//   // Immutable move-only string with sizeof equal to sizeof(void*). The
+//   // string size and the characters are kept in the same heap allocation.
+//   class CompactString {
+//    public:
+//     CompactString(const char* s = "") {
+//       const size_t size = strlen(s);
+//       // size_t[1] followed by char[size + 1].
+//       const L layout(1, size + 1);
+//       p_.reset(new unsigned char[layout.AllocSize()]);
+//       // If running under ASAN, mark the padding bytes, if any, to catch
+//       // memory errors.
+//       layout.PoisonPadding(p_.get());
+//       // Store the size in the allocation.
+//       *layout.Pointer<size_t>(p_.get()) = size;
+//       // Store the characters in the allocation.
+//       memcpy(layout.Pointer<char>(p_.get()), s, size + 1);
+//     }
+//
+//     size_t size() const {
+//       // Equivalent to reinterpret_cast<size_t&>(*p).
+//       return *L::Partial().Pointer<size_t>(p_.get());
+//     }
+//
+//     const char* c_str() const {
+//       // Equivalent to reinterpret_cast<char*>(p.get() + sizeof(size_t)).
+//       // The argument in Partial(1) specifies that we have size_t[1] in front
+//       // of the characters.
+//       return L::Partial(1).Pointer<char>(p_.get());
+//     }
+//
+//    private:
+//     // Our heap allocation contains a size_t followed by an array of chars.
+//     using L = Layout<size_t, char>;
+//     std::unique_ptr<unsigned char[]> p_;
+//   };
+//
+//   int main() {
+//     CompactString s = "hello";
+//     assert(s.size() == 5);
+//     assert(strcmp(s.c_str(), "hello") == 0);
+//   }
+//
+//                               DOCUMENTATION
+//
+// The interface exported by this file consists of:
+// - class `Layout<>` and its public members.
+// - The public members of class `internal_layout::LayoutImpl<>`. That class
+//   isn't intended to be used directly, and its name and template parameter
+//   list are internal implementation details, but the class itself provides
+//   most of the functionality in this file. See comments on its members for
+//   detailed documentation.
+//
+// `Layout<T1,... Tn>::Partial(count1,..., countm)` (where `m` <= `n`) returns a
+// `LayoutImpl<>` object. `Layout<T1,..., Tn> layout(count1,..., countn)`
+// creates a `Layout` object, which exposes the same functionality by inheriting
+// from `LayoutImpl<>`.
+
+#ifndef ABSL_CONTAINER_INTERNAL_LAYOUT_H_
+#define ABSL_CONTAINER_INTERNAL_LAYOUT_H_
+
+#include <assert.h>
+#include <stddef.h>
+#include <stdint.h>
+
+#include <ostream>
+#include <string>
+#include <tuple>
+#include <type_traits>
+#include <typeinfo>
+#include <utility>
+
+#include "absl/base/config.h"
+#include "absl/meta/type_traits.h"
+#include "absl/strings/str_cat.h"
+#include "absl/types/span.h"
+#include "absl/utility/utility.h"
+
+#ifdef ABSL_HAVE_ADDRESS_SANITIZER
+#include <sanitizer/asan_interface.h>
+#endif
+
+#if defined(__GXX_RTTI)
+#define ABSL_INTERNAL_HAS_CXA_DEMANGLE
+#endif
+
+#ifdef ABSL_INTERNAL_HAS_CXA_DEMANGLE
+#include <cxxabi.h>
+#endif
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace container_internal {
+
+// A type wrapper that instructs `Layout` to use the specific alignment for the
+// array. `Layout<..., Aligned<T, N>, ...>` has exactly the same API
+// and behavior as `Layout<..., T, ...>` except that the first element of the
+// array of `T` is aligned to `N` (the rest of the elements follow without
+// padding).
+//
+// Requires: `N >= alignof(T)` and `N` is a power of 2.
+template <class T, size_t N>
+struct Aligned;
+
+namespace internal_layout {
+
+template <class T>
+struct NotAligned {};
+
+template <class T, size_t N>
+struct NotAligned<const Aligned<T, N>> {
+  static_assert(sizeof(T) == 0, "Aligned<T, N> cannot be const-qualified");
+};
+
+template <size_t>
+using IntToSize = size_t;
+
+template <class>
+using TypeToSize = size_t;
+
+template <class T>
+struct Type : NotAligned<T> {
+  using type = T;
+};
+
+template <class T, size_t N>
+struct Type<Aligned<T, N>> {
+  using type = T;
+};
+
+template <class T>
+struct SizeOf : NotAligned<T>, std::integral_constant<size_t, sizeof(T)> {};
+
+template <class T, size_t N>
+struct SizeOf<Aligned<T, N>> : std::integral_constant<size_t, sizeof(T)> {};
+
+// Note: workaround for https://gcc.gnu.org/PR88115
+template <class T>
+struct AlignOf : NotAligned<T> {
+  static constexpr size_t value = alignof(T);
+};
+
+template <class T, size_t N>
+struct AlignOf<Aligned<T, N>> {
+  static_assert(N % alignof(T) == 0,
+                "Custom alignment can't be lower than the type's alignment");
+  static constexpr size_t value = N;
+};
+
+// Does `Ts...` contain `T`?
+template <class T, class... Ts>
+using Contains = absl::disjunction<std::is_same<T, Ts>...>;
+
+template <class From, class To>
+using CopyConst =
+    typename std::conditional<std::is_const<From>::value, const To, To>::type;
+
+// Note: We're not qualifying this with absl:: because it doesn't compile under
+// MSVC.
+template <class T>
+using SliceType = Span<T>;
+
+// This namespace contains no types. It prevents functions defined in it from
+// being found by ADL.
+namespace adl_barrier {
+
+template <class Needle, class... Ts>
+constexpr size_t Find(Needle, Needle, Ts...) {
+  static_assert(!Contains<Needle, Ts...>(), "Duplicate element type");
+  return 0;
+}
+
+template <class Needle, class T, class... Ts>
+constexpr size_t Find(Needle, T, Ts...) {
+  return adl_barrier::Find(Needle(), Ts()...) + 1;
+}
+
+constexpr bool IsPow2(size_t n) { return !(n & (n - 1)); }
+
+// Returns `q * m` for the smallest `q` such that `q * m >= n`.
+// Requires: `m` is a power of two. It's enforced by IsLegalElementType below.
+constexpr size_t Align(size_t n, size_t m) { return (n + m - 1) & ~(m - 1); }
+
+constexpr size_t Min(size_t a, size_t b) { return b < a ? b : a; }
+
+constexpr size_t Max(size_t a) { return a; }
+
+template <class... Ts>
+constexpr size_t Max(size_t a, size_t b, Ts... rest) {
+  return adl_barrier::Max(b < a ? a : b, rest...);
+}
+
+template <class T>
+std::string TypeName() {
+  std::string out;
+  int status = 0;
+  char* demangled = nullptr;
+#ifdef ABSL_INTERNAL_HAS_CXA_DEMANGLE
+  demangled = abi::__cxa_demangle(typeid(T).name(), nullptr, nullptr, &status);
+#endif
+  if (status == 0 && demangled != nullptr) {  // Demangling succeeded.
+    absl::StrAppend(&out, "<", demangled, ">");
+    free(demangled);
+  } else {
+#if defined(__GXX_RTTI) || defined(_CPPRTTI)
+    absl::StrAppend(&out, "<", typeid(T).name(), ">");
+#endif
+  }
+  return out;
+}
+
+}  // namespace adl_barrier
+
+template <bool C>
+using EnableIf = typename std::enable_if<C, int>::type;
+
+// Can `T` be a template argument of `Layout`?
+template <class T>
+using IsLegalElementType = std::integral_constant<
+    bool, !std::is_reference<T>::value && !std::is_volatile<T>::value &&
+              !std::is_reference<typename Type<T>::type>::value &&
+              !std::is_volatile<typename Type<T>::type>::value &&
+              adl_barrier::IsPow2(AlignOf<T>::value)>;
+
+template <class Elements, class SizeSeq, class OffsetSeq>
+class LayoutImpl;
+
+// Public base class of `Layout` and the result type of `Layout::Partial()`.
+//
+// `Elements...` contains all template arguments of `Layout` that created this
+// instance.
+//
+// `SizeSeq...` is `[0, NumSizes)` where `NumSizes` is the number of arguments
+// passed to `Layout::Partial()` or `Layout::Layout()`.
+//
+// `OffsetSeq...` is `[0, NumOffsets)` where `NumOffsets` is
+// `Min(sizeof...(Elements), NumSizes + 1)` (the number of arrays for which we
+// can compute offsets).
+template <class... Elements, size_t... SizeSeq, size_t... OffsetSeq>
+class LayoutImpl<std::tuple<Elements...>, absl::index_sequence<SizeSeq...>,
+                 absl::index_sequence<OffsetSeq...>> {
+ private:
+  static_assert(sizeof...(Elements) > 0, "At least one field is required");
+  static_assert(absl::conjunction<IsLegalElementType<Elements>...>::value,
+                "Invalid element type (see IsLegalElementType)");
+
+  enum {
+    NumTypes = sizeof...(Elements),
+    NumSizes = sizeof...(SizeSeq),
+    NumOffsets = sizeof...(OffsetSeq),
+  };
+
+  // These are guaranteed by `Layout`.
+  static_assert(NumOffsets == adl_barrier::Min(NumTypes, NumSizes + 1),
+                "Internal error");
+  static_assert(NumTypes > 0, "Internal error");
+
+  // Returns the index of `T` in `Elements...`. Results in a compilation error
+  // if `Elements...` doesn't contain exactly one instance of `T`.
+  template <class T>
+  static constexpr size_t ElementIndex() {
+    static_assert(Contains<Type<T>, Type<typename Type<Elements>::type>...>(),
+                  "Type not found");
+    return adl_barrier::Find(Type<T>(),
+                             Type<typename Type<Elements>::type>()...);
+  }
+
+  template <size_t N>
+  using ElementAlignment =
+      AlignOf<typename std::tuple_element<N, std::tuple<Elements...>>::type>;
+
+ public:
+  // Element types of all arrays packed in a tuple.
+  using ElementTypes = std::tuple<typename Type<Elements>::type...>;
+
+  // Element type of the Nth array.
+  template <size_t N>
+  using ElementType = typename std::tuple_element<N, ElementTypes>::type;
+
+  constexpr explicit LayoutImpl(IntToSize<SizeSeq>... sizes)
+      : size_{sizes...} {}
+
+  // Alignment of the layout, equal to the strictest alignment of all elements.
+  // All pointers passed to the methods of layout must be aligned to this value.
+  static constexpr size_t Alignment() {
+    return adl_barrier::Max(AlignOf<Elements>::value...);
+  }
+
+  // Offset in bytes of the Nth array.
+  //
+  //   // int[3], 4 bytes of padding, double[4].
+  //   Layout<int, double> x(3, 4);
+  //   assert(x.Offset<0>() == 0);   // The ints starts from 0.
+  //   assert(x.Offset<1>() == 16);  // The doubles starts from 16.
+  //
+  // Requires: `N <= NumSizes && N < sizeof...(Ts)`.
+  template <size_t N, EnableIf<N == 0> = 0>
+  constexpr size_t Offset() const {
+    return 0;
+  }
+
+  template <size_t N, EnableIf<N != 0> = 0>
+  constexpr size_t Offset() const {
+    static_assert(N < NumOffsets, "Index out of bounds");
+    return adl_barrier::Align(
+        Offset<N - 1>() + SizeOf<ElementType<N - 1>>::value * size_[N - 1],
+        ElementAlignment<N>::value);
+  }
+
+  // Offset in bytes of the array with the specified element type. There must
+  // be exactly one such array and its zero-based index must be at most
+  // `NumSizes`.
+  //
+  //   // int[3], 4 bytes of padding, double[4].
+  //   Layout<int, double> x(3, 4);
+  //   assert(x.Offset<int>() == 0);      // The ints starts from 0.
+  //   assert(x.Offset<double>() == 16);  // The doubles starts from 16.
+  template <class T>
+  constexpr size_t Offset() const {
+    return Offset<ElementIndex<T>()>();
+  }
+
+  // Offsets in bytes of all arrays for which the offsets are known.
+  constexpr std::array<size_t, NumOffsets> Offsets() const {
+    return {{Offset<OffsetSeq>()...}};
+  }
+
+  // The number of elements in the Nth array. This is the Nth argument of
+  // `Layout::Partial()` or `Layout::Layout()` (zero-based).
+  //
+  //   // int[3], 4 bytes of padding, double[4].
+  //   Layout<int, double> x(3, 4);
+  //   assert(x.Size<0>() == 3);
+  //   assert(x.Size<1>() == 4);
+  //
+  // Requires: `N < NumSizes`.
+  template <size_t N>
+  constexpr size_t Size() const {
+    static_assert(N < NumSizes, "Index out of bounds");
+    return size_[N];
+  }
+
+  // The number of elements in the array with the specified element type.
+  // There must be exactly one such array and its zero-based index must be
+  // at most `NumSizes`.
+  //
+  //   // int[3], 4 bytes of padding, double[4].
+  //   Layout<int, double> x(3, 4);
+  //   assert(x.Size<int>() == 3);
+  //   assert(x.Size<double>() == 4);
+  template <class T>
+  constexpr size_t Size() const {
+    return Size<ElementIndex<T>()>();
+  }
+
+  // The number of elements of all arrays for which they are known.
+  constexpr std::array<size_t, NumSizes> Sizes() const {
+    return {{Size<SizeSeq>()...}};
+  }
+
+  // Pointer to the beginning of the Nth array.
+  //
+  // `Char` must be `[const] [signed|unsigned] char`.
+  //
+  //   // int[3], 4 bytes of padding, double[4].
+  //   Layout<int, double> x(3, 4);
+  //   unsigned char* p = new unsigned char[x.AllocSize()];
+  //   int* ints = x.Pointer<0>(p);
+  //   double* doubles = x.Pointer<1>(p);
+  //
+  // Requires: `N <= NumSizes && N < sizeof...(Ts)`.
+  // Requires: `p` is aligned to `Alignment()`.
+  template <size_t N, class Char>
+  CopyConst<Char, ElementType<N>>* Pointer(Char* p) const {
+    using C = typename std::remove_const<Char>::type;
+    static_assert(
+        std::is_same<C, char>() || std::is_same<C, unsigned char>() ||
+            std::is_same<C, signed char>(),
+        "The argument must be a pointer to [const] [signed|unsigned] char");
+    constexpr size_t alignment = Alignment();
+    (void)alignment;
+    assert(reinterpret_cast<uintptr_t>(p) % alignment == 0);
+    return reinterpret_cast<CopyConst<Char, ElementType<N>>*>(p + Offset<N>());
+  }
+
+  // Pointer to the beginning of the array with the specified element type.
+  // There must be exactly one such array and its zero-based index must be at
+  // most `NumSizes`.
+  //
+  // `Char` must be `[const] [signed|unsigned] char`.
+  //
+  //   // int[3], 4 bytes of padding, double[4].
+  //   Layout<int, double> x(3, 4);
+  //   unsigned char* p = new unsigned char[x.AllocSize()];
+  //   int* ints = x.Pointer<int>(p);
+  //   double* doubles = x.Pointer<double>(p);
+  //
+  // Requires: `p` is aligned to `Alignment()`.
+  template <class T, class Char>
+  CopyConst<Char, T>* Pointer(Char* p) const {
+    return Pointer<ElementIndex<T>()>(p);
+  }
+
+  // Pointers to all arrays for which pointers are known.
+  //
+  // `Char` must be `[const] [signed|unsigned] char`.
+  //
+  //   // int[3], 4 bytes of padding, double[4].
+  //   Layout<int, double> x(3, 4);
+  //   unsigned char* p = new unsigned char[x.AllocSize()];
+  //
+  //   int* ints;
+  //   double* doubles;
+  //   std::tie(ints, doubles) = x.Pointers(p);
+  //
+  // Requires: `p` is aligned to `Alignment()`.
+  //
+  // Note: We're not using ElementType alias here because it does not compile
+  // under MSVC.
+  template <class Char>
+  std::tuple<CopyConst<
+      Char, typename std::tuple_element<OffsetSeq, ElementTypes>::type>*...>
+  Pointers(Char* p) const {
+    return std::tuple<CopyConst<Char, ElementType<OffsetSeq>>*...>(
+        Pointer<OffsetSeq>(p)...);
+  }
+
+  // The Nth array.
+  //
+  // `Char` must be `[const] [signed|unsigned] char`.
+  //
+  //   // int[3], 4 bytes of padding, double[4].
+  //   Layout<int, double> x(3, 4);
+  //   unsigned char* p = new unsigned char[x.AllocSize()];
+  //   Span<int> ints = x.Slice<0>(p);
+  //   Span<double> doubles = x.Slice<1>(p);
+  //
+  // Requires: `N < NumSizes`.
+  // Requires: `p` is aligned to `Alignment()`.
+  template <size_t N, class Char>
+  SliceType<CopyConst<Char, ElementType<N>>> Slice(Char* p) const {
+    return SliceType<CopyConst<Char, ElementType<N>>>(Pointer<N>(p), Size<N>());
+  }
+
+  // The array with the specified element type. There must be exactly one
+  // such array and its zero-based index must be less than `NumSizes`.
+  //
+  // `Char` must be `[const] [signed|unsigned] char`.
+  //
+  //   // int[3], 4 bytes of padding, double[4].
+  //   Layout<int, double> x(3, 4);
+  //   unsigned char* p = new unsigned char[x.AllocSize()];
+  //   Span<int> ints = x.Slice<int>(p);
+  //   Span<double> doubles = x.Slice<double>(p);
+  //
+  // Requires: `p` is aligned to `Alignment()`.
+  template <class T, class Char>
+  SliceType<CopyConst<Char, T>> Slice(Char* p) const {
+    return Slice<ElementIndex<T>()>(p);
+  }
+
+  // All arrays with known sizes.
+  //
+  // `Char` must be `[const] [signed|unsigned] char`.
+  //
+  //   // int[3], 4 bytes of padding, double[4].
+  //   Layout<int, double> x(3, 4);
+  //   unsigned char* p = new unsigned char[x.AllocSize()];
+  //
+  //   Span<int> ints;
+  //   Span<double> doubles;
+  //   std::tie(ints, doubles) = x.Slices(p);
+  //
+  // Requires: `p` is aligned to `Alignment()`.
+  //
+  // Note: We're not using ElementType alias here because it does not compile
+  // under MSVC.
+  template <class Char>
+  std::tuple<SliceType<CopyConst<
+      Char, typename std::tuple_element<SizeSeq, ElementTypes>::type>>...>
+  Slices(Char* p) const {
+    // Workaround for https://gcc.gnu.org/bugzilla/show_bug.cgi?id=63875 (fixed
+    // in 6.1).
+    (void)p;
+    return std::tuple<SliceType<CopyConst<Char, ElementType<SizeSeq>>>...>(
+        Slice<SizeSeq>(p)...);
+  }
+
+  // The size of the allocation that fits all arrays.
+  //
+  //   // int[3], 4 bytes of padding, double[4].
+  //   Layout<int, double> x(3, 4);
+  //   unsigned char* p = new unsigned char[x.AllocSize()];  // 48 bytes
+  //
+  // Requires: `NumSizes == sizeof...(Ts)`.
+  constexpr size_t AllocSize() const {
+    static_assert(NumTypes == NumSizes, "You must specify sizes of all fields");
+    return Offset<NumTypes - 1>() +
+        SizeOf<ElementType<NumTypes - 1>>::value * size_[NumTypes - 1];
+  }
+
+  // If built with --config=asan, poisons padding bytes (if any) in the
+  // allocation. The pointer must point to a memory block at least
+  // `AllocSize()` bytes in length.
+  //
+  // `Char` must be `[const] [signed|unsigned] char`.
+  //
+  // Requires: `p` is aligned to `Alignment()`.
+  template <class Char, size_t N = NumOffsets - 1, EnableIf<N == 0> = 0>
+  void PoisonPadding(const Char* p) const {
+    Pointer<0>(p);  // verify the requirements on `Char` and `p`
+  }
+
+  template <class Char, size_t N = NumOffsets - 1, EnableIf<N != 0> = 0>
+  void PoisonPadding(const Char* p) const {
+    static_assert(N < NumOffsets, "Index out of bounds");
+    (void)p;
+#ifdef ABSL_HAVE_ADDRESS_SANITIZER
+    PoisonPadding<Char, N - 1>(p);
+    // The `if` is an optimization. It doesn't affect the observable behaviour.
+    if (ElementAlignment<N - 1>::value % ElementAlignment<N>::value) {
+      size_t start =
+          Offset<N - 1>() + SizeOf<ElementType<N - 1>>::value * size_[N - 1];
+      ASAN_POISON_MEMORY_REGION(p + start, Offset<N>() - start);
+    }
+#endif
+  }
+
+  // Human-readable description of the memory layout. Useful for debugging.
+  // Slow.
+  //
+  //   // char[5], 3 bytes of padding, int[3], 4 bytes of padding, followed
+  //   // by an unknown number of doubles.
+  //   auto x = Layout<char, int, double>::Partial(5, 3);
+  //   assert(x.DebugString() ==
+  //          "@0<char>(1)[5]; @8<int>(4)[3]; @24<double>(8)");
+  //
+  // Each field is in the following format: @offset<type>(sizeof)[size] (<type>
+  // may be missing depending on the target platform). For example,
+  // @8<int>(4)[3] means that at offset 8 we have an array of ints, where each
+  // int is 4 bytes, and we have 3 of those ints. The size of the last field may
+  // be missing (as in the example above). Only fields with known offsets are
+  // described. Type names may differ across platforms: one compiler might
+  // produce "unsigned*" where another produces "unsigned int *".
+  std::string DebugString() const {
+    const auto offsets = Offsets();
+    const size_t sizes[] = {SizeOf<ElementType<OffsetSeq>>::value...};
+    const std::string types[] = {
+        adl_barrier::TypeName<ElementType<OffsetSeq>>()...};
+    std::string res = absl::StrCat("@0", types[0], "(", sizes[0], ")");
+    for (size_t i = 0; i != NumOffsets - 1; ++i) {
+      absl::StrAppend(&res, "[", size_[i], "]; @", offsets[i + 1], types[i + 1],
+                      "(", sizes[i + 1], ")");
+    }
+    // NumSizes is a constant that may be zero. Some compilers cannot see that
+    // inside the if statement "size_[NumSizes - 1]" must be valid.
+    int last = static_cast<int>(NumSizes) - 1;
+    if (NumTypes == NumSizes && last >= 0) {
+      absl::StrAppend(&res, "[", size_[last], "]");
+    }
+    return res;
+  }
+
+ private:
+  // Arguments of `Layout::Partial()` or `Layout::Layout()`.
+  size_t size_[NumSizes > 0 ? NumSizes : 1];
+};
+
+template <size_t NumSizes, class... Ts>
+using LayoutType = LayoutImpl<
+    std::tuple<Ts...>, absl::make_index_sequence<NumSizes>,
+    absl::make_index_sequence<adl_barrier::Min(sizeof...(Ts), NumSizes + 1)>>;
+
+}  // namespace internal_layout
+
+// Descriptor of arrays of various types and sizes laid out in memory one after
+// another. See the top of the file for documentation.
+//
+// Check out the public API of internal_layout::LayoutImpl above. The type is
+// internal to the library but its methods are public, and they are inherited
+// by `Layout`.
+template <class... Ts>
+class Layout : public internal_layout::LayoutType<sizeof...(Ts), Ts...> {
+ public:
+  static_assert(sizeof...(Ts) > 0, "At least one field is required");
+  static_assert(
+      absl::conjunction<internal_layout::IsLegalElementType<Ts>...>::value,
+      "Invalid element type (see IsLegalElementType)");
+
+  // The result type of `Partial()` with `NumSizes` arguments.
+  template <size_t NumSizes>
+  using PartialType = internal_layout::LayoutType<NumSizes, Ts...>;
+
+  // `Layout` knows the element types of the arrays we want to lay out in
+  // memory but not the number of elements in each array.
+  // `Partial(size1, ..., sizeN)` allows us to specify the latter. The
+  // resulting immutable object can be used to obtain pointers to the
+  // individual arrays.
+  //
+  // It's allowed to pass fewer array sizes than the number of arrays. E.g.,
+  // if all you need is to the offset of the second array, you only need to
+  // pass one argument -- the number of elements in the first array.
+  //
+  //   // int[3] followed by 4 bytes of padding and an unknown number of
+  //   // doubles.
+  //   auto x = Layout<int, double>::Partial(3);
+  //   // doubles start at byte 16.
+  //   assert(x.Offset<1>() == 16);
+  //
+  // If you know the number of elements in all arrays, you can still call
+  // `Partial()` but it's more convenient to use the constructor of `Layout`.
+  //
+  //   Layout<int, double> x(3, 5);
+  //
+  // Note: The sizes of the arrays must be specified in number of elements,
+  // not in bytes.
+  //
+  // Requires: `sizeof...(Sizes) <= sizeof...(Ts)`.
+  // Requires: all arguments are convertible to `size_t`.
+  template <class... Sizes>
+  static constexpr PartialType<sizeof...(Sizes)> Partial(Sizes&&... sizes) {
+    static_assert(sizeof...(Sizes) <= sizeof...(Ts), "");
+    return PartialType<sizeof...(Sizes)>(absl::forward<Sizes>(sizes)...);
+  }
+
+  // Creates a layout with the sizes of all arrays specified. If you know
+  // only the sizes of the first N arrays (where N can be zero), you can use
+  // `Partial()` defined above. The constructor is essentially equivalent to
+  // calling `Partial()` and passing in all array sizes; the constructor is
+  // provided as a convenient abbreviation.
+  //
+  // Note: The sizes of the arrays must be specified in number of elements,
+  // not in bytes.
+  constexpr explicit Layout(internal_layout::TypeToSize<Ts>... sizes)
+      : internal_layout::LayoutType<sizeof...(Ts), Ts...>(sizes...) {}
+};
+
+}  // namespace container_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#endif  // ABSL_CONTAINER_INTERNAL_LAYOUT_H_
diff --git a/src/absl/container/internal/node_hash_policy.h b/src/absl/container/internal/node_hash_policy.h
new file mode 100644 (file)
index 0000000..4617162
--- /dev/null
@@ -0,0 +1,92 @@
+// Copyright 2018 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// Adapts a policy for nodes.
+//
+// The node policy should model:
+//
+// struct Policy {
+//   // Returns a new node allocated and constructed using the allocator, using
+//   // the specified arguments.
+//   template <class Alloc, class... Args>
+//   value_type* new_element(Alloc* alloc, Args&&... args) const;
+//
+//   // Destroys and deallocates node using the allocator.
+//   template <class Alloc>
+//   void delete_element(Alloc* alloc, value_type* node) const;
+// };
+//
+// It may also optionally define `value()` and `apply()`. For documentation on
+// these, see hash_policy_traits.h.
+
+#ifndef ABSL_CONTAINER_INTERNAL_NODE_HASH_POLICY_H_
+#define ABSL_CONTAINER_INTERNAL_NODE_HASH_POLICY_H_
+
+#include <cassert>
+#include <cstddef>
+#include <memory>
+#include <type_traits>
+#include <utility>
+
+#include "absl/base/config.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace container_internal {
+
+template <class Reference, class Policy>
+struct node_hash_policy {
+  static_assert(std::is_lvalue_reference<Reference>::value, "");
+
+  using slot_type = typename std::remove_cv<
+      typename std::remove_reference<Reference>::type>::type*;
+
+  template <class Alloc, class... Args>
+  static void construct(Alloc* alloc, slot_type* slot, Args&&... args) {
+    *slot = Policy::new_element(alloc, std::forward<Args>(args)...);
+  }
+
+  template <class Alloc>
+  static void destroy(Alloc* alloc, slot_type* slot) {
+    Policy::delete_element(alloc, *slot);
+  }
+
+  template <class Alloc>
+  static void transfer(Alloc*, slot_type* new_slot, slot_type* old_slot) {
+    *new_slot = *old_slot;
+  }
+
+  static size_t space_used(const slot_type* slot) {
+    if (slot == nullptr) return Policy::element_space_used(nullptr);
+    return Policy::element_space_used(*slot);
+  }
+
+  static Reference element(slot_type* slot) { return **slot; }
+
+  template <class T, class P = Policy>
+  static auto value(T* elem) -> decltype(P::value(elem)) {
+    return P::value(elem);
+  }
+
+  template <class... Ts, class P = Policy>
+  static auto apply(Ts&&... ts) -> decltype(P::apply(std::forward<Ts>(ts)...)) {
+    return P::apply(std::forward<Ts>(ts)...);
+  }
+};
+
+}  // namespace container_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#endif  // ABSL_CONTAINER_INTERNAL_NODE_HASH_POLICY_H_
diff --git a/src/absl/container/internal/raw_hash_map.h b/src/absl/container/internal/raw_hash_map.h
new file mode 100644 (file)
index 0000000..0a02757
--- /dev/null
@@ -0,0 +1,197 @@
+// Copyright 2018 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef ABSL_CONTAINER_INTERNAL_RAW_HASH_MAP_H_
+#define ABSL_CONTAINER_INTERNAL_RAW_HASH_MAP_H_
+
+#include <tuple>
+#include <type_traits>
+#include <utility>
+
+#include "absl/base/internal/throw_delegate.h"
+#include "absl/container/internal/container_memory.h"
+#include "absl/container/internal/raw_hash_set.h"  // IWYU pragma: export
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace container_internal {
+
+template <class Policy, class Hash, class Eq, class Alloc>
+class raw_hash_map : public raw_hash_set<Policy, Hash, Eq, Alloc> {
+  // P is Policy. It's passed as a template argument to support maps that have
+  // incomplete types as values, as in unordered_map<K, IncompleteType>.
+  // MappedReference<> may be a non-reference type.
+  template <class P>
+  using MappedReference = decltype(P::value(
+      std::addressof(std::declval<typename raw_hash_map::reference>())));
+
+  // MappedConstReference<> may be a non-reference type.
+  template <class P>
+  using MappedConstReference = decltype(P::value(
+      std::addressof(std::declval<typename raw_hash_map::const_reference>())));
+
+  using KeyArgImpl =
+      KeyArg<IsTransparent<Eq>::value && IsTransparent<Hash>::value>;
+
+ public:
+  using key_type = typename Policy::key_type;
+  using mapped_type = typename Policy::mapped_type;
+  template <class K>
+  using key_arg = typename KeyArgImpl::template type<K, key_type>;
+
+  static_assert(!std::is_reference<key_type>::value, "");
+  // TODO(alkis): remove this assertion and verify that reference mapped_type is
+  // supported.
+  static_assert(!std::is_reference<mapped_type>::value, "");
+
+  using iterator = typename raw_hash_map::raw_hash_set::iterator;
+  using const_iterator = typename raw_hash_map::raw_hash_set::const_iterator;
+
+  raw_hash_map() {}
+  using raw_hash_map::raw_hash_set::raw_hash_set;
+
+  // The last two template parameters ensure that both arguments are rvalues
+  // (lvalue arguments are handled by the overloads below). This is necessary
+  // for supporting bitfield arguments.
+  //
+  //   union { int n : 1; };
+  //   flat_hash_map<int, int> m;
+  //   m.insert_or_assign(n, n);
+  template <class K = key_type, class V = mapped_type, K* = nullptr,
+            V* = nullptr>
+  std::pair<iterator, bool> insert_or_assign(key_arg<K>&& k, V&& v) {
+    return insert_or_assign_impl(std::forward<K>(k), std::forward<V>(v));
+  }
+
+  template <class K = key_type, class V = mapped_type, K* = nullptr>
+  std::pair<iterator, bool> insert_or_assign(key_arg<K>&& k, const V& v) {
+    return insert_or_assign_impl(std::forward<K>(k), v);
+  }
+
+  template <class K = key_type, class V = mapped_type, V* = nullptr>
+  std::pair<iterator, bool> insert_or_assign(const key_arg<K>& k, V&& v) {
+    return insert_or_assign_impl(k, std::forward<V>(v));
+  }
+
+  template <class K = key_type, class V = mapped_type>
+  std::pair<iterator, bool> insert_or_assign(const key_arg<K>& k, const V& v) {
+    return insert_or_assign_impl(k, v);
+  }
+
+  template <class K = key_type, class V = mapped_type, K* = nullptr,
+            V* = nullptr>
+  iterator insert_or_assign(const_iterator, key_arg<K>&& k, V&& v) {
+    return insert_or_assign(std::forward<K>(k), std::forward<V>(v)).first;
+  }
+
+  template <class K = key_type, class V = mapped_type, K* = nullptr>
+  iterator insert_or_assign(const_iterator, key_arg<K>&& k, const V& v) {
+    return insert_or_assign(std::forward<K>(k), v).first;
+  }
+
+  template <class K = key_type, class V = mapped_type, V* = nullptr>
+  iterator insert_or_assign(const_iterator, const key_arg<K>& k, V&& v) {
+    return insert_or_assign(k, std::forward<V>(v)).first;
+  }
+
+  template <class K = key_type, class V = mapped_type>
+  iterator insert_or_assign(const_iterator, const key_arg<K>& k, const V& v) {
+    return insert_or_assign(k, v).first;
+  }
+
+  // All `try_emplace()` overloads make the same guarantees regarding rvalue
+  // arguments as `std::unordered_map::try_emplace()`, namely that these
+  // functions will not move from rvalue arguments if insertions do not happen.
+  template <class K = key_type, class... Args,
+            typename std::enable_if<
+                !std::is_convertible<K, const_iterator>::value, int>::type = 0,
+            K* = nullptr>
+  std::pair<iterator, bool> try_emplace(key_arg<K>&& k, Args&&... args) {
+    return try_emplace_impl(std::forward<K>(k), std::forward<Args>(args)...);
+  }
+
+  template <class K = key_type, class... Args,
+            typename std::enable_if<
+                !std::is_convertible<K, const_iterator>::value, int>::type = 0>
+  std::pair<iterator, bool> try_emplace(const key_arg<K>& k, Args&&... args) {
+    return try_emplace_impl(k, std::forward<Args>(args)...);
+  }
+
+  template <class K = key_type, class... Args, K* = nullptr>
+  iterator try_emplace(const_iterator, key_arg<K>&& k, Args&&... args) {
+    return try_emplace(std::forward<K>(k), std::forward<Args>(args)...).first;
+  }
+
+  template <class K = key_type, class... Args>
+  iterator try_emplace(const_iterator, const key_arg<K>& k, Args&&... args) {
+    return try_emplace(k, std::forward<Args>(args)...).first;
+  }
+
+  template <class K = key_type, class P = Policy>
+  MappedReference<P> at(const key_arg<K>& key) {
+    auto it = this->find(key);
+    if (it == this->end()) {
+      base_internal::ThrowStdOutOfRange(
+          "absl::container_internal::raw_hash_map<>::at");
+    }
+    return Policy::value(&*it);
+  }
+
+  template <class K = key_type, class P = Policy>
+  MappedConstReference<P> at(const key_arg<K>& key) const {
+    auto it = this->find(key);
+    if (it == this->end()) {
+      base_internal::ThrowStdOutOfRange(
+          "absl::container_internal::raw_hash_map<>::at");
+    }
+    return Policy::value(&*it);
+  }
+
+  template <class K = key_type, class P = Policy, K* = nullptr>
+  MappedReference<P> operator[](key_arg<K>&& key) {
+    return Policy::value(&*try_emplace(std::forward<K>(key)).first);
+  }
+
+  template <class K = key_type, class P = Policy>
+  MappedReference<P> operator[](const key_arg<K>& key) {
+    return Policy::value(&*try_emplace(key).first);
+  }
+
+ private:
+  template <class K, class V>
+  std::pair<iterator, bool> insert_or_assign_impl(K&& k, V&& v) {
+    auto res = this->find_or_prepare_insert(k);
+    if (res.second)
+      this->emplace_at(res.first, std::forward<K>(k), std::forward<V>(v));
+    else
+      Policy::value(&*this->iterator_at(res.first)) = std::forward<V>(v);
+    return {this->iterator_at(res.first), res.second};
+  }
+
+  template <class K = key_type, class... Args>
+  std::pair<iterator, bool> try_emplace_impl(K&& k, Args&&... args) {
+    auto res = this->find_or_prepare_insert(k);
+    if (res.second)
+      this->emplace_at(res.first, std::piecewise_construct,
+                       std::forward_as_tuple(std::forward<K>(k)),
+                       std::forward_as_tuple(std::forward<Args>(args)...));
+    return {this->iterator_at(res.first), res.second};
+  }
+};
+
+}  // namespace container_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#endif  // ABSL_CONTAINER_INTERNAL_RAW_HASH_MAP_H_
diff --git a/src/absl/container/internal/raw_hash_set.cc b/src/absl/container/internal/raw_hash_set.cc
new file mode 100644 (file)
index 0000000..bfef071
--- /dev/null
@@ -0,0 +1,61 @@
+// Copyright 2018 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "absl/container/internal/raw_hash_set.h"
+
+#include <atomic>
+#include <cstddef>
+
+#include "absl/base/config.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace container_internal {
+
+constexpr size_t Group::kWidth;
+
+// Returns "random" seed.
+inline size_t RandomSeed() {
+#ifdef ABSL_HAVE_THREAD_LOCAL
+  static thread_local size_t counter = 0;
+  size_t value = ++counter;
+#else   // ABSL_HAVE_THREAD_LOCAL
+  static std::atomic<size_t> counter(0);
+  size_t value = counter.fetch_add(1, std::memory_order_relaxed);
+#endif  // ABSL_HAVE_THREAD_LOCAL
+  return value ^ static_cast<size_t>(reinterpret_cast<uintptr_t>(&counter));
+}
+
+bool ShouldInsertBackwards(size_t hash, ctrl_t* ctrl) {
+  // To avoid problems with weak hashes and single bit tests, we use % 13.
+  // TODO(kfm,sbenza): revisit after we do unconditional mixing
+  return (H1(hash, ctrl) ^ RandomSeed()) % 13 > 6;
+}
+
+void ConvertDeletedToEmptyAndFullToDeleted(
+    ctrl_t* ctrl, size_t capacity) {
+  assert(ctrl[capacity] == kSentinel);
+  assert(IsValidCapacity(capacity));
+  for (ctrl_t* pos = ctrl; pos != ctrl + capacity + 1; pos += Group::kWidth) {
+    Group{pos}.ConvertSpecialToEmptyAndFullToDeleted(pos);
+  }
+  // Copy the cloned ctrl bytes.
+  std::memcpy(ctrl + capacity + 1, ctrl, Group::kWidth);
+  ctrl[capacity] = kSentinel;
+}
+
+
+}  // namespace container_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
diff --git a/src/absl/container/internal/raw_hash_set.h b/src/absl/container/internal/raw_hash_set.h
new file mode 100644 (file)
index 0000000..8615de8
--- /dev/null
@@ -0,0 +1,1903 @@
+// Copyright 2018 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// An open-addressing
+// hashtable with quadratic probing.
+//
+// This is a low level hashtable on top of which different interfaces can be
+// implemented, like flat_hash_set, node_hash_set, string_hash_set, etc.
+//
+// The table interface is similar to that of std::unordered_set. Notable
+// differences are that most member functions support heterogeneous keys when
+// BOTH the hash and eq functions are marked as transparent. They do so by
+// providing a typedef called `is_transparent`.
+//
+// When heterogeneous lookup is enabled, functions that take key_type act as if
+// they have an overload set like:
+//
+//   iterator find(const key_type& key);
+//   template <class K>
+//   iterator find(const K& key);
+//
+//   size_type erase(const key_type& key);
+//   template <class K>
+//   size_type erase(const K& key);
+//
+//   std::pair<iterator, iterator> equal_range(const key_type& key);
+//   template <class K>
+//   std::pair<iterator, iterator> equal_range(const K& key);
+//
+// When heterogeneous lookup is disabled, only the explicit `key_type` overloads
+// exist.
+//
+// find() also supports passing the hash explicitly:
+//
+//   iterator find(const key_type& key, size_t hash);
+//   template <class U>
+//   iterator find(const U& key, size_t hash);
+//
+// In addition the pointer to element and iterator stability guarantees are
+// weaker: all iterators and pointers are invalidated after a new element is
+// inserted.
+//
+// IMPLEMENTATION DETAILS
+//
+// The table stores elements inline in a slot array. In addition to the slot
+// array the table maintains some control state per slot. The extra state is one
+// byte per slot and stores empty or deleted marks, or alternatively 7 bits from
+// the hash of an occupied slot. The table is split into logical groups of
+// slots, like so:
+//
+//      Group 1         Group 2        Group 3
+// +---------------+---------------+---------------+
+// | | | | | | | | | | | | | | | | | | | | | | | | |
+// +---------------+---------------+---------------+
+//
+// On lookup the hash is split into two parts:
+// - H2: 7 bits (those stored in the control bytes)
+// - H1: the rest of the bits
+// The groups are probed using H1. For each group the slots are matched to H2 in
+// parallel. Because H2 is 7 bits (128 states) and the number of slots per group
+// is low (8 or 16) in almost all cases a match in H2 is also a lookup hit.
+//
+// On insert, once the right group is found (as in lookup), its slots are
+// filled in order.
+//
+// On erase a slot is cleared. In case the group did not have any empty slots
+// before the erase, the erased slot is marked as deleted.
+//
+// Groups without empty slots (but maybe with deleted slots) extend the probe
+// sequence. The probing algorithm is quadratic. Given N the number of groups,
+// the probing function for the i'th probe is:
+//
+//   P(0) = H1 % N
+//
+//   P(i) = (P(i - 1) + i) % N
+//
+// This probing function guarantees that after N probes, all the groups of the
+// table will be probed exactly once.
+
+#ifndef ABSL_CONTAINER_INTERNAL_RAW_HASH_SET_H_
+#define ABSL_CONTAINER_INTERNAL_RAW_HASH_SET_H_
+
+#include <algorithm>
+#include <cmath>
+#include <cstdint>
+#include <cstring>
+#include <iterator>
+#include <limits>
+#include <memory>
+#include <tuple>
+#include <type_traits>
+#include <utility>
+
+#include "absl/base/internal/endian.h"
+#include "absl/base/optimization.h"
+#include "absl/base/port.h"
+#include "absl/container/internal/common.h"
+#include "absl/container/internal/compressed_tuple.h"
+#include "absl/container/internal/container_memory.h"
+#include "absl/container/internal/hash_policy_traits.h"
+#include "absl/container/internal/hashtable_debug_hooks.h"
+#include "absl/container/internal/hashtablez_sampler.h"
+#include "absl/container/internal/have_sse.h"
+#include "absl/container/internal/layout.h"
+#include "absl/memory/memory.h"
+#include "absl/meta/type_traits.h"
+#include "absl/numeric/bits.h"
+#include "absl/utility/utility.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace container_internal {
+
+template <typename AllocType>
+void SwapAlloc(AllocType& lhs, AllocType& rhs,
+               std::true_type /* propagate_on_container_swap */) {
+  using std::swap;
+  swap(lhs, rhs);
+}
+template <typename AllocType>
+void SwapAlloc(AllocType& /*lhs*/, AllocType& /*rhs*/,
+               std::false_type /* propagate_on_container_swap */) {}
+
+template <size_t Width>
+class probe_seq {
+ public:
+  probe_seq(size_t hash, size_t mask) {
+    assert(((mask + 1) & mask) == 0 && "not a mask");
+    mask_ = mask;
+    offset_ = hash & mask_;
+  }
+  size_t offset() const { return offset_; }
+  size_t offset(size_t i) const { return (offset_ + i) & mask_; }
+
+  void next() {
+    index_ += Width;
+    offset_ += index_;
+    offset_ &= mask_;
+  }
+  // 0-based probe index. The i-th probe in the probe sequence.
+  size_t index() const { return index_; }
+
+ private:
+  size_t mask_;
+  size_t offset_;
+  size_t index_ = 0;
+};
+
+template <class ContainerKey, class Hash, class Eq>
+struct RequireUsableKey {
+  template <class PassedKey, class... Args>
+  std::pair<
+      decltype(std::declval<const Hash&>()(std::declval<const PassedKey&>())),
+      decltype(std::declval<const Eq&>()(std::declval<const ContainerKey&>(),
+                                         std::declval<const PassedKey&>()))>*
+  operator()(const PassedKey&, const Args&...) const;
+};
+
+template <class E, class Policy, class Hash, class Eq, class... Ts>
+struct IsDecomposable : std::false_type {};
+
+template <class Policy, class Hash, class Eq, class... Ts>
+struct IsDecomposable<
+    absl::void_t<decltype(
+        Policy::apply(RequireUsableKey<typename Policy::key_type, Hash, Eq>(),
+                      std::declval<Ts>()...))>,
+    Policy, Hash, Eq, Ts...> : std::true_type {};
+
+// TODO(alkis): Switch to std::is_nothrow_swappable when gcc/clang supports it.
+template <class T>
+constexpr bool IsNoThrowSwappable(std::true_type = {} /* is_swappable */) {
+  using std::swap;
+  return noexcept(swap(std::declval<T&>(), std::declval<T&>()));
+}
+template <class T>
+constexpr bool IsNoThrowSwappable(std::false_type /* is_swappable */) {
+  return false;
+}
+
+template <typename T>
+uint32_t TrailingZeros(T x) {
+  ABSL_INTERNAL_ASSUME(x != 0);
+  return countr_zero(x);
+}
+
+// An abstraction over a bitmask. It provides an easy way to iterate through the
+// indexes of the set bits of a bitmask.  When Shift=0 (platforms with SSE),
+// this is a true bitmask.  On non-SSE, platforms the arithematic used to
+// emulate the SSE behavior works in bytes (Shift=3) and leaves each bytes as
+// either 0x00 or 0x80.
+//
+// For example:
+//   for (int i : BitMask<uint32_t, 16>(0x5)) -> yields 0, 2
+//   for (int i : BitMask<uint64_t, 8, 3>(0x0000000080800000)) -> yields 2, 3
+template <class T, int SignificantBits, int Shift = 0>
+class BitMask {
+  static_assert(std::is_unsigned<T>::value, "");
+  static_assert(Shift == 0 || Shift == 3, "");
+
+ public:
+  // These are useful for unit tests (gunit).
+  using value_type = int;
+  using iterator = BitMask;
+  using const_iterator = BitMask;
+
+  explicit BitMask(T mask) : mask_(mask) {}
+  BitMask& operator++() {
+    mask_ &= (mask_ - 1);
+    return *this;
+  }
+  explicit operator bool() const { return mask_ != 0; }
+  int operator*() const { return LowestBitSet(); }
+  uint32_t LowestBitSet() const {
+    return container_internal::TrailingZeros(mask_) >> Shift;
+  }
+  uint32_t HighestBitSet() const {
+    return static_cast<uint32_t>((bit_width(mask_) - 1) >> Shift);
+  }
+
+  BitMask begin() const { return *this; }
+  BitMask end() const { return BitMask(0); }
+
+  uint32_t TrailingZeros() const {
+    return container_internal::TrailingZeros(mask_) >> Shift;
+  }
+
+  uint32_t LeadingZeros() const {
+    constexpr int total_significant_bits = SignificantBits << Shift;
+    constexpr int extra_bits = sizeof(T) * 8 - total_significant_bits;
+    return countl_zero(mask_ << extra_bits) >> Shift;
+  }
+
+ private:
+  friend bool operator==(const BitMask& a, const BitMask& b) {
+    return a.mask_ == b.mask_;
+  }
+  friend bool operator!=(const BitMask& a, const BitMask& b) {
+    return a.mask_ != b.mask_;
+  }
+
+  T mask_;
+};
+
+using ctrl_t = signed char;
+using h2_t = uint8_t;
+
+// The values here are selected for maximum performance. See the static asserts
+// below for details.
+enum Ctrl : ctrl_t {
+  kEmpty = -128,   // 0b10000000
+  kDeleted = -2,   // 0b11111110
+  kSentinel = -1,  // 0b11111111
+};
+static_assert(
+    kEmpty & kDeleted & kSentinel & 0x80,
+    "Special markers need to have the MSB to make checking for them efficient");
+static_assert(kEmpty < kSentinel && kDeleted < kSentinel,
+              "kEmpty and kDeleted must be smaller than kSentinel to make the "
+              "SIMD test of IsEmptyOrDeleted() efficient");
+static_assert(kSentinel == -1,
+              "kSentinel must be -1 to elide loading it from memory into SIMD "
+              "registers (pcmpeqd xmm, xmm)");
+static_assert(kEmpty == -128,
+              "kEmpty must be -128 to make the SIMD check for its "
+              "existence efficient (psignb xmm, xmm)");
+static_assert(~kEmpty & ~kDeleted & kSentinel & 0x7F,
+              "kEmpty and kDeleted must share an unset bit that is not shared "
+              "by kSentinel to make the scalar test for MatchEmptyOrDeleted() "
+              "efficient");
+static_assert(kDeleted == -2,
+              "kDeleted must be -2 to make the implementation of "
+              "ConvertSpecialToEmptyAndFullToDeleted efficient");
+
+// A single block of empty control bytes for tables without any slots allocated.
+// This enables removing a branch in the hot path of find().
+inline ctrl_t* EmptyGroup() {
+  alignas(16) static constexpr ctrl_t empty_group[] = {
+      kSentinel, kEmpty, kEmpty, kEmpty, kEmpty, kEmpty, kEmpty, kEmpty,
+      kEmpty,    kEmpty, kEmpty, kEmpty, kEmpty, kEmpty, kEmpty, kEmpty};
+  return const_cast<ctrl_t*>(empty_group);
+}
+
+// Mixes a randomly generated per-process seed with `hash` and `ctrl` to
+// randomize insertion order within groups.
+bool ShouldInsertBackwards(size_t hash, ctrl_t* ctrl);
+
+// Returns a hash seed.
+//
+// The seed consists of the ctrl_ pointer, which adds enough entropy to ensure
+// non-determinism of iteration order in most cases.
+inline size_t HashSeed(const ctrl_t* ctrl) {
+  // The low bits of the pointer have little or no entropy because of
+  // alignment. We shift the pointer to try to use higher entropy bits. A
+  // good number seems to be 12 bits, because that aligns with page size.
+  return reinterpret_cast<uintptr_t>(ctrl) >> 12;
+}
+
+inline size_t H1(size_t hash, const ctrl_t* ctrl) {
+  return (hash >> 7) ^ HashSeed(ctrl);
+}
+inline ctrl_t H2(size_t hash) { return hash & 0x7F; }
+
+inline bool IsEmpty(ctrl_t c) { return c == kEmpty; }
+inline bool IsFull(ctrl_t c) { return c >= 0; }
+inline bool IsDeleted(ctrl_t c) { return c == kDeleted; }
+inline bool IsEmptyOrDeleted(ctrl_t c) { return c < kSentinel; }
+
+#if ABSL_INTERNAL_RAW_HASH_SET_HAVE_SSE2
+
+// https://github.com/abseil/abseil-cpp/issues/209
+// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=87853
+// _mm_cmpgt_epi8 is broken under GCC with -funsigned-char
+// Work around this by using the portable implementation of Group
+// when using -funsigned-char under GCC.
+inline __m128i _mm_cmpgt_epi8_fixed(__m128i a, __m128i b) {
+#if defined(__GNUC__) && !defined(__clang__)
+  if (std::is_unsigned<char>::value) {
+    const __m128i mask = _mm_set1_epi8(0x80);
+    const __m128i diff = _mm_subs_epi8(b, a);
+    return _mm_cmpeq_epi8(_mm_and_si128(diff, mask), mask);
+  }
+#endif
+  return _mm_cmpgt_epi8(a, b);
+}
+
+struct GroupSse2Impl {
+  static constexpr size_t kWidth = 16;  // the number of slots per group
+
+  explicit GroupSse2Impl(const ctrl_t* pos) {
+    ctrl = _mm_loadu_si128(reinterpret_cast<const __m128i*>(pos));
+  }
+
+  // Returns a bitmask representing the positions of slots that match hash.
+  BitMask<uint32_t, kWidth> Match(h2_t hash) const {
+    auto match = _mm_set1_epi8(hash);
+    return BitMask<uint32_t, kWidth>(
+        _mm_movemask_epi8(_mm_cmpeq_epi8(match, ctrl)));
+  }
+
+  // Returns a bitmask representing the positions of empty slots.
+  BitMask<uint32_t, kWidth> MatchEmpty() const {
+#if ABSL_INTERNAL_RAW_HASH_SET_HAVE_SSSE3
+    // This only works because kEmpty is -128.
+    return BitMask<uint32_t, kWidth>(
+        _mm_movemask_epi8(_mm_sign_epi8(ctrl, ctrl)));
+#else
+    return Match(static_cast<h2_t>(kEmpty));
+#endif
+  }
+
+  // Returns a bitmask representing the positions of empty or deleted slots.
+  BitMask<uint32_t, kWidth> MatchEmptyOrDeleted() const {
+    auto special = _mm_set1_epi8(kSentinel);
+    return BitMask<uint32_t, kWidth>(
+        _mm_movemask_epi8(_mm_cmpgt_epi8_fixed(special, ctrl)));
+  }
+
+  // Returns the number of trailing empty or deleted elements in the group.
+  uint32_t CountLeadingEmptyOrDeleted() const {
+    auto special = _mm_set1_epi8(kSentinel);
+    return TrailingZeros(static_cast<uint32_t>(
+        _mm_movemask_epi8(_mm_cmpgt_epi8_fixed(special, ctrl)) + 1));
+  }
+
+  void ConvertSpecialToEmptyAndFullToDeleted(ctrl_t* dst) const {
+    auto msbs = _mm_set1_epi8(static_cast<char>(-128));
+    auto x126 = _mm_set1_epi8(126);
+#if ABSL_INTERNAL_RAW_HASH_SET_HAVE_SSSE3
+    auto res = _mm_or_si128(_mm_shuffle_epi8(x126, ctrl), msbs);
+#else
+    auto zero = _mm_setzero_si128();
+    auto special_mask = _mm_cmpgt_epi8_fixed(zero, ctrl);
+    auto res = _mm_or_si128(msbs, _mm_andnot_si128(special_mask, x126));
+#endif
+    _mm_storeu_si128(reinterpret_cast<__m128i*>(dst), res);
+  }
+
+  __m128i ctrl;
+};
+#endif  // ABSL_INTERNAL_RAW_HASH_SET_HAVE_SSE2
+
+struct GroupPortableImpl {
+  static constexpr size_t kWidth = 8;
+
+  explicit GroupPortableImpl(const ctrl_t* pos)
+      : ctrl(little_endian::Load64(pos)) {}
+
+  BitMask<uint64_t, kWidth, 3> Match(h2_t hash) const {
+    // For the technique, see:
+    // http://graphics.stanford.edu/~seander/bithacks.html##ValueInWord
+    // (Determine if a word has a byte equal to n).
+    //
+    // Caveat: there are false positives but:
+    // - they only occur if there is a real match
+    // - they never occur on kEmpty, kDeleted, kSentinel
+    // - they will be handled gracefully by subsequent checks in code
+    //
+    // Example:
+    //   v = 0x1716151413121110
+    //   hash = 0x12
+    //   retval = (v - lsbs) & ~v & msbs = 0x0000000080800000
+    constexpr uint64_t msbs = 0x8080808080808080ULL;
+    constexpr uint64_t lsbs = 0x0101010101010101ULL;
+    auto x = ctrl ^ (lsbs * hash);
+    return BitMask<uint64_t, kWidth, 3>((x - lsbs) & ~x & msbs);
+  }
+
+  BitMask<uint64_t, kWidth, 3> MatchEmpty() const {
+    constexpr uint64_t msbs = 0x8080808080808080ULL;
+    return BitMask<uint64_t, kWidth, 3>((ctrl & (~ctrl << 6)) & msbs);
+  }
+
+  BitMask<uint64_t, kWidth, 3> MatchEmptyOrDeleted() const {
+    constexpr uint64_t msbs = 0x8080808080808080ULL;
+    return BitMask<uint64_t, kWidth, 3>((ctrl & (~ctrl << 7)) & msbs);
+  }
+
+  uint32_t CountLeadingEmptyOrDeleted() const {
+    constexpr uint64_t gaps = 0x00FEFEFEFEFEFEFEULL;
+    return (TrailingZeros(((~ctrl & (ctrl >> 7)) | gaps) + 1) + 7) >> 3;
+  }
+
+  void ConvertSpecialToEmptyAndFullToDeleted(ctrl_t* dst) const {
+    constexpr uint64_t msbs = 0x8080808080808080ULL;
+    constexpr uint64_t lsbs = 0x0101010101010101ULL;
+    auto x = ctrl & msbs;
+    auto res = (~x + (x >> 7)) & ~lsbs;
+    little_endian::Store64(dst, res);
+  }
+
+  uint64_t ctrl;
+};
+
+#if ABSL_INTERNAL_RAW_HASH_SET_HAVE_SSE2
+using Group = GroupSse2Impl;
+#else
+using Group = GroupPortableImpl;
+#endif
+
+template <class Policy, class Hash, class Eq, class Alloc>
+class raw_hash_set;
+
+inline bool IsValidCapacity(size_t n) { return ((n + 1) & n) == 0 && n > 0; }
+
+// PRECONDITION:
+//   IsValidCapacity(capacity)
+//   ctrl[capacity] == kSentinel
+//   ctrl[i] != kSentinel for all i < capacity
+// Applies mapping for every byte in ctrl:
+//   DELETED -> EMPTY
+//   EMPTY -> EMPTY
+//   FULL -> DELETED
+void ConvertDeletedToEmptyAndFullToDeleted(ctrl_t* ctrl, size_t capacity);
+
+// Rounds up the capacity to the next power of 2 minus 1, with a minimum of 1.
+inline size_t NormalizeCapacity(size_t n) {
+  return n ? ~size_t{} >> countl_zero(n) : 1;
+}
+
+// General notes on capacity/growth methods below:
+// - We use 7/8th as maximum load factor. For 16-wide groups, that gives an
+//   average of two empty slots per group.
+// - For (capacity+1) >= Group::kWidth, growth is 7/8*capacity.
+// - For (capacity+1) < Group::kWidth, growth == capacity. In this case, we
+//   never need to probe (the whole table fits in one group) so we don't need a
+//   load factor less than 1.
+
+// Given `capacity` of the table, returns the size (i.e. number of full slots)
+// at which we should grow the capacity.
+inline size_t CapacityToGrowth(size_t capacity) {
+  assert(IsValidCapacity(capacity));
+  // `capacity*7/8`
+  if (Group::kWidth == 8 && capacity == 7) {
+    // x-x/8 does not work when x==7.
+    return 6;
+  }
+  return capacity - capacity / 8;
+}
+// From desired "growth" to a lowerbound of the necessary capacity.
+// Might not be a valid one and requires NormalizeCapacity().
+inline size_t GrowthToLowerboundCapacity(size_t growth) {
+  // `growth*8/7`
+  if (Group::kWidth == 8 && growth == 7) {
+    // x+(x-1)/7 does not work when x==7.
+    return 8;
+  }
+  return growth + static_cast<size_t>((static_cast<int64_t>(growth) - 1) / 7);
+}
+
+inline void AssertIsFull(ctrl_t* ctrl) {
+  ABSL_HARDENING_ASSERT((ctrl != nullptr && IsFull(*ctrl)) &&
+                        "Invalid operation on iterator. The element might have "
+                        "been erased, or the table might have rehashed.");
+}
+
+inline void AssertIsValid(ctrl_t* ctrl) {
+  ABSL_HARDENING_ASSERT((ctrl == nullptr || IsFull(*ctrl)) &&
+                        "Invalid operation on iterator. The element might have "
+                        "been erased, or the table might have rehashed.");
+}
+
+struct FindInfo {
+  size_t offset;
+  size_t probe_length;
+};
+
+// The representation of the object has two modes:
+//  - small: For capacities < kWidth-1
+//  - large: For the rest.
+//
+// Differences:
+//  - In small mode we are able to use the whole capacity. The extra control
+//  bytes give us at least one "empty" control byte to stop the iteration.
+//  This is important to make 1 a valid capacity.
+//
+//  - In small mode only the first `capacity()` control bytes after the
+//  sentinel are valid. The rest contain dummy kEmpty values that do not
+//  represent a real slot. This is important to take into account on
+//  find_first_non_full(), where we never try ShouldInsertBackwards() for
+//  small tables.
+inline bool is_small(size_t capacity) { return capacity < Group::kWidth - 1; }
+
+inline probe_seq<Group::kWidth> probe(ctrl_t* ctrl, size_t hash,
+                                      size_t capacity) {
+  return probe_seq<Group::kWidth>(H1(hash, ctrl), capacity);
+}
+
+// Probes the raw_hash_set with the probe sequence for hash and returns the
+// pointer to the first empty or deleted slot.
+// NOTE: this function must work with tables having both kEmpty and kDelete
+// in one group. Such tables appears during drop_deletes_without_resize.
+//
+// This function is very useful when insertions happen and:
+// - the input is already a set
+// - there are enough slots
+// - the element with the hash is not in the table
+inline FindInfo find_first_non_full(ctrl_t* ctrl, size_t hash,
+                                    size_t capacity) {
+  auto seq = probe(ctrl, hash, capacity);
+  while (true) {
+    Group g{ctrl + seq.offset()};
+    auto mask = g.MatchEmptyOrDeleted();
+    if (mask) {
+#if !defined(NDEBUG)
+      // We want to add entropy even when ASLR is not enabled.
+      // In debug build we will randomly insert in either the front or back of
+      // the group.
+      // TODO(kfm,sbenza): revisit after we do unconditional mixing
+      if (!is_small(capacity) && ShouldInsertBackwards(hash, ctrl)) {
+        return {seq.offset(mask.HighestBitSet()), seq.index()};
+      }
+#endif
+      return {seq.offset(mask.LowestBitSet()), seq.index()};
+    }
+    seq.next();
+    assert(seq.index() < capacity && "full table!");
+  }
+}
+
+// Policy: a policy defines how to perform different operations on
+// the slots of the hashtable (see hash_policy_traits.h for the full interface
+// of policy).
+//
+// Hash: a (possibly polymorphic) functor that hashes keys of the hashtable. The
+// functor should accept a key and return size_t as hash. For best performance
+// it is important that the hash function provides high entropy across all bits
+// of the hash.
+//
+// Eq: a (possibly polymorphic) functor that compares two keys for equality. It
+// should accept two (of possibly different type) keys and return a bool: true
+// if they are equal, false if they are not. If two keys compare equal, then
+// their hash values as defined by Hash MUST be equal.
+//
+// Allocator: an Allocator
+// [https://en.cppreference.com/w/cpp/named_req/Allocator] with which
+// the storage of the hashtable will be allocated and the elements will be
+// constructed and destroyed.
+template <class Policy, class Hash, class Eq, class Alloc>
+class raw_hash_set {
+  using PolicyTraits = hash_policy_traits<Policy>;
+  using KeyArgImpl =
+      KeyArg<IsTransparent<Eq>::value && IsTransparent<Hash>::value>;
+
+ public:
+  using init_type = typename PolicyTraits::init_type;
+  using key_type = typename PolicyTraits::key_type;
+  // TODO(sbenza): Hide slot_type as it is an implementation detail. Needs user
+  // code fixes!
+  using slot_type = typename PolicyTraits::slot_type;
+  using allocator_type = Alloc;
+  using size_type = size_t;
+  using difference_type = ptrdiff_t;
+  using hasher = Hash;
+  using key_equal = Eq;
+  using policy_type = Policy;
+  using value_type = typename PolicyTraits::value_type;
+  using reference = value_type&;
+  using const_reference = const value_type&;
+  using pointer = typename absl::allocator_traits<
+      allocator_type>::template rebind_traits<value_type>::pointer;
+  using const_pointer = typename absl::allocator_traits<
+      allocator_type>::template rebind_traits<value_type>::const_pointer;
+
+  // Alias used for heterogeneous lookup functions.
+  // `key_arg<K>` evaluates to `K` when the functors are transparent and to
+  // `key_type` otherwise. It permits template argument deduction on `K` for the
+  // transparent case.
+  template <class K>
+  using key_arg = typename KeyArgImpl::template type<K, key_type>;
+
+ private:
+  // Give an early error when key_type is not hashable/eq.
+  auto KeyTypeCanBeHashed(const Hash& h, const key_type& k) -> decltype(h(k));
+  auto KeyTypeCanBeEq(const Eq& eq, const key_type& k) -> decltype(eq(k, k));
+
+  using Layout = absl::container_internal::Layout<ctrl_t, slot_type>;
+
+  static Layout MakeLayout(size_t capacity) {
+    assert(IsValidCapacity(capacity));
+    return Layout(capacity + Group::kWidth + 1, capacity);
+  }
+
+  using AllocTraits = absl::allocator_traits<allocator_type>;
+  using SlotAlloc = typename absl::allocator_traits<
+      allocator_type>::template rebind_alloc<slot_type>;
+  using SlotAllocTraits = typename absl::allocator_traits<
+      allocator_type>::template rebind_traits<slot_type>;
+
+  static_assert(std::is_lvalue_reference<reference>::value,
+                "Policy::element() must return a reference");
+
+  template <typename T>
+  struct SameAsElementReference
+      : std::is_same<typename std::remove_cv<
+                         typename std::remove_reference<reference>::type>::type,
+                     typename std::remove_cv<
+                         typename std::remove_reference<T>::type>::type> {};
+
+  // An enabler for insert(T&&): T must be convertible to init_type or be the
+  // same as [cv] value_type [ref].
+  // Note: we separate SameAsElementReference into its own type to avoid using
+  // reference unless we need to. MSVC doesn't seem to like it in some
+  // cases.
+  template <class T>
+  using RequiresInsertable = typename std::enable_if<
+      absl::disjunction<std::is_convertible<T, init_type>,
+                        SameAsElementReference<T>>::value,
+      int>::type;
+
+  // RequiresNotInit is a workaround for gcc prior to 7.1.
+  // See https://godbolt.org/g/Y4xsUh.
+  template <class T>
+  using RequiresNotInit =
+      typename std::enable_if<!std::is_same<T, init_type>::value, int>::type;
+
+  template <class... Ts>
+  using IsDecomposable = IsDecomposable<void, PolicyTraits, Hash, Eq, Ts...>;
+
+ public:
+  static_assert(std::is_same<pointer, value_type*>::value,
+                "Allocators with custom pointer types are not supported");
+  static_assert(std::is_same<const_pointer, const value_type*>::value,
+                "Allocators with custom pointer types are not supported");
+
+  class iterator {
+    friend class raw_hash_set;
+
+   public:
+    using iterator_category = std::forward_iterator_tag;
+    using value_type = typename raw_hash_set::value_type;
+    using reference =
+        absl::conditional_t<PolicyTraits::constant_iterators::value,
+                            const value_type&, value_type&>;
+    using pointer = absl::remove_reference_t<reference>*;
+    using difference_type = typename raw_hash_set::difference_type;
+
+    iterator() {}
+
+    // PRECONDITION: not an end() iterator.
+    reference operator*() const {
+      AssertIsFull(ctrl_);
+      return PolicyTraits::element(slot_);
+    }
+
+    // PRECONDITION: not an end() iterator.
+    pointer operator->() const { return &operator*(); }
+
+    // PRECONDITION: not an end() iterator.
+    iterator& operator++() {
+      AssertIsFull(ctrl_);
+      ++ctrl_;
+      ++slot_;
+      skip_empty_or_deleted();
+      return *this;
+    }
+    // PRECONDITION: not an end() iterator.
+    iterator operator++(int) {
+      auto tmp = *this;
+      ++*this;
+      return tmp;
+    }
+
+    friend bool operator==(const iterator& a, const iterator& b) {
+      AssertIsValid(a.ctrl_);
+      AssertIsValid(b.ctrl_);
+      return a.ctrl_ == b.ctrl_;
+    }
+    friend bool operator!=(const iterator& a, const iterator& b) {
+      return !(a == b);
+    }
+
+   private:
+    iterator(ctrl_t* ctrl, slot_type* slot) : ctrl_(ctrl), slot_(slot) {
+      // This assumption helps the compiler know that any non-end iterator is
+      // not equal to any end iterator.
+      ABSL_INTERNAL_ASSUME(ctrl != nullptr);
+    }
+
+    void skip_empty_or_deleted() {
+      while (IsEmptyOrDeleted(*ctrl_)) {
+        uint32_t shift = Group{ctrl_}.CountLeadingEmptyOrDeleted();
+        ctrl_ += shift;
+        slot_ += shift;
+      }
+      if (ABSL_PREDICT_FALSE(*ctrl_ == kSentinel)) ctrl_ = nullptr;
+    }
+
+    ctrl_t* ctrl_ = nullptr;
+    // To avoid uninitialized member warnings, put slot_ in an anonymous union.
+    // The member is not initialized on singleton and end iterators.
+    union {
+      slot_type* slot_;
+    };
+  };
+
+  class const_iterator {
+    friend class raw_hash_set;
+
+   public:
+    using iterator_category = typename iterator::iterator_category;
+    using value_type = typename raw_hash_set::value_type;
+    using reference = typename raw_hash_set::const_reference;
+    using pointer = typename raw_hash_set::const_pointer;
+    using difference_type = typename raw_hash_set::difference_type;
+
+    const_iterator() {}
+    // Implicit construction from iterator.
+    const_iterator(iterator i) : inner_(std::move(i)) {}
+
+    reference operator*() const { return *inner_; }
+    pointer operator->() const { return inner_.operator->(); }
+
+    const_iterator& operator++() {
+      ++inner_;
+      return *this;
+    }
+    const_iterator operator++(int) { return inner_++; }
+
+    friend bool operator==(const const_iterator& a, const const_iterator& b) {
+      return a.inner_ == b.inner_;
+    }
+    friend bool operator!=(const const_iterator& a, const const_iterator& b) {
+      return !(a == b);
+    }
+
+   private:
+    const_iterator(const ctrl_t* ctrl, const slot_type* slot)
+        : inner_(const_cast<ctrl_t*>(ctrl), const_cast<slot_type*>(slot)) {}
+
+    iterator inner_;
+  };
+
+  using node_type = node_handle<Policy, hash_policy_traits<Policy>, Alloc>;
+  using insert_return_type = InsertReturnType<iterator, node_type>;
+
+  raw_hash_set() noexcept(
+      std::is_nothrow_default_constructible<hasher>::value&&
+          std::is_nothrow_default_constructible<key_equal>::value&&
+              std::is_nothrow_default_constructible<allocator_type>::value) {}
+
+  explicit raw_hash_set(size_t bucket_count, const hasher& hash = hasher(),
+                        const key_equal& eq = key_equal(),
+                        const allocator_type& alloc = allocator_type())
+      : ctrl_(EmptyGroup()),
+        settings_(0, HashtablezInfoHandle(), hash, eq, alloc) {
+    if (bucket_count) {
+      capacity_ = NormalizeCapacity(bucket_count);
+      initialize_slots();
+    }
+  }
+
+  raw_hash_set(size_t bucket_count, const hasher& hash,
+               const allocator_type& alloc)
+      : raw_hash_set(bucket_count, hash, key_equal(), alloc) {}
+
+  raw_hash_set(size_t bucket_count, const allocator_type& alloc)
+      : raw_hash_set(bucket_count, hasher(), key_equal(), alloc) {}
+
+  explicit raw_hash_set(const allocator_type& alloc)
+      : raw_hash_set(0, hasher(), key_equal(), alloc) {}
+
+  template <class InputIter>
+  raw_hash_set(InputIter first, InputIter last, size_t bucket_count = 0,
+               const hasher& hash = hasher(), const key_equal& eq = key_equal(),
+               const allocator_type& alloc = allocator_type())
+      : raw_hash_set(bucket_count, hash, eq, alloc) {
+    insert(first, last);
+  }
+
+  template <class InputIter>
+  raw_hash_set(InputIter first, InputIter last, size_t bucket_count,
+               const hasher& hash, const allocator_type& alloc)
+      : raw_hash_set(first, last, bucket_count, hash, key_equal(), alloc) {}
+
+  template <class InputIter>
+  raw_hash_set(InputIter first, InputIter last, size_t bucket_count,
+               const allocator_type& alloc)
+      : raw_hash_set(first, last, bucket_count, hasher(), key_equal(), alloc) {}
+
+  template <class InputIter>
+  raw_hash_set(InputIter first, InputIter last, const allocator_type& alloc)
+      : raw_hash_set(first, last, 0, hasher(), key_equal(), alloc) {}
+
+  // Instead of accepting std::initializer_list<value_type> as the first
+  // argument like std::unordered_set<value_type> does, we have two overloads
+  // that accept std::initializer_list<T> and std::initializer_list<init_type>.
+  // This is advantageous for performance.
+  //
+  //   // Turns {"abc", "def"} into std::initializer_list<std::string>, then
+  //   // copies the strings into the set.
+  //   std::unordered_set<std::string> s = {"abc", "def"};
+  //
+  //   // Turns {"abc", "def"} into std::initializer_list<const char*>, then
+  //   // copies the strings into the set.
+  //   absl::flat_hash_set<std::string> s = {"abc", "def"};
+  //
+  // The same trick is used in insert().
+  //
+  // The enabler is necessary to prevent this constructor from triggering where
+  // the copy constructor is meant to be called.
+  //
+  //   absl::flat_hash_set<int> a, b{a};
+  //
+  // RequiresNotInit<T> is a workaround for gcc prior to 7.1.
+  template <class T, RequiresNotInit<T> = 0, RequiresInsertable<T> = 0>
+  raw_hash_set(std::initializer_list<T> init, size_t bucket_count = 0,
+               const hasher& hash = hasher(), const key_equal& eq = key_equal(),
+               const allocator_type& alloc = allocator_type())
+      : raw_hash_set(init.begin(), init.end(), bucket_count, hash, eq, alloc) {}
+
+  raw_hash_set(std::initializer_list<init_type> init, size_t bucket_count = 0,
+               const hasher& hash = hasher(), const key_equal& eq = key_equal(),
+               const allocator_type& alloc = allocator_type())
+      : raw_hash_set(init.begin(), init.end(), bucket_count, hash, eq, alloc) {}
+
+  template <class T, RequiresNotInit<T> = 0, RequiresInsertable<T> = 0>
+  raw_hash_set(std::initializer_list<T> init, size_t bucket_count,
+               const hasher& hash, const allocator_type& alloc)
+      : raw_hash_set(init, bucket_count, hash, key_equal(), alloc) {}
+
+  raw_hash_set(std::initializer_list<init_type> init, size_t bucket_count,
+               const hasher& hash, const allocator_type& alloc)
+      : raw_hash_set(init, bucket_count, hash, key_equal(), alloc) {}
+
+  template <class T, RequiresNotInit<T> = 0, RequiresInsertable<T> = 0>
+  raw_hash_set(std::initializer_list<T> init, size_t bucket_count,
+               const allocator_type& alloc)
+      : raw_hash_set(init, bucket_count, hasher(), key_equal(), alloc) {}
+
+  raw_hash_set(std::initializer_list<init_type> init, size_t bucket_count,
+               const allocator_type& alloc)
+      : raw_hash_set(init, bucket_count, hasher(), key_equal(), alloc) {}
+
+  template <class T, RequiresNotInit<T> = 0, RequiresInsertable<T> = 0>
+  raw_hash_set(std::initializer_list<T> init, const allocator_type& alloc)
+      : raw_hash_set(init, 0, hasher(), key_equal(), alloc) {}
+
+  raw_hash_set(std::initializer_list<init_type> init,
+               const allocator_type& alloc)
+      : raw_hash_set(init, 0, hasher(), key_equal(), alloc) {}
+
+  raw_hash_set(const raw_hash_set& that)
+      : raw_hash_set(that, AllocTraits::select_on_container_copy_construction(
+                               that.alloc_ref())) {}
+
+  raw_hash_set(const raw_hash_set& that, const allocator_type& a)
+      : raw_hash_set(0, that.hash_ref(), that.eq_ref(), a) {
+    reserve(that.size());
+    // Because the table is guaranteed to be empty, we can do something faster
+    // than a full `insert`.
+    for (const auto& v : that) {
+      const size_t hash = PolicyTraits::apply(HashElement{hash_ref()}, v);
+      auto target = find_first_non_full(ctrl_, hash, capacity_);
+      set_ctrl(target.offset, H2(hash));
+      emplace_at(target.offset, v);
+      infoz().RecordInsert(hash, target.probe_length);
+    }
+    size_ = that.size();
+    growth_left() -= that.size();
+  }
+
+  raw_hash_set(raw_hash_set&& that) noexcept(
+      std::is_nothrow_copy_constructible<hasher>::value&&
+          std::is_nothrow_copy_constructible<key_equal>::value&&
+              std::is_nothrow_copy_constructible<allocator_type>::value)
+      : ctrl_(absl::exchange(that.ctrl_, EmptyGroup())),
+        slots_(absl::exchange(that.slots_, nullptr)),
+        size_(absl::exchange(that.size_, 0)),
+        capacity_(absl::exchange(that.capacity_, 0)),
+        // Hash, equality and allocator are copied instead of moved because
+        // `that` must be left valid. If Hash is std::function<Key>, moving it
+        // would create a nullptr functor that cannot be called.
+        settings_(absl::exchange(that.growth_left(), 0),
+                  absl::exchange(that.infoz(), HashtablezInfoHandle()),
+                  that.hash_ref(), that.eq_ref(), that.alloc_ref()) {}
+
+  raw_hash_set(raw_hash_set&& that, const allocator_type& a)
+      : ctrl_(EmptyGroup()),
+        slots_(nullptr),
+        size_(0),
+        capacity_(0),
+        settings_(0, HashtablezInfoHandle(), that.hash_ref(), that.eq_ref(),
+                  a) {
+    if (a == that.alloc_ref()) {
+      std::swap(ctrl_, that.ctrl_);
+      std::swap(slots_, that.slots_);
+      std::swap(size_, that.size_);
+      std::swap(capacity_, that.capacity_);
+      std::swap(growth_left(), that.growth_left());
+      std::swap(infoz(), that.infoz());
+    } else {
+      reserve(that.size());
+      // Note: this will copy elements of dense_set and unordered_set instead of
+      // moving them. This can be fixed if it ever becomes an issue.
+      for (auto& elem : that) insert(std::move(elem));
+    }
+  }
+
+  raw_hash_set& operator=(const raw_hash_set& that) {
+    raw_hash_set tmp(that,
+                     AllocTraits::propagate_on_container_copy_assignment::value
+                         ? that.alloc_ref()
+                         : alloc_ref());
+    swap(tmp);
+    return *this;
+  }
+
+  raw_hash_set& operator=(raw_hash_set&& that) noexcept(
+      absl::allocator_traits<allocator_type>::is_always_equal::value&&
+          std::is_nothrow_move_assignable<hasher>::value&&
+              std::is_nothrow_move_assignable<key_equal>::value) {
+    // TODO(sbenza): We should only use the operations from the noexcept clause
+    // to make sure we actually adhere to that contract.
+    return move_assign(
+        std::move(that),
+        typename AllocTraits::propagate_on_container_move_assignment());
+  }
+
+  ~raw_hash_set() { destroy_slots(); }
+
+  iterator begin() {
+    auto it = iterator_at(0);
+    it.skip_empty_or_deleted();
+    return it;
+  }
+  iterator end() { return {}; }
+
+  const_iterator begin() const {
+    return const_cast<raw_hash_set*>(this)->begin();
+  }
+  const_iterator end() const { return {}; }
+  const_iterator cbegin() const { return begin(); }
+  const_iterator cend() const { return end(); }
+
+  bool empty() const { return !size(); }
+  size_t size() const { return size_; }
+  size_t capacity() const { return capacity_; }
+  size_t max_size() const { return (std::numeric_limits<size_t>::max)(); }
+
+  ABSL_ATTRIBUTE_REINITIALIZES void clear() {
+    // Iterating over this container is O(bucket_count()). When bucket_count()
+    // is much greater than size(), iteration becomes prohibitively expensive.
+    // For clear() it is more important to reuse the allocated array when the
+    // container is small because allocation takes comparatively long time
+    // compared to destruction of the elements of the container. So we pick the
+    // largest bucket_count() threshold for which iteration is still fast and
+    // past that we simply deallocate the array.
+    if (capacity_ > 127) {
+      destroy_slots();
+    } else if (capacity_) {
+      for (size_t i = 0; i != capacity_; ++i) {
+        if (IsFull(ctrl_[i])) {
+          PolicyTraits::destroy(&alloc_ref(), slots_ + i);
+        }
+      }
+      size_ = 0;
+      reset_ctrl();
+      reset_growth_left();
+    }
+    assert(empty());
+    infoz().RecordStorageChanged(0, capacity_);
+  }
+
+  // This overload kicks in when the argument is an rvalue of insertable and
+  // decomposable type other than init_type.
+  //
+  //   flat_hash_map<std::string, int> m;
+  //   m.insert(std::make_pair("abc", 42));
+  // TODO(cheshire): A type alias T2 is introduced as a workaround for the nvcc
+  // bug.
+  template <class T, RequiresInsertable<T> = 0,
+            class T2 = T,
+            typename std::enable_if<IsDecomposable<T2>::value, int>::type = 0,
+            T* = nullptr>
+  std::pair<iterator, bool> insert(T&& value) {
+    return emplace(std::forward<T>(value));
+  }
+
+  // This overload kicks in when the argument is a bitfield or an lvalue of
+  // insertable and decomposable type.
+  //
+  //   union { int n : 1; };
+  //   flat_hash_set<int> s;
+  //   s.insert(n);
+  //
+  //   flat_hash_set<std::string> s;
+  //   const char* p = "hello";
+  //   s.insert(p);
+  //
+  // TODO(romanp): Once we stop supporting gcc 5.1 and below, replace
+  // RequiresInsertable<T> with RequiresInsertable<const T&>.
+  // We are hitting this bug: https://godbolt.org/g/1Vht4f.
+  template <
+      class T, RequiresInsertable<T> = 0,
+      typename std::enable_if<IsDecomposable<const T&>::value, int>::type = 0>
+  std::pair<iterator, bool> insert(const T& value) {
+    return emplace(value);
+  }
+
+  // This overload kicks in when the argument is an rvalue of init_type. Its
+  // purpose is to handle brace-init-list arguments.
+  //
+  //   flat_hash_map<std::string, int> s;
+  //   s.insert({"abc", 42});
+  std::pair<iterator, bool> insert(init_type&& value) {
+    return emplace(std::move(value));
+  }
+
+  // TODO(cheshire): A type alias T2 is introduced as a workaround for the nvcc
+  // bug.
+  template <class T, RequiresInsertable<T> = 0, class T2 = T,
+            typename std::enable_if<IsDecomposable<T2>::value, int>::type = 0,
+            T* = nullptr>
+  iterator insert(const_iterator, T&& value) {
+    return insert(std::forward<T>(value)).first;
+  }
+
+  // TODO(romanp): Once we stop supporting gcc 5.1 and below, replace
+  // RequiresInsertable<T> with RequiresInsertable<const T&>.
+  // We are hitting this bug: https://godbolt.org/g/1Vht4f.
+  template <
+      class T, RequiresInsertable<T> = 0,
+      typename std::enable_if<IsDecomposable<const T&>::value, int>::type = 0>
+  iterator insert(const_iterator, const T& value) {
+    return insert(value).first;
+  }
+
+  iterator insert(const_iterator, init_type&& value) {
+    return insert(std::move(value)).first;
+  }
+
+  template <class InputIt>
+  void insert(InputIt first, InputIt last) {
+    for (; first != last; ++first) emplace(*first);
+  }
+
+  template <class T, RequiresNotInit<T> = 0, RequiresInsertable<const T&> = 0>
+  void insert(std::initializer_list<T> ilist) {
+    insert(ilist.begin(), ilist.end());
+  }
+
+  void insert(std::initializer_list<init_type> ilist) {
+    insert(ilist.begin(), ilist.end());
+  }
+
+  insert_return_type insert(node_type&& node) {
+    if (!node) return {end(), false, node_type()};
+    const auto& elem = PolicyTraits::element(CommonAccess::GetSlot(node));
+    auto res = PolicyTraits::apply(
+        InsertSlot<false>{*this, std::move(*CommonAccess::GetSlot(node))},
+        elem);
+    if (res.second) {
+      CommonAccess::Reset(&node);
+      return {res.first, true, node_type()};
+    } else {
+      return {res.first, false, std::move(node)};
+    }
+  }
+
+  iterator insert(const_iterator, node_type&& node) {
+    auto res = insert(std::move(node));
+    node = std::move(res.node);
+    return res.position;
+  }
+
+  // This overload kicks in if we can deduce the key from args. This enables us
+  // to avoid constructing value_type if an entry with the same key already
+  // exists.
+  //
+  // For example:
+  //
+  //   flat_hash_map<std::string, std::string> m = {{"abc", "def"}};
+  //   // Creates no std::string copies and makes no heap allocations.
+  //   m.emplace("abc", "xyz");
+  template <class... Args, typename std::enable_if<
+                               IsDecomposable<Args...>::value, int>::type = 0>
+  std::pair<iterator, bool> emplace(Args&&... args) {
+    return PolicyTraits::apply(EmplaceDecomposable{*this},
+                               std::forward<Args>(args)...);
+  }
+
+  // This overload kicks in if we cannot deduce the key from args. It constructs
+  // value_type unconditionally and then either moves it into the table or
+  // destroys.
+  template <class... Args, typename std::enable_if<
+                               !IsDecomposable<Args...>::value, int>::type = 0>
+  std::pair<iterator, bool> emplace(Args&&... args) {
+    alignas(slot_type) unsigned char raw[sizeof(slot_type)];
+    slot_type* slot = reinterpret_cast<slot_type*>(&raw);
+
+    PolicyTraits::construct(&alloc_ref(), slot, std::forward<Args>(args)...);
+    const auto& elem = PolicyTraits::element(slot);
+    return PolicyTraits::apply(InsertSlot<true>{*this, std::move(*slot)}, elem);
+  }
+
+  template <class... Args>
+  iterator emplace_hint(const_iterator, Args&&... args) {
+    return emplace(std::forward<Args>(args)...).first;
+  }
+
+  // Extension API: support for lazy emplace.
+  //
+  // Looks up key in the table. If found, returns the iterator to the element.
+  // Otherwise calls `f` with one argument of type `raw_hash_set::constructor`.
+  //
+  // `f` must abide by several restrictions:
+  //  - it MUST call `raw_hash_set::constructor` with arguments as if a
+  //    `raw_hash_set::value_type` is constructed,
+  //  - it MUST NOT access the container before the call to
+  //    `raw_hash_set::constructor`, and
+  //  - it MUST NOT erase the lazily emplaced element.
+  // Doing any of these is undefined behavior.
+  //
+  // For example:
+  //
+  //   std::unordered_set<ArenaString> s;
+  //   // Makes ArenaStr even if "abc" is in the map.
+  //   s.insert(ArenaString(&arena, "abc"));
+  //
+  //   flat_hash_set<ArenaStr> s;
+  //   // Makes ArenaStr only if "abc" is not in the map.
+  //   s.lazy_emplace("abc", [&](const constructor& ctor) {
+  //     ctor(&arena, "abc");
+  //   });
+  //
+  // WARNING: This API is currently experimental. If there is a way to implement
+  // the same thing with the rest of the API, prefer that.
+  class constructor {
+    friend class raw_hash_set;
+
+   public:
+    template <class... Args>
+    void operator()(Args&&... args) const {
+      assert(*slot_);
+      PolicyTraits::construct(alloc_, *slot_, std::forward<Args>(args)...);
+      *slot_ = nullptr;
+    }
+
+   private:
+    constructor(allocator_type* a, slot_type** slot) : alloc_(a), slot_(slot) {}
+
+    allocator_type* alloc_;
+    slot_type** slot_;
+  };
+
+  template <class K = key_type, class F>
+  iterator lazy_emplace(const key_arg<K>& key, F&& f) {
+    auto res = find_or_prepare_insert(key);
+    if (res.second) {
+      slot_type* slot = slots_ + res.first;
+      std::forward<F>(f)(constructor(&alloc_ref(), &slot));
+      assert(!slot);
+    }
+    return iterator_at(res.first);
+  }
+
+  // Extension API: support for heterogeneous keys.
+  //
+  //   std::unordered_set<std::string> s;
+  //   // Turns "abc" into std::string.
+  //   s.erase("abc");
+  //
+  //   flat_hash_set<std::string> s;
+  //   // Uses "abc" directly without copying it into std::string.
+  //   s.erase("abc");
+  template <class K = key_type>
+  size_type erase(const key_arg<K>& key) {
+    auto it = find(key);
+    if (it == end()) return 0;
+    erase(it);
+    return 1;
+  }
+
+  // Erases the element pointed to by `it`.  Unlike `std::unordered_set::erase`,
+  // this method returns void to reduce algorithmic complexity to O(1).  The
+  // iterator is invalidated, so any increment should be done before calling
+  // erase.  In order to erase while iterating across a map, use the following
+  // idiom (which also works for standard containers):
+  //
+  // for (auto it = m.begin(), end = m.end(); it != end;) {
+  //   // `erase()` will invalidate `it`, so advance `it` first.
+  //   auto copy_it = it++;
+  //   if (<pred>) {
+  //     m.erase(copy_it);
+  //   }
+  // }
+  void erase(const_iterator cit) { erase(cit.inner_); }
+
+  // This overload is necessary because otherwise erase<K>(const K&) would be
+  // a better match if non-const iterator is passed as an argument.
+  void erase(iterator it) {
+    AssertIsFull(it.ctrl_);
+    PolicyTraits::destroy(&alloc_ref(), it.slot_);
+    erase_meta_only(it);
+  }
+
+  iterator erase(const_iterator first, const_iterator last) {
+    while (first != last) {
+      erase(first++);
+    }
+    return last.inner_;
+  }
+
+  // Moves elements from `src` into `this`.
+  // If the element already exists in `this`, it is left unmodified in `src`.
+  template <typename H, typename E>
+  void merge(raw_hash_set<Policy, H, E, Alloc>& src) {  // NOLINT
+    assert(this != &src);
+    for (auto it = src.begin(), e = src.end(); it != e;) {
+      auto next = std::next(it);
+      if (PolicyTraits::apply(InsertSlot<false>{*this, std::move(*it.slot_)},
+                              PolicyTraits::element(it.slot_))
+              .second) {
+        src.erase_meta_only(it);
+      }
+      it = next;
+    }
+  }
+
+  template <typename H, typename E>
+  void merge(raw_hash_set<Policy, H, E, Alloc>&& src) {
+    merge(src);
+  }
+
+  node_type extract(const_iterator position) {
+    AssertIsFull(position.inner_.ctrl_);
+    auto node =
+        CommonAccess::Transfer<node_type>(alloc_ref(), position.inner_.slot_);
+    erase_meta_only(position);
+    return node;
+  }
+
+  template <
+      class K = key_type,
+      typename std::enable_if<!std::is_same<K, iterator>::value, int>::type = 0>
+  node_type extract(const key_arg<K>& key) {
+    auto it = find(key);
+    return it == end() ? node_type() : extract(const_iterator{it});
+  }
+
+  void swap(raw_hash_set& that) noexcept(
+      IsNoThrowSwappable<hasher>() && IsNoThrowSwappable<key_equal>() &&
+      IsNoThrowSwappable<allocator_type>(
+          typename AllocTraits::propagate_on_container_swap{})) {
+    using std::swap;
+    swap(ctrl_, that.ctrl_);
+    swap(slots_, that.slots_);
+    swap(size_, that.size_);
+    swap(capacity_, that.capacity_);
+    swap(growth_left(), that.growth_left());
+    swap(hash_ref(), that.hash_ref());
+    swap(eq_ref(), that.eq_ref());
+    swap(infoz(), that.infoz());
+    SwapAlloc(alloc_ref(), that.alloc_ref(),
+              typename AllocTraits::propagate_on_container_swap{});
+  }
+
+  void rehash(size_t n) {
+    if (n == 0 && capacity_ == 0) return;
+    if (n == 0 && size_ == 0) {
+      destroy_slots();
+      infoz().RecordStorageChanged(0, 0);
+      return;
+    }
+    // bitor is a faster way of doing `max` here. We will round up to the next
+    // power-of-2-minus-1, so bitor is good enough.
+    auto m = NormalizeCapacity(n | GrowthToLowerboundCapacity(size()));
+    // n == 0 unconditionally rehashes as per the standard.
+    if (n == 0 || m > capacity_) {
+      resize(m);
+    }
+  }
+
+  void reserve(size_t n) {
+    size_t m = GrowthToLowerboundCapacity(n);
+    if (m > capacity_) {
+      resize(NormalizeCapacity(m));
+    }
+  }
+
+  // Extension API: support for heterogeneous keys.
+  //
+  //   std::unordered_set<std::string> s;
+  //   // Turns "abc" into std::string.
+  //   s.count("abc");
+  //
+  //   ch_set<std::string> s;
+  //   // Uses "abc" directly without copying it into std::string.
+  //   s.count("abc");
+  template <class K = key_type>
+  size_t count(const key_arg<K>& key) const {
+    return find(key) == end() ? 0 : 1;
+  }
+
+  // Issues CPU prefetch instructions for the memory needed to find or insert
+  // a key.  Like all lookup functions, this support heterogeneous keys.
+  //
+  // NOTE: This is a very low level operation and should not be used without
+  // specific benchmarks indicating its importance.
+  template <class K = key_type>
+  void prefetch(const key_arg<K>& key) const {
+    (void)key;
+#if defined(__GNUC__)
+    auto seq = probe(ctrl_, hash_ref()(key), capacity_);
+    __builtin_prefetch(static_cast<const void*>(ctrl_ + seq.offset()));
+    __builtin_prefetch(static_cast<const void*>(slots_ + seq.offset()));
+#endif  // __GNUC__
+  }
+
+  // The API of find() has two extensions.
+  //
+  // 1. The hash can be passed by the user. It must be equal to the hash of the
+  // key.
+  //
+  // 2. The type of the key argument doesn't have to be key_type. This is so
+  // called heterogeneous key support.
+  template <class K = key_type>
+  iterator find(const key_arg<K>& key, size_t hash) {
+    auto seq = probe(ctrl_, hash, capacity_);
+    while (true) {
+      Group g{ctrl_ + seq.offset()};
+      for (int i : g.Match(H2(hash))) {
+        if (ABSL_PREDICT_TRUE(PolicyTraits::apply(
+                EqualElement<K>{key, eq_ref()},
+                PolicyTraits::element(slots_ + seq.offset(i)))))
+          return iterator_at(seq.offset(i));
+      }
+      if (ABSL_PREDICT_TRUE(g.MatchEmpty())) return end();
+      seq.next();
+      assert(seq.index() < capacity_ && "full table!");
+    }
+  }
+  template <class K = key_type>
+  iterator find(const key_arg<K>& key) {
+    return find(key, hash_ref()(key));
+  }
+
+  template <class K = key_type>
+  const_iterator find(const key_arg<K>& key, size_t hash) const {
+    return const_cast<raw_hash_set*>(this)->find(key, hash);
+  }
+  template <class K = key_type>
+  const_iterator find(const key_arg<K>& key) const {
+    return find(key, hash_ref()(key));
+  }
+
+  template <class K = key_type>
+  bool contains(const key_arg<K>& key) const {
+    return find(key) != end();
+  }
+
+  template <class K = key_type>
+  std::pair<iterator, iterator> equal_range(const key_arg<K>& key) {
+    auto it = find(key);
+    if (it != end()) return {it, std::next(it)};
+    return {it, it};
+  }
+  template <class K = key_type>
+  std::pair<const_iterator, const_iterator> equal_range(
+      const key_arg<K>& key) const {
+    auto it = find(key);
+    if (it != end()) return {it, std::next(it)};
+    return {it, it};
+  }
+
+  size_t bucket_count() const { return capacity_; }
+  float load_factor() const {
+    return capacity_ ? static_cast<double>(size()) / capacity_ : 0.0;
+  }
+  float max_load_factor() const { return 1.0f; }
+  void max_load_factor(float) {
+    // Does nothing.
+  }
+
+  hasher hash_function() const { return hash_ref(); }
+  key_equal key_eq() const { return eq_ref(); }
+  allocator_type get_allocator() const { return alloc_ref(); }
+
+  friend bool operator==(const raw_hash_set& a, const raw_hash_set& b) {
+    if (a.size() != b.size()) return false;
+    const raw_hash_set* outer = &a;
+    const raw_hash_set* inner = &b;
+    if (outer->capacity() > inner->capacity()) std::swap(outer, inner);
+    for (const value_type& elem : *outer)
+      if (!inner->has_element(elem)) return false;
+    return true;
+  }
+
+  friend bool operator!=(const raw_hash_set& a, const raw_hash_set& b) {
+    return !(a == b);
+  }
+
+  friend void swap(raw_hash_set& a,
+                   raw_hash_set& b) noexcept(noexcept(a.swap(b))) {
+    a.swap(b);
+  }
+
+ private:
+  template <class Container, typename Enabler>
+  friend struct absl::container_internal::hashtable_debug_internal::
+      HashtableDebugAccess;
+
+  struct FindElement {
+    template <class K, class... Args>
+    const_iterator operator()(const K& key, Args&&...) const {
+      return s.find(key);
+    }
+    const raw_hash_set& s;
+  };
+
+  struct HashElement {
+    template <class K, class... Args>
+    size_t operator()(const K& key, Args&&...) const {
+      return h(key);
+    }
+    const hasher& h;
+  };
+
+  template <class K1>
+  struct EqualElement {
+    template <class K2, class... Args>
+    bool operator()(const K2& lhs, Args&&...) const {
+      return eq(lhs, rhs);
+    }
+    const K1& rhs;
+    const key_equal& eq;
+  };
+
+  struct EmplaceDecomposable {
+    template <class K, class... Args>
+    std::pair<iterator, bool> operator()(const K& key, Args&&... args) const {
+      auto res = s.find_or_prepare_insert(key);
+      if (res.second) {
+        s.emplace_at(res.first, std::forward<Args>(args)...);
+      }
+      return {s.iterator_at(res.first), res.second};
+    }
+    raw_hash_set& s;
+  };
+
+  template <bool do_destroy>
+  struct InsertSlot {
+    template <class K, class... Args>
+    std::pair<iterator, bool> operator()(const K& key, Args&&...) && {
+      auto res = s.find_or_prepare_insert(key);
+      if (res.second) {
+        PolicyTraits::transfer(&s.alloc_ref(), s.slots_ + res.first, &slot);
+      } else if (do_destroy) {
+        PolicyTraits::destroy(&s.alloc_ref(), &slot);
+      }
+      return {s.iterator_at(res.first), res.second};
+    }
+    raw_hash_set& s;
+    // Constructed slot. Either moved into place or destroyed.
+    slot_type&& slot;
+  };
+
+  // "erases" the object from the container, except that it doesn't actually
+  // destroy the object. It only updates all the metadata of the class.
+  // This can be used in conjunction with Policy::transfer to move the object to
+  // another place.
+  void erase_meta_only(const_iterator it) {
+    assert(IsFull(*it.inner_.ctrl_) && "erasing a dangling iterator");
+    --size_;
+    const size_t index = it.inner_.ctrl_ - ctrl_;
+    const size_t index_before = (index - Group::kWidth) & capacity_;
+    const auto empty_after = Group(it.inner_.ctrl_).MatchEmpty();
+    const auto empty_before = Group(ctrl_ + index_before).MatchEmpty();
+
+    // We count how many consecutive non empties we have to the right and to the
+    // left of `it`. If the sum is >= kWidth then there is at least one probe
+    // window that might have seen a full group.
+    bool was_never_full =
+        empty_before && empty_after &&
+        static_cast<size_t>(empty_after.TrailingZeros() +
+                            empty_before.LeadingZeros()) < Group::kWidth;
+
+    set_ctrl(index, was_never_full ? kEmpty : kDeleted);
+    growth_left() += was_never_full;
+    infoz().RecordErase();
+  }
+
+  void initialize_slots() {
+    assert(capacity_);
+    // Folks with custom allocators often make unwarranted assumptions about the
+    // behavior of their classes vis-a-vis trivial destructability and what
+    // calls they will or wont make.  Avoid sampling for people with custom
+    // allocators to get us out of this mess.  This is not a hard guarantee but
+    // a workaround while we plan the exact guarantee we want to provide.
+    //
+    // People are often sloppy with the exact type of their allocator (sometimes
+    // it has an extra const or is missing the pair, but rebinds made it work
+    // anyway).  To avoid the ambiguity, we work off SlotAlloc which we have
+    // bound more carefully.
+    if (std::is_same<SlotAlloc, std::allocator<slot_type>>::value &&
+        slots_ == nullptr) {
+      infoz() = Sample();
+    }
+
+    auto layout = MakeLayout(capacity_);
+    char* mem = static_cast<char*>(
+        Allocate<Layout::Alignment()>(&alloc_ref(), layout.AllocSize()));
+    ctrl_ = reinterpret_cast<ctrl_t*>(layout.template Pointer<0>(mem));
+    slots_ = layout.template Pointer<1>(mem);
+    reset_ctrl();
+    reset_growth_left();
+    infoz().RecordStorageChanged(size_, capacity_);
+  }
+
+  void destroy_slots() {
+    if (!capacity_) return;
+    for (size_t i = 0; i != capacity_; ++i) {
+      if (IsFull(ctrl_[i])) {
+        PolicyTraits::destroy(&alloc_ref(), slots_ + i);
+      }
+    }
+    auto layout = MakeLayout(capacity_);
+    // Unpoison before returning the memory to the allocator.
+    SanitizerUnpoisonMemoryRegion(slots_, sizeof(slot_type) * capacity_);
+    Deallocate<Layout::Alignment()>(&alloc_ref(), ctrl_, layout.AllocSize());
+    ctrl_ = EmptyGroup();
+    slots_ = nullptr;
+    size_ = 0;
+    capacity_ = 0;
+    growth_left() = 0;
+  }
+
+  void resize(size_t new_capacity) {
+    assert(IsValidCapacity(new_capacity));
+    auto* old_ctrl = ctrl_;
+    auto* old_slots = slots_;
+    const size_t old_capacity = capacity_;
+    capacity_ = new_capacity;
+    initialize_slots();
+
+    size_t total_probe_length = 0;
+    for (size_t i = 0; i != old_capacity; ++i) {
+      if (IsFull(old_ctrl[i])) {
+        size_t hash = PolicyTraits::apply(HashElement{hash_ref()},
+                                          PolicyTraits::element(old_slots + i));
+        auto target = find_first_non_full(ctrl_, hash, capacity_);
+        size_t new_i = target.offset;
+        total_probe_length += target.probe_length;
+        set_ctrl(new_i, H2(hash));
+        PolicyTraits::transfer(&alloc_ref(), slots_ + new_i, old_slots + i);
+      }
+    }
+    if (old_capacity) {
+      SanitizerUnpoisonMemoryRegion(old_slots,
+                                    sizeof(slot_type) * old_capacity);
+      auto layout = MakeLayout(old_capacity);
+      Deallocate<Layout::Alignment()>(&alloc_ref(), old_ctrl,
+                                      layout.AllocSize());
+    }
+    infoz().RecordRehash(total_probe_length);
+  }
+
+  void drop_deletes_without_resize() ABSL_ATTRIBUTE_NOINLINE {
+    assert(IsValidCapacity(capacity_));
+    assert(!is_small(capacity_));
+    // Algorithm:
+    // - mark all DELETED slots as EMPTY
+    // - mark all FULL slots as DELETED
+    // - for each slot marked as DELETED
+    //     hash = Hash(element)
+    //     target = find_first_non_full(hash)
+    //     if target is in the same group
+    //       mark slot as FULL
+    //     else if target is EMPTY
+    //       transfer element to target
+    //       mark slot as EMPTY
+    //       mark target as FULL
+    //     else if target is DELETED
+    //       swap current element with target element
+    //       mark target as FULL
+    //       repeat procedure for current slot with moved from element (target)
+    ConvertDeletedToEmptyAndFullToDeleted(ctrl_, capacity_);
+    alignas(slot_type) unsigned char raw[sizeof(slot_type)];
+    size_t total_probe_length = 0;
+    slot_type* slot = reinterpret_cast<slot_type*>(&raw);
+    for (size_t i = 0; i != capacity_; ++i) {
+      if (!IsDeleted(ctrl_[i])) continue;
+      size_t hash = PolicyTraits::apply(HashElement{hash_ref()},
+                                        PolicyTraits::element(slots_ + i));
+      auto target = find_first_non_full(ctrl_, hash, capacity_);
+      size_t new_i = target.offset;
+      total_probe_length += target.probe_length;
+
+      // Verify if the old and new i fall within the same group wrt the hash.
+      // If they do, we don't need to move the object as it falls already in the
+      // best probe we can.
+      const auto probe_index = [&](size_t pos) {
+        return ((pos - probe(ctrl_, hash, capacity_).offset()) & capacity_) /
+               Group::kWidth;
+      };
+
+      // Element doesn't move.
+      if (ABSL_PREDICT_TRUE(probe_index(new_i) == probe_index(i))) {
+        set_ctrl(i, H2(hash));
+        continue;
+      }
+      if (IsEmpty(ctrl_[new_i])) {
+        // Transfer element to the empty spot.
+        // set_ctrl poisons/unpoisons the slots so we have to call it at the
+        // right time.
+        set_ctrl(new_i, H2(hash));
+        PolicyTraits::transfer(&alloc_ref(), slots_ + new_i, slots_ + i);
+        set_ctrl(i, kEmpty);
+      } else {
+        assert(IsDeleted(ctrl_[new_i]));
+        set_ctrl(new_i, H2(hash));
+        // Until we are done rehashing, DELETED marks previously FULL slots.
+        // Swap i and new_i elements.
+        PolicyTraits::transfer(&alloc_ref(), slot, slots_ + i);
+        PolicyTraits::transfer(&alloc_ref(), slots_ + i, slots_ + new_i);
+        PolicyTraits::transfer(&alloc_ref(), slots_ + new_i, slot);
+        --i;  // repeat
+      }
+    }
+    reset_growth_left();
+    infoz().RecordRehash(total_probe_length);
+  }
+
+  void rehash_and_grow_if_necessary() {
+    if (capacity_ == 0) {
+      resize(1);
+    } else if (size() <= CapacityToGrowth(capacity()) / 2) {
+      // Squash DELETED without growing if there is enough capacity.
+      drop_deletes_without_resize();
+    } else {
+      // Otherwise grow the container.
+      resize(capacity_ * 2 + 1);
+    }
+  }
+
+  bool has_element(const value_type& elem) const {
+    size_t hash = PolicyTraits::apply(HashElement{hash_ref()}, elem);
+    auto seq = probe(ctrl_, hash, capacity_);
+    while (true) {
+      Group g{ctrl_ + seq.offset()};
+      for (int i : g.Match(H2(hash))) {
+        if (ABSL_PREDICT_TRUE(PolicyTraits::element(slots_ + seq.offset(i)) ==
+                              elem))
+          return true;
+      }
+      if (ABSL_PREDICT_TRUE(g.MatchEmpty())) return false;
+      seq.next();
+      assert(seq.index() < capacity_ && "full table!");
+    }
+    return false;
+  }
+
+  // TODO(alkis): Optimize this assuming *this and that don't overlap.
+  raw_hash_set& move_assign(raw_hash_set&& that, std::true_type) {
+    raw_hash_set tmp(std::move(that));
+    swap(tmp);
+    return *this;
+  }
+  raw_hash_set& move_assign(raw_hash_set&& that, std::false_type) {
+    raw_hash_set tmp(std::move(that), alloc_ref());
+    swap(tmp);
+    return *this;
+  }
+
+ protected:
+  template <class K>
+  std::pair<size_t, bool> find_or_prepare_insert(const K& key) {
+    auto hash = hash_ref()(key);
+    auto seq = probe(ctrl_, hash, capacity_);
+    while (true) {
+      Group g{ctrl_ + seq.offset()};
+      for (int i : g.Match(H2(hash))) {
+        if (ABSL_PREDICT_TRUE(PolicyTraits::apply(
+                EqualElement<K>{key, eq_ref()},
+                PolicyTraits::element(slots_ + seq.offset(i)))))
+          return {seq.offset(i), false};
+      }
+      if (ABSL_PREDICT_TRUE(g.MatchEmpty())) break;
+      seq.next();
+      assert(seq.index() < capacity_ && "full table!");
+    }
+    return {prepare_insert(hash), true};
+  }
+
+  size_t prepare_insert(size_t hash) ABSL_ATTRIBUTE_NOINLINE {
+    auto target = find_first_non_full(ctrl_, hash, capacity_);
+    if (ABSL_PREDICT_FALSE(growth_left() == 0 &&
+                           !IsDeleted(ctrl_[target.offset]))) {
+      rehash_and_grow_if_necessary();
+      target = find_first_non_full(ctrl_, hash, capacity_);
+    }
+    ++size_;
+    growth_left() -= IsEmpty(ctrl_[target.offset]);
+    set_ctrl(target.offset, H2(hash));
+    infoz().RecordInsert(hash, target.probe_length);
+    return target.offset;
+  }
+
+  // Constructs the value in the space pointed by the iterator. This only works
+  // after an unsuccessful find_or_prepare_insert() and before any other
+  // modifications happen in the raw_hash_set.
+  //
+  // PRECONDITION: i is an index returned from find_or_prepare_insert(k), where
+  // k is the key decomposed from `forward<Args>(args)...`, and the bool
+  // returned by find_or_prepare_insert(k) was true.
+  // POSTCONDITION: *m.iterator_at(i) == value_type(forward<Args>(args)...).
+  template <class... Args>
+  void emplace_at(size_t i, Args&&... args) {
+    PolicyTraits::construct(&alloc_ref(), slots_ + i,
+                            std::forward<Args>(args)...);
+
+    assert(PolicyTraits::apply(FindElement{*this}, *iterator_at(i)) ==
+               iterator_at(i) &&
+           "constructed value does not match the lookup key");
+  }
+
+  iterator iterator_at(size_t i) { return {ctrl_ + i, slots_ + i}; }
+  const_iterator iterator_at(size_t i) const { return {ctrl_ + i, slots_ + i}; }
+
+ private:
+  friend struct RawHashSetTestOnlyAccess;
+
+  // Reset all ctrl bytes back to kEmpty, except the sentinel.
+  void reset_ctrl() {
+    std::memset(ctrl_, kEmpty, capacity_ + Group::kWidth);
+    ctrl_[capacity_] = kSentinel;
+    SanitizerPoisonMemoryRegion(slots_, sizeof(slot_type) * capacity_);
+  }
+
+  void reset_growth_left() {
+    growth_left() = CapacityToGrowth(capacity()) - size_;
+  }
+
+  // Sets the control byte, and if `i < Group::kWidth`, set the cloned byte at
+  // the end too.
+  void set_ctrl(size_t i, ctrl_t h) {
+    assert(i < capacity_);
+
+    if (IsFull(h)) {
+      SanitizerUnpoisonObject(slots_ + i);
+    } else {
+      SanitizerPoisonObject(slots_ + i);
+    }
+
+    ctrl_[i] = h;
+    ctrl_[((i - Group::kWidth) & capacity_) + 1 +
+          ((Group::kWidth - 1) & capacity_)] = h;
+  }
+
+  size_t& growth_left() { return settings_.template get<0>(); }
+
+  HashtablezInfoHandle& infoz() { return settings_.template get<1>(); }
+
+  hasher& hash_ref() { return settings_.template get<2>(); }
+  const hasher& hash_ref() const { return settings_.template get<2>(); }
+  key_equal& eq_ref() { return settings_.template get<3>(); }
+  const key_equal& eq_ref() const { return settings_.template get<3>(); }
+  allocator_type& alloc_ref() { return settings_.template get<4>(); }
+  const allocator_type& alloc_ref() const {
+    return settings_.template get<4>();
+  }
+
+  // TODO(alkis): Investigate removing some of these fields:
+  // - ctrl/slots can be derived from each other
+  // - size can be moved into the slot array
+  ctrl_t* ctrl_ = EmptyGroup();    // [(capacity + 1) * ctrl_t]
+  slot_type* slots_ = nullptr;     // [capacity * slot_type]
+  size_t size_ = 0;                // number of full slots
+  size_t capacity_ = 0;            // total number of slots
+  absl::container_internal::CompressedTuple<size_t /* growth_left */,
+                                            HashtablezInfoHandle, hasher,
+                                            key_equal, allocator_type>
+      settings_{0, HashtablezInfoHandle{}, hasher{}, key_equal{},
+                allocator_type{}};
+};
+
+// Erases all elements that satisfy the predicate `pred` from the container `c`.
+template <typename P, typename H, typename E, typename A, typename Predicate>
+void EraseIf(Predicate pred, raw_hash_set<P, H, E, A>* c) {
+  for (auto it = c->begin(), last = c->end(); it != last;) {
+    auto copy_it = it++;
+    if (pred(*copy_it)) {
+      c->erase(copy_it);
+    }
+  }
+}
+
+namespace hashtable_debug_internal {
+template <typename Set>
+struct HashtableDebugAccess<Set, absl::void_t<typename Set::raw_hash_set>> {
+  using Traits = typename Set::PolicyTraits;
+  using Slot = typename Traits::slot_type;
+
+  static size_t GetNumProbes(const Set& set,
+                             const typename Set::key_type& key) {
+    size_t num_probes = 0;
+    size_t hash = set.hash_ref()(key);
+    auto seq = probe(set.ctrl_, hash, set.capacity_);
+    while (true) {
+      container_internal::Group g{set.ctrl_ + seq.offset()};
+      for (int i : g.Match(container_internal::H2(hash))) {
+        if (Traits::apply(
+                typename Set::template EqualElement<typename Set::key_type>{
+                    key, set.eq_ref()},
+                Traits::element(set.slots_ + seq.offset(i))))
+          return num_probes;
+        ++num_probes;
+      }
+      if (g.MatchEmpty()) return num_probes;
+      seq.next();
+      ++num_probes;
+    }
+  }
+
+  static size_t AllocatedByteSize(const Set& c) {
+    size_t capacity = c.capacity_;
+    if (capacity == 0) return 0;
+    auto layout = Set::MakeLayout(capacity);
+    size_t m = layout.AllocSize();
+
+    size_t per_slot = Traits::space_used(static_cast<const Slot*>(nullptr));
+    if (per_slot != ~size_t{}) {
+      m += per_slot * c.size();
+    } else {
+      for (size_t i = 0; i != capacity; ++i) {
+        if (container_internal::IsFull(c.ctrl_[i])) {
+          m += Traits::space_used(c.slots_ + i);
+        }
+      }
+    }
+    return m;
+  }
+
+  static size_t LowerBoundAllocatedByteSize(size_t size) {
+    size_t capacity = GrowthToLowerboundCapacity(size);
+    if (capacity == 0) return 0;
+    auto layout = Set::MakeLayout(NormalizeCapacity(capacity));
+    size_t m = layout.AllocSize();
+    size_t per_slot = Traits::space_used(static_cast<const Slot*>(nullptr));
+    if (per_slot != ~size_t{}) {
+      m += per_slot * size;
+    }
+    return m;
+  }
+};
+
+}  // namespace hashtable_debug_internal
+}  // namespace container_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#endif  // ABSL_CONTAINER_INTERNAL_RAW_HASH_SET_H_
diff --git a/src/absl/container/internal/tracked.h b/src/absl/container/internal/tracked.h
new file mode 100644 (file)
index 0000000..29f5829
--- /dev/null
@@ -0,0 +1,83 @@
+// Copyright 2018 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef ABSL_CONTAINER_INTERNAL_TRACKED_H_
+#define ABSL_CONTAINER_INTERNAL_TRACKED_H_
+
+#include <stddef.h>
+
+#include <memory>
+#include <utility>
+
+#include "absl/base/config.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace container_internal {
+
+// A class that tracks its copies and moves so that it can be queried in tests.
+template <class T>
+class Tracked {
+ public:
+  Tracked() {}
+  // NOLINTNEXTLINE(runtime/explicit)
+  Tracked(const T& val) : val_(val) {}
+  Tracked(const Tracked& that)
+      : val_(that.val_),
+        num_moves_(that.num_moves_),
+        num_copies_(that.num_copies_) {
+    ++(*num_copies_);
+  }
+  Tracked(Tracked&& that)
+      : val_(std::move(that.val_)),
+        num_moves_(std::move(that.num_moves_)),
+        num_copies_(std::move(that.num_copies_)) {
+    ++(*num_moves_);
+  }
+  Tracked& operator=(const Tracked& that) {
+    val_ = that.val_;
+    num_moves_ = that.num_moves_;
+    num_copies_ = that.num_copies_;
+    ++(*num_copies_);
+  }
+  Tracked& operator=(Tracked&& that) {
+    val_ = std::move(that.val_);
+    num_moves_ = std::move(that.num_moves_);
+    num_copies_ = std::move(that.num_copies_);
+    ++(*num_moves_);
+  }
+
+  const T& val() const { return val_; }
+
+  friend bool operator==(const Tracked& a, const Tracked& b) {
+    return a.val_ == b.val_;
+  }
+  friend bool operator!=(const Tracked& a, const Tracked& b) {
+    return !(a == b);
+  }
+
+  size_t num_copies() { return *num_copies_; }
+  size_t num_moves() { return *num_moves_; }
+
+ private:
+  T val_;
+  std::shared_ptr<size_t> num_moves_ = std::make_shared<size_t>(0);
+  std::shared_ptr<size_t> num_copies_ = std::make_shared<size_t>(0);
+};
+
+}  // namespace container_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#endif  // ABSL_CONTAINER_INTERNAL_TRACKED_H_
diff --git a/src/absl/container/node_hash_map.h b/src/absl/container/node_hash_map.h
new file mode 100644 (file)
index 0000000..7a39f62
--- /dev/null
@@ -0,0 +1,597 @@
+// Copyright 2018 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// -----------------------------------------------------------------------------
+// File: node_hash_map.h
+// -----------------------------------------------------------------------------
+//
+// An `absl::node_hash_map<K, V>` is an unordered associative container of
+// unique keys and associated values designed to be a more efficient replacement
+// for `std::unordered_map`. Like `unordered_map`, search, insertion, and
+// deletion of map elements can be done as an `O(1)` operation. However,
+// `node_hash_map` (and other unordered associative containers known as the
+// collection of Abseil "Swiss tables") contain other optimizations that result
+// in both memory and computation advantages.
+//
+// In most cases, your default choice for a hash map should be a map of type
+// `flat_hash_map`. However, if you need pointer stability and cannot store
+// a `flat_hash_map` with `unique_ptr` elements, a `node_hash_map` may be a
+// valid alternative. As well, if you are migrating your code from using
+// `std::unordered_map`, a `node_hash_map` provides a more straightforward
+// migration, because it guarantees pointer stability. Consider migrating to
+// `node_hash_map` and perhaps converting to a more efficient `flat_hash_map`
+// upon further review.
+
+#ifndef ABSL_CONTAINER_NODE_HASH_MAP_H_
+#define ABSL_CONTAINER_NODE_HASH_MAP_H_
+
+#include <tuple>
+#include <type_traits>
+#include <utility>
+
+#include "absl/algorithm/container.h"
+#include "absl/container/internal/container_memory.h"
+#include "absl/container/internal/hash_function_defaults.h"  // IWYU pragma: export
+#include "absl/container/internal/node_hash_policy.h"
+#include "absl/container/internal/raw_hash_map.h"  // IWYU pragma: export
+#include "absl/memory/memory.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace container_internal {
+template <class Key, class Value>
+class NodeHashMapPolicy;
+}  // namespace container_internal
+
+// -----------------------------------------------------------------------------
+// absl::node_hash_map
+// -----------------------------------------------------------------------------
+//
+// An `absl::node_hash_map<K, V>` is an unordered associative container which
+// has been optimized for both speed and memory footprint in most common use
+// cases. Its interface is similar to that of `std::unordered_map<K, V>` with
+// the following notable differences:
+//
+// * Supports heterogeneous lookup, through `find()`, `operator[]()` and
+//   `insert()`, provided that the map is provided a compatible heterogeneous
+//   hashing function and equality operator.
+// * Contains a `capacity()` member function indicating the number of element
+//   slots (open, deleted, and empty) within the hash map.
+// * Returns `void` from the `erase(iterator)` overload.
+//
+// By default, `node_hash_map` uses the `absl::Hash` hashing framework.
+// All fundamental and Abseil types that support the `absl::Hash` framework have
+// a compatible equality operator for comparing insertions into `node_hash_map`.
+// If your type is not yet supported by the `absl::Hash` framework, see
+// absl/hash/hash.h for information on extending Abseil hashing to user-defined
+// types.
+//
+// Example:
+//
+//   // Create a node hash map of three strings (that map to strings)
+//   absl::node_hash_map<std::string, std::string> ducks =
+//     {{"a", "huey"}, {"b", "dewey"}, {"c", "louie"}};
+//
+//  // Insert a new element into the node hash map
+//  ducks.insert({"d", "donald"}};
+//
+//  // Force a rehash of the node hash map
+//  ducks.rehash(0);
+//
+//  // Find the element with the key "b"
+//  std::string search_key = "b";
+//  auto result = ducks.find(search_key);
+//  if (result != ducks.end()) {
+//    std::cout << "Result: " << result->second << std::endl;
+//  }
+template <class Key, class Value,
+          class Hash = absl::container_internal::hash_default_hash<Key>,
+          class Eq = absl::container_internal::hash_default_eq<Key>,
+          class Alloc = std::allocator<std::pair<const Key, Value>>>
+class node_hash_map
+    : public absl::container_internal::raw_hash_map<
+          absl::container_internal::NodeHashMapPolicy<Key, Value>, Hash, Eq,
+          Alloc> {
+  using Base = typename node_hash_map::raw_hash_map;
+
+ public:
+  // Constructors and Assignment Operators
+  //
+  // A node_hash_map supports the same overload set as `std::unordered_map`
+  // for construction and assignment:
+  //
+  // *  Default constructor
+  //
+  //    // No allocation for the table's elements is made.
+  //    absl::node_hash_map<int, std::string> map1;
+  //
+  // * Initializer List constructor
+  //
+  //   absl::node_hash_map<int, std::string> map2 =
+  //       {{1, "huey"}, {2, "dewey"}, {3, "louie"},};
+  //
+  // * Copy constructor
+  //
+  //   absl::node_hash_map<int, std::string> map3(map2);
+  //
+  // * Copy assignment operator
+  //
+  //  // Hash functor and Comparator are copied as well
+  //  absl::node_hash_map<int, std::string> map4;
+  //  map4 = map3;
+  //
+  // * Move constructor
+  //
+  //   // Move is guaranteed efficient
+  //   absl::node_hash_map<int, std::string> map5(std::move(map4));
+  //
+  // * Move assignment operator
+  //
+  //   // May be efficient if allocators are compatible
+  //   absl::node_hash_map<int, std::string> map6;
+  //   map6 = std::move(map5);
+  //
+  // * Range constructor
+  //
+  //   std::vector<std::pair<int, std::string>> v = {{1, "a"}, {2, "b"}};
+  //   absl::node_hash_map<int, std::string> map7(v.begin(), v.end());
+  node_hash_map() {}
+  using Base::Base;
+
+  // node_hash_map::begin()
+  //
+  // Returns an iterator to the beginning of the `node_hash_map`.
+  using Base::begin;
+
+  // node_hash_map::cbegin()
+  //
+  // Returns a const iterator to the beginning of the `node_hash_map`.
+  using Base::cbegin;
+
+  // node_hash_map::cend()
+  //
+  // Returns a const iterator to the end of the `node_hash_map`.
+  using Base::cend;
+
+  // node_hash_map::end()
+  //
+  // Returns an iterator to the end of the `node_hash_map`.
+  using Base::end;
+
+  // node_hash_map::capacity()
+  //
+  // Returns the number of element slots (assigned, deleted, and empty)
+  // available within the `node_hash_map`.
+  //
+  // NOTE: this member function is particular to `absl::node_hash_map` and is
+  // not provided in the `std::unordered_map` API.
+  using Base::capacity;
+
+  // node_hash_map::empty()
+  //
+  // Returns whether or not the `node_hash_map` is empty.
+  using Base::empty;
+
+  // node_hash_map::max_size()
+  //
+  // Returns the largest theoretical possible number of elements within a
+  // `node_hash_map` under current memory constraints. This value can be thought
+  // of as the largest value of `std::distance(begin(), end())` for a
+  // `node_hash_map<K, V>`.
+  using Base::max_size;
+
+  // node_hash_map::size()
+  //
+  // Returns the number of elements currently within the `node_hash_map`.
+  using Base::size;
+
+  // node_hash_map::clear()
+  //
+  // Removes all elements from the `node_hash_map`. Invalidates any references,
+  // pointers, or iterators referring to contained elements.
+  //
+  // NOTE: this operation may shrink the underlying buffer. To avoid shrinking
+  // the underlying buffer call `erase(begin(), end())`.
+  using Base::clear;
+
+  // node_hash_map::erase()
+  //
+  // Erases elements within the `node_hash_map`. Erasing does not trigger a
+  // rehash. Overloads are listed below.
+  //
+  // void erase(const_iterator pos):
+  //
+  //   Erases the element at `position` of the `node_hash_map`, returning
+  //   `void`.
+  //
+  //   NOTE: this return behavior is different than that of STL containers in
+  //   general and `std::unordered_map` in particular.
+  //
+  // iterator erase(const_iterator first, const_iterator last):
+  //
+  //   Erases the elements in the open interval [`first`, `last`), returning an
+  //   iterator pointing to `last`.
+  //
+  // size_type erase(const key_type& key):
+  //
+  //   Erases the element with the matching key, if it exists, returning the
+  //   number of elements erased (0 or 1).
+  using Base::erase;
+
+  // node_hash_map::insert()
+  //
+  // Inserts an element of the specified value into the `node_hash_map`,
+  // returning an iterator pointing to the newly inserted element, provided that
+  // an element with the given key does not already exist. If rehashing occurs
+  // due to the insertion, all iterators are invalidated. Overloads are listed
+  // below.
+  //
+  // std::pair<iterator,bool> insert(const init_type& value):
+  //
+  //   Inserts a value into the `node_hash_map`. Returns a pair consisting of an
+  //   iterator to the inserted element (or to the element that prevented the
+  //   insertion) and a `bool` denoting whether the insertion took place.
+  //
+  // std::pair<iterator,bool> insert(T&& value):
+  // std::pair<iterator,bool> insert(init_type&& value):
+  //
+  //   Inserts a moveable value into the `node_hash_map`. Returns a `std::pair`
+  //   consisting of an iterator to the inserted element (or to the element that
+  //   prevented the insertion) and a `bool` denoting whether the insertion took
+  //   place.
+  //
+  // iterator insert(const_iterator hint, const init_type& value):
+  // iterator insert(const_iterator hint, T&& value):
+  // iterator insert(const_iterator hint, init_type&& value);
+  //
+  //   Inserts a value, using the position of `hint` as a non-binding suggestion
+  //   for where to begin the insertion search. Returns an iterator to the
+  //   inserted element, or to the existing element that prevented the
+  //   insertion.
+  //
+  // void insert(InputIterator first, InputIterator last):
+  //
+  //   Inserts a range of values [`first`, `last`).
+  //
+  //   NOTE: Although the STL does not specify which element may be inserted if
+  //   multiple keys compare equivalently, for `node_hash_map` we guarantee the
+  //   first match is inserted.
+  //
+  // void insert(std::initializer_list<init_type> ilist):
+  //
+  //   Inserts the elements within the initializer list `ilist`.
+  //
+  //   NOTE: Although the STL does not specify which element may be inserted if
+  //   multiple keys compare equivalently within the initializer list, for
+  //   `node_hash_map` we guarantee the first match is inserted.
+  using Base::insert;
+
+  // node_hash_map::insert_or_assign()
+  //
+  // Inserts an element of the specified value into the `node_hash_map` provided
+  // that a value with the given key does not already exist, or replaces it with
+  // the element value if a key for that value already exists, returning an
+  // iterator pointing to the newly inserted element. If rehashing occurs due to
+  // the insertion, all iterators are invalidated. Overloads are listed
+  // below.
+  //
+  // std::pair<iterator, bool> insert_or_assign(const init_type& k, T&& obj):
+  // std::pair<iterator, bool> insert_or_assign(init_type&& k, T&& obj):
+  //
+  //   Inserts/Assigns (or moves) the element of the specified key into the
+  //   `node_hash_map`.
+  //
+  // iterator insert_or_assign(const_iterator hint,
+  //                           const init_type& k, T&& obj):
+  // iterator insert_or_assign(const_iterator hint, init_type&& k, T&& obj):
+  //
+  //   Inserts/Assigns (or moves) the element of the specified key into the
+  //   `node_hash_map` using the position of `hint` as a non-binding suggestion
+  //   for where to begin the insertion search.
+  using Base::insert_or_assign;
+
+  // node_hash_map::emplace()
+  //
+  // Inserts an element of the specified value by constructing it in-place
+  // within the `node_hash_map`, provided that no element with the given key
+  // already exists.
+  //
+  // The element may be constructed even if there already is an element with the
+  // key in the container, in which case the newly constructed element will be
+  // destroyed immediately. Prefer `try_emplace()` unless your key is not
+  // copyable or moveable.
+  //
+  // If rehashing occurs due to the insertion, all iterators are invalidated.
+  using Base::emplace;
+
+  // node_hash_map::emplace_hint()
+  //
+  // Inserts an element of the specified value by constructing it in-place
+  // within the `node_hash_map`, using the position of `hint` as a non-binding
+  // suggestion for where to begin the insertion search, and only inserts
+  // provided that no element with the given key already exists.
+  //
+  // The element may be constructed even if there already is an element with the
+  // key in the container, in which case the newly constructed element will be
+  // destroyed immediately. Prefer `try_emplace()` unless your key is not
+  // copyable or moveable.
+  //
+  // If rehashing occurs due to the insertion, all iterators are invalidated.
+  using Base::emplace_hint;
+
+  // node_hash_map::try_emplace()
+  //
+  // Inserts an element of the specified value by constructing it in-place
+  // within the `node_hash_map`, provided that no element with the given key
+  // already exists. Unlike `emplace()`, if an element with the given key
+  // already exists, we guarantee that no element is constructed.
+  //
+  // If rehashing occurs due to the insertion, all iterators are invalidated.
+  // Overloads are listed below.
+  //
+  //   std::pair<iterator, bool> try_emplace(const key_type& k, Args&&... args):
+  //   std::pair<iterator, bool> try_emplace(key_type&& k, Args&&... args):
+  //
+  // Inserts (via copy or move) the element of the specified key into the
+  // `node_hash_map`.
+  //
+  //   iterator try_emplace(const_iterator hint,
+  //                        const init_type& k, Args&&... args):
+  //   iterator try_emplace(const_iterator hint, init_type&& k, Args&&... args):
+  //
+  // Inserts (via copy or move) the element of the specified key into the
+  // `node_hash_map` using the position of `hint` as a non-binding suggestion
+  // for where to begin the insertion search.
+  //
+  // All `try_emplace()` overloads make the same guarantees regarding rvalue
+  // arguments as `std::unordered_map::try_emplace()`, namely that these
+  // functions will not move from rvalue arguments if insertions do not happen.
+  using Base::try_emplace;
+
+  // node_hash_map::extract()
+  //
+  // Extracts the indicated element, erasing it in the process, and returns it
+  // as a C++17-compatible node handle. Overloads are listed below.
+  //
+  // node_type extract(const_iterator position):
+  //
+  //   Extracts the key,value pair of the element at the indicated position and
+  //   returns a node handle owning that extracted data.
+  //
+  // node_type extract(const key_type& x):
+  //
+  //   Extracts the key,value pair of the element with a key matching the passed
+  //   key value and returns a node handle owning that extracted data. If the
+  //   `node_hash_map` does not contain an element with a matching key, this
+  //   function returns an empty node handle.
+  //
+  // NOTE: when compiled in an earlier version of C++ than C++17,
+  // `node_type::key()` returns a const reference to the key instead of a
+  // mutable reference. We cannot safely return a mutable reference without
+  // std::launder (which is not available before C++17).
+  using Base::extract;
+
+  // node_hash_map::merge()
+  //
+  // Extracts elements from a given `source` node hash map into this
+  // `node_hash_map`. If the destination `node_hash_map` already contains an
+  // element with an equivalent key, that element is not extracted.
+  using Base::merge;
+
+  // node_hash_map::swap(node_hash_map& other)
+  //
+  // Exchanges the contents of this `node_hash_map` with those of the `other`
+  // node hash map, avoiding invocation of any move, copy, or swap operations on
+  // individual elements.
+  //
+  // All iterators and references on the `node_hash_map` remain valid, excepting
+  // for the past-the-end iterator, which is invalidated.
+  //
+  // `swap()` requires that the node hash map's hashing and key equivalence
+  // functions be Swappable, and are exchaged using unqualified calls to
+  // non-member `swap()`. If the map's allocator has
+  // `std::allocator_traits<allocator_type>::propagate_on_container_swap::value`
+  // set to `true`, the allocators are also exchanged using an unqualified call
+  // to non-member `swap()`; otherwise, the allocators are not swapped.
+  using Base::swap;
+
+  // node_hash_map::rehash(count)
+  //
+  // Rehashes the `node_hash_map`, setting the number of slots to be at least
+  // the passed value. If the new number of slots increases the load factor more
+  // than the current maximum load factor
+  // (`count` < `size()` / `max_load_factor()`), then the new number of slots
+  // will be at least `size()` / `max_load_factor()`.
+  //
+  // To force a rehash, pass rehash(0).
+  using Base::rehash;
+
+  // node_hash_map::reserve(count)
+  //
+  // Sets the number of slots in the `node_hash_map` to the number needed to
+  // accommodate at least `count` total elements without exceeding the current
+  // maximum load factor, and may rehash the container if needed.
+  using Base::reserve;
+
+  // node_hash_map::at()
+  //
+  // Returns a reference to the mapped value of the element with key equivalent
+  // to the passed key.
+  using Base::at;
+
+  // node_hash_map::contains()
+  //
+  // Determines whether an element with a key comparing equal to the given `key`
+  // exists within the `node_hash_map`, returning `true` if so or `false`
+  // otherwise.
+  using Base::contains;
+
+  // node_hash_map::count(const Key& key) const
+  //
+  // Returns the number of elements with a key comparing equal to the given
+  // `key` within the `node_hash_map`. note that this function will return
+  // either `1` or `0` since duplicate keys are not allowed within a
+  // `node_hash_map`.
+  using Base::count;
+
+  // node_hash_map::equal_range()
+  //
+  // Returns a closed range [first, last], defined by a `std::pair` of two
+  // iterators, containing all elements with the passed key in the
+  // `node_hash_map`.
+  using Base::equal_range;
+
+  // node_hash_map::find()
+  //
+  // Finds an element with the passed `key` within the `node_hash_map`.
+  using Base::find;
+
+  // node_hash_map::operator[]()
+  //
+  // Returns a reference to the value mapped to the passed key within the
+  // `node_hash_map`, performing an `insert()` if the key does not already
+  // exist. If an insertion occurs and results in a rehashing of the container,
+  // all iterators are invalidated. Otherwise iterators are not affected and
+  // references are not invalidated. Overloads are listed below.
+  //
+  // T& operator[](const Key& key):
+  //
+  //   Inserts an init_type object constructed in-place if the element with the
+  //   given key does not exist.
+  //
+  // T& operator[](Key&& key):
+  //
+  //   Inserts an init_type object constructed in-place provided that an element
+  //   with the given key does not exist.
+  using Base::operator[];
+
+  // node_hash_map::bucket_count()
+  //
+  // Returns the number of "buckets" within the `node_hash_map`.
+  using Base::bucket_count;
+
+  // node_hash_map::load_factor()
+  //
+  // Returns the current load factor of the `node_hash_map` (the average number
+  // of slots occupied with a value within the hash map).
+  using Base::load_factor;
+
+  // node_hash_map::max_load_factor()
+  //
+  // Manages the maximum load factor of the `node_hash_map`. Overloads are
+  // listed below.
+  //
+  // float node_hash_map::max_load_factor()
+  //
+  //   Returns the current maximum load factor of the `node_hash_map`.
+  //
+  // void node_hash_map::max_load_factor(float ml)
+  //
+  //   Sets the maximum load factor of the `node_hash_map` to the passed value.
+  //
+  //   NOTE: This overload is provided only for API compatibility with the STL;
+  //   `node_hash_map` will ignore any set load factor and manage its rehashing
+  //   internally as an implementation detail.
+  using Base::max_load_factor;
+
+  // node_hash_map::get_allocator()
+  //
+  // Returns the allocator function associated with this `node_hash_map`.
+  using Base::get_allocator;
+
+  // node_hash_map::hash_function()
+  //
+  // Returns the hashing function used to hash the keys within this
+  // `node_hash_map`.
+  using Base::hash_function;
+
+  // node_hash_map::key_eq()
+  //
+  // Returns the function used for comparing keys equality.
+  using Base::key_eq;
+};
+
+// erase_if(node_hash_map<>, Pred)
+//
+// Erases all elements that satisfy the predicate `pred` from the container `c`.
+template <typename K, typename V, typename H, typename E, typename A,
+          typename Predicate>
+void erase_if(node_hash_map<K, V, H, E, A>& c, Predicate pred) {
+  container_internal::EraseIf(pred, &c);
+}
+
+namespace container_internal {
+
+template <class Key, class Value>
+class NodeHashMapPolicy
+    : public absl::container_internal::node_hash_policy<
+          std::pair<const Key, Value>&, NodeHashMapPolicy<Key, Value>> {
+  using value_type = std::pair<const Key, Value>;
+
+ public:
+  using key_type = Key;
+  using mapped_type = Value;
+  using init_type = std::pair</*non const*/ key_type, mapped_type>;
+
+  template <class Allocator, class... Args>
+  static value_type* new_element(Allocator* alloc, Args&&... args) {
+    using PairAlloc = typename absl::allocator_traits<
+        Allocator>::template rebind_alloc<value_type>;
+    PairAlloc pair_alloc(*alloc);
+    value_type* res =
+        absl::allocator_traits<PairAlloc>::allocate(pair_alloc, 1);
+    absl::allocator_traits<PairAlloc>::construct(pair_alloc, res,
+                                                 std::forward<Args>(args)...);
+    return res;
+  }
+
+  template <class Allocator>
+  static void delete_element(Allocator* alloc, value_type* pair) {
+    using PairAlloc = typename absl::allocator_traits<
+        Allocator>::template rebind_alloc<value_type>;
+    PairAlloc pair_alloc(*alloc);
+    absl::allocator_traits<PairAlloc>::destroy(pair_alloc, pair);
+    absl::allocator_traits<PairAlloc>::deallocate(pair_alloc, pair, 1);
+  }
+
+  template <class F, class... Args>
+  static decltype(absl::container_internal::DecomposePair(
+      std::declval<F>(), std::declval<Args>()...))
+  apply(F&& f, Args&&... args) {
+    return absl::container_internal::DecomposePair(std::forward<F>(f),
+                                                   std::forward<Args>(args)...);
+  }
+
+  static size_t element_space_used(const value_type*) {
+    return sizeof(value_type);
+  }
+
+  static Value& value(value_type* elem) { return elem->second; }
+  static const Value& value(const value_type* elem) { return elem->second; }
+};
+}  // namespace container_internal
+
+namespace container_algorithm_internal {
+
+// Specialization of trait in absl/algorithm/container.h
+template <class Key, class T, class Hash, class KeyEqual, class Allocator>
+struct IsUnorderedContainer<
+    absl::node_hash_map<Key, T, Hash, KeyEqual, Allocator>> : std::true_type {};
+
+}  // namespace container_algorithm_internal
+
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#endif  // ABSL_CONTAINER_NODE_HASH_MAP_H_
diff --git a/src/absl/container/node_hash_set.h b/src/absl/container/node_hash_set.h
new file mode 100644 (file)
index 0000000..93b15f4
--- /dev/null
@@ -0,0 +1,493 @@
+// Copyright 2018 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// -----------------------------------------------------------------------------
+// File: node_hash_set.h
+// -----------------------------------------------------------------------------
+//
+// An `absl::node_hash_set<T>` is an unordered associative container designed to
+// be a more efficient replacement for `std::unordered_set`. Like
+// `unordered_set`, search, insertion, and deletion of set elements can be done
+// as an `O(1)` operation. However, `node_hash_set` (and other unordered
+// associative containers known as the collection of Abseil "Swiss tables")
+// contain other optimizations that result in both memory and computation
+// advantages.
+//
+// In most cases, your default choice for a hash table should be a map of type
+// `flat_hash_map` or a set of type `flat_hash_set`. However, if you need
+// pointer stability, a `node_hash_set` should be your preferred choice. As
+// well, if you are migrating your code from using `std::unordered_set`, a
+// `node_hash_set` should be an easy migration. Consider migrating to
+// `node_hash_set` and perhaps converting to a more efficient `flat_hash_set`
+// upon further review.
+
+#ifndef ABSL_CONTAINER_NODE_HASH_SET_H_
+#define ABSL_CONTAINER_NODE_HASH_SET_H_
+
+#include <type_traits>
+
+#include "absl/algorithm/container.h"
+#include "absl/container/internal/hash_function_defaults.h"  // IWYU pragma: export
+#include "absl/container/internal/node_hash_policy.h"
+#include "absl/container/internal/raw_hash_set.h"  // IWYU pragma: export
+#include "absl/memory/memory.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace container_internal {
+template <typename T>
+struct NodeHashSetPolicy;
+}  // namespace container_internal
+
+// -----------------------------------------------------------------------------
+// absl::node_hash_set
+// -----------------------------------------------------------------------------
+//
+// An `absl::node_hash_set<T>` is an unordered associative container which
+// has been optimized for both speed and memory footprint in most common use
+// cases. Its interface is similar to that of `std::unordered_set<T>` with the
+// following notable differences:
+//
+// * Supports heterogeneous lookup, through `find()`, `operator[]()` and
+//   `insert()`, provided that the set is provided a compatible heterogeneous
+//   hashing function and equality operator.
+// * Contains a `capacity()` member function indicating the number of element
+//   slots (open, deleted, and empty) within the hash set.
+// * Returns `void` from the `erase(iterator)` overload.
+//
+// By default, `node_hash_set` uses the `absl::Hash` hashing framework.
+// All fundamental and Abseil types that support the `absl::Hash` framework have
+// a compatible equality operator for comparing insertions into `node_hash_set`.
+// If your type is not yet supported by the `absl::Hash` framework, see
+// absl/hash/hash.h for information on extending Abseil hashing to user-defined
+// types.
+//
+// Example:
+//
+//   // Create a node hash set of three strings
+//   absl::node_hash_set<std::string> ducks =
+//     {"huey", "dewey", "louie"};
+//
+//  // Insert a new element into the node hash set
+//  ducks.insert("donald");
+//
+//  // Force a rehash of the node hash set
+//  ducks.rehash(0);
+//
+//  // See if "dewey" is present
+//  if (ducks.contains("dewey")) {
+//    std::cout << "We found dewey!" << std::endl;
+//  }
+template <class T, class Hash = absl::container_internal::hash_default_hash<T>,
+          class Eq = absl::container_internal::hash_default_eq<T>,
+          class Alloc = std::allocator<T>>
+class node_hash_set
+    : public absl::container_internal::raw_hash_set<
+          absl::container_internal::NodeHashSetPolicy<T>, Hash, Eq, Alloc> {
+  using Base = typename node_hash_set::raw_hash_set;
+
+ public:
+  // Constructors and Assignment Operators
+  //
+  // A node_hash_set supports the same overload set as `std::unordered_set`
+  // for construction and assignment:
+  //
+  // *  Default constructor
+  //
+  //    // No allocation for the table's elements is made.
+  //    absl::node_hash_set<std::string> set1;
+  //
+  // * Initializer List constructor
+  //
+  //   absl::node_hash_set<std::string> set2 =
+  //       {{"huey"}, {"dewey"}, {"louie"}};
+  //
+  // * Copy constructor
+  //
+  //   absl::node_hash_set<std::string> set3(set2);
+  //
+  // * Copy assignment operator
+  //
+  //  // Hash functor and Comparator are copied as well
+  //  absl::node_hash_set<std::string> set4;
+  //  set4 = set3;
+  //
+  // * Move constructor
+  //
+  //   // Move is guaranteed efficient
+  //   absl::node_hash_set<std::string> set5(std::move(set4));
+  //
+  // * Move assignment operator
+  //
+  //   // May be efficient if allocators are compatible
+  //   absl::node_hash_set<std::string> set6;
+  //   set6 = std::move(set5);
+  //
+  // * Range constructor
+  //
+  //   std::vector<std::string> v = {"a", "b"};
+  //   absl::node_hash_set<std::string> set7(v.begin(), v.end());
+  node_hash_set() {}
+  using Base::Base;
+
+  // node_hash_set::begin()
+  //
+  // Returns an iterator to the beginning of the `node_hash_set`.
+  using Base::begin;
+
+  // node_hash_set::cbegin()
+  //
+  // Returns a const iterator to the beginning of the `node_hash_set`.
+  using Base::cbegin;
+
+  // node_hash_set::cend()
+  //
+  // Returns a const iterator to the end of the `node_hash_set`.
+  using Base::cend;
+
+  // node_hash_set::end()
+  //
+  // Returns an iterator to the end of the `node_hash_set`.
+  using Base::end;
+
+  // node_hash_set::capacity()
+  //
+  // Returns the number of element slots (assigned, deleted, and empty)
+  // available within the `node_hash_set`.
+  //
+  // NOTE: this member function is particular to `absl::node_hash_set` and is
+  // not provided in the `std::unordered_set` API.
+  using Base::capacity;
+
+  // node_hash_set::empty()
+  //
+  // Returns whether or not the `node_hash_set` is empty.
+  using Base::empty;
+
+  // node_hash_set::max_size()
+  //
+  // Returns the largest theoretical possible number of elements within a
+  // `node_hash_set` under current memory constraints. This value can be thought
+  // of the largest value of `std::distance(begin(), end())` for a
+  // `node_hash_set<T>`.
+  using Base::max_size;
+
+  // node_hash_set::size()
+  //
+  // Returns the number of elements currently within the `node_hash_set`.
+  using Base::size;
+
+  // node_hash_set::clear()
+  //
+  // Removes all elements from the `node_hash_set`. Invalidates any references,
+  // pointers, or iterators referring to contained elements.
+  //
+  // NOTE: this operation may shrink the underlying buffer. To avoid shrinking
+  // the underlying buffer call `erase(begin(), end())`.
+  using Base::clear;
+
+  // node_hash_set::erase()
+  //
+  // Erases elements within the `node_hash_set`. Erasing does not trigger a
+  // rehash. Overloads are listed below.
+  //
+  // void erase(const_iterator pos):
+  //
+  //   Erases the element at `position` of the `node_hash_set`, returning
+  //   `void`.
+  //
+  //   NOTE: this return behavior is different than that of STL containers in
+  //   general and `std::unordered_set` in particular.
+  //
+  // iterator erase(const_iterator first, const_iterator last):
+  //
+  //   Erases the elements in the open interval [`first`, `last`), returning an
+  //   iterator pointing to `last`.
+  //
+  // size_type erase(const key_type& key):
+  //
+  //   Erases the element with the matching key, if it exists, returning the
+  //   number of elements erased (0 or 1).
+  using Base::erase;
+
+  // node_hash_set::insert()
+  //
+  // Inserts an element of the specified value into the `node_hash_set`,
+  // returning an iterator pointing to the newly inserted element, provided that
+  // an element with the given key does not already exist. If rehashing occurs
+  // due to the insertion, all iterators are invalidated. Overloads are listed
+  // below.
+  //
+  // std::pair<iterator,bool> insert(const T& value):
+  //
+  //   Inserts a value into the `node_hash_set`. Returns a pair consisting of an
+  //   iterator to the inserted element (or to the element that prevented the
+  //   insertion) and a bool denoting whether the insertion took place.
+  //
+  // std::pair<iterator,bool> insert(T&& value):
+  //
+  //   Inserts a moveable value into the `node_hash_set`. Returns a pair
+  //   consisting of an iterator to the inserted element (or to the element that
+  //   prevented the insertion) and a bool denoting whether the insertion took
+  //   place.
+  //
+  // iterator insert(const_iterator hint, const T& value):
+  // iterator insert(const_iterator hint, T&& value):
+  //
+  //   Inserts a value, using the position of `hint` as a non-binding suggestion
+  //   for where to begin the insertion search. Returns an iterator to the
+  //   inserted element, or to the existing element that prevented the
+  //   insertion.
+  //
+  // void insert(InputIterator first, InputIterator last):
+  //
+  //   Inserts a range of values [`first`, `last`).
+  //
+  //   NOTE: Although the STL does not specify which element may be inserted if
+  //   multiple keys compare equivalently, for `node_hash_set` we guarantee the
+  //   first match is inserted.
+  //
+  // void insert(std::initializer_list<T> ilist):
+  //
+  //   Inserts the elements within the initializer list `ilist`.
+  //
+  //   NOTE: Although the STL does not specify which element may be inserted if
+  //   multiple keys compare equivalently within the initializer list, for
+  //   `node_hash_set` we guarantee the first match is inserted.
+  using Base::insert;
+
+  // node_hash_set::emplace()
+  //
+  // Inserts an element of the specified value by constructing it in-place
+  // within the `node_hash_set`, provided that no element with the given key
+  // already exists.
+  //
+  // The element may be constructed even if there already is an element with the
+  // key in the container, in which case the newly constructed element will be
+  // destroyed immediately.
+  //
+  // If rehashing occurs due to the insertion, all iterators are invalidated.
+  using Base::emplace;
+
+  // node_hash_set::emplace_hint()
+  //
+  // Inserts an element of the specified value by constructing it in-place
+  // within the `node_hash_set`, using the position of `hint` as a non-binding
+  // suggestion for where to begin the insertion search, and only inserts
+  // provided that no element with the given key already exists.
+  //
+  // The element may be constructed even if there already is an element with the
+  // key in the container, in which case the newly constructed element will be
+  // destroyed immediately.
+  //
+  // If rehashing occurs due to the insertion, all iterators are invalidated.
+  using Base::emplace_hint;
+
+  // node_hash_set::extract()
+  //
+  // Extracts the indicated element, erasing it in the process, and returns it
+  // as a C++17-compatible node handle. Overloads are listed below.
+  //
+  // node_type extract(const_iterator position):
+  //
+  //   Extracts the element at the indicated position and returns a node handle
+  //   owning that extracted data.
+  //
+  // node_type extract(const key_type& x):
+  //
+  //   Extracts the element with the key matching the passed key value and
+  //   returns a node handle owning that extracted data. If the `node_hash_set`
+  //   does not contain an element with a matching key, this function returns an
+  // empty node handle.
+  using Base::extract;
+
+  // node_hash_set::merge()
+  //
+  // Extracts elements from a given `source` node hash set into this
+  // `node_hash_set`. If the destination `node_hash_set` already contains an
+  // element with an equivalent key, that element is not extracted.
+  using Base::merge;
+
+  // node_hash_set::swap(node_hash_set& other)
+  //
+  // Exchanges the contents of this `node_hash_set` with those of the `other`
+  // node hash set, avoiding invocation of any move, copy, or swap operations on
+  // individual elements.
+  //
+  // All iterators and references on the `node_hash_set` remain valid, excepting
+  // for the past-the-end iterator, which is invalidated.
+  //
+  // `swap()` requires that the node hash set's hashing and key equivalence
+  // functions be Swappable, and are exchaged using unqualified calls to
+  // non-member `swap()`. If the set's allocator has
+  // `std::allocator_traits<allocator_type>::propagate_on_container_swap::value`
+  // set to `true`, the allocators are also exchanged using an unqualified call
+  // to non-member `swap()`; otherwise, the allocators are not swapped.
+  using Base::swap;
+
+  // node_hash_set::rehash(count)
+  //
+  // Rehashes the `node_hash_set`, setting the number of slots to be at least
+  // the passed value. If the new number of slots increases the load factor more
+  // than the current maximum load factor
+  // (`count` < `size()` / `max_load_factor()`), then the new number of slots
+  // will be at least `size()` / `max_load_factor()`.
+  //
+  // To force a rehash, pass rehash(0).
+  //
+  // NOTE: unlike behavior in `std::unordered_set`, references are also
+  // invalidated upon a `rehash()`.
+  using Base::rehash;
+
+  // node_hash_set::reserve(count)
+  //
+  // Sets the number of slots in the `node_hash_set` to the number needed to
+  // accommodate at least `count` total elements without exceeding the current
+  // maximum load factor, and may rehash the container if needed.
+  using Base::reserve;
+
+  // node_hash_set::contains()
+  //
+  // Determines whether an element comparing equal to the given `key` exists
+  // within the `node_hash_set`, returning `true` if so or `false` otherwise.
+  using Base::contains;
+
+  // node_hash_set::count(const Key& key) const
+  //
+  // Returns the number of elements comparing equal to the given `key` within
+  // the `node_hash_set`. note that this function will return either `1` or `0`
+  // since duplicate elements are not allowed within a `node_hash_set`.
+  using Base::count;
+
+  // node_hash_set::equal_range()
+  //
+  // Returns a closed range [first, last], defined by a `std::pair` of two
+  // iterators, containing all elements with the passed key in the
+  // `node_hash_set`.
+  using Base::equal_range;
+
+  // node_hash_set::find()
+  //
+  // Finds an element with the passed `key` within the `node_hash_set`.
+  using Base::find;
+
+  // node_hash_set::bucket_count()
+  //
+  // Returns the number of "buckets" within the `node_hash_set`. Note that
+  // because a node hash set contains all elements within its internal storage,
+  // this value simply equals the current capacity of the `node_hash_set`.
+  using Base::bucket_count;
+
+  // node_hash_set::load_factor()
+  //
+  // Returns the current load factor of the `node_hash_set` (the average number
+  // of slots occupied with a value within the hash set).
+  using Base::load_factor;
+
+  // node_hash_set::max_load_factor()
+  //
+  // Manages the maximum load factor of the `node_hash_set`. Overloads are
+  // listed below.
+  //
+  // float node_hash_set::max_load_factor()
+  //
+  //   Returns the current maximum load factor of the `node_hash_set`.
+  //
+  // void node_hash_set::max_load_factor(float ml)
+  //
+  //   Sets the maximum load factor of the `node_hash_set` to the passed value.
+  //
+  //   NOTE: This overload is provided only for API compatibility with the STL;
+  //   `node_hash_set` will ignore any set load factor and manage its rehashing
+  //   internally as an implementation detail.
+  using Base::max_load_factor;
+
+  // node_hash_set::get_allocator()
+  //
+  // Returns the allocator function associated with this `node_hash_set`.
+  using Base::get_allocator;
+
+  // node_hash_set::hash_function()
+  //
+  // Returns the hashing function used to hash the keys within this
+  // `node_hash_set`.
+  using Base::hash_function;
+
+  // node_hash_set::key_eq()
+  //
+  // Returns the function used for comparing keys equality.
+  using Base::key_eq;
+};
+
+// erase_if(node_hash_set<>, Pred)
+//
+// Erases all elements that satisfy the predicate `pred` from the container `c`.
+template <typename T, typename H, typename E, typename A, typename Predicate>
+void erase_if(node_hash_set<T, H, E, A>& c, Predicate pred) {
+  container_internal::EraseIf(pred, &c);
+}
+
+namespace container_internal {
+
+template <class T>
+struct NodeHashSetPolicy
+    : absl::container_internal::node_hash_policy<T&, NodeHashSetPolicy<T>> {
+  using key_type = T;
+  using init_type = T;
+  using constant_iterators = std::true_type;
+
+  template <class Allocator, class... Args>
+  static T* new_element(Allocator* alloc, Args&&... args) {
+    using ValueAlloc =
+        typename absl::allocator_traits<Allocator>::template rebind_alloc<T>;
+    ValueAlloc value_alloc(*alloc);
+    T* res = absl::allocator_traits<ValueAlloc>::allocate(value_alloc, 1);
+    absl::allocator_traits<ValueAlloc>::construct(value_alloc, res,
+                                                  std::forward<Args>(args)...);
+    return res;
+  }
+
+  template <class Allocator>
+  static void delete_element(Allocator* alloc, T* elem) {
+    using ValueAlloc =
+        typename absl::allocator_traits<Allocator>::template rebind_alloc<T>;
+    ValueAlloc value_alloc(*alloc);
+    absl::allocator_traits<ValueAlloc>::destroy(value_alloc, elem);
+    absl::allocator_traits<ValueAlloc>::deallocate(value_alloc, elem, 1);
+  }
+
+  template <class F, class... Args>
+  static decltype(absl::container_internal::DecomposeValue(
+      std::declval<F>(), std::declval<Args>()...))
+  apply(F&& f, Args&&... args) {
+    return absl::container_internal::DecomposeValue(
+        std::forward<F>(f), std::forward<Args>(args)...);
+  }
+
+  static size_t element_space_used(const T*) { return sizeof(T); }
+};
+}  // namespace container_internal
+
+namespace container_algorithm_internal {
+
+// Specialization of trait in absl/algorithm/container.h
+template <class Key, class Hash, class KeyEqual, class Allocator>
+struct IsUnorderedContainer<absl::node_hash_set<Key, Hash, KeyEqual, Allocator>>
+    : std::true_type {};
+
+}  // namespace container_algorithm_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#endif  // ABSL_CONTAINER_NODE_HASH_SET_H_
diff --git a/src/absl/debugging/failure_signal_handler.cc b/src/absl/debugging/failure_signal_handler.cc
new file mode 100644 (file)
index 0000000..3ddebd7
--- /dev/null
@@ -0,0 +1,387 @@
+//
+// Copyright 2018 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#include "absl/debugging/failure_signal_handler.h"
+
+#include "absl/base/config.h"
+
+#ifdef _WIN32
+#include <windows.h>
+#else
+#include <sched.h>
+#include <unistd.h>
+#endif
+
+#ifdef __APPLE__
+#include <TargetConditionals.h>
+#endif
+
+#ifdef ABSL_HAVE_MMAP
+#include <sys/mman.h>
+#endif
+
+#include <algorithm>
+#include <atomic>
+#include <cerrno>
+#include <csignal>
+#include <cstdio>
+#include <cstring>
+#include <ctime>
+
+#include "absl/base/attributes.h"
+#include "absl/base/internal/errno_saver.h"
+#include "absl/base/internal/raw_logging.h"
+#include "absl/base/internal/sysinfo.h"
+#include "absl/debugging/internal/examine_stack.h"
+#include "absl/debugging/stacktrace.h"
+
+#ifndef _WIN32
+#define ABSL_HAVE_SIGACTION
+// Apple WatchOS and TVOS don't allow sigaltstack
+#if !(defined(TARGET_OS_WATCH) && TARGET_OS_WATCH) && \
+    !(defined(TARGET_OS_TV) && TARGET_OS_TV)
+#define ABSL_HAVE_SIGALTSTACK
+#endif
+#endif
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+
+ABSL_CONST_INIT static FailureSignalHandlerOptions fsh_options;
+
+// Resets the signal handler for signo to the default action for that
+// signal, then raises the signal.
+static void RaiseToDefaultHandler(int signo) {
+  signal(signo, SIG_DFL);
+  raise(signo);
+}
+
+struct FailureSignalData {
+  const int signo;
+  const char* const as_string;
+#ifdef ABSL_HAVE_SIGACTION
+  struct sigaction previous_action;
+  // StructSigaction is used to silence -Wmissing-field-initializers.
+  using StructSigaction = struct sigaction;
+  #define FSD_PREVIOUS_INIT FailureSignalData::StructSigaction()
+#else
+  void (*previous_handler)(int);
+  #define FSD_PREVIOUS_INIT SIG_DFL
+#endif
+};
+
+ABSL_CONST_INIT static FailureSignalData failure_signal_data[] = {
+    {SIGSEGV, "SIGSEGV", FSD_PREVIOUS_INIT},
+    {SIGILL, "SIGILL", FSD_PREVIOUS_INIT},
+    {SIGFPE, "SIGFPE", FSD_PREVIOUS_INIT},
+    {SIGABRT, "SIGABRT", FSD_PREVIOUS_INIT},
+    {SIGTERM, "SIGTERM", FSD_PREVIOUS_INIT},
+#ifndef _WIN32
+    {SIGBUS, "SIGBUS", FSD_PREVIOUS_INIT},
+    {SIGTRAP, "SIGTRAP", FSD_PREVIOUS_INIT},
+#endif
+};
+
+#undef FSD_PREVIOUS_INIT
+
+static void RaiseToPreviousHandler(int signo) {
+  // Search for the previous handler.
+  for (const auto& it : failure_signal_data) {
+    if (it.signo == signo) {
+#ifdef ABSL_HAVE_SIGACTION
+      sigaction(signo, &it.previous_action, nullptr);
+#else
+      signal(signo, it.previous_handler);
+#endif
+      raise(signo);
+      return;
+    }
+  }
+
+  // Not found, use the default handler.
+  RaiseToDefaultHandler(signo);
+}
+
+namespace debugging_internal {
+
+const char* FailureSignalToString(int signo) {
+  for (const auto& it : failure_signal_data) {
+    if (it.signo == signo) {
+      return it.as_string;
+    }
+  }
+  return "";
+}
+
+}  // namespace debugging_internal
+
+#ifdef ABSL_HAVE_SIGALTSTACK
+
+static bool SetupAlternateStackOnce() {
+#if defined(__wasm__) || defined (__asjms__)
+  const size_t page_mask = getpagesize() - 1;
+#else
+  const size_t page_mask = sysconf(_SC_PAGESIZE) - 1;
+#endif
+  size_t stack_size =
+      (std::max<size_t>(SIGSTKSZ, 65536) + page_mask) & ~page_mask;
+#if defined(ABSL_HAVE_ADDRESS_SANITIZER) || \
+    defined(ABSL_HAVE_MEMORY_SANITIZER) || defined(ABSL_HAVE_THREAD_SANITIZER)
+  // Account for sanitizer instrumentation requiring additional stack space.
+  stack_size *= 5;
+#endif
+
+  stack_t sigstk;
+  memset(&sigstk, 0, sizeof(sigstk));
+  sigstk.ss_size = stack_size;
+
+#ifdef ABSL_HAVE_MMAP
+#ifndef MAP_STACK
+#define MAP_STACK 0
+#endif
+#if defined(MAP_ANON) && !defined(MAP_ANONYMOUS)
+#define MAP_ANONYMOUS MAP_ANON
+#endif
+  sigstk.ss_sp = mmap(nullptr, sigstk.ss_size, PROT_READ | PROT_WRITE,
+                      MAP_PRIVATE | MAP_ANONYMOUS | MAP_STACK, -1, 0);
+  if (sigstk.ss_sp == MAP_FAILED) {
+    ABSL_RAW_LOG(FATAL, "mmap() for alternate signal stack failed");
+  }
+#else
+  sigstk.ss_sp = malloc(sigstk.ss_size);
+  if (sigstk.ss_sp == nullptr) {
+    ABSL_RAW_LOG(FATAL, "malloc() for alternate signal stack failed");
+  }
+#endif
+
+  if (sigaltstack(&sigstk, nullptr) != 0) {
+    ABSL_RAW_LOG(FATAL, "sigaltstack() failed with errno=%d", errno);
+  }
+  return true;
+}
+
+#endif
+
+#ifdef ABSL_HAVE_SIGACTION
+
+// Sets up an alternate stack for signal handlers once.
+// Returns the appropriate flag for sig_action.sa_flags
+// if the system supports using an alternate stack.
+static int MaybeSetupAlternateStack() {
+#ifdef ABSL_HAVE_SIGALTSTACK
+  ABSL_ATTRIBUTE_UNUSED static const bool kOnce = SetupAlternateStackOnce();
+  return SA_ONSTACK;
+#else
+  return 0;
+#endif
+}
+
+static void InstallOneFailureHandler(FailureSignalData* data,
+                                     void (*handler)(int, siginfo_t*, void*)) {
+  struct sigaction act;
+  memset(&act, 0, sizeof(act));
+  sigemptyset(&act.sa_mask);
+  act.sa_flags |= SA_SIGINFO;
+  // SA_NODEFER is required to handle SIGABRT from
+  // ImmediateAbortSignalHandler().
+  act.sa_flags |= SA_NODEFER;
+  if (fsh_options.use_alternate_stack) {
+    act.sa_flags |= MaybeSetupAlternateStack();
+  }
+  act.sa_sigaction = handler;
+  ABSL_RAW_CHECK(sigaction(data->signo, &act, &data->previous_action) == 0,
+                 "sigaction() failed");
+}
+
+#else
+
+static void InstallOneFailureHandler(FailureSignalData* data,
+                                     void (*handler)(int)) {
+  data->previous_handler = signal(data->signo, handler);
+  ABSL_RAW_CHECK(data->previous_handler != SIG_ERR, "signal() failed");
+}
+
+#endif
+
+static void WriteToStderr(const char* data) {
+  absl::base_internal::ErrnoSaver errno_saver;
+  absl::raw_logging_internal::SafeWriteToStderr(data, strlen(data));
+}
+
+static void WriteSignalMessage(int signo, int cpu,
+                               void (*writerfn)(const char*)) {
+  char buf[96];
+  char on_cpu[32] = {0};
+  if (cpu != -1) {
+    snprintf(on_cpu, sizeof(on_cpu), " on cpu %d", cpu);
+  }
+  const char* const signal_string =
+      debugging_internal::FailureSignalToString(signo);
+  if (signal_string != nullptr && signal_string[0] != '\0') {
+    snprintf(buf, sizeof(buf), "*** %s received at time=%ld%s ***\n",
+             signal_string,
+             static_cast<long>(time(nullptr)),   // NOLINT(runtime/int)
+             on_cpu);
+  } else {
+    snprintf(buf, sizeof(buf), "*** Signal %d received at time=%ld%s ***\n",
+             signo, static_cast<long>(time(nullptr)),  // NOLINT(runtime/int)
+             on_cpu);
+  }
+  writerfn(buf);
+}
+
+// `void*` might not be big enough to store `void(*)(const char*)`.
+struct WriterFnStruct {
+  void (*writerfn)(const char*);
+};
+
+// Many of the absl::debugging_internal::Dump* functions in
+// examine_stack.h take a writer function pointer that has a void* arg
+// for historical reasons. failure_signal_handler_writer only takes a
+// data pointer. This function converts between these types.
+static void WriterFnWrapper(const char* data, void* arg) {
+  static_cast<WriterFnStruct*>(arg)->writerfn(data);
+}
+
+// Convenient wrapper around DumpPCAndFrameSizesAndStackTrace() for signal
+// handlers. "noinline" so that GetStackFrames() skips the top-most stack
+// frame for this function.
+ABSL_ATTRIBUTE_NOINLINE static void WriteStackTrace(
+    void* ucontext, bool symbolize_stacktrace,
+    void (*writerfn)(const char*, void*), void* writerfn_arg) {
+  constexpr int kNumStackFrames = 32;
+  void* stack[kNumStackFrames];
+  int frame_sizes[kNumStackFrames];
+  int min_dropped_frames;
+  int depth = absl::GetStackFramesWithContext(
+      stack, frame_sizes, kNumStackFrames,
+      1,  // Do not include this function in stack trace.
+      ucontext, &min_dropped_frames);
+  absl::debugging_internal::DumpPCAndFrameSizesAndStackTrace(
+      absl::debugging_internal::GetProgramCounter(ucontext), stack, frame_sizes,
+      depth, min_dropped_frames, symbolize_stacktrace, writerfn, writerfn_arg);
+}
+
+// Called by AbslFailureSignalHandler() to write the failure info. It is
+// called once with writerfn set to WriteToStderr() and then possibly
+// with writerfn set to the user provided function.
+static void WriteFailureInfo(int signo, void* ucontext, int cpu,
+                             void (*writerfn)(const char*)) {
+  WriterFnStruct writerfn_struct{writerfn};
+  WriteSignalMessage(signo, cpu, writerfn);
+  WriteStackTrace(ucontext, fsh_options.symbolize_stacktrace, WriterFnWrapper,
+                  &writerfn_struct);
+}
+
+// absl::SleepFor() can't be used here since AbslInternalSleepFor()
+// may be overridden to do something that isn't async-signal-safe on
+// some platforms.
+static void PortableSleepForSeconds(int seconds) {
+#ifdef _WIN32
+  Sleep(seconds * 1000);
+#else
+  struct timespec sleep_time;
+  sleep_time.tv_sec = seconds;
+  sleep_time.tv_nsec = 0;
+  while (nanosleep(&sleep_time, &sleep_time) != 0 && errno == EINTR) {}
+#endif
+}
+
+#ifdef ABSL_HAVE_ALARM
+// AbslFailureSignalHandler() installs this as a signal handler for
+// SIGALRM, then sets an alarm to be delivered to the program after a
+// set amount of time. If AbslFailureSignalHandler() hangs for more than
+// the alarm timeout, ImmediateAbortSignalHandler() will abort the
+// program.
+static void ImmediateAbortSignalHandler(int) {
+  RaiseToDefaultHandler(SIGABRT);
+}
+#endif
+
+// absl::base_internal::GetTID() returns pid_t on most platforms, but
+// returns absl::base_internal::pid_t on Windows.
+using GetTidType = decltype(absl::base_internal::GetTID());
+ABSL_CONST_INIT static std::atomic<GetTidType> failed_tid(0);
+
+#ifndef ABSL_HAVE_SIGACTION
+static void AbslFailureSignalHandler(int signo) {
+  void* ucontext = nullptr;
+#else
+static void AbslFailureSignalHandler(int signo, siginfo_t*, void* ucontext) {
+#endif
+
+  const GetTidType this_tid = absl::base_internal::GetTID();
+  GetTidType previous_failed_tid = 0;
+  if (!failed_tid.compare_exchange_strong(
+          previous_failed_tid, static_cast<intptr_t>(this_tid),
+          std::memory_order_acq_rel, std::memory_order_relaxed)) {
+    ABSL_RAW_LOG(
+        ERROR,
+        "Signal %d raised at PC=%p while already in AbslFailureSignalHandler()",
+        signo, absl::debugging_internal::GetProgramCounter(ucontext));
+    if (this_tid != previous_failed_tid) {
+      // Another thread is already in AbslFailureSignalHandler(), so wait
+      // a bit for it to finish. If the other thread doesn't kill us,
+      // we do so after sleeping.
+      PortableSleepForSeconds(3);
+      RaiseToDefaultHandler(signo);
+      // The recursively raised signal may be blocked until we return.
+      return;
+    }
+  }
+
+  // Increase the chance that the CPU we report was the same CPU on which the
+  // signal was received by doing this as early as possible, i.e. after
+  // verifying that this is not a recursive signal handler invocation.
+  int my_cpu = -1;
+#ifdef ABSL_HAVE_SCHED_GETCPU
+  my_cpu = sched_getcpu();
+#endif
+
+#ifdef ABSL_HAVE_ALARM
+  // Set an alarm to abort the program in case this code hangs or deadlocks.
+  if (fsh_options.alarm_on_failure_secs > 0) {
+    alarm(0);  // Cancel any existing alarms.
+    signal(SIGALRM, ImmediateAbortSignalHandler);
+    alarm(fsh_options.alarm_on_failure_secs);
+  }
+#endif
+
+  // First write to stderr.
+  WriteFailureInfo(signo, ucontext, my_cpu, WriteToStderr);
+
+  // Riskier code (because it is less likely to be async-signal-safe)
+  // goes after this point.
+  if (fsh_options.writerfn != nullptr) {
+    WriteFailureInfo(signo, ucontext, my_cpu, fsh_options.writerfn);
+  }
+
+  if (fsh_options.call_previous_handler) {
+    RaiseToPreviousHandler(signo);
+  } else {
+    RaiseToDefaultHandler(signo);
+  }
+}
+
+void InstallFailureSignalHandler(const FailureSignalHandlerOptions& options) {
+  fsh_options = options;
+  for (auto& it : failure_signal_data) {
+    InstallOneFailureHandler(&it, AbslFailureSignalHandler);
+  }
+}
+
+ABSL_NAMESPACE_END
+}  // namespace absl
diff --git a/src/absl/debugging/failure_signal_handler.h b/src/absl/debugging/failure_signal_handler.h
new file mode 100644 (file)
index 0000000..0c0f585
--- /dev/null
@@ -0,0 +1,121 @@
+// Copyright 2018 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// -----------------------------------------------------------------------------
+// File: failure_signal_handler.h
+// -----------------------------------------------------------------------------
+//
+// This file configures the Abseil *failure signal handler* to capture and dump
+// useful debugging information (such as a stacktrace) upon program failure.
+//
+// To use the failure signal handler, call `absl::InstallFailureSignalHandler()`
+// very early in your program, usually in the first few lines of main():
+//
+// int main(int argc, char** argv) {
+//   // Initialize the symbolizer to get a human-readable stack trace
+//   absl::InitializeSymbolizer(argv[0]);
+//
+//   absl::FailureSignalHandlerOptions options;
+//   absl::InstallFailureSignalHandler(options);
+//   DoSomethingInteresting();
+//   return 0;
+// }
+//
+// Any program that raises a fatal signal (such as `SIGSEGV`, `SIGILL`,
+// `SIGFPE`, `SIGABRT`, `SIGTERM`, `SIGBUG`, and `SIGTRAP`) will call the
+// installed failure signal handler and provide debugging information to stderr.
+//
+// Note that you should *not* install the Abseil failure signal handler more
+// than once. You may, of course, have another (non-Abseil) failure signal
+// handler installed (which would be triggered if Abseil's failure signal
+// handler sets `call_previous_handler` to `true`).
+
+#ifndef ABSL_DEBUGGING_FAILURE_SIGNAL_HANDLER_H_
+#define ABSL_DEBUGGING_FAILURE_SIGNAL_HANDLER_H_
+
+#include "absl/base/config.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+
+// FailureSignalHandlerOptions
+//
+// Struct for holding `absl::InstallFailureSignalHandler()` configuration
+// options.
+struct FailureSignalHandlerOptions {
+  // If true, try to symbolize the stacktrace emitted on failure, provided that
+  // you have initialized a symbolizer for that purpose. (See symbolize.h for
+  // more information.)
+  bool symbolize_stacktrace = true;
+
+  // If true, try to run signal handlers on an alternate stack (if supported on
+  // the given platform). An alternate stack is useful for program crashes due
+  // to a stack overflow; by running on a alternate stack, the signal handler
+  // may run even when normal stack space has been exausted. The downside of
+  // using an alternate stack is that extra memory for the alternate stack needs
+  // to be pre-allocated.
+  bool use_alternate_stack = true;
+
+  // If positive, indicates the number of seconds after which the failure signal
+  // handler is invoked to abort the program. Setting such an alarm is useful in
+  // cases where the failure signal handler itself may become hung or
+  // deadlocked.
+  int alarm_on_failure_secs = 3;
+
+  // If true, call the previously registered signal handler for the signal that
+  // was received (if one was registered) after the existing signal handler
+  // runs. This mechanism can be used to chain signal handlers together.
+  //
+  // If false, the signal is raised to the default handler for that signal
+  // (which normally terminates the program).
+  //
+  // IMPORTANT: If true, the chained fatal signal handlers must not try to
+  // recover from the fatal signal. Instead, they should terminate the program
+  // via some mechanism, like raising the default handler for the signal, or by
+  // calling `_exit()`. Note that the failure signal handler may put parts of
+  // the Abseil library into a state from which they cannot recover.
+  bool call_previous_handler = false;
+
+  // If non-null, indicates a pointer to a callback function that will be called
+  // upon failure, with a string argument containing failure data. This function
+  // may be used as a hook to write failure data to a secondary location, such
+  // as a log file. This function may also be called with null data, as a hint
+  // to flush any buffered data before the program may be terminated. Consider
+  // flushing any buffered data in all calls to this function.
+  //
+  // Since this function runs within a signal handler, it should be
+  // async-signal-safe if possible.
+  // See http://man7.org/linux/man-pages/man7/signal-safety.7.html
+  void (*writerfn)(const char*) = nullptr;
+};
+
+// InstallFailureSignalHandler()
+//
+// Installs a signal handler for the common failure signals `SIGSEGV`, `SIGILL`,
+// `SIGFPE`, `SIGABRT`, `SIGTERM`, `SIGBUG`, and `SIGTRAP` (provided they exist
+// on the given platform). The failure signal handler dumps program failure data
+// useful for debugging in an unspecified format to stderr. This data may
+// include the program counter, a stacktrace, and register information on some
+// systems; do not rely on an exact format for the output, as it is subject to
+// change.
+void InstallFailureSignalHandler(const FailureSignalHandlerOptions& options);
+
+namespace debugging_internal {
+const char* FailureSignalToString(int signo);
+}  // namespace debugging_internal
+
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#endif  // ABSL_DEBUGGING_FAILURE_SIGNAL_HANDLER_H_
diff --git a/src/absl/debugging/internal/address_is_readable.cc b/src/absl/debugging/internal/address_is_readable.cc
new file mode 100644 (file)
index 0000000..329c285
--- /dev/null
@@ -0,0 +1,139 @@
+// Copyright 2017 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// base::AddressIsReadable() probes an address to see whether it is readable,
+// without faulting.
+
+#include "absl/debugging/internal/address_is_readable.h"
+
+#if !defined(__linux__) || defined(__ANDROID__)
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace debugging_internal {
+
+// On platforms other than Linux, just return true.
+bool AddressIsReadable(const void* /* addr */) { return true; }
+
+}  // namespace debugging_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#else
+
+#include <fcntl.h>
+#include <sys/syscall.h>
+#include <unistd.h>
+
+#include <atomic>
+#include <cerrno>
+#include <cstdint>
+
+#include "absl/base/internal/errno_saver.h"
+#include "absl/base/internal/raw_logging.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace debugging_internal {
+
+// Pack a pid and two file descriptors into a 64-bit word,
+// using 16, 24, and 24 bits for each respectively.
+static uint64_t Pack(uint64_t pid, uint64_t read_fd, uint64_t write_fd) {
+  ABSL_RAW_CHECK((read_fd >> 24) == 0 && (write_fd >> 24) == 0,
+                 "fd out of range");
+  return (pid << 48) | ((read_fd & 0xffffff) << 24) | (write_fd & 0xffffff);
+}
+
+// Unpack x into a pid and two file descriptors, where x was created with
+// Pack().
+static void Unpack(uint64_t x, int *pid, int *read_fd, int *write_fd) {
+  *pid = x >> 48;
+  *read_fd = (x >> 24) & 0xffffff;
+  *write_fd = x & 0xffffff;
+}
+
+// Return whether the byte at *addr is readable, without faulting.
+// Save and restores errno.   Returns true on systems where
+// unimplemented.
+// This is a namespace-scoped variable for correct zero-initialization.
+static std::atomic<uint64_t> pid_and_fds;  // initially 0, an invalid pid.
+
+bool AddressIsReadable(const void *addr) {
+  absl::base_internal::ErrnoSaver errno_saver;
+  // We test whether a byte is readable by using write().  Normally, this would
+  // be done via a cached file descriptor to /dev/null, but linux fails to
+  // check whether the byte is readable when the destination is /dev/null, so
+  // we use a cached pipe.  We store the pid of the process that created the
+  // pipe to handle the case where a process forks, and the child closes all
+  // the file descriptors and then calls this routine.  This is not perfect:
+  // the child could use the routine, then close all file descriptors and then
+  // use this routine again.  But the likely use of this routine is when
+  // crashing, to test the validity of pages when dumping the stack.  Beware
+  // that we may leak file descriptors, but we're unlikely to leak many.
+  int bytes_written;
+  int current_pid = getpid() & 0xffff;   // we use only the low order 16 bits
+  do {  // until we do not get EBADF trying to use file descriptors
+    int pid;
+    int read_fd;
+    int write_fd;
+    uint64_t local_pid_and_fds = pid_and_fds.load(std::memory_order_acquire);
+    Unpack(local_pid_and_fds, &pid, &read_fd, &write_fd);
+    while (current_pid != pid) {
+      int p[2];
+      // new pipe
+      if (pipe(p) != 0) {
+        ABSL_RAW_LOG(FATAL, "Failed to create pipe, errno=%d", errno);
+      }
+      fcntl(p[0], F_SETFD, FD_CLOEXEC);
+      fcntl(p[1], F_SETFD, FD_CLOEXEC);
+      uint64_t new_pid_and_fds = Pack(current_pid, p[0], p[1]);
+      if (pid_and_fds.compare_exchange_strong(
+              local_pid_and_fds, new_pid_and_fds, std::memory_order_release,
+              std::memory_order_relaxed)) {
+        local_pid_and_fds = new_pid_and_fds;  // fds exposed to other threads
+      } else {  // fds not exposed to other threads; we can close them.
+        close(p[0]);
+        close(p[1]);
+        local_pid_and_fds = pid_and_fds.load(std::memory_order_acquire);
+      }
+      Unpack(local_pid_and_fds, &pid, &read_fd, &write_fd);
+    }
+    errno = 0;
+    // Use syscall(SYS_write, ...) instead of write() to prevent ASAN
+    // and other checkers from complaining about accesses to arbitrary
+    // memory.
+    do {
+      bytes_written = syscall(SYS_write, write_fd, addr, 1);
+    } while (bytes_written == -1 && errno == EINTR);
+    if (bytes_written == 1) {   // remove the byte from the pipe
+      char c;
+      while (read(read_fd, &c, 1) == -1 && errno == EINTR) {
+      }
+    }
+    if (errno == EBADF) {  // Descriptors invalid.
+      // If pid_and_fds contains the problematic file descriptors we just used,
+      // this call will forget them, and the loop will try again.
+      pid_and_fds.compare_exchange_strong(local_pid_and_fds, 0,
+                                          std::memory_order_release,
+                                          std::memory_order_relaxed);
+    }
+  } while (errno == EBADF);
+  return bytes_written == 1;
+}
+
+}  // namespace debugging_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#endif
diff --git a/src/absl/debugging/internal/address_is_readable.h b/src/absl/debugging/internal/address_is_readable.h
new file mode 100644 (file)
index 0000000..4bbaf4d
--- /dev/null
@@ -0,0 +1,32 @@
+// Copyright 2017 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef ABSL_DEBUGGING_INTERNAL_ADDRESS_IS_READABLE_H_
+#define ABSL_DEBUGGING_INTERNAL_ADDRESS_IS_READABLE_H_
+
+#include "absl/base/config.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace debugging_internal {
+
+// Return whether the byte at *addr is readable, without faulting.
+// Save and restores errno.
+bool AddressIsReadable(const void *addr);
+
+}  // namespace debugging_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#endif  // ABSL_DEBUGGING_INTERNAL_ADDRESS_IS_READABLE_H_
diff --git a/src/absl/debugging/internal/demangle.cc b/src/absl/debugging/internal/demangle.cc
new file mode 100644 (file)
index 0000000..5cd5632
--- /dev/null
@@ -0,0 +1,1949 @@
+// Copyright 2018 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// For reference check out:
+// https://itanium-cxx-abi.github.io/cxx-abi/abi.html#mangling
+//
+// Note that we only have partial C++11 support yet.
+
+#include "absl/debugging/internal/demangle.h"
+
+#include <cstdint>
+#include <cstdio>
+#include <limits>
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace debugging_internal {
+
+typedef struct {
+  const char *abbrev;
+  const char *real_name;
+  // Number of arguments in <expression> context, or 0 if disallowed.
+  int arity;
+} AbbrevPair;
+
+// List of operators from Itanium C++ ABI.
+static const AbbrevPair kOperatorList[] = {
+    // New has special syntax (not currently supported).
+    {"nw", "new", 0},
+    {"na", "new[]", 0},
+
+    // Works except that the 'gs' prefix is not supported.
+    {"dl", "delete", 1},
+    {"da", "delete[]", 1},
+
+    {"ps", "+", 1},  // "positive"
+    {"ng", "-", 1},  // "negative"
+    {"ad", "&", 1},  // "address-of"
+    {"de", "*", 1},  // "dereference"
+    {"co", "~", 1},
+
+    {"pl", "+", 2},
+    {"mi", "-", 2},
+    {"ml", "*", 2},
+    {"dv", "/", 2},
+    {"rm", "%", 2},
+    {"an", "&", 2},
+    {"or", "|", 2},
+    {"eo", "^", 2},
+    {"aS", "=", 2},
+    {"pL", "+=", 2},
+    {"mI", "-=", 2},
+    {"mL", "*=", 2},
+    {"dV", "/=", 2},
+    {"rM", "%=", 2},
+    {"aN", "&=", 2},
+    {"oR", "|=", 2},
+    {"eO", "^=", 2},
+    {"ls", "<<", 2},
+    {"rs", ">>", 2},
+    {"lS", "<<=", 2},
+    {"rS", ">>=", 2},
+    {"eq", "==", 2},
+    {"ne", "!=", 2},
+    {"lt", "<", 2},
+    {"gt", ">", 2},
+    {"le", "<=", 2},
+    {"ge", ">=", 2},
+    {"nt", "!", 1},
+    {"aa", "&&", 2},
+    {"oo", "||", 2},
+    {"pp", "++", 1},
+    {"mm", "--", 1},
+    {"cm", ",", 2},
+    {"pm", "->*", 2},
+    {"pt", "->", 0},  // Special syntax
+    {"cl", "()", 0},  // Special syntax
+    {"ix", "[]", 2},
+    {"qu", "?", 3},
+    {"st", "sizeof", 0},  // Special syntax
+    {"sz", "sizeof", 1},  // Not a real operator name, but used in expressions.
+    {nullptr, nullptr, 0},
+};
+
+// List of builtin types from Itanium C++ ABI.
+//
+// Invariant: only one- or two-character type abbreviations here.
+static const AbbrevPair kBuiltinTypeList[] = {
+    {"v", "void", 0},
+    {"w", "wchar_t", 0},
+    {"b", "bool", 0},
+    {"c", "char", 0},
+    {"a", "signed char", 0},
+    {"h", "unsigned char", 0},
+    {"s", "short", 0},
+    {"t", "unsigned short", 0},
+    {"i", "int", 0},
+    {"j", "unsigned int", 0},
+    {"l", "long", 0},
+    {"m", "unsigned long", 0},
+    {"x", "long long", 0},
+    {"y", "unsigned long long", 0},
+    {"n", "__int128", 0},
+    {"o", "unsigned __int128", 0},
+    {"f", "float", 0},
+    {"d", "double", 0},
+    {"e", "long double", 0},
+    {"g", "__float128", 0},
+    {"z", "ellipsis", 0},
+
+    {"De", "decimal128", 0},      // IEEE 754r decimal floating point (128 bits)
+    {"Dd", "decimal64", 0},       // IEEE 754r decimal floating point (64 bits)
+    {"Dc", "decltype(auto)", 0},
+    {"Da", "auto", 0},
+    {"Dn", "std::nullptr_t", 0},  // i.e., decltype(nullptr)
+    {"Df", "decimal32", 0},       // IEEE 754r decimal floating point (32 bits)
+    {"Di", "char32_t", 0},
+    {"Du", "char8_t", 0},
+    {"Ds", "char16_t", 0},
+    {"Dh", "float16", 0},         // IEEE 754r half-precision float (16 bits)
+    {nullptr, nullptr, 0},
+};
+
+// List of substitutions Itanium C++ ABI.
+static const AbbrevPair kSubstitutionList[] = {
+    {"St", "", 0},
+    {"Sa", "allocator", 0},
+    {"Sb", "basic_string", 0},
+    // std::basic_string<char, std::char_traits<char>,std::allocator<char> >
+    {"Ss", "string", 0},
+    // std::basic_istream<char, std::char_traits<char> >
+    {"Si", "istream", 0},
+    // std::basic_ostream<char, std::char_traits<char> >
+    {"So", "ostream", 0},
+    // std::basic_iostream<char, std::char_traits<char> >
+    {"Sd", "iostream", 0},
+    {nullptr, nullptr, 0},
+};
+
+// State needed for demangling.  This struct is copied in almost every stack
+// frame, so every byte counts.
+typedef struct {
+  int mangled_idx;                   // Cursor of mangled name.
+  int out_cur_idx;                   // Cursor of output string.
+  int prev_name_idx;                 // For constructors/destructors.
+  signed int prev_name_length : 16;  // For constructors/destructors.
+  signed int nest_level : 15;        // For nested names.
+  unsigned int append : 1;           // Append flag.
+  // Note: for some reason MSVC can't pack "bool append : 1" into the same int
+  // with the above two fields, so we use an int instead.  Amusingly it can pack
+  // "signed bool" as expected, but relying on that to continue to be a legal
+  // type seems ill-advised (as it's illegal in at least clang).
+} ParseState;
+
+static_assert(sizeof(ParseState) == 4 * sizeof(int),
+              "unexpected size of ParseState");
+
+// One-off state for demangling that's not subject to backtracking -- either
+// constant data, data that's intentionally immune to backtracking (steps), or
+// data that would never be changed by backtracking anyway (recursion_depth).
+//
+// Only one copy of this exists for each call to Demangle, so the size of this
+// struct is nearly inconsequential.
+typedef struct {
+  const char *mangled_begin;  // Beginning of input string.
+  char *out;                  // Beginning of output string.
+  int out_end_idx;            // One past last allowed output character.
+  int recursion_depth;        // For stack exhaustion prevention.
+  int steps;               // Cap how much work we'll do, regardless of depth.
+  ParseState parse_state;  // Backtrackable state copied for most frames.
+} State;
+
+namespace {
+// Prevent deep recursion / stack exhaustion.
+// Also prevent unbounded handling of complex inputs.
+class ComplexityGuard {
+ public:
+  explicit ComplexityGuard(State *state) : state_(state) {
+    ++state->recursion_depth;
+    ++state->steps;
+  }
+  ~ComplexityGuard() { --state_->recursion_depth; }
+
+  // 256 levels of recursion seems like a reasonable upper limit on depth.
+  // 128 is not enough to demagle synthetic tests from demangle_unittest.txt:
+  // "_ZaaZZZZ..." and "_ZaaZcvZcvZ..."
+  static constexpr int kRecursionDepthLimit = 256;
+
+  // We're trying to pick a charitable upper-limit on how many parse steps are
+  // necessary to handle something that a human could actually make use of.
+  // This is mostly in place as a bound on how much work we'll do if we are
+  // asked to demangle an mangled name from an untrusted source, so it should be
+  // much larger than the largest expected symbol, but much smaller than the
+  // amount of work we can do in, e.g., a second.
+  //
+  // Some real-world symbols from an arbitrary binary started failing between
+  // 2^12 and 2^13, so we multiply the latter by an extra factor of 16 to set
+  // the limit.
+  //
+  // Spending one second on 2^17 parse steps would require each step to take
+  // 7.6us, or ~30000 clock cycles, so it's safe to say this can be done in
+  // under a second.
+  static constexpr int kParseStepsLimit = 1 << 17;
+
+  bool IsTooComplex() const {
+    return state_->recursion_depth > kRecursionDepthLimit ||
+           state_->steps > kParseStepsLimit;
+  }
+
+ private:
+  State *state_;
+};
+}  // namespace
+
+// We don't use strlen() in libc since it's not guaranteed to be async
+// signal safe.
+static size_t StrLen(const char *str) {
+  size_t len = 0;
+  while (*str != '\0') {
+    ++str;
+    ++len;
+  }
+  return len;
+}
+
+// Returns true if "str" has at least "n" characters remaining.
+static bool AtLeastNumCharsRemaining(const char *str, int n) {
+  for (int i = 0; i < n; ++i) {
+    if (str[i] == '\0') {
+      return false;
+    }
+  }
+  return true;
+}
+
+// Returns true if "str" has "prefix" as a prefix.
+static bool StrPrefix(const char *str, const char *prefix) {
+  size_t i = 0;
+  while (str[i] != '\0' && prefix[i] != '\0' && str[i] == prefix[i]) {
+    ++i;
+  }
+  return prefix[i] == '\0';  // Consumed everything in "prefix".
+}
+
+static void InitState(State *state, const char *mangled, char *out,
+                      int out_size) {
+  state->mangled_begin = mangled;
+  state->out = out;
+  state->out_end_idx = out_size;
+  state->recursion_depth = 0;
+  state->steps = 0;
+
+  state->parse_state.mangled_idx = 0;
+  state->parse_state.out_cur_idx = 0;
+  state->parse_state.prev_name_idx = 0;
+  state->parse_state.prev_name_length = -1;
+  state->parse_state.nest_level = -1;
+  state->parse_state.append = true;
+}
+
+static inline const char *RemainingInput(State *state) {
+  return &state->mangled_begin[state->parse_state.mangled_idx];
+}
+
+// Returns true and advances "mangled_idx" if we find "one_char_token"
+// at "mangled_idx" position.  It is assumed that "one_char_token" does
+// not contain '\0'.
+static bool ParseOneCharToken(State *state, const char one_char_token) {
+  ComplexityGuard guard(state);
+  if (guard.IsTooComplex()) return false;
+  if (RemainingInput(state)[0] == one_char_token) {
+    ++state->parse_state.mangled_idx;
+    return true;
+  }
+  return false;
+}
+
+// Returns true and advances "mangled_cur" if we find "two_char_token"
+// at "mangled_cur" position.  It is assumed that "two_char_token" does
+// not contain '\0'.
+static bool ParseTwoCharToken(State *state, const char *two_char_token) {
+  ComplexityGuard guard(state);
+  if (guard.IsTooComplex()) return false;
+  if (RemainingInput(state)[0] == two_char_token[0] &&
+      RemainingInput(state)[1] == two_char_token[1]) {
+    state->parse_state.mangled_idx += 2;
+    return true;
+  }
+  return false;
+}
+
+// Returns true and advances "mangled_cur" if we find any character in
+// "char_class" at "mangled_cur" position.
+static bool ParseCharClass(State *state, const char *char_class) {
+  ComplexityGuard guard(state);
+  if (guard.IsTooComplex()) return false;
+  if (RemainingInput(state)[0] == '\0') {
+    return false;
+  }
+  const char *p = char_class;
+  for (; *p != '\0'; ++p) {
+    if (RemainingInput(state)[0] == *p) {
+      ++state->parse_state.mangled_idx;
+      return true;
+    }
+  }
+  return false;
+}
+
+static bool ParseDigit(State *state, int *digit) {
+  char c = RemainingInput(state)[0];
+  if (ParseCharClass(state, "0123456789")) {
+    if (digit != nullptr) {
+      *digit = c - '0';
+    }
+    return true;
+  }
+  return false;
+}
+
+// This function is used for handling an optional non-terminal.
+static bool Optional(bool /*status*/) { return true; }
+
+// This function is used for handling <non-terminal>+ syntax.
+typedef bool (*ParseFunc)(State *);
+static bool OneOrMore(ParseFunc parse_func, State *state) {
+  if (parse_func(state)) {
+    while (parse_func(state)) {
+    }
+    return true;
+  }
+  return false;
+}
+
+// This function is used for handling <non-terminal>* syntax. The function
+// always returns true and must be followed by a termination token or a
+// terminating sequence not handled by parse_func (e.g.
+// ParseOneCharToken(state, 'E')).
+static bool ZeroOrMore(ParseFunc parse_func, State *state) {
+  while (parse_func(state)) {
+  }
+  return true;
+}
+
+// Append "str" at "out_cur_idx".  If there is an overflow, out_cur_idx is
+// set to out_end_idx+1.  The output string is ensured to
+// always terminate with '\0' as long as there is no overflow.
+static void Append(State *state, const char *const str, const int length) {
+  for (int i = 0; i < length; ++i) {
+    if (state->parse_state.out_cur_idx + 1 <
+        state->out_end_idx) {  // +1 for '\0'
+      state->out[state->parse_state.out_cur_idx++] = str[i];
+    } else {
+      // signal overflow
+      state->parse_state.out_cur_idx = state->out_end_idx + 1;
+      break;
+    }
+  }
+  if (state->parse_state.out_cur_idx < state->out_end_idx) {
+    state->out[state->parse_state.out_cur_idx] =
+        '\0';  // Terminate it with '\0'
+  }
+}
+
+// We don't use equivalents in libc to avoid locale issues.
+static bool IsLower(char c) { return c >= 'a' && c <= 'z'; }
+
+static bool IsAlpha(char c) {
+  return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z');
+}
+
+static bool IsDigit(char c) { return c >= '0' && c <= '9'; }
+
+// Returns true if "str" is a function clone suffix.  These suffixes are used
+// by GCC 4.5.x and later versions (and our locally-modified version of GCC
+// 4.4.x) to indicate functions which have been cloned during optimization.
+// We treat any sequence (.<alpha>+.<digit>+)+ as a function clone suffix.
+// Additionally, '_' is allowed along with the alphanumeric sequence.
+static bool IsFunctionCloneSuffix(const char *str) {
+  size_t i = 0;
+  while (str[i] != '\0') {
+    bool parsed = false;
+    // Consume a single [.<alpha> | _]*[.<digit>]* sequence.
+    if (str[i] == '.' && (IsAlpha(str[i + 1]) || str[i + 1] == '_')) {
+      parsed = true;
+      i += 2;
+      while (IsAlpha(str[i]) || str[i] == '_') {
+        ++i;
+      }
+    }
+    if (str[i] == '.' && IsDigit(str[i + 1])) {
+      parsed = true;
+      i += 2;
+      while (IsDigit(str[i])) {
+        ++i;
+      }
+    }
+    if (!parsed)
+      return false;
+  }
+  return true;  // Consumed everything in "str".
+}
+
+static bool EndsWith(State *state, const char chr) {
+  return state->parse_state.out_cur_idx > 0 &&
+         state->parse_state.out_cur_idx < state->out_end_idx &&
+         chr == state->out[state->parse_state.out_cur_idx - 1];
+}
+
+// Append "str" with some tweaks, iff "append" state is true.
+static void MaybeAppendWithLength(State *state, const char *const str,
+                                  const int length) {
+  if (state->parse_state.append && length > 0) {
+    // Append a space if the output buffer ends with '<' and "str"
+    // starts with '<' to avoid <<<.
+    if (str[0] == '<' && EndsWith(state, '<')) {
+      Append(state, " ", 1);
+    }
+    // Remember the last identifier name for ctors/dtors,
+    // but only if we haven't yet overflown the buffer.
+    if (state->parse_state.out_cur_idx < state->out_end_idx &&
+        (IsAlpha(str[0]) || str[0] == '_')) {
+      state->parse_state.prev_name_idx = state->parse_state.out_cur_idx;
+      state->parse_state.prev_name_length = length;
+    }
+    Append(state, str, length);
+  }
+}
+
+// Appends a positive decimal number to the output if appending is enabled.
+static bool MaybeAppendDecimal(State *state, unsigned int val) {
+  // Max {32-64}-bit unsigned int is 20 digits.
+  constexpr size_t kMaxLength = 20;
+  char buf[kMaxLength];
+
+  // We can't use itoa or sprintf as neither is specified to be
+  // async-signal-safe.
+  if (state->parse_state.append) {
+    // We can't have a one-before-the-beginning pointer, so instead start with
+    // one-past-the-end and manipulate one character before the pointer.
+    char *p = &buf[kMaxLength];
+    do {  // val=0 is the only input that should write a leading zero digit.
+      *--p = (val % 10) + '0';
+      val /= 10;
+    } while (p > buf && val != 0);
+
+    // 'p' landed on the last character we set.  How convenient.
+    Append(state, p, kMaxLength - (p - buf));
+  }
+
+  return true;
+}
+
+// A convenient wrapper around MaybeAppendWithLength().
+// Returns true so that it can be placed in "if" conditions.
+static bool MaybeAppend(State *state, const char *const str) {
+  if (state->parse_state.append) {
+    int length = StrLen(str);
+    MaybeAppendWithLength(state, str, length);
+  }
+  return true;
+}
+
+// This function is used for handling nested names.
+static bool EnterNestedName(State *state) {
+  state->parse_state.nest_level = 0;
+  return true;
+}
+
+// This function is used for handling nested names.
+static bool LeaveNestedName(State *state, int16_t prev_value) {
+  state->parse_state.nest_level = prev_value;
+  return true;
+}
+
+// Disable the append mode not to print function parameters, etc.
+static bool DisableAppend(State *state) {
+  state->parse_state.append = false;
+  return true;
+}
+
+// Restore the append mode to the previous state.
+static bool RestoreAppend(State *state, bool prev_value) {
+  state->parse_state.append = prev_value;
+  return true;
+}
+
+// Increase the nest level for nested names.
+static void MaybeIncreaseNestLevel(State *state) {
+  if (state->parse_state.nest_level > -1) {
+    ++state->parse_state.nest_level;
+  }
+}
+
+// Appends :: for nested names if necessary.
+static void MaybeAppendSeparator(State *state) {
+  if (state->parse_state.nest_level >= 1) {
+    MaybeAppend(state, "::");
+  }
+}
+
+// Cancel the last separator if necessary.
+static void MaybeCancelLastSeparator(State *state) {
+  if (state->parse_state.nest_level >= 1 && state->parse_state.append &&
+      state->parse_state.out_cur_idx >= 2) {
+    state->parse_state.out_cur_idx -= 2;
+    state->out[state->parse_state.out_cur_idx] = '\0';
+  }
+}
+
+// Returns true if the identifier of the given length pointed to by
+// "mangled_cur" is anonymous namespace.
+static bool IdentifierIsAnonymousNamespace(State *state, int length) {
+  // Returns true if "anon_prefix" is a proper prefix of "mangled_cur".
+  static const char anon_prefix[] = "_GLOBAL__N_";
+  return (length > static_cast<int>(sizeof(anon_prefix) - 1) &&
+          StrPrefix(RemainingInput(state), anon_prefix));
+}
+
+// Forward declarations of our parsing functions.
+static bool ParseMangledName(State *state);
+static bool ParseEncoding(State *state);
+static bool ParseName(State *state);
+static bool ParseUnscopedName(State *state);
+static bool ParseNestedName(State *state);
+static bool ParsePrefix(State *state);
+static bool ParseUnqualifiedName(State *state);
+static bool ParseSourceName(State *state);
+static bool ParseLocalSourceName(State *state);
+static bool ParseUnnamedTypeName(State *state);
+static bool ParseNumber(State *state, int *number_out);
+static bool ParseFloatNumber(State *state);
+static bool ParseSeqId(State *state);
+static bool ParseIdentifier(State *state, int length);
+static bool ParseOperatorName(State *state, int *arity);
+static bool ParseSpecialName(State *state);
+static bool ParseCallOffset(State *state);
+static bool ParseNVOffset(State *state);
+static bool ParseVOffset(State *state);
+static bool ParseCtorDtorName(State *state);
+static bool ParseDecltype(State *state);
+static bool ParseType(State *state);
+static bool ParseCVQualifiers(State *state);
+static bool ParseBuiltinType(State *state);
+static bool ParseFunctionType(State *state);
+static bool ParseBareFunctionType(State *state);
+static bool ParseClassEnumType(State *state);
+static bool ParseArrayType(State *state);
+static bool ParsePointerToMemberType(State *state);
+static bool ParseTemplateParam(State *state);
+static bool ParseTemplateTemplateParam(State *state);
+static bool ParseTemplateArgs(State *state);
+static bool ParseTemplateArg(State *state);
+static bool ParseBaseUnresolvedName(State *state);
+static bool ParseUnresolvedName(State *state);
+static bool ParseExpression(State *state);
+static bool ParseExprPrimary(State *state);
+static bool ParseExprCastValue(State *state);
+static bool ParseLocalName(State *state);
+static bool ParseLocalNameSuffix(State *state);
+static bool ParseDiscriminator(State *state);
+static bool ParseSubstitution(State *state, bool accept_std);
+
+// Implementation note: the following code is a straightforward
+// translation of the Itanium C++ ABI defined in BNF with a couple of
+// exceptions.
+//
+// - Support GNU extensions not defined in the Itanium C++ ABI
+// - <prefix> and <template-prefix> are combined to avoid infinite loop
+// - Reorder patterns to shorten the code
+// - Reorder patterns to give greedier functions precedence
+//   We'll mark "Less greedy than" for these cases in the code
+//
+// Each parsing function changes the parse state and returns true on
+// success, or returns false and doesn't change the parse state (note:
+// the parse-steps counter increases regardless of success or failure).
+// To ensure that the parse state isn't changed in the latter case, we
+// save the original state before we call multiple parsing functions
+// consecutively with &&, and restore it if unsuccessful.  See
+// ParseEncoding() as an example of this convention.  We follow the
+// convention throughout the code.
+//
+// Originally we tried to do demangling without following the full ABI
+// syntax but it turned out we needed to follow the full syntax to
+// parse complicated cases like nested template arguments.  Note that
+// implementing a full-fledged demangler isn't trivial (libiberty's
+// cp-demangle.c has +4300 lines).
+//
+// Note that (foo) in <(foo) ...> is a modifier to be ignored.
+//
+// Reference:
+// - Itanium C++ ABI
+//   <https://mentorembedded.github.io/cxx-abi/abi.html#mangling>
+
+// <mangled-name> ::= _Z <encoding>
+static bool ParseMangledName(State *state) {
+  ComplexityGuard guard(state);
+  if (guard.IsTooComplex()) return false;
+  return ParseTwoCharToken(state, "_Z") && ParseEncoding(state);
+}
+
+// <encoding> ::= <(function) name> <bare-function-type>
+//            ::= <(data) name>
+//            ::= <special-name>
+static bool ParseEncoding(State *state) {
+  ComplexityGuard guard(state);
+  if (guard.IsTooComplex()) return false;
+  // Implementing the first two productions together as <name>
+  // [<bare-function-type>] avoids exponential blowup of backtracking.
+  //
+  // Since Optional(...) can't fail, there's no need to copy the state for
+  // backtracking.
+  if (ParseName(state) && Optional(ParseBareFunctionType(state))) {
+    return true;
+  }
+
+  if (ParseSpecialName(state)) {
+    return true;
+  }
+  return false;
+}
+
+// <name> ::= <nested-name>
+//        ::= <unscoped-template-name> <template-args>
+//        ::= <unscoped-name>
+//        ::= <local-name>
+static bool ParseName(State *state) {
+  ComplexityGuard guard(state);
+  if (guard.IsTooComplex()) return false;
+  if (ParseNestedName(state) || ParseLocalName(state)) {
+    return true;
+  }
+
+  // We reorganize the productions to avoid re-parsing unscoped names.
+  // - Inline <unscoped-template-name> productions:
+  //   <name> ::= <substitution> <template-args>
+  //          ::= <unscoped-name> <template-args>
+  //          ::= <unscoped-name>
+  // - Merge the two productions that start with unscoped-name:
+  //   <name> ::= <unscoped-name> [<template-args>]
+
+  ParseState copy = state->parse_state;
+  // "std<...>" isn't a valid name.
+  if (ParseSubstitution(state, /*accept_std=*/false) &&
+      ParseTemplateArgs(state)) {
+    return true;
+  }
+  state->parse_state = copy;
+
+  // Note there's no need to restore state after this since only the first
+  // subparser can fail.
+  return ParseUnscopedName(state) && Optional(ParseTemplateArgs(state));
+}
+
+// <unscoped-name> ::= <unqualified-name>
+//                 ::= St <unqualified-name>
+static bool ParseUnscopedName(State *state) {
+  ComplexityGuard guard(state);
+  if (guard.IsTooComplex()) return false;
+  if (ParseUnqualifiedName(state)) {
+    return true;
+  }
+
+  ParseState copy = state->parse_state;
+  if (ParseTwoCharToken(state, "St") && MaybeAppend(state, "std::") &&
+      ParseUnqualifiedName(state)) {
+    return true;
+  }
+  state->parse_state = copy;
+  return false;
+}
+
+// <ref-qualifer> ::= R // lvalue method reference qualifier
+//                ::= O // rvalue method reference qualifier
+static inline bool ParseRefQualifier(State *state) {
+  return ParseCharClass(state, "OR");
+}
+
+// <nested-name> ::= N [<CV-qualifiers>] [<ref-qualifier>] <prefix>
+//                   <unqualified-name> E
+//               ::= N [<CV-qualifiers>] [<ref-qualifier>] <template-prefix>
+//                   <template-args> E
+static bool ParseNestedName(State *state) {
+  ComplexityGuard guard(state);
+  if (guard.IsTooComplex()) return false;
+  ParseState copy = state->parse_state;
+  if (ParseOneCharToken(state, 'N') && EnterNestedName(state) &&
+      Optional(ParseCVQualifiers(state)) &&
+      Optional(ParseRefQualifier(state)) && ParsePrefix(state) &&
+      LeaveNestedName(state, copy.nest_level) &&
+      ParseOneCharToken(state, 'E')) {
+    return true;
+  }
+  state->parse_state = copy;
+  return false;
+}
+
+// This part is tricky.  If we literally translate them to code, we'll
+// end up infinite loop.  Hence we merge them to avoid the case.
+//
+// <prefix> ::= <prefix> <unqualified-name>
+//          ::= <template-prefix> <template-args>
+//          ::= <template-param>
+//          ::= <substitution>
+//          ::= # empty
+// <template-prefix> ::= <prefix> <(template) unqualified-name>
+//                   ::= <template-param>
+//                   ::= <substitution>
+static bool ParsePrefix(State *state) {
+  ComplexityGuard guard(state);
+  if (guard.IsTooComplex()) return false;
+  bool has_something = false;
+  while (true) {
+    MaybeAppendSeparator(state);
+    if (ParseTemplateParam(state) ||
+        ParseSubstitution(state, /*accept_std=*/true) ||
+        ParseUnscopedName(state) ||
+        (ParseOneCharToken(state, 'M') && ParseUnnamedTypeName(state))) {
+      has_something = true;
+      MaybeIncreaseNestLevel(state);
+      continue;
+    }
+    MaybeCancelLastSeparator(state);
+    if (has_something && ParseTemplateArgs(state)) {
+      return ParsePrefix(state);
+    } else {
+      break;
+    }
+  }
+  return true;
+}
+
+// <unqualified-name> ::= <operator-name>
+//                    ::= <ctor-dtor-name>
+//                    ::= <source-name>
+//                    ::= <local-source-name> // GCC extension; see below.
+//                    ::= <unnamed-type-name>
+static bool ParseUnqualifiedName(State *state) {
+  ComplexityGuard guard(state);
+  if (guard.IsTooComplex()) return false;
+  return (ParseOperatorName(state, nullptr) || ParseCtorDtorName(state) ||
+          ParseSourceName(state) || ParseLocalSourceName(state) ||
+          ParseUnnamedTypeName(state));
+}
+
+// <source-name> ::= <positive length number> <identifier>
+static bool ParseSourceName(State *state) {
+  ComplexityGuard guard(state);
+  if (guard.IsTooComplex()) return false;
+  ParseState copy = state->parse_state;
+  int length = -1;
+  if (ParseNumber(state, &length) && ParseIdentifier(state, length)) {
+    return true;
+  }
+  state->parse_state = copy;
+  return false;
+}
+
+// <local-source-name> ::= L <source-name> [<discriminator>]
+//
+// References:
+//   https://gcc.gnu.org/bugzilla/show_bug.cgi?id=31775
+//   https://gcc.gnu.org/viewcvs?view=rev&revision=124467
+static bool ParseLocalSourceName(State *state) {
+  ComplexityGuard guard(state);
+  if (guard.IsTooComplex()) return false;
+  ParseState copy = state->parse_state;
+  if (ParseOneCharToken(state, 'L') && ParseSourceName(state) &&
+      Optional(ParseDiscriminator(state))) {
+    return true;
+  }
+  state->parse_state = copy;
+  return false;
+}
+
+// <unnamed-type-name> ::= Ut [<(nonnegative) number>] _
+//                     ::= <closure-type-name>
+// <closure-type-name> ::= Ul <lambda-sig> E [<(nonnegative) number>] _
+// <lambda-sig>        ::= <(parameter) type>+
+static bool ParseUnnamedTypeName(State *state) {
+  ComplexityGuard guard(state);
+  if (guard.IsTooComplex()) return false;
+  ParseState copy = state->parse_state;
+  // Type's 1-based index n is encoded as { "", n == 1; itoa(n-2), otherwise }.
+  // Optionally parse the encoded value into 'which' and add 2 to get the index.
+  int which = -1;
+
+  // Unnamed type local to function or class.
+  if (ParseTwoCharToken(state, "Ut") && Optional(ParseNumber(state, &which)) &&
+      which <= std::numeric_limits<int>::max() - 2 &&  // Don't overflow.
+      ParseOneCharToken(state, '_')) {
+    MaybeAppend(state, "{unnamed type#");
+    MaybeAppendDecimal(state, 2 + which);
+    MaybeAppend(state, "}");
+    return true;
+  }
+  state->parse_state = copy;
+
+  // Closure type.
+  which = -1;
+  if (ParseTwoCharToken(state, "Ul") && DisableAppend(state) &&
+      OneOrMore(ParseType, state) && RestoreAppend(state, copy.append) &&
+      ParseOneCharToken(state, 'E') && Optional(ParseNumber(state, &which)) &&
+      which <= std::numeric_limits<int>::max() - 2 &&  // Don't overflow.
+      ParseOneCharToken(state, '_')) {
+    MaybeAppend(state, "{lambda()#");
+    MaybeAppendDecimal(state, 2 + which);
+    MaybeAppend(state, "}");
+    return true;
+  }
+  state->parse_state = copy;
+
+  return false;
+}
+
+// <number> ::= [n] <non-negative decimal integer>
+// If "number_out" is non-null, then *number_out is set to the value of the
+// parsed number on success.
+static bool ParseNumber(State *state, int *number_out) {
+  ComplexityGuard guard(state);
+  if (guard.IsTooComplex()) return false;
+  bool negative = false;
+  if (ParseOneCharToken(state, 'n')) {
+    negative = true;
+  }
+  const char *p = RemainingInput(state);
+  uint64_t number = 0;
+  for (; *p != '\0'; ++p) {
+    if (IsDigit(*p)) {
+      number = number * 10 + (*p - '0');
+    } else {
+      break;
+    }
+  }
+  // Apply the sign with uint64_t arithmetic so overflows aren't UB.  Gives
+  // "incorrect" results for out-of-range inputs, but negative values only
+  // appear for literals, which aren't printed.
+  if (negative) {
+    number = ~number + 1;
+  }
+  if (p != RemainingInput(state)) {  // Conversion succeeded.
+    state->parse_state.mangled_idx += p - RemainingInput(state);
+    if (number_out != nullptr) {
+      // Note: possibly truncate "number".
+      *number_out = number;
+    }
+    return true;
+  }
+  return false;
+}
+
+// Floating-point literals are encoded using a fixed-length lowercase
+// hexadecimal string.
+static bool ParseFloatNumber(State *state) {
+  ComplexityGuard guard(state);
+  if (guard.IsTooComplex()) return false;
+  const char *p = RemainingInput(state);
+  for (; *p != '\0'; ++p) {
+    if (!IsDigit(*p) && !(*p >= 'a' && *p <= 'f')) {
+      break;
+    }
+  }
+  if (p != RemainingInput(state)) {  // Conversion succeeded.
+    state->parse_state.mangled_idx += p - RemainingInput(state);
+    return true;
+  }
+  return false;
+}
+
+// The <seq-id> is a sequence number in base 36,
+// using digits and upper case letters
+static bool ParseSeqId(State *state) {
+  ComplexityGuard guard(state);
+  if (guard.IsTooComplex()) return false;
+  const char *p = RemainingInput(state);
+  for (; *p != '\0'; ++p) {
+    if (!IsDigit(*p) && !(*p >= 'A' && *p <= 'Z')) {
+      break;
+    }
+  }
+  if (p != RemainingInput(state)) {  // Conversion succeeded.
+    state->parse_state.mangled_idx += p - RemainingInput(state);
+    return true;
+  }
+  return false;
+}
+
+// <identifier> ::= <unqualified source code identifier> (of given length)
+static bool ParseIdentifier(State *state, int length) {
+  ComplexityGuard guard(state);
+  if (guard.IsTooComplex()) return false;
+  if (length < 0 || !AtLeastNumCharsRemaining(RemainingInput(state), length)) {
+    return false;
+  }
+  if (IdentifierIsAnonymousNamespace(state, length)) {
+    MaybeAppend(state, "(anonymous namespace)");
+  } else {
+    MaybeAppendWithLength(state, RemainingInput(state), length);
+  }
+  state->parse_state.mangled_idx += length;
+  return true;
+}
+
+// <operator-name> ::= nw, and other two letters cases
+//                 ::= cv <type>  # (cast)
+//                 ::= v  <digit> <source-name> # vendor extended operator
+static bool ParseOperatorName(State *state, int *arity) {
+  ComplexityGuard guard(state);
+  if (guard.IsTooComplex()) return false;
+  if (!AtLeastNumCharsRemaining(RemainingInput(state), 2)) {
+    return false;
+  }
+  // First check with "cv" (cast) case.
+  ParseState copy = state->parse_state;
+  if (ParseTwoCharToken(state, "cv") && MaybeAppend(state, "operator ") &&
+      EnterNestedName(state) && ParseType(state) &&
+      LeaveNestedName(state, copy.nest_level)) {
+    if (arity != nullptr) {
+      *arity = 1;
+    }
+    return true;
+  }
+  state->parse_state = copy;
+
+  // Then vendor extended operators.
+  if (ParseOneCharToken(state, 'v') && ParseDigit(state, arity) &&
+      ParseSourceName(state)) {
+    return true;
+  }
+  state->parse_state = copy;
+
+  // Other operator names should start with a lower alphabet followed
+  // by a lower/upper alphabet.
+  if (!(IsLower(RemainingInput(state)[0]) &&
+        IsAlpha(RemainingInput(state)[1]))) {
+    return false;
+  }
+  // We may want to perform a binary search if we really need speed.
+  const AbbrevPair *p;
+  for (p = kOperatorList; p->abbrev != nullptr; ++p) {
+    if (RemainingInput(state)[0] == p->abbrev[0] &&
+        RemainingInput(state)[1] == p->abbrev[1]) {
+      if (arity != nullptr) {
+        *arity = p->arity;
+      }
+      MaybeAppend(state, "operator");
+      if (IsLower(*p->real_name)) {  // new, delete, etc.
+        MaybeAppend(state, " ");
+      }
+      MaybeAppend(state, p->real_name);
+      state->parse_state.mangled_idx += 2;
+      return true;
+    }
+  }
+  return false;
+}
+
+// <special-name> ::= TV <type>
+//                ::= TT <type>
+//                ::= TI <type>
+//                ::= TS <type>
+//                ::= TH <type>  # thread-local
+//                ::= Tc <call-offset> <call-offset> <(base) encoding>
+//                ::= GV <(object) name>
+//                ::= T <call-offset> <(base) encoding>
+// G++ extensions:
+//                ::= TC <type> <(offset) number> _ <(base) type>
+//                ::= TF <type>
+//                ::= TJ <type>
+//                ::= GR <name>
+//                ::= GA <encoding>
+//                ::= Th <call-offset> <(base) encoding>
+//                ::= Tv <call-offset> <(base) encoding>
+//
+// Note: we don't care much about them since they don't appear in
+// stack traces.  The are special data.
+static bool ParseSpecialName(State *state) {
+  ComplexityGuard guard(state);
+  if (guard.IsTooComplex()) return false;
+  ParseState copy = state->parse_state;
+  if (ParseOneCharToken(state, 'T') && ParseCharClass(state, "VTISH") &&
+      ParseType(state)) {
+    return true;
+  }
+  state->parse_state = copy;
+
+  if (ParseTwoCharToken(state, "Tc") && ParseCallOffset(state) &&
+      ParseCallOffset(state) && ParseEncoding(state)) {
+    return true;
+  }
+  state->parse_state = copy;
+
+  if (ParseTwoCharToken(state, "GV") && ParseName(state)) {
+    return true;
+  }
+  state->parse_state = copy;
+
+  if (ParseOneCharToken(state, 'T') && ParseCallOffset(state) &&
+      ParseEncoding(state)) {
+    return true;
+  }
+  state->parse_state = copy;
+
+  // G++ extensions
+  if (ParseTwoCharToken(state, "TC") && ParseType(state) &&
+      ParseNumber(state, nullptr) && ParseOneCharToken(state, '_') &&
+      DisableAppend(state) && ParseType(state)) {
+    RestoreAppend(state, copy.append);
+    return true;
+  }
+  state->parse_state = copy;
+
+  if (ParseOneCharToken(state, 'T') && ParseCharClass(state, "FJ") &&
+      ParseType(state)) {
+    return true;
+  }
+  state->parse_state = copy;
+
+  if (ParseTwoCharToken(state, "GR") && ParseName(state)) {
+    return true;
+  }
+  state->parse_state = copy;
+
+  if (ParseTwoCharToken(state, "GA") && ParseEncoding(state)) {
+    return true;
+  }
+  state->parse_state = copy;
+
+  if (ParseOneCharToken(state, 'T') && ParseCharClass(state, "hv") &&
+      ParseCallOffset(state) && ParseEncoding(state)) {
+    return true;
+  }
+  state->parse_state = copy;
+  return false;
+}
+
+// <call-offset> ::= h <nv-offset> _
+//               ::= v <v-offset> _
+static bool ParseCallOffset(State *state) {
+  ComplexityGuard guard(state);
+  if (guard.IsTooComplex()) return false;
+  ParseState copy = state->parse_state;
+  if (ParseOneCharToken(state, 'h') && ParseNVOffset(state) &&
+      ParseOneCharToken(state, '_')) {
+    return true;
+  }
+  state->parse_state = copy;
+
+  if (ParseOneCharToken(state, 'v') && ParseVOffset(state) &&
+      ParseOneCharToken(state, '_')) {
+    return true;
+  }
+  state->parse_state = copy;
+
+  return false;
+}
+
+// <nv-offset> ::= <(offset) number>
+static bool ParseNVOffset(State *state) {
+  ComplexityGuard guard(state);
+  if (guard.IsTooComplex()) return false;
+  return ParseNumber(state, nullptr);
+}
+
+// <v-offset>  ::= <(offset) number> _ <(virtual offset) number>
+static bool ParseVOffset(State *state) {
+  ComplexityGuard guard(state);
+  if (guard.IsTooComplex()) return false;
+  ParseState copy = state->parse_state;
+  if (ParseNumber(state, nullptr) && ParseOneCharToken(state, '_') &&
+      ParseNumber(state, nullptr)) {
+    return true;
+  }
+  state->parse_state = copy;
+  return false;
+}
+
+// <ctor-dtor-name> ::= C1 | C2 | C3 | CI1 <base-class-type> | CI2
+// <base-class-type>
+//                  ::= D0 | D1 | D2
+// # GCC extensions: "unified" constructor/destructor.  See
+// #
+// https://github.com/gcc-mirror/gcc/blob/7ad17b583c3643bd4557f29b8391ca7ef08391f5/gcc/cp/mangle.c#L1847
+//                  ::= C4 | D4
+static bool ParseCtorDtorName(State *state) {
+  ComplexityGuard guard(state);
+  if (guard.IsTooComplex()) return false;
+  ParseState copy = state->parse_state;
+  if (ParseOneCharToken(state, 'C')) {
+    if (ParseCharClass(state, "1234")) {
+      const char *const prev_name =
+          state->out + state->parse_state.prev_name_idx;
+      MaybeAppendWithLength(state, prev_name,
+                            state->parse_state.prev_name_length);
+      return true;
+    } else if (ParseOneCharToken(state, 'I') && ParseCharClass(state, "12") &&
+               ParseClassEnumType(state)) {
+      return true;
+    }
+  }
+  state->parse_state = copy;
+
+  if (ParseOneCharToken(state, 'D') && ParseCharClass(state, "0124")) {
+    const char *const prev_name = state->out + state->parse_state.prev_name_idx;
+    MaybeAppend(state, "~");
+    MaybeAppendWithLength(state, prev_name,
+                          state->parse_state.prev_name_length);
+    return true;
+  }
+  state->parse_state = copy;
+  return false;
+}
+
+// <decltype> ::= Dt <expression> E  # decltype of an id-expression or class
+//                                   # member access (C++0x)
+//            ::= DT <expression> E  # decltype of an expression (C++0x)
+static bool ParseDecltype(State *state) {
+  ComplexityGuard guard(state);
+  if (guard.IsTooComplex()) return false;
+
+  ParseState copy = state->parse_state;
+  if (ParseOneCharToken(state, 'D') && ParseCharClass(state, "tT") &&
+      ParseExpression(state) && ParseOneCharToken(state, 'E')) {
+    return true;
+  }
+  state->parse_state = copy;
+
+  return false;
+}
+
+// <type> ::= <CV-qualifiers> <type>
+//        ::= P <type>   # pointer-to
+//        ::= R <type>   # reference-to
+//        ::= O <type>   # rvalue reference-to (C++0x)
+//        ::= C <type>   # complex pair (C 2000)
+//        ::= G <type>   # imaginary (C 2000)
+//        ::= U <source-name> <type>  # vendor extended type qualifier
+//        ::= <builtin-type>
+//        ::= <function-type>
+//        ::= <class-enum-type>  # note: just an alias for <name>
+//        ::= <array-type>
+//        ::= <pointer-to-member-type>
+//        ::= <template-template-param> <template-args>
+//        ::= <template-param>
+//        ::= <decltype>
+//        ::= <substitution>
+//        ::= Dp <type>          # pack expansion of (C++0x)
+//        ::= Dv <num-elems> _   # GNU vector extension
+//
+static bool ParseType(State *state) {
+  ComplexityGuard guard(state);
+  if (guard.IsTooComplex()) return false;
+  ParseState copy = state->parse_state;
+
+  // We should check CV-qualifers, and PRGC things first.
+  //
+  // CV-qualifiers overlap with some operator names, but an operator name is not
+  // valid as a type.  To avoid an ambiguity that can lead to exponential time
+  // complexity, refuse to backtrack the CV-qualifiers.
+  //
+  // _Z4aoeuIrMvvE
+  //  => _Z 4aoeuI        rM  v     v   E
+  //         aoeu<operator%=, void, void>
+  //  => _Z 4aoeuI r Mv v              E
+  //         aoeu<void void::* restrict>
+  //
+  // By consuming the CV-qualifiers first, the former parse is disabled.
+  if (ParseCVQualifiers(state)) {
+    const bool result = ParseType(state);
+    if (!result) state->parse_state = copy;
+    return result;
+  }
+  state->parse_state = copy;
+
+  // Similarly, these tag characters can overlap with other <name>s resulting in
+  // two different parse prefixes that land on <template-args> in the same
+  // place, such as "C3r1xI...".  So, disable the "ctor-name = C3" parse by
+  // refusing to backtrack the tag characters.
+  if (ParseCharClass(state, "OPRCG")) {
+    const bool result = ParseType(state);
+    if (!result) state->parse_state = copy;
+    return result;
+  }
+  state->parse_state = copy;
+
+  if (ParseTwoCharToken(state, "Dp") && ParseType(state)) {
+    return true;
+  }
+  state->parse_state = copy;
+
+  if (ParseOneCharToken(state, 'U') && ParseSourceName(state) &&
+      ParseType(state)) {
+    return true;
+  }
+  state->parse_state = copy;
+
+  if (ParseBuiltinType(state) || ParseFunctionType(state) ||
+      ParseClassEnumType(state) || ParseArrayType(state) ||
+      ParsePointerToMemberType(state) || ParseDecltype(state) ||
+      // "std" on its own isn't a type.
+      ParseSubstitution(state, /*accept_std=*/false)) {
+    return true;
+  }
+
+  if (ParseTemplateTemplateParam(state) && ParseTemplateArgs(state)) {
+    return true;
+  }
+  state->parse_state = copy;
+
+  // Less greedy than <template-template-param> <template-args>.
+  if (ParseTemplateParam(state)) {
+    return true;
+  }
+
+  if (ParseTwoCharToken(state, "Dv") && ParseNumber(state, nullptr) &&
+      ParseOneCharToken(state, '_')) {
+    return true;
+  }
+  state->parse_state = copy;
+
+  return false;
+}
+
+// <CV-qualifiers> ::= [r] [V] [K]
+// We don't allow empty <CV-qualifiers> to avoid infinite loop in
+// ParseType().
+static bool ParseCVQualifiers(State *state) {
+  ComplexityGuard guard(state);
+  if (guard.IsTooComplex()) return false;
+  int num_cv_qualifiers = 0;
+  num_cv_qualifiers += ParseOneCharToken(state, 'r');
+  num_cv_qualifiers += ParseOneCharToken(state, 'V');
+  num_cv_qualifiers += ParseOneCharToken(state, 'K');
+  return num_cv_qualifiers > 0;
+}
+
+// <builtin-type> ::= v, etc.  # single-character builtin types
+//                ::= u <source-name>
+//                ::= Dd, etc.  # two-character builtin types
+//
+// Not supported:
+//                ::= DF <number> _ # _FloatN (N bits)
+//
+static bool ParseBuiltinType(State *state) {
+  ComplexityGuard guard(state);
+  if (guard.IsTooComplex()) return false;
+  const AbbrevPair *p;
+  for (p = kBuiltinTypeList; p->abbrev != nullptr; ++p) {
+    // Guaranteed only 1- or 2-character strings in kBuiltinTypeList.
+    if (p->abbrev[1] == '\0') {
+      if (ParseOneCharToken(state, p->abbrev[0])) {
+        MaybeAppend(state, p->real_name);
+        return true;
+      }
+    } else if (p->abbrev[2] == '\0' && ParseTwoCharToken(state, p->abbrev)) {
+      MaybeAppend(state, p->real_name);
+      return true;
+    }
+  }
+
+  ParseState copy = state->parse_state;
+  if (ParseOneCharToken(state, 'u') && ParseSourceName(state)) {
+    return true;
+  }
+  state->parse_state = copy;
+  return false;
+}
+
+//  <exception-spec> ::= Do                # non-throwing
+//                                           exception-specification (e.g.,
+//                                           noexcept, throw())
+//                   ::= DO <expression> E # computed (instantiation-dependent)
+//                                           noexcept
+//                   ::= Dw <type>+ E      # dynamic exception specification
+//                                           with instantiation-dependent types
+static bool ParseExceptionSpec(State *state) {
+  ComplexityGuard guard(state);
+  if (guard.IsTooComplex()) return false;
+
+  if (ParseTwoCharToken(state, "Do")) return true;
+
+  ParseState copy = state->parse_state;
+  if (ParseTwoCharToken(state, "DO") && ParseExpression(state) &&
+      ParseOneCharToken(state, 'E')) {
+    return true;
+  }
+  state->parse_state = copy;
+  if (ParseTwoCharToken(state, "Dw") && OneOrMore(ParseType, state) &&
+      ParseOneCharToken(state, 'E')) {
+    return true;
+  }
+  state->parse_state = copy;
+
+  return false;
+}
+
+// <function-type> ::= [exception-spec] F [Y] <bare-function-type> [O] E
+static bool ParseFunctionType(State *state) {
+  ComplexityGuard guard(state);
+  if (guard.IsTooComplex()) return false;
+  ParseState copy = state->parse_state;
+  if (Optional(ParseExceptionSpec(state)) && ParseOneCharToken(state, 'F') &&
+      Optional(ParseOneCharToken(state, 'Y')) && ParseBareFunctionType(state) &&
+      Optional(ParseOneCharToken(state, 'O')) &&
+      ParseOneCharToken(state, 'E')) {
+    return true;
+  }
+  state->parse_state = copy;
+  return false;
+}
+
+// <bare-function-type> ::= <(signature) type>+
+static bool ParseBareFunctionType(State *state) {
+  ComplexityGuard guard(state);
+  if (guard.IsTooComplex()) return false;
+  ParseState copy = state->parse_state;
+  DisableAppend(state);
+  if (OneOrMore(ParseType, state)) {
+    RestoreAppend(state, copy.append);
+    MaybeAppend(state, "()");
+    return true;
+  }
+  state->parse_state = copy;
+  return false;
+}
+
+// <class-enum-type> ::= <name>
+static bool ParseClassEnumType(State *state) {
+  ComplexityGuard guard(state);
+  if (guard.IsTooComplex()) return false;
+  return ParseName(state);
+}
+
+// <array-type> ::= A <(positive dimension) number> _ <(element) type>
+//              ::= A [<(dimension) expression>] _ <(element) type>
+static bool ParseArrayType(State *state) {
+  ComplexityGuard guard(state);
+  if (guard.IsTooComplex()) return false;
+  ParseState copy = state->parse_state;
+  if (ParseOneCharToken(state, 'A') && ParseNumber(state, nullptr) &&
+      ParseOneCharToken(state, '_') && ParseType(state)) {
+    return true;
+  }
+  state->parse_state = copy;
+
+  if (ParseOneCharToken(state, 'A') && Optional(ParseExpression(state)) &&
+      ParseOneCharToken(state, '_') && ParseType(state)) {
+    return true;
+  }
+  state->parse_state = copy;
+  return false;
+}
+
+// <pointer-to-member-type> ::= M <(class) type> <(member) type>
+static bool ParsePointerToMemberType(State *state) {
+  ComplexityGuard guard(state);
+  if (guard.IsTooComplex()) return false;
+  ParseState copy = state->parse_state;
+  if (ParseOneCharToken(state, 'M') && ParseType(state) && ParseType(state)) {
+    return true;
+  }
+  state->parse_state = copy;
+  return false;
+}
+
+// <template-param> ::= T_
+//                  ::= T <parameter-2 non-negative number> _
+static bool ParseTemplateParam(State *state) {
+  ComplexityGuard guard(state);
+  if (guard.IsTooComplex()) return false;
+  if (ParseTwoCharToken(state, "T_")) {
+    MaybeAppend(state, "?");  // We don't support template substitutions.
+    return true;
+  }
+
+  ParseState copy = state->parse_state;
+  if (ParseOneCharToken(state, 'T') && ParseNumber(state, nullptr) &&
+      ParseOneCharToken(state, '_')) {
+    MaybeAppend(state, "?");  // We don't support template substitutions.
+    return true;
+  }
+  state->parse_state = copy;
+  return false;
+}
+
+// <template-template-param> ::= <template-param>
+//                           ::= <substitution>
+static bool ParseTemplateTemplateParam(State *state) {
+  ComplexityGuard guard(state);
+  if (guard.IsTooComplex()) return false;
+  return (ParseTemplateParam(state) ||
+          // "std" on its own isn't a template.
+          ParseSubstitution(state, /*accept_std=*/false));
+}
+
+// <template-args> ::= I <template-arg>+ E
+static bool ParseTemplateArgs(State *state) {
+  ComplexityGuard guard(state);
+  if (guard.IsTooComplex()) return false;
+  ParseState copy = state->parse_state;
+  DisableAppend(state);
+  if (ParseOneCharToken(state, 'I') && OneOrMore(ParseTemplateArg, state) &&
+      ParseOneCharToken(state, 'E')) {
+    RestoreAppend(state, copy.append);
+    MaybeAppend(state, "<>");
+    return true;
+  }
+  state->parse_state = copy;
+  return false;
+}
+
+// <template-arg>  ::= <type>
+//                 ::= <expr-primary>
+//                 ::= J <template-arg>* E        # argument pack
+//                 ::= X <expression> E
+static bool ParseTemplateArg(State *state) {
+  ComplexityGuard guard(state);
+  if (guard.IsTooComplex()) return false;
+  ParseState copy = state->parse_state;
+  if (ParseOneCharToken(state, 'J') && ZeroOrMore(ParseTemplateArg, state) &&
+      ParseOneCharToken(state, 'E')) {
+    return true;
+  }
+  state->parse_state = copy;
+
+  // There can be significant overlap between the following leading to
+  // exponential backtracking:
+  //
+  //   <expr-primary> ::= L <type> <expr-cast-value> E
+  //                 e.g. L 2xxIvE 1                 E
+  //   <type>         ==> <local-source-name> <template-args>
+  //                 e.g. L 2xx               IvE
+  //
+  // This means parsing an entire <type> twice, and <type> can contain
+  // <template-arg>, so this can generate exponential backtracking.  There is
+  // only overlap when the remaining input starts with "L <source-name>", so
+  // parse all cases that can start this way jointly to share the common prefix.
+  //
+  // We have:
+  //
+  //   <template-arg> ::= <type>
+  //                  ::= <expr-primary>
+  //
+  // First, drop all the productions of <type> that must start with something
+  // other than 'L'.  All that's left is <class-enum-type>; inline it.
+  //
+  //   <type> ::= <nested-name> # starts with 'N'
+  //          ::= <unscoped-name>
+  //          ::= <unscoped-template-name> <template-args>
+  //          ::= <local-name> # starts with 'Z'
+  //
+  // Drop and inline again:
+  //
+  //   <type> ::= <unscoped-name>
+  //          ::= <unscoped-name> <template-args>
+  //          ::= <substitution> <template-args> # starts with 'S'
+  //
+  // Merge the first two, inline <unscoped-name>, drop last:
+  //
+  //   <type> ::= <unqualified-name> [<template-args>]
+  //          ::= St <unqualified-name> [<template-args>] # starts with 'S'
+  //
+  // Drop and inline:
+  //
+  //   <type> ::= <operator-name> [<template-args>] # starts with lowercase
+  //          ::= <ctor-dtor-name> [<template-args>] # starts with 'C' or 'D'
+  //          ::= <source-name> [<template-args>] # starts with digit
+  //          ::= <local-source-name> [<template-args>]
+  //          ::= <unnamed-type-name> [<template-args>] # starts with 'U'
+  //
+  // One more time:
+  //
+  //   <type> ::= L <source-name> [<template-args>]
+  //
+  // Likewise with <expr-primary>:
+  //
+  //   <expr-primary> ::= L <type> <expr-cast-value> E
+  //                  ::= LZ <encoding> E # cannot overlap; drop
+  //                  ::= L <mangled_name> E # cannot overlap; drop
+  //
+  // By similar reasoning as shown above, the only <type>s starting with
+  // <source-name> are "<source-name> [<template-args>]".  Inline this.
+  //
+  //   <expr-primary> ::= L <source-name> [<template-args>] <expr-cast-value> E
+  //
+  // Now inline both of these into <template-arg>:
+  //
+  //   <template-arg> ::= L <source-name> [<template-args>]
+  //                  ::= L <source-name> [<template-args>] <expr-cast-value> E
+  //
+  // Merge them and we're done:
+  //   <template-arg>
+  //     ::= L <source-name> [<template-args>] [<expr-cast-value> E]
+  if (ParseLocalSourceName(state) && Optional(ParseTemplateArgs(state))) {
+    copy = state->parse_state;
+    if (ParseExprCastValue(state) && ParseOneCharToken(state, 'E')) {
+      return true;
+    }
+    state->parse_state = copy;
+    return true;
+  }
+
+  // Now that the overlapping cases can't reach this code, we can safely call
+  // both of these.
+  if (ParseType(state) || ParseExprPrimary(state)) {
+    return true;
+  }
+  state->parse_state = copy;
+
+  if (ParseOneCharToken(state, 'X') && ParseExpression(state) &&
+      ParseOneCharToken(state, 'E')) {
+    return true;
+  }
+  state->parse_state = copy;
+  return false;
+}
+
+// <unresolved-type> ::= <template-param> [<template-args>]
+//                   ::= <decltype>
+//                   ::= <substitution>
+static inline bool ParseUnresolvedType(State *state) {
+  // No ComplexityGuard because we don't copy the state in this stack frame.
+  return (ParseTemplateParam(state) && Optional(ParseTemplateArgs(state))) ||
+         ParseDecltype(state) || ParseSubstitution(state, /*accept_std=*/false);
+}
+
+// <simple-id> ::= <source-name> [<template-args>]
+static inline bool ParseSimpleId(State *state) {
+  // No ComplexityGuard because we don't copy the state in this stack frame.
+
+  // Note: <simple-id> cannot be followed by a parameter pack; see comment in
+  // ParseUnresolvedType.
+  return ParseSourceName(state) && Optional(ParseTemplateArgs(state));
+}
+
+// <base-unresolved-name> ::= <source-name> [<template-args>]
+//                        ::= on <operator-name> [<template-args>]
+//                        ::= dn <destructor-name>
+static bool ParseBaseUnresolvedName(State *state) {
+  ComplexityGuard guard(state);
+  if (guard.IsTooComplex()) return false;
+
+  if (ParseSimpleId(state)) {
+    return true;
+  }
+
+  ParseState copy = state->parse_state;
+  if (ParseTwoCharToken(state, "on") && ParseOperatorName(state, nullptr) &&
+      Optional(ParseTemplateArgs(state))) {
+    return true;
+  }
+  state->parse_state = copy;
+
+  if (ParseTwoCharToken(state, "dn") &&
+      (ParseUnresolvedType(state) || ParseSimpleId(state))) {
+    return true;
+  }
+  state->parse_state = copy;
+
+  return false;
+}
+
+// <unresolved-name> ::= [gs] <base-unresolved-name>
+//                   ::= sr <unresolved-type> <base-unresolved-name>
+//                   ::= srN <unresolved-type> <unresolved-qualifier-level>+ E
+//                         <base-unresolved-name>
+//                   ::= [gs] sr <unresolved-qualifier-level>+ E
+//                         <base-unresolved-name>
+static bool ParseUnresolvedName(State *state) {
+  ComplexityGuard guard(state);
+  if (guard.IsTooComplex()) return false;
+
+  ParseState copy = state->parse_state;
+  if (Optional(ParseTwoCharToken(state, "gs")) &&
+      ParseBaseUnresolvedName(state)) {
+    return true;
+  }
+  state->parse_state = copy;
+
+  if (ParseTwoCharToken(state, "sr") && ParseUnresolvedType(state) &&
+      ParseBaseUnresolvedName(state)) {
+    return true;
+  }
+  state->parse_state = copy;
+
+  if (ParseTwoCharToken(state, "sr") && ParseOneCharToken(state, 'N') &&
+      ParseUnresolvedType(state) &&
+      OneOrMore(/* <unresolved-qualifier-level> ::= */ ParseSimpleId, state) &&
+      ParseOneCharToken(state, 'E') && ParseBaseUnresolvedName(state)) {
+    return true;
+  }
+  state->parse_state = copy;
+
+  if (Optional(ParseTwoCharToken(state, "gs")) &&
+      ParseTwoCharToken(state, "sr") &&
+      OneOrMore(/* <unresolved-qualifier-level> ::= */ ParseSimpleId, state) &&
+      ParseOneCharToken(state, 'E') && ParseBaseUnresolvedName(state)) {
+    return true;
+  }
+  state->parse_state = copy;
+
+  return false;
+}
+
+// <expression> ::= <1-ary operator-name> <expression>
+//              ::= <2-ary operator-name> <expression> <expression>
+//              ::= <3-ary operator-name> <expression> <expression> <expression>
+//              ::= cl <expression>+ E
+//              ::= cv <type> <expression>      # type (expression)
+//              ::= cv <type> _ <expression>* E # type (expr-list)
+//              ::= st <type>
+//              ::= <template-param>
+//              ::= <function-param>
+//              ::= <expr-primary>
+//              ::= dt <expression> <unresolved-name> # expr.name
+//              ::= pt <expression> <unresolved-name> # expr->name
+//              ::= sp <expression>         # argument pack expansion
+//              ::= sr <type> <unqualified-name> <template-args>
+//              ::= sr <type> <unqualified-name>
+// <function-param> ::= fp <(top-level) CV-qualifiers> _
+//                  ::= fp <(top-level) CV-qualifiers> <number> _
+//                  ::= fL <number> p <(top-level) CV-qualifiers> _
+//                  ::= fL <number> p <(top-level) CV-qualifiers> <number> _
+static bool ParseExpression(State *state) {
+  ComplexityGuard guard(state);
+  if (guard.IsTooComplex()) return false;
+  if (ParseTemplateParam(state) || ParseExprPrimary(state)) {
+    return true;
+  }
+
+  // Object/function call expression.
+  ParseState copy = state->parse_state;
+  if (ParseTwoCharToken(state, "cl") && OneOrMore(ParseExpression, state) &&
+      ParseOneCharToken(state, 'E')) {
+    return true;
+  }
+  state->parse_state = copy;
+
+  // Function-param expression (level 0).
+  if (ParseTwoCharToken(state, "fp") && Optional(ParseCVQualifiers(state)) &&
+      Optional(ParseNumber(state, nullptr)) && ParseOneCharToken(state, '_')) {
+    return true;
+  }
+  state->parse_state = copy;
+
+  // Function-param expression (level 1+).
+  if (ParseTwoCharToken(state, "fL") && Optional(ParseNumber(state, nullptr)) &&
+      ParseOneCharToken(state, 'p') && Optional(ParseCVQualifiers(state)) &&
+      Optional(ParseNumber(state, nullptr)) && ParseOneCharToken(state, '_')) {
+    return true;
+  }
+  state->parse_state = copy;
+
+  // Parse the conversion expressions jointly to avoid re-parsing the <type> in
+  // their common prefix.  Parsed as:
+  // <expression> ::= cv <type> <conversion-args>
+  // <conversion-args> ::= _ <expression>* E
+  //                   ::= <expression>
+  //
+  // Also don't try ParseOperatorName after seeing "cv", since ParseOperatorName
+  // also needs to accept "cv <type>" in other contexts.
+  if (ParseTwoCharToken(state, "cv")) {
+    if (ParseType(state)) {
+      ParseState copy2 = state->parse_state;
+      if (ParseOneCharToken(state, '_') && ZeroOrMore(ParseExpression, state) &&
+          ParseOneCharToken(state, 'E')) {
+        return true;
+      }
+      state->parse_state = copy2;
+      if (ParseExpression(state)) {
+        return true;
+      }
+    }
+  } else {
+    // Parse unary, binary, and ternary operator expressions jointly, taking
+    // care not to re-parse subexpressions repeatedly. Parse like:
+    //   <expression> ::= <operator-name> <expression>
+    //                    [<one-to-two-expressions>]
+    //   <one-to-two-expressions> ::= <expression> [<expression>]
+    int arity = -1;
+    if (ParseOperatorName(state, &arity) &&
+        arity > 0 &&  // 0 arity => disabled.
+        (arity < 3 || ParseExpression(state)) &&
+        (arity < 2 || ParseExpression(state)) &&
+        (arity < 1 || ParseExpression(state))) {
+      return true;
+    }
+  }
+  state->parse_state = copy;
+
+  // sizeof type
+  if (ParseTwoCharToken(state, "st") && ParseType(state)) {
+    return true;
+  }
+  state->parse_state = copy;
+
+  // Object and pointer member access expressions.
+  if ((ParseTwoCharToken(state, "dt") || ParseTwoCharToken(state, "pt")) &&
+      ParseExpression(state) && ParseType(state)) {
+    return true;
+  }
+  state->parse_state = copy;
+
+  // Pointer-to-member access expressions.  This parses the same as a binary
+  // operator, but it's implemented separately because "ds" shouldn't be
+  // accepted in other contexts that parse an operator name.
+  if (ParseTwoCharToken(state, "ds") && ParseExpression(state) &&
+      ParseExpression(state)) {
+    return true;
+  }
+  state->parse_state = copy;
+
+  // Parameter pack expansion
+  if (ParseTwoCharToken(state, "sp") && ParseExpression(state)) {
+    return true;
+  }
+  state->parse_state = copy;
+
+  return ParseUnresolvedName(state);
+}
+
+// <expr-primary> ::= L <type> <(value) number> E
+//                ::= L <type> <(value) float> E
+//                ::= L <mangled-name> E
+//                // A bug in g++'s C++ ABI version 2 (-fabi-version=2).
+//                ::= LZ <encoding> E
+//
+// Warning, subtle: the "bug" LZ production above is ambiguous with the first
+// production where <type> starts with <local-name>, which can lead to
+// exponential backtracking in two scenarios:
+//
+// - When whatever follows the E in the <local-name> in the first production is
+//   not a name, we backtrack the whole <encoding> and re-parse the whole thing.
+//
+// - When whatever follows the <local-name> in the first production is not a
+//   number and this <expr-primary> may be followed by a name, we backtrack the
+//   <name> and re-parse it.
+//
+// Moreover this ambiguity isn't always resolved -- for example, the following
+// has two different parses:
+//
+//   _ZaaILZ4aoeuE1x1EvE
+//   => operator&&<aoeu, x, E, void>
+//   => operator&&<(aoeu::x)(1), void>
+//
+// To resolve this, we just do what GCC's demangler does, and refuse to parse
+// casts to <local-name> types.
+static bool ParseExprPrimary(State *state) {
+  ComplexityGuard guard(state);
+  if (guard.IsTooComplex()) return false;
+  ParseState copy = state->parse_state;
+
+  // The "LZ" special case: if we see LZ, we commit to accept "LZ <encoding> E"
+  // or fail, no backtracking.
+  if (ParseTwoCharToken(state, "LZ")) {
+    if (ParseEncoding(state) && ParseOneCharToken(state, 'E')) {
+      return true;
+    }
+
+    state->parse_state = copy;
+    return false;
+  }
+
+  // The merged cast production.
+  if (ParseOneCharToken(state, 'L') && ParseType(state) &&
+      ParseExprCastValue(state)) {
+    return true;
+  }
+  state->parse_state = copy;
+
+  if (ParseOneCharToken(state, 'L') && ParseMangledName(state) &&
+      ParseOneCharToken(state, 'E')) {
+    return true;
+  }
+  state->parse_state = copy;
+
+  return false;
+}
+
+// <number> or <float>, followed by 'E', as described above ParseExprPrimary.
+static bool ParseExprCastValue(State *state) {
+  ComplexityGuard guard(state);
+  if (guard.IsTooComplex()) return false;
+  // We have to be able to backtrack after accepting a number because we could
+  // have e.g. "7fffE", which will accept "7" as a number but then fail to find
+  // the 'E'.
+  ParseState copy = state->parse_state;
+  if (ParseNumber(state, nullptr) && ParseOneCharToken(state, 'E')) {
+    return true;
+  }
+  state->parse_state = copy;
+
+  if (ParseFloatNumber(state) && ParseOneCharToken(state, 'E')) {
+    return true;
+  }
+  state->parse_state = copy;
+
+  return false;
+}
+
+// <local-name> ::= Z <(function) encoding> E <(entity) name> [<discriminator>]
+//              ::= Z <(function) encoding> E s [<discriminator>]
+//
+// Parsing a common prefix of these two productions together avoids an
+// exponential blowup of backtracking.  Parse like:
+//   <local-name> := Z <encoding> E <local-name-suffix>
+//   <local-name-suffix> ::= s [<discriminator>]
+//                       ::= <name> [<discriminator>]
+
+static bool ParseLocalNameSuffix(State *state) {
+  ComplexityGuard guard(state);
+  if (guard.IsTooComplex()) return false;
+
+  if (MaybeAppend(state, "::") && ParseName(state) &&
+      Optional(ParseDiscriminator(state))) {
+    return true;
+  }
+
+  // Since we're not going to overwrite the above "::" by re-parsing the
+  // <encoding> (whose trailing '\0' byte was in the byte now holding the
+  // first ':'), we have to rollback the "::" if the <name> parse failed.
+  if (state->parse_state.append) {
+    state->out[state->parse_state.out_cur_idx - 2] = '\0';
+  }
+
+  return ParseOneCharToken(state, 's') && Optional(ParseDiscriminator(state));
+}
+
+static bool ParseLocalName(State *state) {
+  ComplexityGuard guard(state);
+  if (guard.IsTooComplex()) return false;
+  ParseState copy = state->parse_state;
+  if (ParseOneCharToken(state, 'Z') && ParseEncoding(state) &&
+      ParseOneCharToken(state, 'E') && ParseLocalNameSuffix(state)) {
+    return true;
+  }
+  state->parse_state = copy;
+  return false;
+}
+
+// <discriminator> := _ <(non-negative) number>
+static bool ParseDiscriminator(State *state) {
+  ComplexityGuard guard(state);
+  if (guard.IsTooComplex()) return false;
+  ParseState copy = state->parse_state;
+  if (ParseOneCharToken(state, '_') && ParseNumber(state, nullptr)) {
+    return true;
+  }
+  state->parse_state = copy;
+  return false;
+}
+
+// <substitution> ::= S_
+//                ::= S <seq-id> _
+//                ::= St, etc.
+//
+// "St" is special in that it's not valid as a standalone name, and it *is*
+// allowed to precede a name without being wrapped in "N...E".  This means that
+// if we accept it on its own, we can accept "St1a" and try to parse
+// template-args, then fail and backtrack, accept "St" on its own, then "1a" as
+// an unqualified name and re-parse the same template-args.  To block this
+// exponential backtracking, we disable it with 'accept_std=false' in
+// problematic contexts.
+static bool ParseSubstitution(State *state, bool accept_std) {
+  ComplexityGuard guard(state);
+  if (guard.IsTooComplex()) return false;
+  if (ParseTwoCharToken(state, "S_")) {
+    MaybeAppend(state, "?");  // We don't support substitutions.
+    return true;
+  }
+
+  ParseState copy = state->parse_state;
+  if (ParseOneCharToken(state, 'S') && ParseSeqId(state) &&
+      ParseOneCharToken(state, '_')) {
+    MaybeAppend(state, "?");  // We don't support substitutions.
+    return true;
+  }
+  state->parse_state = copy;
+
+  // Expand abbreviations like "St" => "std".
+  if (ParseOneCharToken(state, 'S')) {
+    const AbbrevPair *p;
+    for (p = kSubstitutionList; p->abbrev != nullptr; ++p) {
+      if (RemainingInput(state)[0] == p->abbrev[1] &&
+          (accept_std || p->abbrev[1] != 't')) {
+        MaybeAppend(state, "std");
+        if (p->real_name[0] != '\0') {
+          MaybeAppend(state, "::");
+          MaybeAppend(state, p->real_name);
+        }
+        ++state->parse_state.mangled_idx;
+        return true;
+      }
+    }
+  }
+  state->parse_state = copy;
+  return false;
+}
+
+// Parse <mangled-name>, optionally followed by either a function-clone suffix
+// or version suffix.  Returns true only if all of "mangled_cur" was consumed.
+static bool ParseTopLevelMangledName(State *state) {
+  ComplexityGuard guard(state);
+  if (guard.IsTooComplex()) return false;
+  if (ParseMangledName(state)) {
+    if (RemainingInput(state)[0] != '\0') {
+      // Drop trailing function clone suffix, if any.
+      if (IsFunctionCloneSuffix(RemainingInput(state))) {
+        return true;
+      }
+      // Append trailing version suffix if any.
+      // ex. _Z3foo@@GLIBCXX_3.4
+      if (RemainingInput(state)[0] == '@') {
+        MaybeAppend(state, RemainingInput(state));
+        return true;
+      }
+      return false;  // Unconsumed suffix.
+    }
+    return true;
+  }
+  return false;
+}
+
+static bool Overflowed(const State *state) {
+  return state->parse_state.out_cur_idx >= state->out_end_idx;
+}
+
+// The demangler entry point.
+bool Demangle(const char *mangled, char *out, int out_size) {
+  State state;
+  InitState(&state, mangled, out, out_size);
+  return ParseTopLevelMangledName(&state) && !Overflowed(&state) &&
+         state.parse_state.out_cur_idx > 0;
+}
+
+}  // namespace debugging_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
diff --git a/src/absl/debugging/internal/demangle.h b/src/absl/debugging/internal/demangle.h
new file mode 100644 (file)
index 0000000..c314d9b
--- /dev/null
@@ -0,0 +1,71 @@
+// Copyright 2018 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// An async-signal-safe and thread-safe demangler for Itanium C++ ABI
+// (aka G++ V3 ABI).
+//
+// The demangler is implemented to be used in async signal handlers to
+// symbolize stack traces.  We cannot use libstdc++'s
+// abi::__cxa_demangle() in such signal handlers since it's not async
+// signal safe (it uses malloc() internally).
+//
+// Note that this demangler doesn't support full demangling.  More
+// specifically, it doesn't print types of function parameters and
+// types of template arguments.  It just skips them.  However, it's
+// still very useful to extract basic information such as class,
+// function, constructor, destructor, and operator names.
+//
+// See the implementation note in demangle.cc if you are interested.
+//
+// Example:
+//
+// | Mangled Name  | The Demangler | abi::__cxa_demangle()
+// |---------------|---------------|-----------------------
+// | _Z1fv         | f()           | f()
+// | _Z1fi         | f()           | f(int)
+// | _Z3foo3bar    | foo()         | foo(bar)
+// | _Z1fIiEvi     | f<>()         | void f<int>(int)
+// | _ZN1N1fE      | N::f          | N::f
+// | _ZN3Foo3BarEv | Foo::Bar()    | Foo::Bar()
+// | _Zrm1XS_"     | operator%()   | operator%(X, X)
+// | _ZN3FooC1Ev   | Foo::Foo()    | Foo::Foo()
+// | _Z1fSs        | f()           | f(std::basic_string<char,
+// |               |               |   std::char_traits<char>,
+// |               |               |   std::allocator<char> >)
+//
+// See the unit test for more examples.
+//
+// Note: we might want to write demanglers for ABIs other than Itanium
+// C++ ABI in the future.
+//
+
+#ifndef ABSL_DEBUGGING_INTERNAL_DEMANGLE_H_
+#define ABSL_DEBUGGING_INTERNAL_DEMANGLE_H_
+
+#include "absl/base/config.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace debugging_internal {
+
+// Demangle `mangled`.  On success, return true and write the
+// demangled symbol name to `out`.  Otherwise, return false.
+// `out` is modified even if demangling is unsuccessful.
+bool Demangle(const char *mangled, char *out, int out_size);
+
+}  // namespace debugging_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#endif  // ABSL_DEBUGGING_INTERNAL_DEMANGLE_H_
diff --git a/src/absl/debugging/internal/elf_mem_image.cc b/src/absl/debugging/internal/elf_mem_image.cc
new file mode 100644 (file)
index 0000000..24cc013
--- /dev/null
@@ -0,0 +1,382 @@
+// Copyright 2017 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// Allow dynamic symbol lookup in an in-memory Elf image.
+//
+
+#include "absl/debugging/internal/elf_mem_image.h"
+
+#ifdef ABSL_HAVE_ELF_MEM_IMAGE  // defined in elf_mem_image.h
+
+#include <string.h>
+#include <cassert>
+#include <cstddef>
+#include "absl/base/internal/raw_logging.h"
+
+// From binutils/include/elf/common.h (this doesn't appear to be documented
+// anywhere else).
+//
+//   /* This flag appears in a Versym structure.  It means that the symbol
+//      is hidden, and is only visible with an explicit version number.
+//      This is a GNU extension.  */
+//   #define VERSYM_HIDDEN           0x8000
+//
+//   /* This is the mask for the rest of the Versym information.  */
+//   #define VERSYM_VERSION          0x7fff
+
+#define VERSYM_VERSION 0x7fff
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace debugging_internal {
+
+namespace {
+
+#if __WORDSIZE == 32
+const int kElfClass = ELFCLASS32;
+int ElfBind(const ElfW(Sym) *symbol) { return ELF32_ST_BIND(symbol->st_info); }
+int ElfType(const ElfW(Sym) *symbol) { return ELF32_ST_TYPE(symbol->st_info); }
+#elif __WORDSIZE == 64
+const int kElfClass = ELFCLASS64;
+int ElfBind(const ElfW(Sym) *symbol) { return ELF64_ST_BIND(symbol->st_info); }
+int ElfType(const ElfW(Sym) *symbol) { return ELF64_ST_TYPE(symbol->st_info); }
+#else
+const int kElfClass = -1;
+int ElfBind(const ElfW(Sym) *) {
+  ABSL_RAW_LOG(FATAL, "Unexpected word size");
+  return 0;
+}
+int ElfType(const ElfW(Sym) *) {
+  ABSL_RAW_LOG(FATAL, "Unexpected word size");
+  return 0;
+}
+#endif
+
+// Extract an element from one of the ELF tables, cast it to desired type.
+// This is just a simple arithmetic and a glorified cast.
+// Callers are responsible for bounds checking.
+template <typename T>
+const T *GetTableElement(const ElfW(Ehdr) * ehdr, ElfW(Off) table_offset,
+                         ElfW(Word) element_size, size_t index) {
+  return reinterpret_cast<const T*>(reinterpret_cast<const char *>(ehdr)
+                                    + table_offset
+                                    + index * element_size);
+}
+
+}  // namespace
+
+// The value of this variable doesn't matter; it's used only for its
+// unique address.
+const int ElfMemImage::kInvalidBaseSentinel = 0;
+
+ElfMemImage::ElfMemImage(const void *base) {
+  ABSL_RAW_CHECK(base != kInvalidBase, "bad pointer");
+  Init(base);
+}
+
+int ElfMemImage::GetNumSymbols() const {
+  if (!hash_) {
+    return 0;
+  }
+  // See http://www.caldera.com/developers/gabi/latest/ch5.dynamic.html#hash
+  return hash_[1];
+}
+
+const ElfW(Sym) *ElfMemImage::GetDynsym(int index) const {
+  ABSL_RAW_CHECK(index < GetNumSymbols(), "index out of range");
+  return dynsym_ + index;
+}
+
+const ElfW(Versym) *ElfMemImage::GetVersym(int index) const {
+  ABSL_RAW_CHECK(index < GetNumSymbols(), "index out of range");
+  return versym_ + index;
+}
+
+const ElfW(Phdr) *ElfMemImage::GetPhdr(int index) const {
+  ABSL_RAW_CHECK(index < ehdr_->e_phnum, "index out of range");
+  return GetTableElement<ElfW(Phdr)>(ehdr_,
+                                     ehdr_->e_phoff,
+                                     ehdr_->e_phentsize,
+                                     index);
+}
+
+const char *ElfMemImage::GetDynstr(ElfW(Word) offset) const {
+  ABSL_RAW_CHECK(offset < strsize_, "offset out of range");
+  return dynstr_ + offset;
+}
+
+const void *ElfMemImage::GetSymAddr(const ElfW(Sym) *sym) const {
+  if (sym->st_shndx == SHN_UNDEF || sym->st_shndx >= SHN_LORESERVE) {
+    // Symbol corresponds to "special" (e.g. SHN_ABS) section.
+    return reinterpret_cast<const void *>(sym->st_value);
+  }
+  ABSL_RAW_CHECK(link_base_ < sym->st_value, "symbol out of range");
+  return GetTableElement<char>(ehdr_, 0, 1, sym->st_value - link_base_);
+}
+
+const ElfW(Verdef) *ElfMemImage::GetVerdef(int index) const {
+  ABSL_RAW_CHECK(0 <= index && static_cast<size_t>(index) <= verdefnum_,
+                 "index out of range");
+  const ElfW(Verdef) *version_definition = verdef_;
+  while (version_definition->vd_ndx < index && version_definition->vd_next) {
+    const char *const version_definition_as_char =
+        reinterpret_cast<const char *>(version_definition);
+    version_definition =
+        reinterpret_cast<const ElfW(Verdef) *>(version_definition_as_char +
+                                               version_definition->vd_next);
+  }
+  return version_definition->vd_ndx == index ? version_definition : nullptr;
+}
+
+const ElfW(Verdaux) *ElfMemImage::GetVerdefAux(
+    const ElfW(Verdef) *verdef) const {
+  return reinterpret_cast<const ElfW(Verdaux) *>(verdef+1);
+}
+
+const char *ElfMemImage::GetVerstr(ElfW(Word) offset) const {
+  ABSL_RAW_CHECK(offset < strsize_, "offset out of range");
+  return dynstr_ + offset;
+}
+
+void ElfMemImage::Init(const void *base) {
+  ehdr_      = nullptr;
+  dynsym_    = nullptr;
+  dynstr_    = nullptr;
+  versym_    = nullptr;
+  verdef_    = nullptr;
+  hash_      = nullptr;
+  strsize_   = 0;
+  verdefnum_ = 0;
+  link_base_ = ~0L;  // Sentinel: PT_LOAD .p_vaddr can't possibly be this.
+  if (!base) {
+    return;
+  }
+  const char *const base_as_char = reinterpret_cast<const char *>(base);
+  if (base_as_char[EI_MAG0] != ELFMAG0 || base_as_char[EI_MAG1] != ELFMAG1 ||
+      base_as_char[EI_MAG2] != ELFMAG2 || base_as_char[EI_MAG3] != ELFMAG3) {
+    assert(false);
+    return;
+  }
+  int elf_class = base_as_char[EI_CLASS];
+  if (elf_class != kElfClass) {
+    assert(false);
+    return;
+  }
+  switch (base_as_char[EI_DATA]) {
+    case ELFDATA2LSB: {
+      if (__LITTLE_ENDIAN != __BYTE_ORDER) {
+        assert(false);
+        return;
+      }
+      break;
+    }
+    case ELFDATA2MSB: {
+      if (__BIG_ENDIAN != __BYTE_ORDER) {
+        assert(false);
+        return;
+      }
+      break;
+    }
+    default: {
+      assert(false);
+      return;
+    }
+  }
+
+  ehdr_ = reinterpret_cast<const ElfW(Ehdr) *>(base);
+  const ElfW(Phdr) *dynamic_program_header = nullptr;
+  for (int i = 0; i < ehdr_->e_phnum; ++i) {
+    const ElfW(Phdr) *const program_header = GetPhdr(i);
+    switch (program_header->p_type) {
+      case PT_LOAD:
+        if (!~link_base_) {
+          link_base_ = program_header->p_vaddr;
+        }
+        break;
+      case PT_DYNAMIC:
+        dynamic_program_header = program_header;
+        break;
+    }
+  }
+  if (!~link_base_ || !dynamic_program_header) {
+    assert(false);
+    // Mark this image as not present. Can not recur infinitely.
+    Init(nullptr);
+    return;
+  }
+  ptrdiff_t relocation =
+      base_as_char - reinterpret_cast<const char *>(link_base_);
+  ElfW(Dyn) *dynamic_entry =
+      reinterpret_cast<ElfW(Dyn) *>(dynamic_program_header->p_vaddr +
+                                    relocation);
+  for (; dynamic_entry->d_tag != DT_NULL; ++dynamic_entry) {
+    const ElfW(Xword) value = dynamic_entry->d_un.d_val + relocation;
+    switch (dynamic_entry->d_tag) {
+      case DT_HASH:
+        hash_ = reinterpret_cast<ElfW(Word) *>(value);
+        break;
+      case DT_SYMTAB:
+        dynsym_ = reinterpret_cast<ElfW(Sym) *>(value);
+        break;
+      case DT_STRTAB:
+        dynstr_ = reinterpret_cast<const char *>(value);
+        break;
+      case DT_VERSYM:
+        versym_ = reinterpret_cast<ElfW(Versym) *>(value);
+        break;
+      case DT_VERDEF:
+        verdef_ = reinterpret_cast<ElfW(Verdef) *>(value);
+        break;
+      case DT_VERDEFNUM:
+        verdefnum_ = dynamic_entry->d_un.d_val;
+        break;
+      case DT_STRSZ:
+        strsize_ = dynamic_entry->d_un.d_val;
+        break;
+      default:
+        // Unrecognized entries explicitly ignored.
+        break;
+    }
+  }
+  if (!hash_ || !dynsym_ || !dynstr_ || !versym_ ||
+      !verdef_ || !verdefnum_ || !strsize_) {
+    assert(false);  // invalid VDSO
+    // Mark this image as not present. Can not recur infinitely.
+    Init(nullptr);
+    return;
+  }
+}
+
+bool ElfMemImage::LookupSymbol(const char *name,
+                               const char *version,
+                               int type,
+                               SymbolInfo *info_out) const {
+  for (const SymbolInfo& info : *this) {
+    if (strcmp(info.name, name) == 0 && strcmp(info.version, version) == 0 &&
+        ElfType(info.symbol) == type) {
+      if (info_out) {
+        *info_out = info;
+      }
+      return true;
+    }
+  }
+  return false;
+}
+
+bool ElfMemImage::LookupSymbolByAddress(const void *address,
+                                        SymbolInfo *info_out) const {
+  for (const SymbolInfo& info : *this) {
+    const char *const symbol_start =
+        reinterpret_cast<const char *>(info.address);
+    const char *const symbol_end = symbol_start + info.symbol->st_size;
+    if (symbol_start <= address && address < symbol_end) {
+      if (info_out) {
+        // Client wants to know details for that symbol (the usual case).
+        if (ElfBind(info.symbol) == STB_GLOBAL) {
+          // Strong symbol; just return it.
+          *info_out = info;
+          return true;
+        } else {
+          // Weak or local. Record it, but keep looking for a strong one.
+          *info_out = info;
+        }
+      } else {
+        // Client only cares if there is an overlapping symbol.
+        return true;
+      }
+    }
+  }
+  return false;
+}
+
+ElfMemImage::SymbolIterator::SymbolIterator(const void *const image, int index)
+    : index_(index), image_(image) {
+}
+
+const ElfMemImage::SymbolInfo *ElfMemImage::SymbolIterator::operator->() const {
+  return &info_;
+}
+
+const ElfMemImage::SymbolInfo& ElfMemImage::SymbolIterator::operator*() const {
+  return info_;
+}
+
+bool ElfMemImage::SymbolIterator::operator==(const SymbolIterator &rhs) const {
+  return this->image_ == rhs.image_ && this->index_ == rhs.index_;
+}
+
+bool ElfMemImage::SymbolIterator::operator!=(const SymbolIterator &rhs) const {
+  return !(*this == rhs);
+}
+
+ElfMemImage::SymbolIterator &ElfMemImage::SymbolIterator::operator++() {
+  this->Update(1);
+  return *this;
+}
+
+ElfMemImage::SymbolIterator ElfMemImage::begin() const {
+  SymbolIterator it(this, 0);
+  it.Update(0);
+  return it;
+}
+
+ElfMemImage::SymbolIterator ElfMemImage::end() const {
+  return SymbolIterator(this, GetNumSymbols());
+}
+
+void ElfMemImage::SymbolIterator::Update(int increment) {
+  const ElfMemImage *image = reinterpret_cast<const ElfMemImage *>(image_);
+  ABSL_RAW_CHECK(image->IsPresent() || increment == 0, "");
+  if (!image->IsPresent()) {
+    return;
+  }
+  index_ += increment;
+  if (index_ >= image->GetNumSymbols()) {
+    index_ = image->GetNumSymbols();
+    return;
+  }
+  const ElfW(Sym)    *symbol = image->GetDynsym(index_);
+  const ElfW(Versym) *version_symbol = image->GetVersym(index_);
+  ABSL_RAW_CHECK(symbol && version_symbol, "");
+  const char *const symbol_name = image->GetDynstr(symbol->st_name);
+  const ElfW(Versym) version_index = version_symbol[0] & VERSYM_VERSION;
+  const ElfW(Verdef) *version_definition = nullptr;
+  const char *version_name = "";
+  if (symbol->st_shndx == SHN_UNDEF) {
+    // Undefined symbols reference DT_VERNEED, not DT_VERDEF, and
+    // version_index could well be greater than verdefnum_, so calling
+    // GetVerdef(version_index) may trigger assertion.
+  } else {
+    version_definition = image->GetVerdef(version_index);
+  }
+  if (version_definition) {
+    // I am expecting 1 or 2 auxiliary entries: 1 for the version itself,
+    // optional 2nd if the version has a parent.
+    ABSL_RAW_CHECK(
+        version_definition->vd_cnt == 1 || version_definition->vd_cnt == 2,
+        "wrong number of entries");
+    const ElfW(Verdaux) *version_aux = image->GetVerdefAux(version_definition);
+    version_name = image->GetVerstr(version_aux->vda_name);
+  }
+  info_.name    = symbol_name;
+  info_.version = version_name;
+  info_.address = image->GetSymAddr(symbol);
+  info_.symbol  = symbol;
+}
+
+}  // namespace debugging_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#endif  // ABSL_HAVE_ELF_MEM_IMAGE
diff --git a/src/absl/debugging/internal/elf_mem_image.h b/src/absl/debugging/internal/elf_mem_image.h
new file mode 100644 (file)
index 0000000..46bfade
--- /dev/null
@@ -0,0 +1,134 @@
+/*
+ * Copyright 2017 The Abseil Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// Allow dynamic symbol lookup for in-memory Elf images.
+
+#ifndef ABSL_DEBUGGING_INTERNAL_ELF_MEM_IMAGE_H_
+#define ABSL_DEBUGGING_INTERNAL_ELF_MEM_IMAGE_H_
+
+// Including this will define the __GLIBC__ macro if glibc is being
+// used.
+#include <climits>
+
+#include "absl/base/config.h"
+
+// Maybe one day we can rewrite this file not to require the elf
+// symbol extensions in glibc, but for right now we need them.
+#ifdef ABSL_HAVE_ELF_MEM_IMAGE
+#error ABSL_HAVE_ELF_MEM_IMAGE cannot be directly set
+#endif
+
+#if defined(__ELF__) && defined(__GLIBC__) && !defined(__native_client__) && \
+    !defined(__asmjs__) && !defined(__wasm__)
+#define ABSL_HAVE_ELF_MEM_IMAGE 1
+#endif
+
+#ifdef ABSL_HAVE_ELF_MEM_IMAGE
+
+#include <link.h>  // for ElfW
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace debugging_internal {
+
+// An in-memory ELF image (may not exist on disk).
+class ElfMemImage {
+ private:
+  // Sentinel: there could never be an elf image at &kInvalidBaseSentinel.
+  static const int kInvalidBaseSentinel;
+
+ public:
+  // Sentinel: there could never be an elf image at this address.
+  static constexpr const void *const kInvalidBase =
+    static_cast<const void*>(&kInvalidBaseSentinel);
+
+  // Information about a single vdso symbol.
+  // All pointers are into .dynsym, .dynstr, or .text of the VDSO.
+  // Do not free() them or modify through them.
+  struct SymbolInfo {
+    const char      *name;      // E.g. "__vdso_getcpu"
+    const char      *version;   // E.g. "LINUX_2.6", could be ""
+                                // for unversioned symbol.
+    const void      *address;   // Relocated symbol address.
+    const ElfW(Sym) *symbol;    // Symbol in the dynamic symbol table.
+  };
+
+  // Supports iteration over all dynamic symbols.
+  class SymbolIterator {
+   public:
+    friend class ElfMemImage;
+    const SymbolInfo *operator->() const;
+    const SymbolInfo &operator*() const;
+    SymbolIterator& operator++();
+    bool operator!=(const SymbolIterator &rhs) const;
+    bool operator==(const SymbolIterator &rhs) const;
+   private:
+    SymbolIterator(const void *const image, int index);
+    void Update(int incr);
+    SymbolInfo info_;
+    int index_;
+    const void *const image_;
+  };
+
+
+  explicit ElfMemImage(const void *base);
+  void                 Init(const void *base);
+  bool                 IsPresent() const { return ehdr_ != nullptr; }
+  const ElfW(Phdr)*    GetPhdr(int index) const;
+  const ElfW(Sym)*     GetDynsym(int index) const;
+  const ElfW(Versym)*  GetVersym(int index) const;
+  const ElfW(Verdef)*  GetVerdef(int index) const;
+  const ElfW(Verdaux)* GetVerdefAux(const ElfW(Verdef) *verdef) const;
+  const char*          GetDynstr(ElfW(Word) offset) const;
+  const void*          GetSymAddr(const ElfW(Sym) *sym) const;
+  const char*          GetVerstr(ElfW(Word) offset) const;
+  int                  GetNumSymbols() const;
+
+  SymbolIterator begin() const;
+  SymbolIterator end() const;
+
+  // Look up versioned dynamic symbol in the image.
+  // Returns false if image is not present, or doesn't contain given
+  // symbol/version/type combination.
+  // If info_out is non-null, additional details are filled in.
+  bool LookupSymbol(const char *name, const char *version,
+                    int symbol_type, SymbolInfo *info_out) const;
+
+  // Find info about symbol (if any) which overlaps given address.
+  // Returns true if symbol was found; false if image isn't present
+  // or doesn't have a symbol overlapping given address.
+  // If info_out is non-null, additional details are filled in.
+  bool LookupSymbolByAddress(const void *address, SymbolInfo *info_out) const;
+
+ private:
+  const ElfW(Ehdr) *ehdr_;
+  const ElfW(Sym) *dynsym_;
+  const ElfW(Versym) *versym_;
+  const ElfW(Verdef) *verdef_;
+  const ElfW(Word) *hash_;
+  const char *dynstr_;
+  size_t strsize_;
+  size_t verdefnum_;
+  ElfW(Addr) link_base_;     // Link-time base (p_vaddr of first PT_LOAD).
+};
+
+}  // namespace debugging_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#endif  // ABSL_HAVE_ELF_MEM_IMAGE
+
+#endif  // ABSL_DEBUGGING_INTERNAL_ELF_MEM_IMAGE_H_
diff --git a/src/absl/debugging/internal/examine_stack.cc b/src/absl/debugging/internal/examine_stack.cc
new file mode 100644 (file)
index 0000000..589a3ef
--- /dev/null
@@ -0,0 +1,203 @@
+//
+// Copyright 2018 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#include "absl/debugging/internal/examine_stack.h"
+
+#ifndef _WIN32
+#include <unistd.h>
+#endif
+
+#ifdef __APPLE__
+#include <sys/ucontext.h>
+#endif
+
+#include <csignal>
+#include <cstdio>
+
+#include "absl/base/attributes.h"
+#include "absl/base/internal/raw_logging.h"
+#include "absl/base/macros.h"
+#include "absl/debugging/stacktrace.h"
+#include "absl/debugging/symbolize.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace debugging_internal {
+
+// Returns the program counter from signal context, nullptr if
+// unknown. vuc is a ucontext_t*. We use void* to avoid the use of
+// ucontext_t on non-POSIX systems.
+void* GetProgramCounter(void* vuc) {
+#ifdef __linux__
+  if (vuc != nullptr) {
+    ucontext_t* context = reinterpret_cast<ucontext_t*>(vuc);
+#if defined(__aarch64__)
+    return reinterpret_cast<void*>(context->uc_mcontext.pc);
+#elif defined(__alpha__)
+    return reinterpret_cast<void*>(context->uc_mcontext.sc_pc);
+#elif defined(__arm__)
+    return reinterpret_cast<void*>(context->uc_mcontext.arm_pc);
+#elif defined(__hppa__)
+    return reinterpret_cast<void*>(context->uc_mcontext.sc_iaoq[0]);
+#elif defined(__i386__)
+    if (14 < ABSL_ARRAYSIZE(context->uc_mcontext.gregs))
+      return reinterpret_cast<void*>(context->uc_mcontext.gregs[14]);
+#elif defined(__ia64__)
+    return reinterpret_cast<void*>(context->uc_mcontext.sc_ip);
+#elif defined(__m68k__)
+    return reinterpret_cast<void*>(context->uc_mcontext.gregs[16]);
+#elif defined(__mips__)
+    return reinterpret_cast<void*>(context->uc_mcontext.pc);
+#elif defined(__powerpc64__)
+    return reinterpret_cast<void*>(context->uc_mcontext.gp_regs[32]);
+#elif defined(__powerpc__)
+    return reinterpret_cast<void*>(context->uc_mcontext.uc_regs->gregs[32]);
+#elif defined(__riscv)
+    return reinterpret_cast<void*>(context->uc_mcontext.__gregs[REG_PC]);
+#elif defined(__s390__) && !defined(__s390x__)
+    return reinterpret_cast<void*>(context->uc_mcontext.psw.addr & 0x7fffffff);
+#elif defined(__s390__) && defined(__s390x__)
+    return reinterpret_cast<void*>(context->uc_mcontext.psw.addr);
+#elif defined(__sh__)
+    return reinterpret_cast<void*>(context->uc_mcontext.pc);
+#elif defined(__sparc__) && !defined(__arch64__)
+    return reinterpret_cast<void*>(context->uc_mcontext.gregs[19]);
+#elif defined(__sparc__) && defined(__arch64__)
+    return reinterpret_cast<void*>(context->uc_mcontext.mc_gregs[19]);
+#elif defined(__x86_64__)
+    if (16 < ABSL_ARRAYSIZE(context->uc_mcontext.gregs))
+      return reinterpret_cast<void*>(context->uc_mcontext.gregs[16]);
+#elif defined(__e2k__)
+    return reinterpret_cast<void*>(context->uc_mcontext.cr0_hi);
+#else
+#error "Undefined Architecture."
+#endif
+  }
+#elif defined(__APPLE__)
+  if (vuc != nullptr) {
+    ucontext_t* signal_ucontext = reinterpret_cast<ucontext_t*>(vuc);
+#if defined(__aarch64__)
+    return reinterpret_cast<void*>(
+        __darwin_arm_thread_state64_get_pc(signal_ucontext->uc_mcontext->__ss));
+#elif defined(__arm__)
+#if __DARWIN_UNIX03
+    return reinterpret_cast<void*>(signal_ucontext->uc_mcontext->__ss.__pc);
+#else
+    return reinterpret_cast<void*>(signal_ucontext->uc_mcontext->ss.pc);
+#endif
+#elif defined(__i386__)
+#if __DARWIN_UNIX03
+    return reinterpret_cast<void*>(signal_ucontext->uc_mcontext->__ss.__eip);
+#else
+    return reinterpret_cast<void*>(signal_ucontext->uc_mcontext->ss.eip);
+#endif
+#elif defined(__x86_64__)
+#if __DARWIN_UNIX03
+    return reinterpret_cast<void*>(signal_ucontext->uc_mcontext->__ss.__rip);
+#else
+    return reinterpret_cast<void*>(signal_ucontext->uc_mcontext->ss.rip);
+#endif
+#endif
+  }
+#elif defined(__akaros__)
+  auto* ctx = reinterpret_cast<struct user_context*>(vuc);
+  return reinterpret_cast<void*>(get_user_ctx_pc(ctx));
+#endif
+  static_cast<void>(vuc);
+  return nullptr;
+}
+
+// The %p field width for printf() functions is two characters per byte,
+// and two extra for the leading "0x".
+static constexpr int kPrintfPointerFieldWidth = 2 + 2 * sizeof(void*);
+
+// Print a program counter, its stack frame size, and its symbol name.
+// Note that there is a separate symbolize_pc argument. Return addresses may be
+// at the end of the function, and this allows the caller to back up from pc if
+// appropriate.
+static void DumpPCAndFrameSizeAndSymbol(void (*writerfn)(const char*, void*),
+                                        void* writerfn_arg, void* pc,
+                                        void* symbolize_pc, int framesize,
+                                        const char* const prefix) {
+  char tmp[1024];
+  const char* symbol = "(unknown)";
+  if (absl::Symbolize(symbolize_pc, tmp, sizeof(tmp))) {
+    symbol = tmp;
+  }
+  char buf[1024];
+  if (framesize <= 0) {
+    snprintf(buf, sizeof(buf), "%s@ %*p  (unknown)  %s\n", prefix,
+             kPrintfPointerFieldWidth, pc, symbol);
+  } else {
+    snprintf(buf, sizeof(buf), "%s@ %*p  %9d  %s\n", prefix,
+             kPrintfPointerFieldWidth, pc, framesize, symbol);
+  }
+  writerfn(buf, writerfn_arg);
+}
+
+// Print a program counter and the corresponding stack frame size.
+static void DumpPCAndFrameSize(void (*writerfn)(const char*, void*),
+                               void* writerfn_arg, void* pc, int framesize,
+                               const char* const prefix) {
+  char buf[100];
+  if (framesize <= 0) {
+    snprintf(buf, sizeof(buf), "%s@ %*p  (unknown)\n", prefix,
+             kPrintfPointerFieldWidth, pc);
+  } else {
+    snprintf(buf, sizeof(buf), "%s@ %*p  %9d\n", prefix,
+             kPrintfPointerFieldWidth, pc, framesize);
+  }
+  writerfn(buf, writerfn_arg);
+}
+
+void DumpPCAndFrameSizesAndStackTrace(
+    void* pc, void* const stack[], int frame_sizes[], int depth,
+    int min_dropped_frames, bool symbolize_stacktrace,
+    void (*writerfn)(const char*, void*), void* writerfn_arg) {
+  if (pc != nullptr) {
+    // We don't know the stack frame size for PC, use 0.
+    if (symbolize_stacktrace) {
+      DumpPCAndFrameSizeAndSymbol(writerfn, writerfn_arg, pc, pc, 0, "PC: ");
+    } else {
+      DumpPCAndFrameSize(writerfn, writerfn_arg, pc, 0, "PC: ");
+    }
+  }
+  for (int i = 0; i < depth; i++) {
+    if (symbolize_stacktrace) {
+      // Pass the previous address of pc as the symbol address because pc is a
+      // return address, and an overrun may occur when the function ends with a
+      // call to a function annotated noreturn (e.g. CHECK). Note that we don't
+      // do this for pc above, as the adjustment is only correct for return
+      // addresses.
+      DumpPCAndFrameSizeAndSymbol(writerfn, writerfn_arg, stack[i],
+                                  reinterpret_cast<char*>(stack[i]) - 1,
+                                  frame_sizes[i], "    ");
+    } else {
+      DumpPCAndFrameSize(writerfn, writerfn_arg, stack[i], frame_sizes[i],
+                         "    ");
+    }
+  }
+  if (min_dropped_frames > 0) {
+    char buf[100];
+    snprintf(buf, sizeof(buf), "    @ ... and at least %d more frames\n",
+             min_dropped_frames);
+    writerfn(buf, writerfn_arg);
+  }
+}
+
+}  // namespace debugging_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
diff --git a/src/absl/debugging/internal/examine_stack.h b/src/absl/debugging/internal/examine_stack.h
new file mode 100644 (file)
index 0000000..3933691
--- /dev/null
@@ -0,0 +1,42 @@
+//
+// Copyright 2018 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#ifndef ABSL_DEBUGGING_INTERNAL_EXAMINE_STACK_H_
+#define ABSL_DEBUGGING_INTERNAL_EXAMINE_STACK_H_
+
+#include "absl/base/config.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace debugging_internal {
+
+// Returns the program counter from signal context, or nullptr if
+// unknown. `vuc` is a ucontext_t*. We use void* to avoid the use of
+// ucontext_t on non-POSIX systems.
+void* GetProgramCounter(void* vuc);
+
+// Uses `writerfn` to dump the program counter, stack trace, and stack
+// frame sizes.
+void DumpPCAndFrameSizesAndStackTrace(
+    void* pc, void* const stack[], int frame_sizes[], int depth,
+    int min_dropped_frames, bool symbolize_stacktrace,
+    void (*writerfn)(const char*, void*), void* writerfn_arg);
+
+}  // namespace debugging_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#endif  // ABSL_DEBUGGING_INTERNAL_EXAMINE_STACK_H_
diff --git a/src/absl/debugging/internal/stack_consumption.cc b/src/absl/debugging/internal/stack_consumption.cc
new file mode 100644 (file)
index 0000000..e3dd51c
--- /dev/null
@@ -0,0 +1,185 @@
+//
+// Copyright 2018 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "absl/debugging/internal/stack_consumption.h"
+
+#ifdef ABSL_INTERNAL_HAVE_DEBUGGING_STACK_CONSUMPTION
+
+#include <signal.h>
+#include <sys/mman.h>
+#include <unistd.h>
+
+#include <string.h>
+
+#include "absl/base/attributes.h"
+#include "absl/base/internal/raw_logging.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace debugging_internal {
+namespace {
+
+// This code requires that we know the direction in which the stack
+// grows. It is commonly believed that this can be detected by putting
+// a variable on the stack and then passing its address to a function
+// that compares the address of this variable to the address of a
+// variable on the function's own stack. However, this is unspecified
+// behavior in C++: If two pointers p and q of the same type point to
+// different objects that are not members of the same object or
+// elements of the same array or to different functions, or if only
+// one of them is null, the results of p<q, p>q, p<=q, and p>=q are
+// unspecified. Therefore, instead we hardcode the direction of the
+// stack on platforms we know about.
+#if defined(__i386__) || defined(__x86_64__) || defined(__ppc__) || \
+    defined(__aarch64__)
+constexpr bool kStackGrowsDown = true;
+#else
+#error Need to define kStackGrowsDown
+#endif
+
+// To measure the stack footprint of some code, we create a signal handler
+// (for SIGUSR2 say) that exercises this code on an alternate stack. This
+// alternate stack is initialized to some known pattern (0x55, 0x55, 0x55,
+// ...). We then self-send this signal, and after the signal handler returns,
+// look at the alternate stack buffer to see what portion has been touched.
+//
+// This trick gives us the the stack footprint of the signal handler.  But the
+// signal handler, even before the code for it is exercised, consumes some
+// stack already. We however only want the stack usage of the code inside the
+// signal handler. To measure this accurately, we install two signal handlers:
+// one that does nothing and just returns, and the user-provided signal
+// handler. The difference between the stack consumption of these two signals
+// handlers should give us the stack foorprint of interest.
+
+void EmptySignalHandler(int) {}
+
+// This is arbitrary value, and could be increase further, at the cost of
+// memset()ting it all to known sentinel value.
+constexpr int kAlternateStackSize = 64 << 10;  // 64KiB
+
+constexpr int kSafetyMargin = 32;
+constexpr char kAlternateStackFillValue = 0x55;
+
+// These helper functions look at the alternate stack buffer, and figure
+// out what portion of this buffer has been touched - this is the stack
+// consumption of the signal handler running on this alternate stack.
+// This function will return -1 if the alternate stack buffer has not been
+// touched. It will abort the program if the buffer has overflowed or is about
+// to overflow.
+int GetStackConsumption(const void* const altstack) {
+  const char* begin;
+  int increment;
+  if (kStackGrowsDown) {
+    begin = reinterpret_cast<const char*>(altstack);
+    increment = 1;
+  } else {
+    begin = reinterpret_cast<const char*>(altstack) + kAlternateStackSize - 1;
+    increment = -1;
+  }
+
+  for (int usage_count = kAlternateStackSize; usage_count > 0; --usage_count) {
+    if (*begin != kAlternateStackFillValue) {
+      ABSL_RAW_CHECK(usage_count <= kAlternateStackSize - kSafetyMargin,
+                     "Buffer has overflowed or is about to overflow");
+      return usage_count;
+    }
+    begin += increment;
+  }
+
+  ABSL_RAW_LOG(FATAL, "Unreachable code");
+  return -1;
+}
+
+}  // namespace
+
+int GetSignalHandlerStackConsumption(void (*signal_handler)(int)) {
+  // The alt-signal-stack cannot be heap allocated because there is a
+  // bug in glibc-2.2 where some signal handler setup code looks at the
+  // current stack pointer to figure out what thread is currently running.
+  // Therefore, the alternate stack must be allocated from the main stack
+  // itself.
+  void* altstack = mmap(nullptr, kAlternateStackSize, PROT_READ | PROT_WRITE,
+                        MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+  ABSL_RAW_CHECK(altstack != MAP_FAILED, "mmap() failed");
+
+  // Set up the alt-signal-stack (and save the older one).
+  stack_t sigstk;
+  memset(&sigstk, 0, sizeof(sigstk));
+  sigstk.ss_sp = altstack;
+  sigstk.ss_size = kAlternateStackSize;
+  sigstk.ss_flags = 0;
+  stack_t old_sigstk;
+  memset(&old_sigstk, 0, sizeof(old_sigstk));
+  ABSL_RAW_CHECK(sigaltstack(&sigstk, &old_sigstk) == 0,
+                 "sigaltstack() failed");
+
+  // Set up SIGUSR1 and SIGUSR2 signal handlers (and save the older ones).
+  struct sigaction sa;
+  memset(&sa, 0, sizeof(sa));
+  struct sigaction old_sa1, old_sa2;
+  sigemptyset(&sa.sa_mask);
+  sa.sa_flags = SA_ONSTACK;
+
+  // SIGUSR1 maps to EmptySignalHandler.
+  sa.sa_handler = EmptySignalHandler;
+  ABSL_RAW_CHECK(sigaction(SIGUSR1, &sa, &old_sa1) == 0, "sigaction() failed");
+
+  // SIGUSR2 maps to signal_handler.
+  sa.sa_handler = signal_handler;
+  ABSL_RAW_CHECK(sigaction(SIGUSR2, &sa, &old_sa2) == 0, "sigaction() failed");
+
+  // Send SIGUSR1 signal and measure the stack consumption of the empty
+  // signal handler.
+  // The first signal might use more stack space. Run once and ignore the
+  // results to get that out of the way.
+  ABSL_RAW_CHECK(kill(getpid(), SIGUSR1) == 0, "kill() failed");
+
+  memset(altstack, kAlternateStackFillValue, kAlternateStackSize);
+  ABSL_RAW_CHECK(kill(getpid(), SIGUSR1) == 0, "kill() failed");
+  int base_stack_consumption = GetStackConsumption(altstack);
+
+  // Send SIGUSR2 signal and measure the stack consumption of signal_handler.
+  ABSL_RAW_CHECK(kill(getpid(), SIGUSR2) == 0, "kill() failed");
+  int signal_handler_stack_consumption = GetStackConsumption(altstack);
+
+  // Now restore the old alt-signal-stack and signal handlers.
+  if (old_sigstk.ss_sp == nullptr && old_sigstk.ss_size == 0 &&
+      (old_sigstk.ss_flags & SS_DISABLE)) {
+    // https://git.musl-libc.org/cgit/musl/commit/src/signal/sigaltstack.c?id=7829f42a2c8944555439380498ab8b924d0f2070
+    // The original stack has ss_size==0 and ss_flags==SS_DISABLE, but some
+    // versions of musl have a bug that rejects ss_size==0. Work around this by
+    // setting ss_size to MINSIGSTKSZ, which should be ignored by the kernel
+    // when SS_DISABLE is set.
+    old_sigstk.ss_size = MINSIGSTKSZ;
+  }
+  ABSL_RAW_CHECK(sigaltstack(&old_sigstk, nullptr) == 0,
+                 "sigaltstack() failed");
+  ABSL_RAW_CHECK(sigaction(SIGUSR1, &old_sa1, nullptr) == 0,
+                 "sigaction() failed");
+  ABSL_RAW_CHECK(sigaction(SIGUSR2, &old_sa2, nullptr) == 0,
+                 "sigaction() failed");
+
+  ABSL_RAW_CHECK(munmap(altstack, kAlternateStackSize) == 0, "munmap() failed");
+  if (signal_handler_stack_consumption != -1 && base_stack_consumption != -1) {
+    return signal_handler_stack_consumption - base_stack_consumption;
+  }
+  return -1;
+}
+
+}  // namespace debugging_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#endif  // ABSL_INTERNAL_HAVE_DEBUGGING_STACK_CONSUMPTION
diff --git a/src/absl/debugging/internal/stack_consumption.h b/src/absl/debugging/internal/stack_consumption.h
new file mode 100644 (file)
index 0000000..2b5e715
--- /dev/null
@@ -0,0 +1,50 @@
+//
+// Copyright 2018 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// Helper function for measuring stack consumption of signal handlers.
+
+#ifndef ABSL_DEBUGGING_INTERNAL_STACK_CONSUMPTION_H_
+#define ABSL_DEBUGGING_INTERNAL_STACK_CONSUMPTION_H_
+
+#include "absl/base/config.h"
+
+// The code in this module is not portable.
+// Use this feature test macro to detect its availability.
+#ifdef ABSL_INTERNAL_HAVE_DEBUGGING_STACK_CONSUMPTION
+#error ABSL_INTERNAL_HAVE_DEBUGGING_STACK_CONSUMPTION cannot be set directly
+#elif !defined(__APPLE__) && !defined(_WIN32) &&                     \
+    (defined(__i386__) || defined(__x86_64__) || defined(__ppc__) || \
+     defined(__aarch64__))
+#define ABSL_INTERNAL_HAVE_DEBUGGING_STACK_CONSUMPTION 1
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace debugging_internal {
+
+// Returns the stack consumption in bytes for the code exercised by
+// signal_handler.  To measure stack consumption, signal_handler is registered
+// as a signal handler, so the code that it exercises must be async-signal
+// safe.  The argument of signal_handler is an implementation detail of signal
+// handlers and should ignored by the code for signal_handler.  Use global
+// variables to pass information between your test code and signal_handler.
+int GetSignalHandlerStackConsumption(void (*signal_handler)(int));
+
+}  // namespace debugging_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#endif  // ABSL_INTERNAL_HAVE_DEBUGGING_STACK_CONSUMPTION
+
+#endif  // ABSL_DEBUGGING_INTERNAL_STACK_CONSUMPTION_H_
diff --git a/src/absl/debugging/internal/stacktrace_aarch64-inl.inc b/src/absl/debugging/internal/stacktrace_aarch64-inl.inc
new file mode 100644 (file)
index 0000000..f4859d7
--- /dev/null
@@ -0,0 +1,199 @@
+#ifndef ABSL_DEBUGGING_INTERNAL_STACKTRACE_AARCH64_INL_H_
+#define ABSL_DEBUGGING_INTERNAL_STACKTRACE_AARCH64_INL_H_
+
+// Generate stack tracer for aarch64
+
+#if defined(__linux__)
+#include <sys/mman.h>
+#include <ucontext.h>
+#include <unistd.h>
+#endif
+
+#include <atomic>
+#include <cassert>
+#include <cstdint>
+#include <iostream>
+
+#include "absl/base/attributes.h"
+#include "absl/debugging/internal/address_is_readable.h"
+#include "absl/debugging/internal/vdso_support.h"  // a no-op on non-elf or non-glibc systems
+#include "absl/debugging/stacktrace.h"
+
+static const uintptr_t kUnknownFrameSize = 0;
+
+#if defined(__linux__)
+// Returns the address of the VDSO __kernel_rt_sigreturn function, if present.
+static const unsigned char* GetKernelRtSigreturnAddress() {
+  constexpr uintptr_t kImpossibleAddress = 1;
+  ABSL_CONST_INIT static std::atomic<uintptr_t> memoized{kImpossibleAddress};
+  uintptr_t address = memoized.load(std::memory_order_relaxed);
+  if (address != kImpossibleAddress) {
+    return reinterpret_cast<const unsigned char*>(address);
+  }
+
+  address = reinterpret_cast<uintptr_t>(nullptr);
+
+#ifdef ABSL_HAVE_VDSO_SUPPORT
+  absl::debugging_internal::VDSOSupport vdso;
+  if (vdso.IsPresent()) {
+    absl::debugging_internal::VDSOSupport::SymbolInfo symbol_info;
+    auto lookup = [&](int type) {
+      return vdso.LookupSymbol("__kernel_rt_sigreturn", "LINUX_2.6.39", type,
+                               &symbol_info);
+    };
+    if ((!lookup(STT_FUNC) && !lookup(STT_NOTYPE)) ||
+        symbol_info.address == nullptr) {
+      // Unexpected: VDSO is present, yet the expected symbol is missing
+      // or null.
+      assert(false && "VDSO is present, but doesn't have expected symbol");
+    } else {
+      if (reinterpret_cast<uintptr_t>(symbol_info.address) !=
+          kImpossibleAddress) {
+        address = reinterpret_cast<uintptr_t>(symbol_info.address);
+      } else {
+        assert(false && "VDSO returned invalid address");
+      }
+    }
+  }
+#endif
+
+  memoized.store(address, std::memory_order_relaxed);
+  return reinterpret_cast<const unsigned char*>(address);
+}
+#endif  // __linux__
+
+// Compute the size of a stack frame in [low..high).  We assume that
+// low < high.  Return size of kUnknownFrameSize.
+template<typename T>
+static inline uintptr_t ComputeStackFrameSize(const T* low,
+                                              const T* high) {
+  const char* low_char_ptr = reinterpret_cast<const char *>(low);
+  const char* high_char_ptr = reinterpret_cast<const char *>(high);
+  return low < high ? high_char_ptr - low_char_ptr : kUnknownFrameSize;
+}
+
+// Given a pointer to a stack frame, locate and return the calling
+// stackframe, or return null if no stackframe can be found. Perform sanity
+// checks (the strictness of which is controlled by the boolean parameter
+// "STRICT_UNWINDING") to reduce the chance that a bad pointer is returned.
+template<bool STRICT_UNWINDING, bool WITH_CONTEXT>
+ABSL_ATTRIBUTE_NO_SANITIZE_ADDRESS  // May read random elements from stack.
+ABSL_ATTRIBUTE_NO_SANITIZE_MEMORY   // May read random elements from stack.
+static void **NextStackFrame(void **old_frame_pointer, const void *uc) {
+  void **new_frame_pointer = reinterpret_cast<void**>(*old_frame_pointer);
+  bool check_frame_size = true;
+
+#if defined(__linux__)
+  if (WITH_CONTEXT && uc != nullptr) {
+    // Check to see if next frame's return address is __kernel_rt_sigreturn.
+    if (old_frame_pointer[1] == GetKernelRtSigreturnAddress()) {
+      const ucontext_t *ucv = static_cast<const ucontext_t *>(uc);
+      // old_frame_pointer[0] is not suitable for unwinding, look at
+      // ucontext to discover frame pointer before signal.
+      void **const pre_signal_frame_pointer =
+          reinterpret_cast<void **>(ucv->uc_mcontext.regs[29]);
+
+      // Check that alleged frame pointer is actually readable. This is to
+      // prevent "double fault" in case we hit the first fault due to e.g.
+      // stack corruption.
+      if (!absl::debugging_internal::AddressIsReadable(
+              pre_signal_frame_pointer))
+        return nullptr;
+
+      // Alleged frame pointer is readable, use it for further unwinding.
+      new_frame_pointer = pre_signal_frame_pointer;
+
+      // Skip frame size check if we return from a signal. We may be using a
+      // an alternate stack for signals.
+      check_frame_size = false;
+    }
+  }
+#endif
+
+  // aarch64 ABI requires stack pointer to be 16-byte-aligned.
+  if ((reinterpret_cast<uintptr_t>(new_frame_pointer) & 15) != 0)
+    return nullptr;
+
+  // Check frame size.  In strict mode, we assume frames to be under
+  // 100,000 bytes.  In non-strict mode, we relax the limit to 1MB.
+  if (check_frame_size) {
+    const uintptr_t max_size = STRICT_UNWINDING ? 100000 : 1000000;
+    const uintptr_t frame_size =
+        ComputeStackFrameSize(old_frame_pointer, new_frame_pointer);
+    if (frame_size == kUnknownFrameSize || frame_size > max_size)
+      return nullptr;
+  }
+
+  return new_frame_pointer;
+}
+
+template <bool IS_STACK_FRAMES, bool IS_WITH_CONTEXT>
+ABSL_ATTRIBUTE_NO_SANITIZE_ADDRESS  // May read random elements from stack.
+ABSL_ATTRIBUTE_NO_SANITIZE_MEMORY   // May read random elements from stack.
+static int UnwindImpl(void** result, int* sizes, int max_depth, int skip_count,
+                      const void *ucp, int *min_dropped_frames) {
+#ifdef __GNUC__
+  void **frame_pointer = reinterpret_cast<void**>(__builtin_frame_address(0));
+#else
+# error reading stack point not yet supported on this platform.
+#endif
+
+  skip_count++;    // Skip the frame for this function.
+  int n = 0;
+
+  // The frame pointer points to low address of a frame.  The first 64-bit
+  // word of a frame points to the next frame up the call chain, which normally
+  // is just after the high address of the current frame.  The second word of
+  // a frame contains return adress of to the caller.   To find a pc value
+  // associated with the current frame, we need to go down a level in the call
+  // chain.  So we remember return the address of the last frame seen.  This
+  // does not work for the first stack frame, which belongs to UnwindImp() but
+  // we skip the frame for UnwindImp() anyway.
+  void* prev_return_address = nullptr;
+
+  while (frame_pointer && n < max_depth) {
+    // The absl::GetStackFrames routine is called when we are in some
+    // informational context (the failure signal handler for example).
+    // Use the non-strict unwinding rules to produce a stack trace
+    // that is as complete as possible (even if it contains a few bogus
+    // entries in some rare cases).
+    void **next_frame_pointer =
+        NextStackFrame<!IS_STACK_FRAMES, IS_WITH_CONTEXT>(frame_pointer, ucp);
+
+    if (skip_count > 0) {
+      skip_count--;
+    } else {
+      result[n] = prev_return_address;
+      if (IS_STACK_FRAMES) {
+        sizes[n] = ComputeStackFrameSize(frame_pointer, next_frame_pointer);
+      }
+      n++;
+    }
+    prev_return_address = frame_pointer[1];
+    frame_pointer = next_frame_pointer;
+  }
+  if (min_dropped_frames != nullptr) {
+    // Implementation detail: we clamp the max of frames we are willing to
+    // count, so as not to spend too much time in the loop below.
+    const int kMaxUnwind = 200;
+    int j = 0;
+    for (; frame_pointer != nullptr && j < kMaxUnwind; j++) {
+      frame_pointer =
+          NextStackFrame<!IS_STACK_FRAMES, IS_WITH_CONTEXT>(frame_pointer, ucp);
+    }
+    *min_dropped_frames = j;
+  }
+  return n;
+}
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace debugging_internal {
+bool StackTraceWorksForTest() {
+  return true;
+}
+}  // namespace debugging_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#endif  // ABSL_DEBUGGING_INTERNAL_STACKTRACE_AARCH64_INL_H_
diff --git a/src/absl/debugging/internal/stacktrace_arm-inl.inc b/src/absl/debugging/internal/stacktrace_arm-inl.inc
new file mode 100644 (file)
index 0000000..2a1bf2e
--- /dev/null
@@ -0,0 +1,134 @@
+// Copyright 2017 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// This is inspired by Craig Silverstein's PowerPC stacktrace code.
+
+#ifndef ABSL_DEBUGGING_INTERNAL_STACKTRACE_ARM_INL_H_
+#define ABSL_DEBUGGING_INTERNAL_STACKTRACE_ARM_INL_H_
+
+#include <cstdint>
+
+#include "absl/debugging/stacktrace.h"
+
+// WARNING:
+// This only works if all your code is in either ARM or THUMB mode.  With
+// interworking, the frame pointer of the caller can either be in r11 (ARM
+// mode) or r7 (THUMB mode).  A callee only saves the frame pointer of its
+// mode in a fixed location on its stack frame.  If the caller is a different
+// mode, there is no easy way to find the frame pointer.  It can either be
+// still in the designated register or saved on stack along with other callee
+// saved registers.
+
+// Given a pointer to a stack frame, locate and return the calling
+// stackframe, or return nullptr if no stackframe can be found. Perform sanity
+// checks (the strictness of which is controlled by the boolean parameter
+// "STRICT_UNWINDING") to reduce the chance that a bad pointer is returned.
+template<bool STRICT_UNWINDING>
+static void **NextStackFrame(void **old_sp) {
+  void **new_sp = (void**) old_sp[-1];
+
+  // Check that the transition from frame pointer old_sp to frame
+  // pointer new_sp isn't clearly bogus
+  if (STRICT_UNWINDING) {
+    // With the stack growing downwards, older stack frame must be
+    // at a greater address that the current one.
+    if (new_sp <= old_sp) return nullptr;
+    // Assume stack frames larger than 100,000 bytes are bogus.
+    if ((uintptr_t)new_sp - (uintptr_t)old_sp > 100000) return nullptr;
+  } else {
+    // In the non-strict mode, allow discontiguous stack frames.
+    // (alternate-signal-stacks for example).
+    if (new_sp == old_sp) return nullptr;
+    // And allow frames upto about 1MB.
+    if ((new_sp > old_sp)
+        && ((uintptr_t)new_sp - (uintptr_t)old_sp > 1000000)) return nullptr;
+  }
+  if ((uintptr_t)new_sp & (sizeof(void *) - 1)) return nullptr;
+  return new_sp;
+}
+
+// This ensures that absl::GetStackTrace sets up the Link Register properly.
+#ifdef __GNUC__
+void StacktraceArmDummyFunction() __attribute__((noinline));
+void StacktraceArmDummyFunction() { __asm__ volatile(""); }
+#else
+# error StacktraceArmDummyFunction() needs to be ported to this platform.
+#endif
+
+template <bool IS_STACK_FRAMES, bool IS_WITH_CONTEXT>
+static int UnwindImpl(void** result, int* sizes, int max_depth, int skip_count,
+                      const void * /* ucp */, int *min_dropped_frames) {
+#ifdef __GNUC__
+  void **sp = reinterpret_cast<void**>(__builtin_frame_address(0));
+#else
+# error reading stack point not yet supported on this platform.
+#endif
+
+  // On ARM, the return address is stored in the link register (r14).
+  // This is not saved on the stack frame of a leaf function.  To
+  // simplify code that reads return addresses, we call a dummy
+  // function so that the return address of this function is also
+  // stored in the stack frame.  This works at least for gcc.
+  StacktraceArmDummyFunction();
+
+  int n = 0;
+  while (sp && n < max_depth) {
+    // The absl::GetStackFrames routine is called when we are in some
+    // informational context (the failure signal handler for example).
+    // Use the non-strict unwinding rules to produce a stack trace
+    // that is as complete as possible (even if it contains a few bogus
+    // entries in some rare cases).
+    void **next_sp = NextStackFrame<!IS_STACK_FRAMES>(sp);
+
+    if (skip_count > 0) {
+      skip_count--;
+    } else {
+      result[n] = *sp;
+
+      if (IS_STACK_FRAMES) {
+        if (next_sp > sp) {
+          sizes[n] = (uintptr_t)next_sp - (uintptr_t)sp;
+        } else {
+          // A frame-size of 0 is used to indicate unknown frame size.
+          sizes[n] = 0;
+        }
+      }
+      n++;
+    }
+    sp = next_sp;
+  }
+  if (min_dropped_frames != nullptr) {
+    // Implementation detail: we clamp the max of frames we are willing to
+    // count, so as not to spend too much time in the loop below.
+    const int kMaxUnwind = 200;
+    int j = 0;
+    for (; sp != nullptr && j < kMaxUnwind; j++) {
+      sp = NextStackFrame<!IS_STACK_FRAMES>(sp);
+    }
+    *min_dropped_frames = j;
+  }
+  return n;
+}
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace debugging_internal {
+bool StackTraceWorksForTest() {
+  return false;
+}
+}  // namespace debugging_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#endif  // ABSL_DEBUGGING_INTERNAL_STACKTRACE_ARM_INL_H_
diff --git a/src/absl/debugging/internal/stacktrace_config.h b/src/absl/debugging/internal/stacktrace_config.h
new file mode 100644 (file)
index 0000000..cca410d
--- /dev/null
@@ -0,0 +1,80 @@
+/*
+ * Copyright 2017 The Abseil Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+
+ * Defines ABSL_STACKTRACE_INL_HEADER to the *-inl.h containing
+ * actual unwinder implementation.
+ * This header is "private" to stacktrace.cc.
+ * DO NOT include it into any other files.
+*/
+#ifndef ABSL_DEBUGGING_INTERNAL_STACKTRACE_CONFIG_H_
+#define ABSL_DEBUGGING_INTERNAL_STACKTRACE_CONFIG_H_
+
+#include "absl/base/config.h"
+
+#if defined(ABSL_STACKTRACE_INL_HEADER)
+#error ABSL_STACKTRACE_INL_HEADER cannot be directly set
+
+#elif defined(_WIN32)
+#define ABSL_STACKTRACE_INL_HEADER \
+    "absl/debugging/internal/stacktrace_win32-inl.inc"
+
+#elif defined(__APPLE__)
+#ifdef ABSL_HAVE_THREAD_LOCAL
+// Thread local support required for UnwindImpl.
+#define ABSL_STACKTRACE_INL_HEADER \
+  "absl/debugging/internal/stacktrace_generic-inl.inc"
+#endif
+
+#elif defined(__linux__) && !defined(__ANDROID__)
+
+#if defined(NO_FRAME_POINTER) && \
+    (defined(__i386__) || defined(__x86_64__) || defined(__aarch64__))
+// Note: The libunwind-based implementation is not available to open-source
+// users.
+#define ABSL_STACKTRACE_INL_HEADER \
+  "absl/debugging/internal/stacktrace_libunwind-inl.inc"
+#define STACKTRACE_USES_LIBUNWIND 1
+#elif defined(NO_FRAME_POINTER) && defined(__has_include)
+#if __has_include(<execinfo.h>)
+// Note: When using glibc this may require -funwind-tables to function properly.
+#define ABSL_STACKTRACE_INL_HEADER \
+  "absl/debugging/internal/stacktrace_generic-inl.inc"
+#endif
+#elif defined(__i386__) || defined(__x86_64__)
+#define ABSL_STACKTRACE_INL_HEADER \
+  "absl/debugging/internal/stacktrace_x86-inl.inc"
+#elif defined(__ppc__) || defined(__PPC__)
+#define ABSL_STACKTRACE_INL_HEADER \
+  "absl/debugging/internal/stacktrace_powerpc-inl.inc"
+#elif defined(__aarch64__)
+#define ABSL_STACKTRACE_INL_HEADER \
+  "absl/debugging/internal/stacktrace_aarch64-inl.inc"
+#elif defined(__has_include)
+#if __has_include(<execinfo.h>)
+// Note: When using glibc this may require -funwind-tables to function properly.
+#define ABSL_STACKTRACE_INL_HEADER \
+  "absl/debugging/internal/stacktrace_generic-inl.inc"
+#endif
+#endif
+
+#endif
+
+// Fallback to the empty implementation.
+#if !defined(ABSL_STACKTRACE_INL_HEADER)
+#define ABSL_STACKTRACE_INL_HEADER \
+  "absl/debugging/internal/stacktrace_unimplemented-inl.inc"
+#endif
+
+#endif  // ABSL_DEBUGGING_INTERNAL_STACKTRACE_CONFIG_H_
diff --git a/src/absl/debugging/internal/stacktrace_generic-inl.inc b/src/absl/debugging/internal/stacktrace_generic-inl.inc
new file mode 100644 (file)
index 0000000..b2792a1
--- /dev/null
@@ -0,0 +1,108 @@
+// Copyright 2017 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// Portable implementation - just use glibc
+//
+// Note:  The glibc implementation may cause a call to malloc.
+// This can cause a deadlock in HeapProfiler.
+
+#ifndef ABSL_DEBUGGING_INTERNAL_STACKTRACE_GENERIC_INL_H_
+#define ABSL_DEBUGGING_INTERNAL_STACKTRACE_GENERIC_INL_H_
+
+#include <execinfo.h>
+#include <atomic>
+#include <cstring>
+
+#include "absl/debugging/stacktrace.h"
+#include "absl/base/attributes.h"
+
+// Sometimes, we can try to get a stack trace from within a stack
+// trace, because we don't block signals inside this code (which would be too
+// expensive: the two extra system calls per stack trace do matter here).
+// That can cause a self-deadlock.
+// Protect against such reentrant call by failing to get a stack trace.
+//
+// We use __thread here because the code here is extremely low level -- it is
+// called while collecting stack traces from within malloc and mmap, and thus
+// can not call anything which might call malloc or mmap itself.
+static __thread int recursive = 0;
+
+// The stack trace function might be invoked very early in the program's
+// execution (e.g. from the very first malloc if using tcmalloc). Also, the
+// glibc implementation itself will trigger malloc the first time it is called.
+// As such, we suppress usage of backtrace during this early stage of execution.
+static std::atomic<bool> disable_stacktraces(true);  // Disabled until healthy.
+// Waiting until static initializers run seems to be late enough.
+// This file is included into stacktrace.cc so this will only run once.
+ABSL_ATTRIBUTE_UNUSED static int stacktraces_enabler = []() {
+  void* unused_stack[1];
+  // Force the first backtrace to happen early to get the one-time shared lib
+  // loading (allocation) out of the way. After the first call it is much safer
+  // to use backtrace from a signal handler if we crash somewhere later.
+  backtrace(unused_stack, 1);
+  disable_stacktraces.store(false, std::memory_order_relaxed);
+  return 0;
+}();
+
+template <bool IS_STACK_FRAMES, bool IS_WITH_CONTEXT>
+static int UnwindImpl(void** result, int* sizes, int max_depth, int skip_count,
+                      const void *ucp, int *min_dropped_frames) {
+  if (recursive || disable_stacktraces.load(std::memory_order_relaxed)) {
+    return 0;
+  }
+  ++recursive;
+
+  static_cast<void>(ucp);  // Unused.
+  static const int kStackLength = 64;
+  void * stack[kStackLength];
+  int size;
+
+  size = backtrace(stack, kStackLength);
+  skip_count++;  // we want to skip the current frame as well
+  int result_count = size - skip_count;
+  if (result_count < 0)
+    result_count = 0;
+  if (result_count > max_depth)
+    result_count = max_depth;
+  for (int i = 0; i < result_count; i++)
+    result[i] = stack[i + skip_count];
+
+  if (IS_STACK_FRAMES) {
+    // No implementation for finding out the stack frame sizes yet.
+    memset(sizes, 0, sizeof(*sizes) * result_count);
+  }
+  if (min_dropped_frames != nullptr) {
+    if (size - skip_count - max_depth > 0) {
+      *min_dropped_frames = size - skip_count - max_depth;
+    } else {
+      *min_dropped_frames = 0;
+    }
+  }
+
+  --recursive;
+
+  return result_count;
+}
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace debugging_internal {
+bool StackTraceWorksForTest() {
+  return true;
+}
+}  // namespace debugging_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#endif  // ABSL_DEBUGGING_INTERNAL_STACKTRACE_GENERIC_INL_H_
diff --git a/src/absl/debugging/internal/stacktrace_powerpc-inl.inc b/src/absl/debugging/internal/stacktrace_powerpc-inl.inc
new file mode 100644 (file)
index 0000000..cf8c051
--- /dev/null
@@ -0,0 +1,253 @@
+// Copyright 2017 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// Produce stack trace.  I'm guessing (hoping!) the code is much like
+// for x86.  For apple machines, at least, it seems to be; see
+//    https://developer.apple.com/documentation/mac/runtimehtml/RTArch-59.html
+//    https://www.linux-foundation.org/spec/ELF/ppc64/PPC-elf64abi-1.9.html#STACK
+// Linux has similar code: http://patchwork.ozlabs.org/linuxppc/patch?id=8882
+
+#ifndef ABSL_DEBUGGING_INTERNAL_STACKTRACE_POWERPC_INL_H_
+#define ABSL_DEBUGGING_INTERNAL_STACKTRACE_POWERPC_INL_H_
+
+#if defined(__linux__)
+#include <asm/ptrace.h>   // for PT_NIP.
+#include <ucontext.h>     // for ucontext_t
+#endif
+
+#include <unistd.h>
+#include <cassert>
+#include <cstdint>
+#include <cstdio>
+
+#include "absl/base/attributes.h"
+#include "absl/base/optimization.h"
+#include "absl/base/port.h"
+#include "absl/debugging/stacktrace.h"
+#include "absl/debugging/internal/address_is_readable.h"
+#include "absl/debugging/internal/vdso_support.h"  // a no-op on non-elf or non-glibc systems
+
+// Given a stack pointer, return the saved link register value.
+// Note that this is the link register for a callee.
+static inline void *StacktracePowerPCGetLR(void **sp) {
+  // PowerPC has 3 main ABIs, which say where in the stack the
+  // Link Register is.  For DARWIN and AIX (used by apple and
+  // linux ppc64), it's in sp[2].  For SYSV (used by linux ppc),
+  // it's in sp[1].
+#if defined(_CALL_AIX) || defined(_CALL_DARWIN)
+  return *(sp+2);
+#elif defined(_CALL_SYSV)
+  return *(sp+1);
+#elif defined(__APPLE__) || defined(__FreeBSD__) || \
+    (defined(__linux__) && defined(__PPC64__))
+  // This check is in case the compiler doesn't define _CALL_AIX/etc.
+  return *(sp+2);
+#elif defined(__linux)
+  // This check is in case the compiler doesn't define _CALL_SYSV.
+  return *(sp+1);
+#else
+#error Need to specify the PPC ABI for your archiecture.
+#endif
+}
+
+// Given a pointer to a stack frame, locate and return the calling
+// stackframe, or return null if no stackframe can be found. Perform sanity
+// checks (the strictness of which is controlled by the boolean parameter
+// "STRICT_UNWINDING") to reduce the chance that a bad pointer is returned.
+template<bool STRICT_UNWINDING, bool IS_WITH_CONTEXT>
+ABSL_ATTRIBUTE_NO_SANITIZE_ADDRESS  // May read random elements from stack.
+ABSL_ATTRIBUTE_NO_SANITIZE_MEMORY   // May read random elements from stack.
+static void **NextStackFrame(void **old_sp, const void *uc) {
+  void **new_sp = (void **) *old_sp;
+  enum { kStackAlignment = 16 };
+
+  // Check that the transition from frame pointer old_sp to frame
+  // pointer new_sp isn't clearly bogus
+  if (STRICT_UNWINDING) {
+    // With the stack growing downwards, older stack frame must be
+    // at a greater address that the current one.
+    if (new_sp <= old_sp) return nullptr;
+    // Assume stack frames larger than 100,000 bytes are bogus.
+    if ((uintptr_t)new_sp - (uintptr_t)old_sp > 100000) return nullptr;
+  } else {
+    // In the non-strict mode, allow discontiguous stack frames.
+    // (alternate-signal-stacks for example).
+    if (new_sp == old_sp) return nullptr;
+    // And allow frames upto about 1MB.
+    if ((new_sp > old_sp)
+        && ((uintptr_t)new_sp - (uintptr_t)old_sp > 1000000)) return nullptr;
+  }
+  if ((uintptr_t)new_sp % kStackAlignment != 0) return nullptr;
+
+#if defined(__linux__)
+  enum StackTraceKernelSymbolStatus {
+      kNotInitialized = 0, kAddressValid, kAddressInvalid };
+
+  if (IS_WITH_CONTEXT && uc != nullptr) {
+    static StackTraceKernelSymbolStatus kernel_symbol_status =
+        kNotInitialized;  // Sentinel: not computed yet.
+    // Initialize with sentinel value: __kernel_rt_sigtramp_rt64 can not
+    // possibly be there.
+    static const unsigned char *kernel_sigtramp_rt64_address = nullptr;
+    if (kernel_symbol_status == kNotInitialized) {
+      absl::debugging_internal::VDSOSupport vdso;
+      if (vdso.IsPresent()) {
+        absl::debugging_internal::VDSOSupport::SymbolInfo
+            sigtramp_rt64_symbol_info;
+        if (!vdso.LookupSymbol(
+                "__kernel_sigtramp_rt64", "LINUX_2.6.15",
+                absl::debugging_internal::VDSOSupport::kVDSOSymbolType,
+                &sigtramp_rt64_symbol_info) ||
+            sigtramp_rt64_symbol_info.address == nullptr) {
+          // Unexpected: VDSO is present, yet the expected symbol is missing
+          // or null.
+          assert(false && "VDSO is present, but doesn't have expected symbol");
+          kernel_symbol_status = kAddressInvalid;
+        } else {
+          kernel_sigtramp_rt64_address =
+              reinterpret_cast<const unsigned char *>(
+                  sigtramp_rt64_symbol_info.address);
+          kernel_symbol_status = kAddressValid;
+        }
+      } else {
+        kernel_symbol_status = kAddressInvalid;
+      }
+    }
+
+    if (new_sp != nullptr &&
+        kernel_symbol_status == kAddressValid &&
+        StacktracePowerPCGetLR(new_sp) == kernel_sigtramp_rt64_address) {
+      const ucontext_t* signal_context =
+          reinterpret_cast<const ucontext_t*>(uc);
+      void **const sp_before_signal =
+#if defined(__PPC64__)
+          reinterpret_cast<void **>(signal_context->uc_mcontext.gp_regs[PT_R1]);
+#else
+          reinterpret_cast<void **>(
+              signal_context->uc_mcontext.uc_regs->gregs[PT_R1]);
+#endif
+      // Check that alleged sp before signal is nonnull and is reasonably
+      // aligned.
+      if (sp_before_signal != nullptr &&
+          ((uintptr_t)sp_before_signal % kStackAlignment) == 0) {
+        // Check that alleged stack pointer is actually readable. This is to
+        // prevent a "double fault" in case we hit the first fault due to e.g.
+        // a stack corruption.
+        if (absl::debugging_internal::AddressIsReadable(sp_before_signal)) {
+          // Alleged stack pointer is readable, use it for further unwinding.
+          new_sp = sp_before_signal;
+        }
+      }
+    }
+  }
+#endif
+
+  return new_sp;
+}
+
+// This ensures that absl::GetStackTrace sets up the Link Register properly.
+ABSL_ATTRIBUTE_NOINLINE static void AbslStacktracePowerPCDummyFunction() {
+  ABSL_BLOCK_TAIL_CALL_OPTIMIZATION();
+}
+
+template <bool IS_STACK_FRAMES, bool IS_WITH_CONTEXT>
+ABSL_ATTRIBUTE_NO_SANITIZE_ADDRESS  // May read random elements from stack.
+ABSL_ATTRIBUTE_NO_SANITIZE_MEMORY   // May read random elements from stack.
+static int UnwindImpl(void** result, int* sizes, int max_depth, int skip_count,
+                      const void *ucp, int *min_dropped_frames) {
+  void **sp;
+  // Apple macOS uses an old version of gnu as -- both Darwin 7.9.0 (Panther)
+  // and Darwin 8.8.1 (Tiger) use as 1.38.  This means we have to use a
+  // different asm syntax.  I don't know quite the best way to discriminate
+  // systems using the old as from the new one; I've gone with __APPLE__.
+#ifdef __APPLE__
+  __asm__ volatile ("mr %0,r1" : "=r" (sp));
+#else
+  __asm__ volatile ("mr %0,1" : "=r" (sp));
+#endif
+
+  // On PowerPC, the "Link Register" or "Link Record" (LR), is a stack
+  // entry that holds the return address of the subroutine call (what
+  // instruction we run after our function finishes).  This is the
+  // same as the stack-pointer of our parent routine, which is what we
+  // want here.  While the compiler will always(?) set up LR for
+  // subroutine calls, it may not for leaf functions (such as this one).
+  // This routine forces the compiler (at least gcc) to push it anyway.
+  AbslStacktracePowerPCDummyFunction();
+
+  // The LR save area is used by the callee, so the top entry is bogus.
+  skip_count++;
+
+  int n = 0;
+
+  // Unlike ABIs of X86 and ARM, PowerPC ABIs say that return address (in
+  // the link register) of a function call is stored in the caller's stack
+  // frame instead of the callee's.  When we look for the return address
+  // associated with a stack frame, we need to make sure that there is a
+  // caller frame before it.  So we call NextStackFrame before entering the
+  // loop below and check next_sp instead of sp for loop termination.
+  // The outermost frame is set up by runtimes and it does not have a
+  // caller frame, so it is skipped.
+
+  // The absl::GetStackFrames routine is called when we are in some
+  // informational context (the failure signal handler for example).
+  // Use the non-strict unwinding rules to produce a stack trace
+  // that is as complete as possible (even if it contains a few
+  // bogus entries in some rare cases).
+  void **next_sp = NextStackFrame<!IS_STACK_FRAMES, IS_WITH_CONTEXT>(sp, ucp);
+
+  while (next_sp && n < max_depth) {
+    if (skip_count > 0) {
+      skip_count--;
+    } else {
+      result[n] = StacktracePowerPCGetLR(sp);
+      if (IS_STACK_FRAMES) {
+        if (next_sp > sp) {
+          sizes[n] = (uintptr_t)next_sp - (uintptr_t)sp;
+        } else {
+          // A frame-size of 0 is used to indicate unknown frame size.
+          sizes[n] = 0;
+        }
+      }
+      n++;
+    }
+
+    sp = next_sp;
+    next_sp = NextStackFrame<!IS_STACK_FRAMES, IS_WITH_CONTEXT>(sp, ucp);
+  }
+
+  if (min_dropped_frames != nullptr) {
+    // Implementation detail: we clamp the max of frames we are willing to
+    // count, so as not to spend too much time in the loop below.
+    const int kMaxUnwind = 1000;
+    int j = 0;
+    for (; next_sp != nullptr && j < kMaxUnwind; j++) {
+      next_sp = NextStackFrame<!IS_STACK_FRAMES, IS_WITH_CONTEXT>(next_sp, ucp);
+    }
+    *min_dropped_frames = j;
+  }
+  return n;
+}
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace debugging_internal {
+bool StackTraceWorksForTest() {
+  return true;
+}
+}  // namespace debugging_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#endif  // ABSL_DEBUGGING_INTERNAL_STACKTRACE_POWERPC_INL_H_
diff --git a/src/absl/debugging/internal/stacktrace_unimplemented-inl.inc b/src/absl/debugging/internal/stacktrace_unimplemented-inl.inc
new file mode 100644 (file)
index 0000000..5b8fb19
--- /dev/null
@@ -0,0 +1,24 @@
+#ifndef ABSL_DEBUGGING_INTERNAL_STACKTRACE_UNIMPLEMENTED_INL_H_
+#define ABSL_DEBUGGING_INTERNAL_STACKTRACE_UNIMPLEMENTED_INL_H_
+
+template <bool IS_STACK_FRAMES, bool IS_WITH_CONTEXT>
+static int UnwindImpl(void** /* result */, int* /* sizes */,
+                      int /* max_depth */, int /* skip_count */,
+                      const void* /* ucp */, int *min_dropped_frames) {
+  if (min_dropped_frames != nullptr) {
+    *min_dropped_frames = 0;
+  }
+  return 0;
+}
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace debugging_internal {
+bool StackTraceWorksForTest() {
+  return false;
+}
+}  // namespace debugging_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#endif  // ABSL_DEBUGGING_INTERNAL_STACKTRACE_UNIMPLEMENTED_INL_H_
diff --git a/src/absl/debugging/internal/stacktrace_win32-inl.inc b/src/absl/debugging/internal/stacktrace_win32-inl.inc
new file mode 100644 (file)
index 0000000..1c666c8
--- /dev/null
@@ -0,0 +1,93 @@
+// Copyright 2017 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// Produces a stack trace for Windows.  Normally, one could use
+// stacktrace_x86-inl.h or stacktrace_x86_64-inl.h -- and indeed, that
+// should work for binaries compiled using MSVC in "debug" mode.
+// However, in "release" mode, Windows uses frame-pointer
+// optimization, which makes getting a stack trace very difficult.
+//
+// There are several approaches one can take.  One is to use Windows
+// intrinsics like StackWalk64.  These can work, but have restrictions
+// on how successful they can be.  Another attempt is to write a
+// version of stacktrace_x86-inl.h that has heuristic support for
+// dealing with FPO, similar to what WinDbg does (see
+// http://www.nynaeve.net/?p=97).  There are (non-working) examples of
+// these approaches, complete with TODOs, in stacktrace_win32-inl.h#1
+//
+// The solution we've ended up doing is to call the undocumented
+// windows function RtlCaptureStackBackTrace, which probably doesn't
+// work with FPO but at least is fast, and doesn't require a symbol
+// server.
+//
+// This code is inspired by a patch from David Vitek:
+//   https://code.google.com/p/google-perftools/issues/detail?id=83
+
+#ifndef ABSL_DEBUGGING_INTERNAL_STACKTRACE_WIN32_INL_H_
+#define ABSL_DEBUGGING_INTERNAL_STACKTRACE_WIN32_INL_H_
+
+#include <windows.h>    // for GetProcAddress and GetModuleHandle
+#include <cassert>
+
+typedef USHORT NTAPI RtlCaptureStackBackTrace_Function(
+    IN ULONG frames_to_skip,
+    IN ULONG frames_to_capture,
+    OUT PVOID *backtrace,
+    OUT PULONG backtrace_hash);
+
+// It is not possible to load RtlCaptureStackBackTrace at static init time in
+// UWP. CaptureStackBackTrace is the public version of RtlCaptureStackBackTrace
+#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP) && \
+    !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
+static RtlCaptureStackBackTrace_Function* const RtlCaptureStackBackTrace_fn =
+    &::CaptureStackBackTrace;
+#else
+// Load the function we need at static init time, where we don't have
+// to worry about someone else holding the loader's lock.
+static RtlCaptureStackBackTrace_Function* const RtlCaptureStackBackTrace_fn =
+    (RtlCaptureStackBackTrace_Function*)GetProcAddress(
+        GetModuleHandleA("ntdll.dll"), "RtlCaptureStackBackTrace");
+#endif  // WINAPI_PARTITION_APP && !WINAPI_PARTITION_DESKTOP
+
+template <bool IS_STACK_FRAMES, bool IS_WITH_CONTEXT>
+static int UnwindImpl(void** result, int* sizes, int max_depth, int skip_count,
+                      const void*, int* min_dropped_frames) {
+  int n = 0;
+  if (!RtlCaptureStackBackTrace_fn) {
+    // can't find a stacktrace with no function to call
+  } else {
+    n = (int)RtlCaptureStackBackTrace_fn(skip_count + 2, max_depth, result, 0);
+  }
+  if (IS_STACK_FRAMES) {
+    // No implementation for finding out the stack frame sizes yet.
+    memset(sizes, 0, sizeof(*sizes) * n);
+  }
+  if (min_dropped_frames != nullptr) {
+    // Not implemented.
+    *min_dropped_frames = 0;
+  }
+  return n;
+}
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace debugging_internal {
+bool StackTraceWorksForTest() {
+  return false;
+}
+}  // namespace debugging_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#endif  // ABSL_DEBUGGING_INTERNAL_STACKTRACE_WIN32_INL_H_
diff --git a/src/absl/debugging/internal/stacktrace_x86-inl.inc b/src/absl/debugging/internal/stacktrace_x86-inl.inc
new file mode 100644 (file)
index 0000000..bc320ff
--- /dev/null
@@ -0,0 +1,346 @@
+// Copyright 2017 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// Produce stack trace
+
+#ifndef ABSL_DEBUGGING_INTERNAL_STACKTRACE_X86_INL_INC_
+#define ABSL_DEBUGGING_INTERNAL_STACKTRACE_X86_INL_INC_
+
+#if defined(__linux__) && (defined(__i386__) || defined(__x86_64__))
+#include <ucontext.h>  // for ucontext_t
+#endif
+
+#if !defined(_WIN32)
+#include <unistd.h>
+#endif
+
+#include <cassert>
+#include <cstdint>
+
+#include "absl/base/macros.h"
+#include "absl/base/port.h"
+#include "absl/debugging/internal/address_is_readable.h"
+#include "absl/debugging/internal/vdso_support.h"  // a no-op on non-elf or non-glibc systems
+#include "absl/debugging/stacktrace.h"
+
+#include "absl/base/internal/raw_logging.h"
+
+using absl::debugging_internal::AddressIsReadable;
+
+#if defined(__linux__) && defined(__i386__)
+// Count "push %reg" instructions in VDSO __kernel_vsyscall(),
+// preceeding "syscall" or "sysenter".
+// If __kernel_vsyscall uses frame pointer, answer 0.
+//
+// kMaxBytes tells how many instruction bytes of __kernel_vsyscall
+// to analyze before giving up. Up to kMaxBytes+1 bytes of
+// instructions could be accessed.
+//
+// Here are known __kernel_vsyscall instruction sequences:
+//
+// SYSENTER (linux-2.6.26/arch/x86/vdso/vdso32/sysenter.S).
+// Used on Intel.
+//  0xffffe400 <__kernel_vsyscall+0>:       push   %ecx
+//  0xffffe401 <__kernel_vsyscall+1>:       push   %edx
+//  0xffffe402 <__kernel_vsyscall+2>:       push   %ebp
+//  0xffffe403 <__kernel_vsyscall+3>:       mov    %esp,%ebp
+//  0xffffe405 <__kernel_vsyscall+5>:       sysenter
+//
+// SYSCALL (see linux-2.6.26/arch/x86/vdso/vdso32/syscall.S).
+// Used on AMD.
+//  0xffffe400 <__kernel_vsyscall+0>:       push   %ebp
+//  0xffffe401 <__kernel_vsyscall+1>:       mov    %ecx,%ebp
+//  0xffffe403 <__kernel_vsyscall+3>:       syscall
+//
+
+// The sequence below isn't actually expected in Google fleet,
+// here only for completeness. Remove this comment from OSS release.
+
+// i386 (see linux-2.6.26/arch/x86/vdso/vdso32/int80.S)
+//  0xffffe400 <__kernel_vsyscall+0>:       int $0x80
+//  0xffffe401 <__kernel_vsyscall+1>:       ret
+//
+static const int kMaxBytes = 10;
+
+// We use assert()s instead of DCHECK()s -- this is too low level
+// for DCHECK().
+
+static int CountPushInstructions(const unsigned char *const addr) {
+  int result = 0;
+  for (int i = 0; i < kMaxBytes; ++i) {
+    if (addr[i] == 0x89) {
+      // "mov reg,reg"
+      if (addr[i + 1] == 0xE5) {
+        // Found "mov %esp,%ebp".
+        return 0;
+      }
+      ++i;  // Skip register encoding byte.
+    } else if (addr[i] == 0x0F &&
+               (addr[i + 1] == 0x34 || addr[i + 1] == 0x05)) {
+      // Found "sysenter" or "syscall".
+      return result;
+    } else if ((addr[i] & 0xF0) == 0x50) {
+      // Found "push %reg".
+      ++result;
+    } else if (addr[i] == 0xCD && addr[i + 1] == 0x80) {
+      // Found "int $0x80"
+      assert(result == 0);
+      return 0;
+    } else {
+      // Unexpected instruction.
+      assert(false && "unexpected instruction in __kernel_vsyscall");
+      return 0;
+    }
+  }
+  // Unexpected: didn't find SYSENTER or SYSCALL in
+  // [__kernel_vsyscall, __kernel_vsyscall + kMaxBytes) interval.
+  assert(false && "did not find SYSENTER or SYSCALL in __kernel_vsyscall");
+  return 0;
+}
+#endif
+
+// Assume stack frames larger than 100,000 bytes are bogus.
+static const int kMaxFrameBytes = 100000;
+
+// Returns the stack frame pointer from signal context, 0 if unknown.
+// vuc is a ucontext_t *.  We use void* to avoid the use
+// of ucontext_t on non-POSIX systems.
+static uintptr_t GetFP(const void *vuc) {
+#if !defined(__linux__)
+  static_cast<void>(vuc);  // Avoid an unused argument compiler warning.
+#else
+  if (vuc != nullptr) {
+    auto *uc = reinterpret_cast<const ucontext_t *>(vuc);
+#if defined(__i386__)
+    const auto bp = uc->uc_mcontext.gregs[REG_EBP];
+    const auto sp = uc->uc_mcontext.gregs[REG_ESP];
+#elif defined(__x86_64__)
+    const auto bp = uc->uc_mcontext.gregs[REG_RBP];
+    const auto sp = uc->uc_mcontext.gregs[REG_RSP];
+#else
+    const uintptr_t bp = 0;
+    const uintptr_t sp = 0;
+#endif
+    // Sanity-check that the base pointer is valid.  It should be as long as
+    // SHRINK_WRAP_FRAME_POINTER is not set, but it's possible that some code in
+    // the process is compiled with --copt=-fomit-frame-pointer or
+    // --copt=-momit-leaf-frame-pointer.
+    //
+    // TODO(bcmills): -momit-leaf-frame-pointer is currently the default
+    // behavior when building with clang.  Talk to the C++ toolchain team about
+    // fixing that.
+    if (bp >= sp && bp - sp <= kMaxFrameBytes) return bp;
+
+    // If bp isn't a plausible frame pointer, return the stack pointer instead.
+    // If we're lucky, it points to the start of a stack frame; otherwise, we'll
+    // get one frame of garbage in the stack trace and fail the sanity check on
+    // the next iteration.
+    return sp;
+  }
+#endif
+  return 0;
+}
+
+// Given a pointer to a stack frame, locate and return the calling
+// stackframe, or return null if no stackframe can be found. Perform sanity
+// checks (the strictness of which is controlled by the boolean parameter
+// "STRICT_UNWINDING") to reduce the chance that a bad pointer is returned.
+template <bool STRICT_UNWINDING, bool WITH_CONTEXT>
+ABSL_ATTRIBUTE_NO_SANITIZE_ADDRESS  // May read random elements from stack.
+ABSL_ATTRIBUTE_NO_SANITIZE_MEMORY   // May read random elements from stack.
+static void **NextStackFrame(void **old_fp, const void *uc) {
+  void **new_fp = (void **)*old_fp;
+
+#if defined(__linux__) && defined(__i386__)
+  if (WITH_CONTEXT && uc != nullptr) {
+    // How many "push %reg" instructions are there at __kernel_vsyscall?
+    // This is constant for a given kernel and processor, so compute
+    // it only once.
+    static int num_push_instructions = -1;  // Sentinel: not computed yet.
+    // Initialize with sentinel value: __kernel_rt_sigreturn can not possibly
+    // be there.
+    static const unsigned char *kernel_rt_sigreturn_address = nullptr;
+    static const unsigned char *kernel_vsyscall_address = nullptr;
+    if (num_push_instructions == -1) {
+#ifdef ABSL_HAVE_VDSO_SUPPORT
+      absl::debugging_internal::VDSOSupport vdso;
+      if (vdso.IsPresent()) {
+        absl::debugging_internal::VDSOSupport::SymbolInfo
+            rt_sigreturn_symbol_info;
+        absl::debugging_internal::VDSOSupport::SymbolInfo vsyscall_symbol_info;
+        if (!vdso.LookupSymbol("__kernel_rt_sigreturn", "LINUX_2.5", STT_FUNC,
+                               &rt_sigreturn_symbol_info) ||
+            !vdso.LookupSymbol("__kernel_vsyscall", "LINUX_2.5", STT_FUNC,
+                               &vsyscall_symbol_info) ||
+            rt_sigreturn_symbol_info.address == nullptr ||
+            vsyscall_symbol_info.address == nullptr) {
+          // Unexpected: 32-bit VDSO is present, yet one of the expected
+          // symbols is missing or null.
+          assert(false && "VDSO is present, but doesn't have expected symbols");
+          num_push_instructions = 0;
+        } else {
+          kernel_rt_sigreturn_address =
+              reinterpret_cast<const unsigned char *>(
+                  rt_sigreturn_symbol_info.address);
+          kernel_vsyscall_address =
+              reinterpret_cast<const unsigned char *>(
+                  vsyscall_symbol_info.address);
+          num_push_instructions =
+              CountPushInstructions(kernel_vsyscall_address);
+        }
+      } else {
+        num_push_instructions = 0;
+      }
+#else  // ABSL_HAVE_VDSO_SUPPORT
+      num_push_instructions = 0;
+#endif  // ABSL_HAVE_VDSO_SUPPORT
+    }
+    if (num_push_instructions != 0 && kernel_rt_sigreturn_address != nullptr &&
+        old_fp[1] == kernel_rt_sigreturn_address) {
+      const ucontext_t *ucv = static_cast<const ucontext_t *>(uc);
+      // This kernel does not use frame pointer in its VDSO code,
+      // and so %ebp is not suitable for unwinding.
+      void **const reg_ebp =
+          reinterpret_cast<void **>(ucv->uc_mcontext.gregs[REG_EBP]);
+      const unsigned char *const reg_eip =
+          reinterpret_cast<unsigned char *>(ucv->uc_mcontext.gregs[REG_EIP]);
+      if (new_fp == reg_ebp && kernel_vsyscall_address <= reg_eip &&
+          reg_eip - kernel_vsyscall_address < kMaxBytes) {
+        // We "stepped up" to __kernel_vsyscall, but %ebp is not usable.
+        // Restore from 'ucv' instead.
+        void **const reg_esp =
+            reinterpret_cast<void **>(ucv->uc_mcontext.gregs[REG_ESP]);
+        // Check that alleged %esp is not null and is reasonably aligned.
+        if (reg_esp &&
+            ((uintptr_t)reg_esp & (sizeof(reg_esp) - 1)) == 0) {
+          // Check that alleged %esp is actually readable. This is to prevent
+          // "double fault" in case we hit the first fault due to e.g. stack
+          // corruption.
+          void *const reg_esp2 = reg_esp[num_push_instructions - 1];
+          if (AddressIsReadable(reg_esp2)) {
+            // Alleged %esp is readable, use it for further unwinding.
+            new_fp = reinterpret_cast<void **>(reg_esp2);
+          }
+        }
+      }
+    }
+  }
+#endif
+
+  const uintptr_t old_fp_u = reinterpret_cast<uintptr_t>(old_fp);
+  const uintptr_t new_fp_u = reinterpret_cast<uintptr_t>(new_fp);
+
+  // Check that the transition from frame pointer old_fp to frame
+  // pointer new_fp isn't clearly bogus.  Skip the checks if new_fp
+  // matches the signal context, so that we don't skip out early when
+  // using an alternate signal stack.
+  //
+  // TODO(bcmills): The GetFP call should be completely unnecessary when
+  // SHRINK_WRAP_FRAME_POINTER is set (because we should be back in the thread's
+  // stack by this point), but it is empirically still needed (e.g. when the
+  // stack includes a call to abort).  unw_get_reg returns UNW_EBADREG for some
+  // frames.  Figure out why GetValidFrameAddr and/or libunwind isn't doing what
+  // it's supposed to.
+  if (STRICT_UNWINDING &&
+      (!WITH_CONTEXT || uc == nullptr || new_fp_u != GetFP(uc))) {
+    // With the stack growing downwards, older stack frame must be
+    // at a greater address that the current one.
+    if (new_fp_u <= old_fp_u) return nullptr;
+    if (new_fp_u - old_fp_u > kMaxFrameBytes) return nullptr;
+  } else {
+    if (new_fp == nullptr) return nullptr;  // skip AddressIsReadable() below
+    // In the non-strict mode, allow discontiguous stack frames.
+    // (alternate-signal-stacks for example).
+    if (new_fp == old_fp) return nullptr;
+  }
+
+  if (new_fp_u & (sizeof(void *) - 1)) return nullptr;
+#ifdef __i386__
+  // On 32-bit machines, the stack pointer can be very close to
+  // 0xffffffff, so we explicitly check for a pointer into the
+  // last two pages in the address space
+  if (new_fp_u >= 0xffffe000) return nullptr;
+#endif
+#if !defined(_WIN32)
+  if (!STRICT_UNWINDING) {
+    // Lax sanity checks cause a crash in 32-bit tcmalloc/crash_reason_test
+    // on AMD-based machines with VDSO-enabled kernels.
+    // Make an extra sanity check to insure new_fp is readable.
+    // Note: NextStackFrame<false>() is only called while the program
+    //       is already on its last leg, so it's ok to be slow here.
+
+    if (!AddressIsReadable(new_fp)) {
+      return nullptr;
+    }
+  }
+#endif
+  return new_fp;
+}
+
+template <bool IS_STACK_FRAMES, bool IS_WITH_CONTEXT>
+ABSL_ATTRIBUTE_NO_SANITIZE_ADDRESS  // May read random elements from stack.
+ABSL_ATTRIBUTE_NO_SANITIZE_MEMORY   // May read random elements from stack.
+ABSL_ATTRIBUTE_NOINLINE
+static int UnwindImpl(void **result, int *sizes, int max_depth, int skip_count,
+                      const void *ucp, int *min_dropped_frames) {
+  int n = 0;
+  void **fp = reinterpret_cast<void **>(__builtin_frame_address(0));
+
+  while (fp && n < max_depth) {
+    if (*(fp + 1) == reinterpret_cast<void *>(0)) {
+      // In 64-bit code, we often see a frame that
+      // points to itself and has a return address of 0.
+      break;
+    }
+    void **next_fp = NextStackFrame<!IS_STACK_FRAMES, IS_WITH_CONTEXT>(fp, ucp);
+    if (skip_count > 0) {
+      skip_count--;
+    } else {
+      result[n] = *(fp + 1);
+      if (IS_STACK_FRAMES) {
+        if (next_fp > fp) {
+          sizes[n] = (uintptr_t)next_fp - (uintptr_t)fp;
+        } else {
+          // A frame-size of 0 is used to indicate unknown frame size.
+          sizes[n] = 0;
+        }
+      }
+      n++;
+    }
+    fp = next_fp;
+  }
+  if (min_dropped_frames != nullptr) {
+    // Implementation detail: we clamp the max of frames we are willing to
+    // count, so as not to spend too much time in the loop below.
+    const int kMaxUnwind = 1000;
+    int j = 0;
+    for (; fp != nullptr && j < kMaxUnwind; j++) {
+      fp = NextStackFrame<!IS_STACK_FRAMES, IS_WITH_CONTEXT>(fp, ucp);
+    }
+    *min_dropped_frames = j;
+  }
+  return n;
+}
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace debugging_internal {
+bool StackTraceWorksForTest() {
+  return true;
+}
+}  // namespace debugging_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#endif  // ABSL_DEBUGGING_INTERNAL_STACKTRACE_X86_INL_INC_
diff --git a/src/absl/debugging/internal/symbolize.h b/src/absl/debugging/internal/symbolize.h
new file mode 100644 (file)
index 0000000..4f26130
--- /dev/null
@@ -0,0 +1,147 @@
+// Copyright 2018 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// This file contains internal parts of the Abseil symbolizer.
+// Do not depend on the anything in this file, it may change at anytime.
+
+#ifndef ABSL_DEBUGGING_INTERNAL_SYMBOLIZE_H_
+#define ABSL_DEBUGGING_INTERNAL_SYMBOLIZE_H_
+
+#ifdef __cplusplus
+
+#include <cstddef>
+#include <cstdint>
+
+#include "absl/base/config.h"
+#include "absl/strings/string_view.h"
+
+#ifdef ABSL_INTERNAL_HAVE_ELF_SYMBOLIZE
+#error ABSL_INTERNAL_HAVE_ELF_SYMBOLIZE cannot be directly set
+#elif defined(__ELF__) && defined(__GLIBC__) && !defined(__native_client__) && \
+    !defined(__asmjs__) && !defined(__wasm__)
+#define ABSL_INTERNAL_HAVE_ELF_SYMBOLIZE 1
+
+#include <elf.h>
+#include <link.h>  // For ElfW() macro.
+#include <functional>
+#include <string>
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace debugging_internal {
+
+// Iterates over all sections, invoking callback on each with the section name
+// and the section header.
+//
+// Returns true on success; otherwise returns false in case of errors.
+//
+// This is not async-signal-safe.
+bool ForEachSection(int fd,
+                    const std::function<bool(absl::string_view name,
+                                             const ElfW(Shdr) &)>& callback);
+
+// Gets the section header for the given name, if it exists. Returns true on
+// success. Otherwise, returns false.
+bool GetSectionHeaderByName(int fd, const char *name, size_t name_len,
+                            ElfW(Shdr) *out);
+
+}  // namespace debugging_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#endif  // ABSL_INTERNAL_HAVE_ELF_SYMBOLIZE
+
+#ifdef ABSL_INTERNAL_HAVE_DARWIN_SYMBOLIZE
+#error ABSL_INTERNAL_HAVE_DARWIN_SYMBOLIZE cannot be directly set
+#elif defined(__APPLE__)
+#define ABSL_INTERNAL_HAVE_DARWIN_SYMBOLIZE 1
+#endif
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace debugging_internal {
+
+struct SymbolDecoratorArgs {
+  // The program counter we are getting symbolic name for.
+  const void *pc;
+  // 0 for main executable, load address for shared libraries.
+  ptrdiff_t relocation;
+  // Read-only file descriptor for ELF image covering "pc",
+  // or -1 if no such ELF image exists in /proc/self/maps.
+  int fd;
+  // Output buffer, size.
+  // Note: the buffer may not be empty -- default symbolizer may have already
+  // produced some output, and earlier decorators may have adorned it in
+  // some way. You are free to replace or augment the contents (within the
+  // symbol_buf_size limit).
+  char *const symbol_buf;
+  size_t symbol_buf_size;
+  // Temporary scratch space, size.
+  // Use that space in preference to allocating your own stack buffer to
+  // conserve stack.
+  char *const tmp_buf;
+  size_t tmp_buf_size;
+  // User-provided argument
+  void* arg;
+};
+using SymbolDecorator = void (*)(const SymbolDecoratorArgs *);
+
+// Installs a function-pointer as a decorator. Returns a value less than zero
+// if the system cannot install the decorator. Otherwise, returns a unique
+// identifier corresponding to the decorator. This identifier can be used to
+// uninstall the decorator - See RemoveSymbolDecorator() below.
+int InstallSymbolDecorator(SymbolDecorator decorator, void* arg);
+
+// Removes a previously installed function-pointer decorator. Parameter "ticket"
+// is the return-value from calling InstallSymbolDecorator().
+bool RemoveSymbolDecorator(int ticket);
+
+// Remove all installed decorators.  Returns true if successful, false if
+// symbolization is currently in progress.
+bool RemoveAllSymbolDecorators(void);
+
+// Registers an address range to a file mapping.
+//
+// Preconditions:
+//   start <= end
+//   filename != nullptr
+//
+// Returns true if the file was successfully registered.
+bool RegisterFileMappingHint(const void* start, const void* end,
+                             uint64_t offset, const char* filename);
+
+// Looks up the file mapping registered by RegisterFileMappingHint for an
+// address range. If there is one, the file name is stored in *filename and
+// *start and *end are modified to reflect the registered mapping. Returns
+// whether any hint was found.
+bool GetFileMappingHint(const void** start, const void** end, uint64_t* offset,
+                        const char** filename);
+
+}  // namespace debugging_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#endif  // __cplusplus
+
+#include <stdbool.h>
+
+#ifdef __cplusplus
+extern "C"
+#endif  // __cplusplus
+
+    bool
+    AbslInternalGetFileMappingHint(const void** start, const void** end,
+                                   uint64_t* offset, const char** filename);
+
+#endif  // ABSL_DEBUGGING_INTERNAL_SYMBOLIZE_H_
diff --git a/src/absl/debugging/internal/vdso_support.cc b/src/absl/debugging/internal/vdso_support.cc
new file mode 100644 (file)
index 0000000..6be16d9
--- /dev/null
@@ -0,0 +1,173 @@
+// Copyright 2017 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// Allow dynamic symbol lookup in the kernel VDSO page.
+//
+// VDSOSupport -- a class representing kernel VDSO (if present).
+
+#include "absl/debugging/internal/vdso_support.h"
+
+#ifdef ABSL_HAVE_VDSO_SUPPORT     // defined in vdso_support.h
+
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/syscall.h>
+#include <unistd.h>
+
+#if __GLIBC_PREREQ(2, 16)  // GLIBC-2.16 implements getauxval.
+#include <sys/auxv.h>
+#endif
+
+#include "absl/base/dynamic_annotations.h"
+#include "absl/base/internal/raw_logging.h"
+#include "absl/base/port.h"
+
+#ifndef AT_SYSINFO_EHDR
+#define AT_SYSINFO_EHDR 33  // for crosstoolv10
+#endif
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace debugging_internal {
+
+ABSL_CONST_INIT
+std::atomic<const void *> VDSOSupport::vdso_base_(
+    debugging_internal::ElfMemImage::kInvalidBase);
+
+std::atomic<VDSOSupport::GetCpuFn> VDSOSupport::getcpu_fn_(&InitAndGetCPU);
+VDSOSupport::VDSOSupport()
+    // If vdso_base_ is still set to kInvalidBase, we got here
+    // before VDSOSupport::Init has been called. Call it now.
+    : image_(vdso_base_.load(std::memory_order_relaxed) ==
+                     debugging_internal::ElfMemImage::kInvalidBase
+                 ? Init()
+                 : vdso_base_.load(std::memory_order_relaxed)) {}
+
+// NOTE: we can't use GoogleOnceInit() below, because we can be
+// called by tcmalloc, and none of the *once* stuff may be functional yet.
+//
+// In addition, we hope that the VDSOSupportHelper constructor
+// causes this code to run before there are any threads, and before
+// InitGoogle() has executed any chroot or setuid calls.
+//
+// Finally, even if there is a race here, it is harmless, because
+// the operation should be idempotent.
+const void *VDSOSupport::Init() {
+  const auto kInvalidBase = debugging_internal::ElfMemImage::kInvalidBase;
+#if __GLIBC_PREREQ(2, 16)
+  if (vdso_base_.load(std::memory_order_relaxed) == kInvalidBase) {
+    errno = 0;
+    const void *const sysinfo_ehdr =
+        reinterpret_cast<const void *>(getauxval(AT_SYSINFO_EHDR));
+    if (errno == 0) {
+      vdso_base_.store(sysinfo_ehdr, std::memory_order_relaxed);
+    }
+  }
+#endif  // __GLIBC_PREREQ(2, 16)
+  if (vdso_base_.load(std::memory_order_relaxed) == kInvalidBase) {
+    int fd = open("/proc/self/auxv", O_RDONLY);
+    if (fd == -1) {
+      // Kernel too old to have a VDSO.
+      vdso_base_.store(nullptr, std::memory_order_relaxed);
+      getcpu_fn_.store(&GetCPUViaSyscall, std::memory_order_relaxed);
+      return nullptr;
+    }
+    ElfW(auxv_t) aux;
+    while (read(fd, &aux, sizeof(aux)) == sizeof(aux)) {
+      if (aux.a_type == AT_SYSINFO_EHDR) {
+        vdso_base_.store(reinterpret_cast<void *>(aux.a_un.a_val),
+                         std::memory_order_relaxed);
+        break;
+      }
+    }
+    close(fd);
+    if (vdso_base_.load(std::memory_order_relaxed) == kInvalidBase) {
+      // Didn't find AT_SYSINFO_EHDR in auxv[].
+      vdso_base_.store(nullptr, std::memory_order_relaxed);
+    }
+  }
+  GetCpuFn fn = &GetCPUViaSyscall;  // default if VDSO not present.
+  if (vdso_base_.load(std::memory_order_relaxed)) {
+    VDSOSupport vdso;
+    SymbolInfo info;
+    if (vdso.LookupSymbol("__vdso_getcpu", "LINUX_2.6", STT_FUNC, &info)) {
+      fn = reinterpret_cast<GetCpuFn>(const_cast<void *>(info.address));
+    }
+  }
+  // Subtle: this code runs outside of any locks; prevent compiler
+  // from assigning to getcpu_fn_ more than once.
+  getcpu_fn_.store(fn, std::memory_order_relaxed);
+  return vdso_base_.load(std::memory_order_relaxed);
+}
+
+const void *VDSOSupport::SetBase(const void *base) {
+  ABSL_RAW_CHECK(base != debugging_internal::ElfMemImage::kInvalidBase,
+                 "internal error");
+  const void *old_base = vdso_base_.load(std::memory_order_relaxed);
+  vdso_base_.store(base, std::memory_order_relaxed);
+  image_.Init(base);
+  // Also reset getcpu_fn_, so GetCPU could be tested with simulated VDSO.
+  getcpu_fn_.store(&InitAndGetCPU, std::memory_order_relaxed);
+  return old_base;
+}
+
+bool VDSOSupport::LookupSymbol(const char *name,
+                               const char *version,
+                               int type,
+                               SymbolInfo *info) const {
+  return image_.LookupSymbol(name, version, type, info);
+}
+
+bool VDSOSupport::LookupSymbolByAddress(const void *address,
+                                        SymbolInfo *info_out) const {
+  return image_.LookupSymbolByAddress(address, info_out);
+}
+
+// NOLINT on 'long' because this routine mimics kernel api.
+long VDSOSupport::GetCPUViaSyscall(unsigned *cpu,  // NOLINT(runtime/int)
+                                   void *, void *) {
+#ifdef SYS_getcpu
+  return syscall(SYS_getcpu, cpu, nullptr, nullptr);
+#else
+  // x86_64 never implemented sys_getcpu(), except as a VDSO call.
+  static_cast<void>(cpu);  // Avoid an unused argument compiler warning.
+  errno = ENOSYS;
+  return -1;
+#endif
+}
+
+// Use fast __vdso_getcpu if available.
+long VDSOSupport::InitAndGetCPU(unsigned *cpu,  // NOLINT(runtime/int)
+                                void *x, void *y) {
+  Init();
+  GetCpuFn fn = getcpu_fn_.load(std::memory_order_relaxed);
+  ABSL_RAW_CHECK(fn != &InitAndGetCPU, "Init() did not set getcpu_fn_");
+  return (*fn)(cpu, x, y);
+}
+
+// This function must be very fast, and may be called from very
+// low level (e.g. tcmalloc). Hence I avoid things like
+// GoogleOnceInit() and ::operator new.
+ABSL_ATTRIBUTE_NO_SANITIZE_MEMORY
+int GetCPU() {
+  unsigned cpu;
+  int ret_code = (*VDSOSupport::getcpu_fn_)(&cpu, nullptr, nullptr);
+  return ret_code == 0 ? cpu : ret_code;
+}
+
+}  // namespace debugging_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#endif  // ABSL_HAVE_VDSO_SUPPORT
diff --git a/src/absl/debugging/internal/vdso_support.h b/src/absl/debugging/internal/vdso_support.h
new file mode 100644 (file)
index 0000000..6562c6c
--- /dev/null
@@ -0,0 +1,158 @@
+//
+// Copyright 2017 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// Allow dynamic symbol lookup in the kernel VDSO page.
+//
+// VDSO stands for "Virtual Dynamic Shared Object" -- a page of
+// executable code, which looks like a shared library, but doesn't
+// necessarily exist anywhere on disk, and which gets mmap()ed into
+// every process by kernels which support VDSO, such as 2.6.x for 32-bit
+// executables, and 2.6.24 and above for 64-bit executables.
+//
+// More details could be found here:
+// http://www.trilithium.com/johan/2005/08/linux-gate/
+//
+// VDSOSupport -- a class representing kernel VDSO (if present).
+//
+// Example usage:
+//  VDSOSupport vdso;
+//  VDSOSupport::SymbolInfo info;
+//  typedef (*FN)(unsigned *, void *, void *);
+//  FN fn = nullptr;
+//  if (vdso.LookupSymbol("__vdso_getcpu", "LINUX_2.6", STT_FUNC, &info)) {
+//     fn = reinterpret_cast<FN>(info.address);
+//  }
+
+#ifndef ABSL_DEBUGGING_INTERNAL_VDSO_SUPPORT_H_
+#define ABSL_DEBUGGING_INTERNAL_VDSO_SUPPORT_H_
+
+#include <atomic>
+
+#include "absl/base/attributes.h"
+#include "absl/debugging/internal/elf_mem_image.h"
+
+#ifdef ABSL_HAVE_ELF_MEM_IMAGE
+
+#ifdef ABSL_HAVE_VDSO_SUPPORT
+#error ABSL_HAVE_VDSO_SUPPORT cannot be directly set
+#else
+#define ABSL_HAVE_VDSO_SUPPORT 1
+#endif
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace debugging_internal {
+
+// NOTE: this class may be used from within tcmalloc, and can not
+// use any memory allocation routines.
+class VDSOSupport {
+ public:
+  VDSOSupport();
+
+  typedef ElfMemImage::SymbolInfo SymbolInfo;
+  typedef ElfMemImage::SymbolIterator SymbolIterator;
+
+  // On PowerPC64 VDSO symbols can either be of type STT_FUNC or STT_NOTYPE
+  // depending on how the kernel is built.  The kernel is normally built with
+  // STT_NOTYPE type VDSO symbols.  Let's make things simpler first by using a
+  // compile-time constant.
+#ifdef __powerpc64__
+  enum { kVDSOSymbolType = STT_NOTYPE };
+#else
+  enum { kVDSOSymbolType = STT_FUNC };
+#endif
+
+  // Answers whether we have a vdso at all.
+  bool IsPresent() const { return image_.IsPresent(); }
+
+  // Allow to iterate over all VDSO symbols.
+  SymbolIterator begin() const { return image_.begin(); }
+  SymbolIterator end() const { return image_.end(); }
+
+  // Look up versioned dynamic symbol in the kernel VDSO.
+  // Returns false if VDSO is not present, or doesn't contain given
+  // symbol/version/type combination.
+  // If info_out != nullptr, additional details are filled in.
+  bool LookupSymbol(const char *name, const char *version,
+                    int symbol_type, SymbolInfo *info_out) const;
+
+  // Find info about symbol (if any) which overlaps given address.
+  // Returns true if symbol was found; false if VDSO isn't present
+  // or doesn't have a symbol overlapping given address.
+  // If info_out != nullptr, additional details are filled in.
+  bool LookupSymbolByAddress(const void *address, SymbolInfo *info_out) const;
+
+  // Used only for testing. Replace real VDSO base with a mock.
+  // Returns previous value of vdso_base_. After you are done testing,
+  // you are expected to call SetBase() with previous value, in order to
+  // reset state to the way it was.
+  const void *SetBase(const void *s);
+
+  // Computes vdso_base_ and returns it. Should be called as early as
+  // possible; before any thread creation, chroot or setuid.
+  static const void *Init();
+
+ private:
+  // image_ represents VDSO ELF image in memory.
+  // image_.ehdr_ == nullptr implies there is no VDSO.
+  ElfMemImage image_;
+
+  // Cached value of auxv AT_SYSINFO_EHDR, computed once.
+  // This is a tri-state:
+  //   kInvalidBase   => value hasn't been determined yet.
+  //              0   => there is no VDSO.
+  //           else   => vma of VDSO Elf{32,64}_Ehdr.
+  //
+  // When testing with mock VDSO, low bit is set.
+  // The low bit is always available because vdso_base_ is
+  // page-aligned.
+  static std::atomic<const void *> vdso_base_;
+
+  // NOLINT on 'long' because these routines mimic kernel api.
+  // The 'cache' parameter may be used by some versions of the kernel,
+  // and should be nullptr or point to a static buffer containing at
+  // least two 'long's.
+  static long InitAndGetCPU(unsigned *cpu, void *cache,     // NOLINT 'long'.
+                            void *unused);
+  static long GetCPUViaSyscall(unsigned *cpu, void *cache,  // NOLINT 'long'.
+                               void *unused);
+  typedef long (*GetCpuFn)(unsigned *cpu, void *cache,      // NOLINT 'long'.
+                           void *unused);
+
+  // This function pointer may point to InitAndGetCPU,
+  // GetCPUViaSyscall, or __vdso_getcpu at different stages of initialization.
+  ABSL_CONST_INIT static std::atomic<GetCpuFn> getcpu_fn_;
+
+  friend int GetCPU(void);  // Needs access to getcpu_fn_.
+
+  VDSOSupport(const VDSOSupport&) = delete;
+  VDSOSupport& operator=(const VDSOSupport&) = delete;
+};
+
+// Same as sched_getcpu() on later glibc versions.
+// Return current CPU, using (fast) __vdso_getcpu@LINUX_2.6 if present,
+// otherwise use syscall(SYS_getcpu,...).
+// May return -1 with errno == ENOSYS if the kernel doesn't
+// support SYS_getcpu.
+int GetCPU();
+
+}  // namespace debugging_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#endif  // ABSL_HAVE_ELF_MEM_IMAGE
+
+#endif  // ABSL_DEBUGGING_INTERNAL_VDSO_SUPPORT_H_
diff --git a/src/absl/debugging/leak_check.cc b/src/absl/debugging/leak_check.cc
new file mode 100644 (file)
index 0000000..764ca0a
--- /dev/null
@@ -0,0 +1,69 @@
+// Copyright 2017 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// Wrappers around lsan_interface functions.
+// When lsan is not linked in, these functions are not available,
+// therefore Abseil code which depends on these functions is conditioned on the
+// definition of LEAK_SANITIZER.
+#include "absl/base/attributes.h"
+#include "absl/debugging/leak_check.h"
+
+#ifndef LEAK_SANITIZER
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+bool HaveLeakSanitizer() { return false; }
+bool LeakCheckerIsActive() { return false; }
+void DoIgnoreLeak(const void*) { }
+void RegisterLivePointers(const void*, size_t) { }
+void UnRegisterLivePointers(const void*, size_t) { }
+LeakCheckDisabler::LeakCheckDisabler() { }
+LeakCheckDisabler::~LeakCheckDisabler() { }
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#else
+
+#include <sanitizer/lsan_interface.h>
+
+#if ABSL_HAVE_ATTRIBUTE_WEAK
+extern "C" ABSL_ATTRIBUTE_WEAK int __lsan_is_turned_off();
+#endif
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+bool HaveLeakSanitizer() { return true; }
+
+#if ABSL_HAVE_ATTRIBUTE_WEAK
+bool LeakCheckerIsActive() {
+  return !(&__lsan_is_turned_off && __lsan_is_turned_off());
+}
+#else
+bool LeakCheckerIsActive() { return true; }
+#endif
+
+bool FindAndReportLeaks() { return __lsan_do_recoverable_leak_check(); }
+void DoIgnoreLeak(const void* ptr) { __lsan_ignore_object(ptr); }
+void RegisterLivePointers(const void* ptr, size_t size) {
+  __lsan_register_root_region(ptr, size);
+}
+void UnRegisterLivePointers(const void* ptr, size_t size) {
+  __lsan_unregister_root_region(ptr, size);
+}
+LeakCheckDisabler::LeakCheckDisabler() { __lsan_disable(); }
+LeakCheckDisabler::~LeakCheckDisabler() { __lsan_enable(); }
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#endif  // LEAK_SANITIZER
diff --git a/src/absl/debugging/leak_check.h b/src/absl/debugging/leak_check.h
new file mode 100644 (file)
index 0000000..5fc2b05
--- /dev/null
@@ -0,0 +1,133 @@
+// Copyright 2018 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// -----------------------------------------------------------------------------
+// File: leak_check.h
+// -----------------------------------------------------------------------------
+//
+// This file contains functions that affect leak checking behavior within
+// targets built with the LeakSanitizer (LSan), a memory leak detector that is
+// integrated within the AddressSanitizer (ASan) as an additional component, or
+// which can be used standalone. LSan and ASan are included (or can be provided)
+// as additional components for most compilers such as Clang, gcc and MSVC.
+// Note: this leak checking API is not yet supported in MSVC.
+// Leak checking is enabled by default in all ASan builds.
+//
+// See https://github.com/google/sanitizers/wiki/AddressSanitizerLeakSanitizer
+//
+// -----------------------------------------------------------------------------
+#ifndef ABSL_DEBUGGING_LEAK_CHECK_H_
+#define ABSL_DEBUGGING_LEAK_CHECK_H_
+
+#include <cstddef>
+
+#include "absl/base/config.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+
+// HaveLeakSanitizer()
+//
+// Returns true if a leak-checking sanitizer (either ASan or standalone LSan) is
+// currently built into this target.
+bool HaveLeakSanitizer();
+
+// LeakCheckerIsActive()
+//
+// Returns true if a leak-checking sanitizer (either ASan or standalone LSan) is
+// currently built into this target and is turned on.
+bool LeakCheckerIsActive();
+
+// DoIgnoreLeak()
+//
+// Implements `IgnoreLeak()` below. This function should usually
+// not be called directly; calling `IgnoreLeak()` is preferred.
+void DoIgnoreLeak(const void* ptr);
+
+// IgnoreLeak()
+//
+// Instruct the leak sanitizer to ignore leak warnings on the object referenced
+// by the passed pointer, as well as all heap objects transitively referenced
+// by it. The passed object pointer can point to either the beginning of the
+// object or anywhere within it.
+//
+// Example:
+//
+//   static T* obj = IgnoreLeak(new T(...));
+//
+// If the passed `ptr` does not point to an actively allocated object at the
+// time `IgnoreLeak()` is called, the call is a no-op; if it is actively
+// allocated, leak sanitizer will assume this object is referenced even if
+// there is no actual reference in user memory.
+//
+template <typename T>
+T* IgnoreLeak(T* ptr) {
+  DoIgnoreLeak(ptr);
+  return ptr;
+}
+
+// FindAndReportLeaks()
+//
+// If any leaks are detected, prints a leak report and returns true.  This
+// function may be called repeatedly, and does not affect end-of-process leak
+// checking.
+//
+// Example:
+// if (FindAndReportLeaks()) {
+//   ... diagnostic already printed. Exit with failure code.
+//   exit(1)
+// }
+bool FindAndReportLeaks();
+
+// LeakCheckDisabler
+//
+// This helper class indicates that any heap allocations done in the code block
+// covered by the scoped object, which should be allocated on the stack, will
+// not be reported as leaks. Leak check disabling will occur within the code
+// block and any nested function calls within the code block.
+//
+// Example:
+//
+//   void Foo() {
+//     LeakCheckDisabler disabler;
+//     ... code that allocates objects whose leaks should be ignored ...
+//   }
+//
+// REQUIRES: Destructor runs in same thread as constructor
+class LeakCheckDisabler {
+ public:
+  LeakCheckDisabler();
+  LeakCheckDisabler(const LeakCheckDisabler&) = delete;
+  LeakCheckDisabler& operator=(const LeakCheckDisabler&) = delete;
+  ~LeakCheckDisabler();
+};
+
+// RegisterLivePointers()
+//
+// Registers `ptr[0,size-1]` as pointers to memory that is still actively being
+// referenced and for which leak checking should be ignored. This function is
+// useful if you store pointers in mapped memory, for memory ranges that we know
+// are correct but for which normal analysis would flag as leaked code.
+void RegisterLivePointers(const void* ptr, size_t size);
+
+// UnRegisterLivePointers()
+//
+// Deregisters the pointers previously marked as active in
+// `RegisterLivePointers()`, enabling leak checking of those pointers.
+void UnRegisterLivePointers(const void* ptr, size_t size);
+
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#endif  // ABSL_DEBUGGING_LEAK_CHECK_H_
diff --git a/src/absl/debugging/leak_check_disable.cc b/src/absl/debugging/leak_check_disable.cc
new file mode 100644 (file)
index 0000000..924d6e3
--- /dev/null
@@ -0,0 +1,20 @@
+// Copyright 2017 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// Disable LeakSanitizer when this file is linked in.
+// This function overrides __lsan_is_turned_off from sanitizer/lsan_interface.h
+extern "C" int __lsan_is_turned_off();
+extern "C" int __lsan_is_turned_off() {
+  return 1;
+}
diff --git a/src/absl/debugging/stacktrace.cc b/src/absl/debugging/stacktrace.cc
new file mode 100644 (file)
index 0000000..1f7c7d8
--- /dev/null
@@ -0,0 +1,140 @@
+// Copyright 2017 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// Produce stack trace.
+//
+// There are three different ways we can try to get the stack trace:
+//
+// 1) Our hand-coded stack-unwinder.  This depends on a certain stack
+//    layout, which is used by gcc (and those systems using a
+//    gcc-compatible ABI) on x86 systems, at least since gcc 2.95.
+//    It uses the frame pointer to do its work.
+//
+// 2) The libunwind library.  This is still in development, and as a
+//    separate library adds a new dependency, but doesn't need a frame
+//    pointer.  It also doesn't call malloc.
+//
+// 3) The gdb unwinder -- also the one used by the c++ exception code.
+//    It's obviously well-tested, but has a fatal flaw: it can call
+//    malloc() from the unwinder.  This is a problem because we're
+//    trying to use the unwinder to instrument malloc().
+//
+// Note: if you add a new implementation here, make sure it works
+// correctly when absl::GetStackTrace() is called with max_depth == 0.
+// Some code may do that.
+
+#include "absl/debugging/stacktrace.h"
+
+#include <atomic>
+
+#include "absl/base/attributes.h"
+#include "absl/base/port.h"
+#include "absl/debugging/internal/stacktrace_config.h"
+
+#if defined(ABSL_STACKTRACE_INL_HEADER)
+#include ABSL_STACKTRACE_INL_HEADER
+#else
+# error Cannot calculate stack trace: will need to write for your environment
+
+# include "absl/debugging/internal/stacktrace_aarch64-inl.inc"
+# include "absl/debugging/internal/stacktrace_arm-inl.inc"
+# include "absl/debugging/internal/stacktrace_generic-inl.inc"
+# include "absl/debugging/internal/stacktrace_powerpc-inl.inc"
+# include "absl/debugging/internal/stacktrace_unimplemented-inl.inc"
+# include "absl/debugging/internal/stacktrace_win32-inl.inc"
+# include "absl/debugging/internal/stacktrace_x86-inl.inc"
+#endif
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace {
+
+typedef int (*Unwinder)(void**, int*, int, int, const void*, int*);
+std::atomic<Unwinder> custom;
+
+template <bool IS_STACK_FRAMES, bool IS_WITH_CONTEXT>
+ABSL_ATTRIBUTE_ALWAYS_INLINE inline int Unwind(void** result, int* sizes,
+                                               int max_depth, int skip_count,
+                                               const void* uc,
+                                               int* min_dropped_frames) {
+  Unwinder f = &UnwindImpl<IS_STACK_FRAMES, IS_WITH_CONTEXT>;
+  Unwinder g = custom.load(std::memory_order_acquire);
+  if (g != nullptr) f = g;
+
+  // Add 1 to skip count for the unwinder function itself
+  int size = (*f)(result, sizes, max_depth, skip_count + 1, uc,
+                  min_dropped_frames);
+  // To disable tail call to (*f)(...)
+  ABSL_BLOCK_TAIL_CALL_OPTIMIZATION();
+  return size;
+}
+
+}  // anonymous namespace
+
+ABSL_ATTRIBUTE_NOINLINE ABSL_ATTRIBUTE_NO_TAIL_CALL int GetStackFrames(
+    void** result, int* sizes, int max_depth, int skip_count) {
+  return Unwind<true, false>(result, sizes, max_depth, skip_count, nullptr,
+                             nullptr);
+}
+
+ABSL_ATTRIBUTE_NOINLINE ABSL_ATTRIBUTE_NO_TAIL_CALL int
+GetStackFramesWithContext(void** result, int* sizes, int max_depth,
+                          int skip_count, const void* uc,
+                          int* min_dropped_frames) {
+  return Unwind<true, true>(result, sizes, max_depth, skip_count, uc,
+                            min_dropped_frames);
+}
+
+ABSL_ATTRIBUTE_NOINLINE ABSL_ATTRIBUTE_NO_TAIL_CALL int GetStackTrace(
+    void** result, int max_depth, int skip_count) {
+  return Unwind<false, false>(result, nullptr, max_depth, skip_count, nullptr,
+                              nullptr);
+}
+
+ABSL_ATTRIBUTE_NOINLINE ABSL_ATTRIBUTE_NO_TAIL_CALL int
+GetStackTraceWithContext(void** result, int max_depth, int skip_count,
+                         const void* uc, int* min_dropped_frames) {
+  return Unwind<false, true>(result, nullptr, max_depth, skip_count, uc,
+                             min_dropped_frames);
+}
+
+void SetStackUnwinder(Unwinder w) {
+  custom.store(w, std::memory_order_release);
+}
+
+int DefaultStackUnwinder(void** pcs, int* sizes, int depth, int skip,
+                         const void* uc, int* min_dropped_frames) {
+  skip++;  // For this function
+  Unwinder f = nullptr;
+  if (sizes == nullptr) {
+    if (uc == nullptr) {
+      f = &UnwindImpl<false, false>;
+    } else {
+      f = &UnwindImpl<false, true>;
+    }
+  } else {
+    if (uc == nullptr) {
+      f = &UnwindImpl<true, false>;
+    } else {
+      f = &UnwindImpl<true, true>;
+    }
+  }
+  volatile int x = 0;
+  int n = (*f)(pcs, sizes, depth, skip, uc, min_dropped_frames);
+  x = 1; (void) x;  // To disable tail call to (*f)(...)
+  return n;
+}
+
+ABSL_NAMESPACE_END
+}  // namespace absl
diff --git a/src/absl/debugging/stacktrace.h b/src/absl/debugging/stacktrace.h
new file mode 100644 (file)
index 0000000..0ec0ffd
--- /dev/null
@@ -0,0 +1,231 @@
+// Copyright 2018 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// -----------------------------------------------------------------------------
+// File: stacktrace.h
+// -----------------------------------------------------------------------------
+//
+// This file contains routines to extract the current stack trace and associated
+// stack frames. These functions are thread-safe and async-signal-safe.
+//
+// Note that stack trace functionality is platform dependent and requires
+// additional support from the compiler/build system in most cases. (That is,
+// this functionality generally only works on platforms/builds that have been
+// specifically configured to support it.)
+//
+// Note: stack traces in Abseil that do not utilize a symbolizer will result in
+// frames consisting of function addresses rather than human-readable function
+// names. (See symbolize.h for information on symbolizing these values.)
+
+#ifndef ABSL_DEBUGGING_STACKTRACE_H_
+#define ABSL_DEBUGGING_STACKTRACE_H_
+
+#include "absl/base/config.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+
+// GetStackFrames()
+//
+// Records program counter values for up to `max_depth` frames, skipping the
+// most recent `skip_count` stack frames, stores their corresponding values
+// and sizes in `results` and `sizes` buffers, and returns the number of frames
+// stored. (Note that the frame generated for the `absl::GetStackFrames()`
+// routine itself is also skipped.)
+//
+// Example:
+//
+//      main() { foo(); }
+//      foo() { bar(); }
+//      bar() {
+//        void* result[10];
+//        int sizes[10];
+//        int depth = absl::GetStackFrames(result, sizes, 10, 1);
+//      }
+//
+// The current stack frame would consist of three function calls: `bar()`,
+// `foo()`, and then `main()`; however, since the `GetStackFrames()` call sets
+// `skip_count` to `1`, it will skip the frame for `bar()`, the most recently
+// invoked function call. It will therefore return 2 and fill `result` with
+// program counters within the following functions:
+//
+//      result[0]       foo()
+//      result[1]       main()
+//
+// (Note: in practice, a few more entries after `main()` may be added to account
+// for startup processes.)
+//
+// Corresponding stack frame sizes will also be recorded:
+//
+//    sizes[0]       16
+//    sizes[1]       16
+//
+// (Stack frame sizes of `16` above are just for illustration purposes.)
+//
+// Stack frame sizes of 0 or less indicate that those frame sizes couldn't
+// be identified.
+//
+// This routine may return fewer stack frame entries than are
+// available. Also note that `result` and `sizes` must both be non-null.
+extern int GetStackFrames(void** result, int* sizes, int max_depth,
+                          int skip_count);
+
+// GetStackFramesWithContext()
+//
+// Records program counter values obtained from a signal handler. Records
+// program counter values for up to `max_depth` frames, skipping the most recent
+// `skip_count` stack frames, stores their corresponding values and sizes in
+// `results` and `sizes` buffers, and returns the number of frames stored. (Note
+// that the frame generated for the `absl::GetStackFramesWithContext()` routine
+// itself is also skipped.)
+//
+// The `uc` parameter, if non-null, should be a pointer to a `ucontext_t` value
+// passed to a signal handler registered via the `sa_sigaction` field of a
+// `sigaction` struct. (See
+// http://man7.org/linux/man-pages/man2/sigaction.2.html.) The `uc` value may
+// help a stack unwinder to provide a better stack trace under certain
+// conditions. `uc` may safely be null.
+//
+// The `min_dropped_frames` output parameter, if non-null, points to the
+// location to note any dropped stack frames, if any, due to buffer limitations
+// or other reasons. (This value will be set to `0` if no frames were dropped.)
+// The number of total stack frames is guaranteed to be >= skip_count +
+// max_depth + *min_dropped_frames.
+extern int GetStackFramesWithContext(void** result, int* sizes, int max_depth,
+                                     int skip_count, const void* uc,
+                                     int* min_dropped_frames);
+
+// GetStackTrace()
+//
+// Records program counter values for up to `max_depth` frames, skipping the
+// most recent `skip_count` stack frames, stores their corresponding values
+// in `results`, and returns the number of frames
+// stored. Note that this function is similar to `absl::GetStackFrames()`
+// except that it returns the stack trace only, and not stack frame sizes.
+//
+// Example:
+//
+//      main() { foo(); }
+//      foo() { bar(); }
+//      bar() {
+//        void* result[10];
+//        int depth = absl::GetStackTrace(result, 10, 1);
+//      }
+//
+// This produces:
+//
+//      result[0]       foo
+//      result[1]       main
+//           ....       ...
+//
+// `result` must not be null.
+extern int GetStackTrace(void** result, int max_depth, int skip_count);
+
+// GetStackTraceWithContext()
+//
+// Records program counter values obtained from a signal handler. Records
+// program counter values for up to `max_depth` frames, skipping the most recent
+// `skip_count` stack frames, stores their corresponding values in `results`,
+// and returns the number of frames stored. (Note that the frame generated for
+// the `absl::GetStackFramesWithContext()` routine itself is also skipped.)
+//
+// The `uc` parameter, if non-null, should be a pointer to a `ucontext_t` value
+// passed to a signal handler registered via the `sa_sigaction` field of a
+// `sigaction` struct. (See
+// http://man7.org/linux/man-pages/man2/sigaction.2.html.) The `uc` value may
+// help a stack unwinder to provide a better stack trace under certain
+// conditions. `uc` may safely be null.
+//
+// The `min_dropped_frames` output parameter, if non-null, points to the
+// location to note any dropped stack frames, if any, due to buffer limitations
+// or other reasons. (This value will be set to `0` if no frames were dropped.)
+// The number of total stack frames is guaranteed to be >= skip_count +
+// max_depth + *min_dropped_frames.
+extern int GetStackTraceWithContext(void** result, int max_depth,
+                                    int skip_count, const void* uc,
+                                    int* min_dropped_frames);
+
+// SetStackUnwinder()
+//
+// Provides a custom function for unwinding stack frames that will be used in
+// place of the default stack unwinder when invoking the static
+// GetStack{Frames,Trace}{,WithContext}() functions above.
+//
+// The arguments passed to the unwinder function will match the
+// arguments passed to `absl::GetStackFramesWithContext()` except that sizes
+// will be non-null iff the caller is interested in frame sizes.
+//
+// If unwinder is set to null, we revert to the default stack-tracing behavior.
+//
+// *****************************************************************************
+// WARNING
+// *****************************************************************************
+//
+// absl::SetStackUnwinder is not suitable for general purpose use.  It is
+// provided for custom runtimes.
+// Some things to watch out for when calling `absl::SetStackUnwinder()`:
+//
+// (a) The unwinder may be called from within signal handlers and
+// therefore must be async-signal-safe.
+//
+// (b) Even after a custom stack unwinder has been unregistered, other
+// threads may still be in the process of using that unwinder.
+// Therefore do not clean up any state that may be needed by an old
+// unwinder.
+// *****************************************************************************
+extern void SetStackUnwinder(int (*unwinder)(void** pcs, int* sizes,
+                                             int max_depth, int skip_count,
+                                             const void* uc,
+                                             int* min_dropped_frames));
+
+// DefaultStackUnwinder()
+//
+// Records program counter values of up to `max_depth` frames, skipping the most
+// recent `skip_count` stack frames, and stores their corresponding values in
+// `pcs`. (Note that the frame generated for this call itself is also skipped.)
+// This function acts as a generic stack-unwinder; prefer usage of the more
+// specific `GetStack{Trace,Frames}{,WithContext}()` functions above.
+//
+// If you have set your own stack unwinder (with the `SetStackUnwinder()`
+// function above, you can still get the default stack unwinder by calling
+// `DefaultStackUnwinder()`, which will ignore any previously set stack unwinder
+// and use the default one instead.
+//
+// Because this function is generic, only `pcs` is guaranteed to be non-null
+// upon return. It is legal for `sizes`, `uc`, and `min_dropped_frames` to all
+// be null when called.
+//
+// The semantics are the same as the corresponding `GetStack*()` function in the
+// case where `absl::SetStackUnwinder()` was never called. Equivalents are:
+//
+//                       null sizes         |        non-nullptr sizes
+//             |==========================================================|
+//     null uc | GetStackTrace()            | GetStackFrames()            |
+// non-null uc | GetStackTraceWithContext() | GetStackFramesWithContext() |
+//             |==========================================================|
+extern int DefaultStackUnwinder(void** pcs, int* sizes, int max_depth,
+                                int skip_count, const void* uc,
+                                int* min_dropped_frames);
+
+namespace debugging_internal {
+// Returns true for platforms which are expected to have functioning stack trace
+// implementations. Intended to be used for tests which want to exclude
+// verification of logic known to be broken because stack traces are not
+// working.
+extern bool StackTraceWorksForTest();
+}  // namespace debugging_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#endif  // ABSL_DEBUGGING_STACKTRACE_H_
diff --git a/src/absl/debugging/symbolize.cc b/src/absl/debugging/symbolize.cc
new file mode 100644 (file)
index 0000000..2d5235c
--- /dev/null
@@ -0,0 +1,37 @@
+#include "cpp-compat.h"
+// Copyright 2018 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "absl/debugging/symbolize.h"
+
+#ifdef _WIN32
+#include <winapifamily.h>
+#if !(WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP)) || \
+    WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
+// UWP doesn't have access to win32 APIs.
+#define ABSL_INTERNAL_HAVE_SYMBOLIZE_WIN32
+#endif
+#endif
+
+#if defined(ABSL_INTERNAL_HAVE_ELF_SYMBOLIZE)
+#include "absl/debugging/symbolize_elf.inc"
+#elif defined(ABSL_INTERNAL_HAVE_SYMBOLIZE_WIN32)
+// The Windows Symbolizer only works if PDB files containing the debug info
+// are available to the program at runtime.
+#include "absl/debugging/symbolize_win32.inc"
+#elif defined(__APPLE__)
+#include "absl/debugging/symbolize_darwin.inc"
+#else
+#include "absl/debugging/symbolize_unimplemented.inc"
+#endif
diff --git a/src/absl/debugging/symbolize.h b/src/absl/debugging/symbolize.h
new file mode 100644 (file)
index 0000000..43d93a8
--- /dev/null
@@ -0,0 +1,99 @@
+// Copyright 2018 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// -----------------------------------------------------------------------------
+// File: symbolize.h
+// -----------------------------------------------------------------------------
+//
+// This file configures the Abseil symbolizer for use in converting instruction
+// pointer addresses (program counters) into human-readable names (function
+// calls, etc.) within Abseil code.
+//
+// The symbolizer may be invoked from several sources:
+//
+//   * Implicitly, through the installation of an Abseil failure signal handler.
+//     (See failure_signal_handler.h for more information.)
+//   * By calling `Symbolize()` directly on a program counter you obtain through
+//     `absl::GetStackTrace()` or `absl::GetStackFrames()`. (See stacktrace.h
+//     for more information.
+//   * By calling `Symbolize()` directly on a program counter you obtain through
+//     other means (which would be platform-dependent).
+//
+// In all of the above cases, the symbolizer must first be initialized before
+// any program counter values can be symbolized. If you are installing a failure
+// signal handler, initialize the symbolizer before you do so.
+//
+// Example:
+//
+//   int main(int argc, char** argv) {
+//     // Initialize the Symbolizer before installing the failure signal handler
+//     absl::InitializeSymbolizer(argv[0]);
+//
+//     // Now you may install the failure signal handler
+//     absl::FailureSignalHandlerOptions options;
+//     absl::InstallFailureSignalHandler(options);
+//
+//     // Start running your main program
+//     ...
+//     return 0;
+//  }
+//
+#ifndef ABSL_DEBUGGING_SYMBOLIZE_H_
+#define ABSL_DEBUGGING_SYMBOLIZE_H_
+
+#include "absl/debugging/internal/symbolize.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+
+// InitializeSymbolizer()
+//
+// Initializes the program counter symbolizer, given the path of the program
+// (typically obtained through `main()`s `argv[0]`). The Abseil symbolizer
+// allows you to read program counters (instruction pointer values) using their
+// human-readable names within output such as stack traces.
+//
+// Example:
+//
+// int main(int argc, char *argv[]) {
+//   absl::InitializeSymbolizer(argv[0]);
+//   // Now you can use the symbolizer
+// }
+void InitializeSymbolizer(const char* argv0);
+//
+// Symbolize()
+//
+// Symbolizes a program counter (instruction pointer value) `pc` and, on
+// success, writes the name to `out`. The symbol name is demangled, if possible.
+// Note that the symbolized name may be truncated and will be NUL-terminated.
+// Demangling is supported for symbols generated by GCC 3.x or newer). Returns
+// `false` on failure.
+//
+// Example:
+//
+//   // Print a program counter and its symbol name.
+//   static void DumpPCAndSymbol(void *pc) {
+//     char tmp[1024];
+//     const char *symbol = "(unknown)";
+//     if (absl::Symbolize(pc, tmp, sizeof(tmp))) {
+//       symbol = tmp;
+//     }
+//     absl::PrintF("%p  %s\n", pc, symbol);
+//  }
+bool Symbolize(const void *pc, char *out, int out_size);
+
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#endif  // ABSL_DEBUGGING_SYMBOLIZE_H_
diff --git a/src/absl/debugging/symbolize_darwin.inc b/src/absl/debugging/symbolize_darwin.inc
new file mode 100644 (file)
index 0000000..443ce9e
--- /dev/null
@@ -0,0 +1,101 @@
+// Copyright 2020 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <cxxabi.h>
+#include <execinfo.h>
+
+#include <algorithm>
+#include <cstring>
+
+#include "absl/base/internal/raw_logging.h"
+#include "absl/debugging/internal/demangle.h"
+#include "absl/strings/numbers.h"
+#include "absl/strings/str_cat.h"
+#include "absl/strings/string_view.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+
+void InitializeSymbolizer(const char*) {}
+
+namespace debugging_internal {
+namespace {
+
+static std::string GetSymbolString(absl::string_view backtrace_line) {
+  // Example Backtrace lines:
+  // 0   libimaging_shared.dylib             0x018c152a
+  // _ZNSt11_Deque_baseIN3nik7mediadb4PageESaIS2_EE17_M_initialize_mapEm + 3478
+  //
+  // or
+  // 0   libimaging_shared.dylib             0x0000000001895c39
+  // _ZN3nik4util19register_shared_ptrINS_3gpu7TextureEEEvPKvS5_ + 39
+  //
+  // or
+  // 0   mysterious_app                      0x0124000120120009 main + 17
+  auto address_pos = backtrace_line.find(" 0x");
+  if (address_pos == absl::string_view::npos) return std::string();
+  absl::string_view symbol_view = backtrace_line.substr(address_pos + 1);
+
+  auto space_pos = symbol_view.find(" ");
+  if (space_pos == absl::string_view::npos) return std::string();
+  symbol_view = symbol_view.substr(space_pos + 1);  // to mangled symbol
+
+  auto plus_pos = symbol_view.find(" + ");
+  if (plus_pos == absl::string_view::npos) return std::string();
+  symbol_view = symbol_view.substr(0, plus_pos);  // strip remainng
+
+  return std::string(symbol_view);
+}
+
+}  // namespace
+}  // namespace debugging_internal
+
+bool Symbolize(const void* pc, char* out, int out_size) {
+  if (out_size <= 0 || pc == nullptr) {
+    out = nullptr;
+    return false;
+  }
+
+  // This allocates a char* array.
+  char** frame_strings = backtrace_symbols(const_cast<void**>(&pc), 1);
+
+  if (frame_strings == nullptr) return false;
+
+  std::string symbol = debugging_internal::GetSymbolString(frame_strings[0]);
+  free(frame_strings);
+
+  char tmp_buf[1024];
+  if (debugging_internal::Demangle(symbol.c_str(), tmp_buf, sizeof(tmp_buf))) {
+    size_t len = strlen(tmp_buf);
+    if (len + 1 <= static_cast<size_t>(out_size)) {  // +1 for '\0'
+      assert(len < sizeof(tmp_buf));
+      memmove(out, tmp_buf, len + 1);
+    }
+  } else {
+    strncpy(out, symbol.c_str(), out_size);
+  }
+
+  if (out[out_size - 1] != '\0') {
+    // strncpy() does not '\0' terminate when it truncates.
+    static constexpr char kEllipsis[] = "...";
+    int ellipsis_size = std::min<int>(sizeof(kEllipsis) - 1, out_size - 1);
+    memcpy(out + out_size - ellipsis_size - 1, kEllipsis, ellipsis_size);
+    out[out_size - 1] = '\0';
+  }
+
+  return true;
+}
+
+ABSL_NAMESPACE_END
+}  // namespace absl
diff --git a/src/absl/debugging/symbolize_elf.inc b/src/absl/debugging/symbolize_elf.inc
new file mode 100644 (file)
index 0000000..99f25aa
--- /dev/null
@@ -0,0 +1,1560 @@
+// Copyright 2018 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// This library provides Symbolize() function that symbolizes program
+// counters to their corresponding symbol names on linux platforms.
+// This library has a minimal implementation of an ELF symbol table
+// reader (i.e. it doesn't depend on libelf, etc.).
+//
+// The algorithm used in Symbolize() is as follows.
+//
+//   1. Go through a list of maps in /proc/self/maps and find the map
+//   containing the program counter.
+//
+//   2. Open the mapped file and find a regular symbol table inside.
+//   Iterate over symbols in the symbol table and look for the symbol
+//   containing the program counter.  If such a symbol is found,
+//   obtain the symbol name, and demangle the symbol if possible.
+//   If the symbol isn't found in the regular symbol table (binary is
+//   stripped), try the same thing with a dynamic symbol table.
+//
+// Note that Symbolize() is originally implemented to be used in
+// signal handlers, hence it doesn't use malloc() and other unsafe
+// operations.  It should be both thread-safe and async-signal-safe.
+//
+// Implementation note:
+//
+// We don't use heaps but only use stacks.  We want to reduce the
+// stack consumption so that the symbolizer can run on small stacks.
+//
+// Here are some numbers collected with GCC 4.1.0 on x86:
+// - sizeof(Elf32_Sym)  = 16
+// - sizeof(Elf32_Shdr) = 40
+// - sizeof(Elf64_Sym)  = 24
+// - sizeof(Elf64_Shdr) = 64
+//
+// This implementation is intended to be async-signal-safe but uses some
+// functions which are not guaranteed to be so, such as memchr() and
+// memmove().  We assume they are async-signal-safe.
+
+#include <dlfcn.h>
+#include <elf.h>
+#include <fcntl.h>
+#include <link.h>  // For ElfW() macro.
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <algorithm>
+#include <array>
+#include <atomic>
+#include <cerrno>
+#include <cinttypes>
+#include <climits>
+#include <cstdint>
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
+
+#include "absl/base/casts.h"
+#include "absl/base/dynamic_annotations.h"
+#include "absl/base/internal/low_level_alloc.h"
+#include "absl/base/internal/raw_logging.h"
+#include "absl/base/internal/spinlock.h"
+#include "absl/base/port.h"
+#include "absl/debugging/internal/demangle.h"
+#include "absl/debugging/internal/vdso_support.h"
+#include "absl/strings/string_view.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+
+// Value of argv[0]. Used by MaybeInitializeObjFile().
+static char *argv0_value = nullptr;
+
+void InitializeSymbolizer(const char *argv0) {
+#ifdef ABSL_HAVE_VDSO_SUPPORT
+  // We need to make sure VDSOSupport::Init() is called before any setuid or
+  // chroot calls, so InitializeSymbolizer() should be called very early in the
+  // life of a program.
+  absl::debugging_internal::VDSOSupport::Init();
+#endif
+  if (argv0_value != nullptr) {
+    free(argv0_value);
+    argv0_value = nullptr;
+  }
+  if (argv0 != nullptr && argv0[0] != '\0') {
+    argv0_value = strdup(argv0);
+  }
+}
+
+namespace debugging_internal {
+namespace {
+
+// Re-runs fn until it doesn't cause EINTR.
+#define NO_INTR(fn) \
+  do {              \
+  } while ((fn) < 0 && errno == EINTR)
+
+// On Linux, ELF_ST_* are defined in <linux/elf.h>.  To make this portable
+// we define our own ELF_ST_BIND and ELF_ST_TYPE if not available.
+#ifndef ELF_ST_BIND
+#define ELF_ST_BIND(info) (((unsigned char)(info)) >> 4)
+#endif
+
+#ifndef ELF_ST_TYPE
+#define ELF_ST_TYPE(info) (((unsigned char)(info)) & 0xF)
+#endif
+
+// Some platforms use a special .opd section to store function pointers.
+const char kOpdSectionName[] = ".opd";
+
+#if (defined(__powerpc__) && !(_CALL_ELF > 1)) || defined(__ia64)
+// Use opd section for function descriptors on these platforms, the function
+// address is the first word of the descriptor.
+enum { kPlatformUsesOPDSections = 1 };
+#else  // not PPC or IA64
+enum { kPlatformUsesOPDSections = 0 };
+#endif
+
+// This works for PowerPC & IA64 only.  A function descriptor consist of two
+// pointers and the first one is the function's entry.
+const size_t kFunctionDescriptorSize = sizeof(void *) * 2;
+
+const int kMaxDecorators = 10;  // Seems like a reasonable upper limit.
+
+struct InstalledSymbolDecorator {
+  SymbolDecorator fn;
+  void *arg;
+  int ticket;
+};
+
+int g_num_decorators;
+InstalledSymbolDecorator g_decorators[kMaxDecorators];
+
+struct FileMappingHint {
+  const void *start;
+  const void *end;
+  uint64_t offset;
+  const char *filename;
+};
+
+// Protects g_decorators.
+// We are using SpinLock and not a Mutex here, because we may be called
+// from inside Mutex::Lock itself, and it prohibits recursive calls.
+// This happens in e.g. base/stacktrace_syscall_unittest.
+// Moreover, we are using only TryLock(), if the decorator list
+// is being modified (is busy), we skip all decorators, and possibly
+// loose some info. Sorry, that's the best we could do.
+ABSL_CONST_INIT absl::base_internal::SpinLock g_decorators_mu(
+    absl::kConstInit, absl::base_internal::SCHEDULE_KERNEL_ONLY);
+
+const int kMaxFileMappingHints = 8;
+int g_num_file_mapping_hints;
+FileMappingHint g_file_mapping_hints[kMaxFileMappingHints];
+// Protects g_file_mapping_hints.
+ABSL_CONST_INIT absl::base_internal::SpinLock g_file_mapping_mu(
+    absl::kConstInit, absl::base_internal::SCHEDULE_KERNEL_ONLY);
+
+// Async-signal-safe function to zero a buffer.
+// memset() is not guaranteed to be async-signal-safe.
+static void SafeMemZero(void* p, size_t size) {
+  unsigned char *c = static_cast<unsigned char *>(p);
+  while (size--) {
+    *c++ = 0;
+  }
+}
+
+struct ObjFile {
+  ObjFile()
+      : filename(nullptr),
+        start_addr(nullptr),
+        end_addr(nullptr),
+        offset(0),
+        fd(-1),
+        elf_type(-1) {
+    SafeMemZero(&elf_header, sizeof(elf_header));
+    SafeMemZero(&phdr[0], sizeof(phdr));
+  }
+
+  char *filename;
+  const void *start_addr;
+  const void *end_addr;
+  uint64_t offset;
+
+  // The following fields are initialized on the first access to the
+  // object file.
+  int fd;
+  int elf_type;
+  ElfW(Ehdr) elf_header;
+
+  // PT_LOAD program header describing executable code.
+  // Normally we expect just one, but SWIFT binaries have two.
+  std::array<ElfW(Phdr), 2> phdr;
+};
+
+// Build 4-way associative cache for symbols. Within each cache line, symbols
+// are replaced in LRU order.
+enum {
+  ASSOCIATIVITY = 4,
+};
+struct SymbolCacheLine {
+  const void *pc[ASSOCIATIVITY];
+  char *name[ASSOCIATIVITY];
+
+  // age[i] is incremented when a line is accessed. it's reset to zero if the
+  // i'th entry is read.
+  uint32_t age[ASSOCIATIVITY];
+};
+
+// ---------------------------------------------------------------
+// An async-signal-safe arena for LowLevelAlloc
+static std::atomic<base_internal::LowLevelAlloc::Arena *> g_sig_safe_arena;
+
+static base_internal::LowLevelAlloc::Arena *SigSafeArena() {
+  return g_sig_safe_arena.load(std::memory_order_acquire);
+}
+
+static void InitSigSafeArena() {
+  if (SigSafeArena() == nullptr) {
+    base_internal::LowLevelAlloc::Arena *new_arena =
+        base_internal::LowLevelAlloc::NewArena(
+            base_internal::LowLevelAlloc::kAsyncSignalSafe);
+    base_internal::LowLevelAlloc::Arena *old_value = nullptr;
+    if (!g_sig_safe_arena.compare_exchange_strong(old_value, new_arena,
+                                                  std::memory_order_release,
+                                                  std::memory_order_relaxed)) {
+      // We lost a race to allocate an arena; deallocate.
+      base_internal::LowLevelAlloc::DeleteArena(new_arena);
+    }
+  }
+}
+
+// ---------------------------------------------------------------
+// An AddrMap is a vector of ObjFile, using SigSafeArena() for allocation.
+
+class AddrMap {
+ public:
+  AddrMap() : size_(0), allocated_(0), obj_(nullptr) {}
+  ~AddrMap() { base_internal::LowLevelAlloc::Free(obj_); }
+  int Size() const { return size_; }
+  ObjFile *At(int i) { return &obj_[i]; }
+  ObjFile *Add();
+  void Clear();
+
+ private:
+  int size_;       // count of valid elements (<= allocated_)
+  int allocated_;  // count of allocated elements
+  ObjFile *obj_;   // array of allocated_ elements
+  AddrMap(const AddrMap &) = delete;
+  AddrMap &operator=(const AddrMap &) = delete;
+};
+
+void AddrMap::Clear() {
+  for (int i = 0; i != size_; i++) {
+    At(i)->~ObjFile();
+  }
+  size_ = 0;
+}
+
+ObjFile *AddrMap::Add() {
+  if (size_ == allocated_) {
+    int new_allocated = allocated_ * 2 + 50;
+    ObjFile *new_obj_ =
+        static_cast<ObjFile *>(base_internal::LowLevelAlloc::AllocWithArena(
+            new_allocated * sizeof(*new_obj_), SigSafeArena()));
+    if (obj_) {
+      memcpy(new_obj_, obj_, allocated_ * sizeof(*new_obj_));
+      base_internal::LowLevelAlloc::Free(obj_);
+    }
+    obj_ = new_obj_;
+    allocated_ = new_allocated;
+  }
+  return new (&obj_[size_++]) ObjFile;
+}
+
+// ---------------------------------------------------------------
+
+enum FindSymbolResult { SYMBOL_NOT_FOUND = 1, SYMBOL_TRUNCATED, SYMBOL_FOUND };
+
+class Symbolizer {
+ public:
+  Symbolizer();
+  ~Symbolizer();
+  const char *GetSymbol(const void *const pc);
+
+ private:
+  char *CopyString(const char *s) {
+    int len = strlen(s);
+    char *dst = static_cast<char *>(
+        base_internal::LowLevelAlloc::AllocWithArena(len + 1, SigSafeArena()));
+    ABSL_RAW_CHECK(dst != nullptr, "out of memory");
+    memcpy(dst, s, len + 1);
+    return dst;
+  }
+  ObjFile *FindObjFile(const void *const start,
+                       size_t size) ABSL_ATTRIBUTE_NOINLINE;
+  static bool RegisterObjFile(const char *filename,
+                              const void *const start_addr,
+                              const void *const end_addr, uint64_t offset,
+                              void *arg);
+  SymbolCacheLine *GetCacheLine(const void *const pc);
+  const char *FindSymbolInCache(const void *const pc);
+  const char *InsertSymbolInCache(const void *const pc, const char *name);
+  void AgeSymbols(SymbolCacheLine *line);
+  void ClearAddrMap();
+  FindSymbolResult GetSymbolFromObjectFile(const ObjFile &obj,
+                                           const void *const pc,
+                                           const ptrdiff_t relocation,
+                                           char *out, int out_size,
+                                           char *tmp_buf, int tmp_buf_size);
+
+  enum {
+    SYMBOL_BUF_SIZE = 3072,
+    TMP_BUF_SIZE = 1024,
+    SYMBOL_CACHE_LINES = 128,
+  };
+
+  AddrMap addr_map_;
+
+  bool ok_;
+  bool addr_map_read_;
+
+  char symbol_buf_[SYMBOL_BUF_SIZE];
+
+  // tmp_buf_ will be used to store arrays of ElfW(Shdr) and ElfW(Sym)
+  // so we ensure that tmp_buf_ is properly aligned to store either.
+  alignas(16) char tmp_buf_[TMP_BUF_SIZE];
+  static_assert(alignof(ElfW(Shdr)) <= 16,
+                "alignment of tmp buf too small for Shdr");
+  static_assert(alignof(ElfW(Sym)) <= 16,
+                "alignment of tmp buf too small for Sym");
+
+  SymbolCacheLine symbol_cache_[SYMBOL_CACHE_LINES];
+};
+
+static std::atomic<Symbolizer *> g_cached_symbolizer;
+
+}  // namespace
+
+static int SymbolizerSize() {
+#if defined(__wasm__) || defined(__asmjs__)
+  int pagesize = getpagesize();
+#else
+  int pagesize = sysconf(_SC_PAGESIZE);
+#endif
+  return ((sizeof(Symbolizer) - 1) / pagesize + 1) * pagesize;
+}
+
+// Return (and set null) g_cached_symbolized_state if it is not null.
+// Otherwise return a new symbolizer.
+static Symbolizer *AllocateSymbolizer() {
+  InitSigSafeArena();
+  Symbolizer *symbolizer =
+      g_cached_symbolizer.exchange(nullptr, std::memory_order_acquire);
+  if (symbolizer != nullptr) {
+    return symbolizer;
+  }
+  return new (base_internal::LowLevelAlloc::AllocWithArena(
+      SymbolizerSize(), SigSafeArena())) Symbolizer();
+}
+
+// Set g_cached_symbolize_state to s if it is null, otherwise
+// delete s.
+static void FreeSymbolizer(Symbolizer *s) {
+  Symbolizer *old_cached_symbolizer = nullptr;
+  if (!g_cached_symbolizer.compare_exchange_strong(old_cached_symbolizer, s,
+                                                   std::memory_order_release,
+                                                   std::memory_order_relaxed)) {
+    s->~Symbolizer();
+    base_internal::LowLevelAlloc::Free(s);
+  }
+}
+
+Symbolizer::Symbolizer() : ok_(true), addr_map_read_(false) {
+  for (SymbolCacheLine &symbol_cache_line : symbol_cache_) {
+    for (size_t j = 0; j < ABSL_ARRAYSIZE(symbol_cache_line.name); ++j) {
+      symbol_cache_line.pc[j] = nullptr;
+      symbol_cache_line.name[j] = nullptr;
+      symbol_cache_line.age[j] = 0;
+    }
+  }
+}
+
+Symbolizer::~Symbolizer() {
+  for (SymbolCacheLine &symbol_cache_line : symbol_cache_) {
+    for (char *s : symbol_cache_line.name) {
+      base_internal::LowLevelAlloc::Free(s);
+    }
+  }
+  ClearAddrMap();
+}
+
+// We don't use assert() since it's not guaranteed to be
+// async-signal-safe.  Instead we define a minimal assertion
+// macro. So far, we don't need pretty printing for __FILE__, etc.
+#define SAFE_ASSERT(expr) ((expr) ? static_cast<void>(0) : cpp_compat_abort())
+
+// Read up to "count" bytes from file descriptor "fd" into the buffer
+// starting at "buf" while handling short reads and EINTR.  On
+// success, return the number of bytes read.  Otherwise, return -1.
+static ssize_t ReadPersistent(int fd, void *buf, size_t count) {
+  SAFE_ASSERT(fd >= 0);
+  SAFE_ASSERT(count <= SSIZE_MAX);
+  char *buf0 = reinterpret_cast<char *>(buf);
+  size_t num_bytes = 0;
+  while (num_bytes < count) {
+    ssize_t len;
+    NO_INTR(len = read(fd, buf0 + num_bytes, count - num_bytes));
+    if (len < 0) {  // There was an error other than EINTR.
+      ABSL_RAW_LOG(WARNING, "read failed: errno=%d", errno);
+      return -1;
+    }
+    if (len == 0) {  // Reached EOF.
+      break;
+    }
+    num_bytes += len;
+  }
+  SAFE_ASSERT(num_bytes <= count);
+  return static_cast<ssize_t>(num_bytes);
+}
+
+// Read up to "count" bytes from "offset" in the file pointed by file
+// descriptor "fd" into the buffer starting at "buf".  On success,
+// return the number of bytes read.  Otherwise, return -1.
+static ssize_t ReadFromOffset(const int fd, void *buf, const size_t count,
+                              const off_t offset) {
+  off_t off = lseek(fd, offset, SEEK_SET);
+  if (off == (off_t)-1) {
+    ABSL_RAW_LOG(WARNING, "lseek(%d, %ju, SEEK_SET) failed: errno=%d", fd,
+                 static_cast<uintmax_t>(offset), errno);
+    return -1;
+  }
+  return ReadPersistent(fd, buf, count);
+}
+
+// Try reading exactly "count" bytes from "offset" bytes in a file
+// pointed by "fd" into the buffer starting at "buf" while handling
+// short reads and EINTR.  On success, return true. Otherwise, return
+// false.
+static bool ReadFromOffsetExact(const int fd, void *buf, const size_t count,
+                                const off_t offset) {
+  ssize_t len = ReadFromOffset(fd, buf, count, offset);
+  return len >= 0 && static_cast<size_t>(len) == count;
+}
+
+// Returns elf_header.e_type if the file pointed by fd is an ELF binary.
+static int FileGetElfType(const int fd) {
+  ElfW(Ehdr) elf_header;
+  if (!ReadFromOffsetExact(fd, &elf_header, sizeof(elf_header), 0)) {
+    return -1;
+  }
+  if (memcmp(elf_header.e_ident, ELFMAG, SELFMAG) != 0) {
+    return -1;
+  }
+  return elf_header.e_type;
+}
+
+// Read the section headers in the given ELF binary, and if a section
+// of the specified type is found, set the output to this section header
+// and return true.  Otherwise, return false.
+// To keep stack consumption low, we would like this function to not get
+// inlined.
+static ABSL_ATTRIBUTE_NOINLINE bool GetSectionHeaderByType(
+    const int fd, ElfW(Half) sh_num, const off_t sh_offset, ElfW(Word) type,
+    ElfW(Shdr) * out, char *tmp_buf, int tmp_buf_size) {
+  ElfW(Shdr) *buf = reinterpret_cast<ElfW(Shdr) *>(tmp_buf);
+  const int buf_entries = tmp_buf_size / sizeof(buf[0]);
+  const int buf_bytes = buf_entries * sizeof(buf[0]);
+
+  for (int i = 0; i < sh_num;) {
+    const ssize_t num_bytes_left = (sh_num - i) * sizeof(buf[0]);
+    const ssize_t num_bytes_to_read =
+        (buf_bytes > num_bytes_left) ? num_bytes_left : buf_bytes;
+    const off_t offset = sh_offset + i * sizeof(buf[0]);
+    const ssize_t len = ReadFromOffset(fd, buf, num_bytes_to_read, offset);
+    if (len % sizeof(buf[0]) != 0) {
+      ABSL_RAW_LOG(
+          WARNING,
+          "Reading %zd bytes from offset %ju returned %zd which is not a "
+          "multiple of %zu.",
+          num_bytes_to_read, static_cast<uintmax_t>(offset), len,
+          sizeof(buf[0]));
+      return false;
+    }
+    const ssize_t num_headers_in_buf = len / sizeof(buf[0]);
+    SAFE_ASSERT(num_headers_in_buf <= buf_entries);
+    for (int j = 0; j < num_headers_in_buf; ++j) {
+      if (buf[j].sh_type == type) {
+        *out = buf[j];
+        return true;
+      }
+    }
+    i += num_headers_in_buf;
+  }
+  return false;
+}
+
+// There is no particular reason to limit section name to 63 characters,
+// but there has (as yet) been no need for anything longer either.
+const int kMaxSectionNameLen = 64;
+
+bool ForEachSection(int fd,
+                    const std::function<bool(absl::string_view name,
+                                             const ElfW(Shdr) &)> &callback) {
+  ElfW(Ehdr) elf_header;
+  if (!ReadFromOffsetExact(fd, &elf_header, sizeof(elf_header), 0)) {
+    return false;
+  }
+
+  ElfW(Shdr) shstrtab;
+  off_t shstrtab_offset =
+      (elf_header.e_shoff + elf_header.e_shentsize * elf_header.e_shstrndx);
+  if (!ReadFromOffsetExact(fd, &shstrtab, sizeof(shstrtab), shstrtab_offset)) {
+    return false;
+  }
+
+  for (int i = 0; i < elf_header.e_shnum; ++i) {
+    ElfW(Shdr) out;
+    off_t section_header_offset =
+        (elf_header.e_shoff + elf_header.e_shentsize * i);
+    if (!ReadFromOffsetExact(fd, &out, sizeof(out), section_header_offset)) {
+      return false;
+    }
+    off_t name_offset = shstrtab.sh_offset + out.sh_name;
+    char header_name[kMaxSectionNameLen];
+    ssize_t n_read =
+        ReadFromOffset(fd, &header_name, kMaxSectionNameLen, name_offset);
+    if (n_read == -1) {
+      return false;
+    } else if (n_read > kMaxSectionNameLen) {
+      // Long read?
+      return false;
+    }
+
+    absl::string_view name(header_name, strnlen(header_name, n_read));
+    if (!callback(name, out)) {
+      break;
+    }
+  }
+  return true;
+}
+
+// name_len should include terminating '\0'.
+bool GetSectionHeaderByName(int fd, const char *name, size_t name_len,
+                            ElfW(Shdr) * out) {
+  char header_name[kMaxSectionNameLen];
+  if (sizeof(header_name) < name_len) {
+    ABSL_RAW_LOG(WARNING,
+                 "Section name '%s' is too long (%zu); "
+                 "section will not be found (even if present).",
+                 name, name_len);
+    // No point in even trying.
+    return false;
+  }
+
+  ElfW(Ehdr) elf_header;
+  if (!ReadFromOffsetExact(fd, &elf_header, sizeof(elf_header), 0)) {
+    return false;
+  }
+
+  ElfW(Shdr) shstrtab;
+  off_t shstrtab_offset =
+      (elf_header.e_shoff + elf_header.e_shentsize * elf_header.e_shstrndx);
+  if (!ReadFromOffsetExact(fd, &shstrtab, sizeof(shstrtab), shstrtab_offset)) {
+    return false;
+  }
+
+  for (int i = 0; i < elf_header.e_shnum; ++i) {
+    off_t section_header_offset =
+        (elf_header.e_shoff + elf_header.e_shentsize * i);
+    if (!ReadFromOffsetExact(fd, out, sizeof(*out), section_header_offset)) {
+      return false;
+    }
+    off_t name_offset = shstrtab.sh_offset + out->sh_name;
+    ssize_t n_read = ReadFromOffset(fd, &header_name, name_len, name_offset);
+    if (n_read < 0) {
+      return false;
+    } else if (static_cast<size_t>(n_read) != name_len) {
+      // Short read -- name could be at end of file.
+      continue;
+    }
+    if (memcmp(header_name, name, name_len) == 0) {
+      return true;
+    }
+  }
+  return false;
+}
+
+// Compare symbols at in the same address.
+// Return true if we should pick symbol1.
+static bool ShouldPickFirstSymbol(const ElfW(Sym) & symbol1,
+                                  const ElfW(Sym) & symbol2) {
+  // If one of the symbols is weak and the other is not, pick the one
+  // this is not a weak symbol.
+  char bind1 = ELF_ST_BIND(symbol1.st_info);
+  char bind2 = ELF_ST_BIND(symbol1.st_info);
+  if (bind1 == STB_WEAK && bind2 != STB_WEAK) return false;
+  if (bind2 == STB_WEAK && bind1 != STB_WEAK) return true;
+
+  // If one of the symbols has zero size and the other is not, pick the
+  // one that has non-zero size.
+  if (symbol1.st_size != 0 && symbol2.st_size == 0) {
+    return true;
+  }
+  if (symbol1.st_size == 0 && symbol2.st_size != 0) {
+    return false;
+  }
+
+  // If one of the symbols has no type and the other is not, pick the
+  // one that has a type.
+  char type1 = ELF_ST_TYPE(symbol1.st_info);
+  char type2 = ELF_ST_TYPE(symbol1.st_info);
+  if (type1 != STT_NOTYPE && type2 == STT_NOTYPE) {
+    return true;
+  }
+  if (type1 == STT_NOTYPE && type2 != STT_NOTYPE) {
+    return false;
+  }
+
+  // Pick the first one, if we still cannot decide.
+  return true;
+}
+
+// Return true if an address is inside a section.
+static bool InSection(const void *address, const ElfW(Shdr) * section) {
+  const char *start = reinterpret_cast<const char *>(section->sh_addr);
+  size_t size = static_cast<size_t>(section->sh_size);
+  return start <= address && address < (start + size);
+}
+
+static const char *ComputeOffset(const char *base, ptrdiff_t offset) {
+  // Note: cast to uintptr_t to avoid undefined behavior when base evaluates to
+  // zero and offset is non-zero.
+  return reinterpret_cast<const char *>(
+      reinterpret_cast<uintptr_t>(base) + offset);
+}
+
+// Read a symbol table and look for the symbol containing the
+// pc. Iterate over symbols in a symbol table and look for the symbol
+// containing "pc".  If the symbol is found, and its name fits in
+// out_size, the name is written into out and SYMBOL_FOUND is returned.
+// If the name does not fit, truncated name is written into out,
+// and SYMBOL_TRUNCATED is returned. Out is NUL-terminated.
+// If the symbol is not found, SYMBOL_NOT_FOUND is returned;
+// To keep stack consumption low, we would like this function to not get
+// inlined.
+static ABSL_ATTRIBUTE_NOINLINE FindSymbolResult FindSymbol(
+    const void *const pc, const int fd, char *out, int out_size,
+    ptrdiff_t relocation, const ElfW(Shdr) * strtab, const ElfW(Shdr) * symtab,
+    const ElfW(Shdr) * opd, char *tmp_buf, int tmp_buf_size) {
+  if (symtab == nullptr) {
+    return SYMBOL_NOT_FOUND;
+  }
+
+  // Read multiple symbols at once to save read() calls.
+  ElfW(Sym) *buf = reinterpret_cast<ElfW(Sym) *>(tmp_buf);
+  const int buf_entries = tmp_buf_size / sizeof(buf[0]);
+
+  const int num_symbols = symtab->sh_size / symtab->sh_entsize;
+
+  // On platforms using an .opd section (PowerPC & IA64), a function symbol
+  // has the address of a function descriptor, which contains the real
+  // starting address.  However, we do not always want to use the real
+  // starting address because we sometimes want to symbolize a function
+  // pointer into the .opd section, e.g. FindSymbol(&foo,...).
+  const bool pc_in_opd =
+      kPlatformUsesOPDSections && opd != nullptr && InSection(pc, opd);
+  const bool deref_function_descriptor_pointer =
+      kPlatformUsesOPDSections && opd != nullptr && !pc_in_opd;
+
+  ElfW(Sym) best_match;
+  SafeMemZero(&best_match, sizeof(best_match));
+  bool found_match = false;
+  for (int i = 0; i < num_symbols;) {
+    off_t offset = symtab->sh_offset + i * symtab->sh_entsize;
+    const int num_remaining_symbols = num_symbols - i;
+    const int entries_in_chunk = std::min(num_remaining_symbols, buf_entries);
+    const int bytes_in_chunk = entries_in_chunk * sizeof(buf[0]);
+    const ssize_t len = ReadFromOffset(fd, buf, bytes_in_chunk, offset);
+    SAFE_ASSERT(len % sizeof(buf[0]) == 0);
+    const ssize_t num_symbols_in_buf = len / sizeof(buf[0]);
+    SAFE_ASSERT(num_symbols_in_buf <= entries_in_chunk);
+    for (int j = 0; j < num_symbols_in_buf; ++j) {
+      const ElfW(Sym) &symbol = buf[j];
+
+      // For a DSO, a symbol address is relocated by the loading address.
+      // We keep the original address for opd redirection below.
+      const char *const original_start_address =
+          reinterpret_cast<const char *>(symbol.st_value);
+      const char *start_address =
+          ComputeOffset(original_start_address, relocation);
+
+      if (deref_function_descriptor_pointer &&
+          InSection(original_start_address, opd)) {
+        // The opd section is mapped into memory.  Just dereference
+        // start_address to get the first double word, which points to the
+        // function entry.
+        start_address = *reinterpret_cast<const char *const *>(start_address);
+      }
+
+      // If pc is inside the .opd section, it points to a function descriptor.
+      const size_t size = pc_in_opd ? kFunctionDescriptorSize : symbol.st_size;
+      const void *const end_address = ComputeOffset(start_address, size);
+      if (symbol.st_value != 0 &&  // Skip null value symbols.
+          symbol.st_shndx != 0 &&  // Skip undefined symbols.
+#ifdef STT_TLS
+          ELF_ST_TYPE(symbol.st_info) != STT_TLS &&  // Skip thread-local data.
+#endif                                               // STT_TLS
+          ((start_address <= pc && pc < end_address) ||
+           (start_address == pc && pc == end_address))) {
+        if (!found_match || ShouldPickFirstSymbol(symbol, best_match)) {
+          found_match = true;
+          best_match = symbol;
+        }
+      }
+    }
+    i += num_symbols_in_buf;
+  }
+
+  if (found_match) {
+    const size_t off = strtab->sh_offset + best_match.st_name;
+    const ssize_t n_read = ReadFromOffset(fd, out, out_size, off);
+    if (n_read <= 0) {
+      // This should never happen.
+      ABSL_RAW_LOG(WARNING,
+                   "Unable to read from fd %d at offset %zu: n_read = %zd", fd,
+                   off, n_read);
+      return SYMBOL_NOT_FOUND;
+    }
+    ABSL_RAW_CHECK(n_read <= out_size, "ReadFromOffset read too much data.");
+
+    // strtab->sh_offset points into .strtab-like section that contains
+    // NUL-terminated strings: '\0foo\0barbaz\0...".
+    //
+    // sh_offset+st_name points to the start of symbol name, but we don't know
+    // how long the symbol is, so we try to read as much as we have space for,
+    // and usually over-read (i.e. there is a NUL somewhere before n_read).
+    if (memchr(out, '\0', n_read) == nullptr) {
+      // Either out_size was too small (n_read == out_size and no NUL), or
+      // we tried to read past the EOF (n_read < out_size) and .strtab is
+      // corrupt (missing terminating NUL; should never happen for valid ELF).
+      out[n_read - 1] = '\0';
+      return SYMBOL_TRUNCATED;
+    }
+    return SYMBOL_FOUND;
+  }
+
+  return SYMBOL_NOT_FOUND;
+}
+
+// Get the symbol name of "pc" from the file pointed by "fd".  Process
+// both regular and dynamic symbol tables if necessary.
+// See FindSymbol() comment for description of return value.
+FindSymbolResult Symbolizer::GetSymbolFromObjectFile(
+    const ObjFile &obj, const void *const pc, const ptrdiff_t relocation,
+    char *out, int out_size, char *tmp_buf, int tmp_buf_size) {
+  ElfW(Shdr) symtab;
+  ElfW(Shdr) strtab;
+  ElfW(Shdr) opd;
+  ElfW(Shdr) *opd_ptr = nullptr;
+
+  // On platforms using an .opd sections for function descriptor, read
+  // the section header.  The .opd section is in data segment and should be
+  // loaded but we check that it is mapped just to be extra careful.
+  if (kPlatformUsesOPDSections) {
+    if (GetSectionHeaderByName(obj.fd, kOpdSectionName,
+                               sizeof(kOpdSectionName) - 1, &opd) &&
+        FindObjFile(reinterpret_cast<const char *>(opd.sh_addr) + relocation,
+                    opd.sh_size) != nullptr) {
+      opd_ptr = &opd;
+    } else {
+      return SYMBOL_NOT_FOUND;
+    }
+  }
+
+  // Consult a regular symbol table, then fall back to the dynamic symbol table.
+  for (const auto symbol_table_type : {SHT_SYMTAB, SHT_DYNSYM}) {
+    if (!GetSectionHeaderByType(obj.fd, obj.elf_header.e_shnum,
+                                obj.elf_header.e_shoff, symbol_table_type,
+                                &symtab, tmp_buf, tmp_buf_size)) {
+      continue;
+    }
+    if (!ReadFromOffsetExact(
+            obj.fd, &strtab, sizeof(strtab),
+            obj.elf_header.e_shoff + symtab.sh_link * sizeof(symtab))) {
+      continue;
+    }
+    const FindSymbolResult rc =
+        FindSymbol(pc, obj.fd, out, out_size, relocation, &strtab, &symtab,
+                   opd_ptr, tmp_buf, tmp_buf_size);
+    if (rc != SYMBOL_NOT_FOUND) {
+      return rc;
+    }
+  }
+
+  return SYMBOL_NOT_FOUND;
+}
+
+namespace {
+// Thin wrapper around a file descriptor so that the file descriptor
+// gets closed for sure.
+class FileDescriptor {
+ public:
+  explicit FileDescriptor(int fd) : fd_(fd) {}
+  FileDescriptor(const FileDescriptor &) = delete;
+  FileDescriptor &operator=(const FileDescriptor &) = delete;
+
+  ~FileDescriptor() {
+    if (fd_ >= 0) {
+      NO_INTR(close(fd_));
+    }
+  }
+
+  int get() const { return fd_; }
+
+ private:
+  const int fd_;
+};
+
+// Helper class for reading lines from file.
+//
+// Note: we don't use ProcMapsIterator since the object is big (it has
+// a 5k array member) and uses async-unsafe functions such as sscanf()
+// and snprintf().
+class LineReader {
+ public:
+  explicit LineReader(int fd, char *buf, int buf_len)
+      : fd_(fd),
+        buf_len_(buf_len),
+        buf_(buf),
+        bol_(buf),
+        eol_(buf),
+        eod_(buf) {}
+
+  LineReader(const LineReader &) = delete;
+  LineReader &operator=(const LineReader &) = delete;
+
+  // Read '\n'-terminated line from file.  On success, modify "bol"
+  // and "eol", then return true.  Otherwise, return false.
+  //
+  // Note: if the last line doesn't end with '\n', the line will be
+  // dropped.  It's an intentional behavior to make the code simple.
+  bool ReadLine(const char **bol, const char **eol) {
+    if (BufferIsEmpty()) {  // First time.
+      const ssize_t num_bytes = ReadPersistent(fd_, buf_, buf_len_);
+      if (num_bytes <= 0) {  // EOF or error.
+        return false;
+      }
+      eod_ = buf_ + num_bytes;
+      bol_ = buf_;
+    } else {
+      bol_ = eol_ + 1;            // Advance to the next line in the buffer.
+      SAFE_ASSERT(bol_ <= eod_);  // "bol_" can point to "eod_".
+      if (!HasCompleteLine()) {
+        const int incomplete_line_length = eod_ - bol_;
+        // Move the trailing incomplete line to the beginning.
+        memmove(buf_, bol_, incomplete_line_length);
+        // Read text from file and append it.
+        char *const append_pos = buf_ + incomplete_line_length;
+        const int capacity_left = buf_len_ - incomplete_line_length;
+        const ssize_t num_bytes =
+            ReadPersistent(fd_, append_pos, capacity_left);
+        if (num_bytes <= 0) {  // EOF or error.
+          return false;
+        }
+        eod_ = append_pos + num_bytes;
+        bol_ = buf_;
+      }
+    }
+    eol_ = FindLineFeed();
+    if (eol_ == nullptr) {  // '\n' not found.  Malformed line.
+      return false;
+    }
+    *eol_ = '\0';  // Replace '\n' with '\0'.
+
+    *bol = bol_;
+    *eol = eol_;
+    return true;
+  }
+
+ private:
+  char *FindLineFeed() const {
+    return reinterpret_cast<char *>(memchr(bol_, '\n', eod_ - bol_));
+  }
+
+  bool BufferIsEmpty() const { return buf_ == eod_; }
+
+  bool HasCompleteLine() const {
+    return !BufferIsEmpty() && FindLineFeed() != nullptr;
+  }
+
+  const int fd_;
+  const int buf_len_;
+  char *const buf_;
+  char *bol_;
+  char *eol_;
+  const char *eod_;  // End of data in "buf_".
+};
+}  // namespace
+
+// Place the hex number read from "start" into "*hex".  The pointer to
+// the first non-hex character or "end" is returned.
+static const char *GetHex(const char *start, const char *end,
+                          uint64_t *const value) {
+  uint64_t hex = 0;
+  const char *p;
+  for (p = start; p < end; ++p) {
+    int ch = *p;
+    if ((ch >= '0' && ch <= '9') || (ch >= 'A' && ch <= 'F') ||
+        (ch >= 'a' && ch <= 'f')) {
+      hex = (hex << 4) | (ch < 'A' ? ch - '0' : (ch & 0xF) + 9);
+    } else {  // Encountered the first non-hex character.
+      break;
+    }
+  }
+  SAFE_ASSERT(p <= end);
+  *value = hex;
+  return p;
+}
+
+static const char *GetHex(const char *start, const char *end,
+                          const void **const addr) {
+  uint64_t hex = 0;
+  const char *p = GetHex(start, end, &hex);
+  *addr = reinterpret_cast<void *>(hex);
+  return p;
+}
+
+// Normally we are only interested in "r?x" maps.
+// On the PowerPC, function pointers point to descriptors in the .opd
+// section.  The descriptors themselves are not executable code, so
+// we need to relax the check below to "r??".
+static bool ShouldUseMapping(const char *const flags) {
+  return flags[0] == 'r' && (kPlatformUsesOPDSections || flags[2] == 'x');
+}
+
+// Read /proc/self/maps and run "callback" for each mmapped file found.  If
+// "callback" returns false, stop scanning and return true. Else continue
+// scanning /proc/self/maps. Return true if no parse error is found.
+static ABSL_ATTRIBUTE_NOINLINE bool ReadAddrMap(
+    bool (*callback)(const char *filename, const void *const start_addr,
+                     const void *const end_addr, uint64_t offset, void *arg),
+    void *arg, void *tmp_buf, int tmp_buf_size) {
+  // Use /proc/self/task/<pid>/maps instead of /proc/self/maps. The latter
+  // requires kernel to stop all threads, and is significantly slower when there
+  // are 1000s of threads.
+  char maps_path[80];
+  snprintf(maps_path, sizeof(maps_path), "/proc/self/task/%d/maps", getpid());
+
+  int maps_fd;
+  NO_INTR(maps_fd = open(maps_path, O_RDONLY));
+  FileDescriptor wrapped_maps_fd(maps_fd);
+  if (wrapped_maps_fd.get() < 0) {
+    ABSL_RAW_LOG(WARNING, "%s: errno=%d", maps_path, errno);
+    return false;
+  }
+
+  // Iterate over maps and look for the map containing the pc.  Then
+  // look into the symbol tables inside.
+  LineReader reader(wrapped_maps_fd.get(), static_cast<char *>(tmp_buf),
+                    tmp_buf_size);
+  while (true) {
+    const char *cursor;
+    const char *eol;
+    if (!reader.ReadLine(&cursor, &eol)) {  // EOF or malformed line.
+      break;
+    }
+
+    const char *line = cursor;
+    const void *start_address;
+    // Start parsing line in /proc/self/maps.  Here is an example:
+    //
+    // 08048000-0804c000 r-xp 00000000 08:01 2142121    /bin/cat
+    //
+    // We want start address (08048000), end address (0804c000), flags
+    // (r-xp) and file name (/bin/cat).
+
+    // Read start address.
+    cursor = GetHex(cursor, eol, &start_address);
+    if (cursor == eol || *cursor != '-') {
+      ABSL_RAW_LOG(WARNING, "Corrupt /proc/self/maps line: %s", line);
+      return false;
+    }
+    ++cursor;  // Skip '-'.
+
+    // Read end address.
+    const void *end_address;
+    cursor = GetHex(cursor, eol, &end_address);
+    if (cursor == eol || *cursor != ' ') {
+      ABSL_RAW_LOG(WARNING, "Corrupt /proc/self/maps line: %s", line);
+      return false;
+    }
+    ++cursor;  // Skip ' '.
+
+    // Read flags.  Skip flags until we encounter a space or eol.
+    const char *const flags_start = cursor;
+    while (cursor < eol && *cursor != ' ') {
+      ++cursor;
+    }
+    // We expect at least four letters for flags (ex. "r-xp").
+    if (cursor == eol || cursor < flags_start + 4) {
+      ABSL_RAW_LOG(WARNING, "Corrupt /proc/self/maps: %s", line);
+      return false;
+    }
+
+    // Check flags.
+    if (!ShouldUseMapping(flags_start)) {
+      continue;  // We skip this map.
+    }
+    ++cursor;  // Skip ' '.
+
+    // Read file offset.
+    uint64_t offset;
+    cursor = GetHex(cursor, eol, &offset);
+    ++cursor;  // Skip ' '.
+
+    // Skip to file name.  "cursor" now points to dev.  We need to skip at least
+    // two spaces for dev and inode.
+    int num_spaces = 0;
+    while (cursor < eol) {
+      if (*cursor == ' ') {
+        ++num_spaces;
+      } else if (num_spaces >= 2) {
+        // The first non-space character after  skipping two spaces
+        // is the beginning of the file name.
+        break;
+      }
+      ++cursor;
+    }
+
+    // Check whether this entry corresponds to our hint table for the true
+    // filename.
+    bool hinted =
+        GetFileMappingHint(&start_address, &end_address, &offset, &cursor);
+    if (!hinted && (cursor == eol || cursor[0] == '[')) {
+      // not an object file, typically [vdso] or [vsyscall]
+      continue;
+    }
+    if (!callback(cursor, start_address, end_address, offset, arg)) break;
+  }
+  return true;
+}
+
+// Find the objfile mapped in address region containing [addr, addr + len).
+ObjFile *Symbolizer::FindObjFile(const void *const addr, size_t len) {
+  for (int i = 0; i < 2; ++i) {
+    if (!ok_) return nullptr;
+
+    // Read /proc/self/maps if necessary
+    if (!addr_map_read_) {
+      addr_map_read_ = true;
+      if (!ReadAddrMap(RegisterObjFile, this, tmp_buf_, TMP_BUF_SIZE)) {
+        ok_ = false;
+        return nullptr;
+      }
+    }
+
+    int lo = 0;
+    int hi = addr_map_.Size();
+    while (lo < hi) {
+      int mid = (lo + hi) / 2;
+      if (addr < addr_map_.At(mid)->end_addr) {
+        hi = mid;
+      } else {
+        lo = mid + 1;
+      }
+    }
+    if (lo != addr_map_.Size()) {
+      ObjFile *obj = addr_map_.At(lo);
+      SAFE_ASSERT(obj->end_addr > addr);
+      if (addr >= obj->start_addr &&
+          reinterpret_cast<const char *>(addr) + len <= obj->end_addr)
+        return obj;
+    }
+
+    // The address mapping may have changed since it was last read.  Retry.
+    ClearAddrMap();
+  }
+  return nullptr;
+}
+
+void Symbolizer::ClearAddrMap() {
+  for (int i = 0; i != addr_map_.Size(); i++) {
+    ObjFile *o = addr_map_.At(i);
+    base_internal::LowLevelAlloc::Free(o->filename);
+    if (o->fd >= 0) {
+      NO_INTR(close(o->fd));
+    }
+  }
+  addr_map_.Clear();
+  addr_map_read_ = false;
+}
+
+// Callback for ReadAddrMap to register objfiles in an in-memory table.
+bool Symbolizer::RegisterObjFile(const char *filename,
+                                 const void *const start_addr,
+                                 const void *const end_addr, uint64_t offset,
+                                 void *arg) {
+  Symbolizer *impl = static_cast<Symbolizer *>(arg);
+
+  // Files are supposed to be added in the increasing address order.  Make
+  // sure that's the case.
+  int addr_map_size = impl->addr_map_.Size();
+  if (addr_map_size != 0) {
+    ObjFile *old = impl->addr_map_.At(addr_map_size - 1);
+    if (old->end_addr > end_addr) {
+      ABSL_RAW_LOG(ERROR,
+                   "Unsorted addr map entry: 0x%" PRIxPTR ": %s <-> 0x%" PRIxPTR
+                   ": %s",
+                   reinterpret_cast<uintptr_t>(end_addr), filename,
+                   reinterpret_cast<uintptr_t>(old->end_addr), old->filename);
+      return true;
+    } else if (old->end_addr == end_addr) {
+      // The same entry appears twice. This sometimes happens for [vdso].
+      if (old->start_addr != start_addr ||
+          strcmp(old->filename, filename) != 0) {
+        ABSL_RAW_LOG(ERROR,
+                     "Duplicate addr 0x%" PRIxPTR ": %s <-> 0x%" PRIxPTR ": %s",
+                     reinterpret_cast<uintptr_t>(end_addr), filename,
+                     reinterpret_cast<uintptr_t>(old->end_addr), old->filename);
+      }
+      return true;
+    }
+  }
+  ObjFile *obj = impl->addr_map_.Add();
+  obj->filename = impl->CopyString(filename);
+  obj->start_addr = start_addr;
+  obj->end_addr = end_addr;
+  obj->offset = offset;
+  obj->elf_type = -1;  // filled on demand
+  obj->fd = -1;        // opened on demand
+  return true;
+}
+
+// This function wraps the Demangle function to provide an interface
+// where the input symbol is demangled in-place.
+// To keep stack consumption low, we would like this function to not
+// get inlined.
+static ABSL_ATTRIBUTE_NOINLINE void DemangleInplace(char *out, int out_size,
+                                                    char *tmp_buf,
+                                                    int tmp_buf_size) {
+  if (Demangle(out, tmp_buf, tmp_buf_size)) {
+    // Demangling succeeded. Copy to out if the space allows.
+    int len = strlen(tmp_buf);
+    if (len + 1 <= out_size) {  // +1 for '\0'.
+      SAFE_ASSERT(len < tmp_buf_size);
+      memmove(out, tmp_buf, len + 1);
+    }
+  }
+}
+
+SymbolCacheLine *Symbolizer::GetCacheLine(const void *const pc) {
+  uintptr_t pc0 = reinterpret_cast<uintptr_t>(pc);
+  pc0 >>= 3;  // drop the low 3 bits
+
+  // Shuffle bits.
+  pc0 ^= (pc0 >> 6) ^ (pc0 >> 12) ^ (pc0 >> 18);
+  return &symbol_cache_[pc0 % SYMBOL_CACHE_LINES];
+}
+
+void Symbolizer::AgeSymbols(SymbolCacheLine *line) {
+  for (uint32_t &age : line->age) {
+    ++age;
+  }
+}
+
+const char *Symbolizer::FindSymbolInCache(const void *const pc) {
+  if (pc == nullptr) return nullptr;
+
+  SymbolCacheLine *line = GetCacheLine(pc);
+  for (size_t i = 0; i < ABSL_ARRAYSIZE(line->pc); ++i) {
+    if (line->pc[i] == pc) {
+      AgeSymbols(line);
+      line->age[i] = 0;
+      return line->name[i];
+    }
+  }
+  return nullptr;
+}
+
+const char *Symbolizer::InsertSymbolInCache(const void *const pc,
+                                            const char *name) {
+  SAFE_ASSERT(pc != nullptr);
+
+  SymbolCacheLine *line = GetCacheLine(pc);
+  uint32_t max_age = 0;
+  int oldest_index = -1;
+  for (size_t i = 0; i < ABSL_ARRAYSIZE(line->pc); ++i) {
+    if (line->pc[i] == nullptr) {
+      AgeSymbols(line);
+      line->pc[i] = pc;
+      line->name[i] = CopyString(name);
+      line->age[i] = 0;
+      return line->name[i];
+    }
+    if (line->age[i] >= max_age) {
+      max_age = line->age[i];
+      oldest_index = i;
+    }
+  }
+
+  AgeSymbols(line);
+  ABSL_RAW_CHECK(oldest_index >= 0, "Corrupt cache");
+  base_internal::LowLevelAlloc::Free(line->name[oldest_index]);
+  line->pc[oldest_index] = pc;
+  line->name[oldest_index] = CopyString(name);
+  line->age[oldest_index] = 0;
+  return line->name[oldest_index];
+}
+
+static void MaybeOpenFdFromSelfExe(ObjFile *obj) {
+  if (memcmp(obj->start_addr, ELFMAG, SELFMAG) != 0) {
+    return;
+  }
+  int fd = open("/proc/self/exe", O_RDONLY);
+  if (fd == -1) {
+    return;
+  }
+  // Verify that contents of /proc/self/exe matches in-memory image of
+  // the binary. This can fail if the "deleted" binary is in fact not
+  // the main executable, or for binaries that have the first PT_LOAD
+  // segment smaller than 4K. We do it in four steps so that the
+  // buffer is smaller and we don't consume too much stack space.
+  const char *mem = reinterpret_cast<const char *>(obj->start_addr);
+  for (int i = 0; i < 4; ++i) {
+    char buf[1024];
+    ssize_t n = read(fd, buf, sizeof(buf));
+    if (n != sizeof(buf) || memcmp(buf, mem, sizeof(buf)) != 0) {
+      close(fd);
+      return;
+    }
+    mem += sizeof(buf);
+  }
+  obj->fd = fd;
+}
+
+static bool MaybeInitializeObjFile(ObjFile *obj) {
+  if (obj->fd < 0) {
+    obj->fd = open(obj->filename, O_RDONLY);
+
+    if (obj->fd < 0) {
+      // Getting /proc/self/exe here means that we were hinted.
+      if (strcmp(obj->filename, "/proc/self/exe") == 0) {
+        // /proc/self/exe may be inaccessible (due to setuid, etc.), so try
+        // accessing the binary via argv0.
+        if (argv0_value != nullptr) {
+          obj->fd = open(argv0_value, O_RDONLY);
+        }
+      } else {
+        MaybeOpenFdFromSelfExe(obj);
+      }
+    }
+
+    if (obj->fd < 0) {
+      ABSL_RAW_LOG(WARNING, "%s: open failed: errno=%d", obj->filename, errno);
+      return false;
+    }
+    obj->elf_type = FileGetElfType(obj->fd);
+    if (obj->elf_type < 0) {
+      ABSL_RAW_LOG(WARNING, "%s: wrong elf type: %d", obj->filename,
+                   obj->elf_type);
+      return false;
+    }
+
+    if (!ReadFromOffsetExact(obj->fd, &obj->elf_header, sizeof(obj->elf_header),
+                             0)) {
+      ABSL_RAW_LOG(WARNING, "%s: failed to read elf header", obj->filename);
+      return false;
+    }
+    const int phnum = obj->elf_header.e_phnum;
+    const int phentsize = obj->elf_header.e_phentsize;
+    size_t phoff = obj->elf_header.e_phoff;
+    size_t num_executable_load_segments = 0;
+    for (int j = 0; j < phnum; j++) {
+      ElfW(Phdr) phdr;
+      if (!ReadFromOffsetExact(obj->fd, &phdr, sizeof(phdr), phoff)) {
+        ABSL_RAW_LOG(WARNING, "%s: failed to read program header %d",
+                     obj->filename, j);
+        return false;
+      }
+      phoff += phentsize;
+      constexpr int rx = PF_X | PF_R;
+      if (phdr.p_type != PT_LOAD || (phdr.p_flags & rx) != rx) {
+        // Not a LOAD segment, or not executable code.
+        continue;
+      }
+      if (num_executable_load_segments < obj->phdr.size()) {
+        memcpy(&obj->phdr[num_executable_load_segments++], &phdr, sizeof(phdr));
+      } else {
+        ABSL_RAW_LOG(WARNING, "%s: too many executable LOAD segments",
+                     obj->filename);
+        break;
+      }
+    }
+    if (num_executable_load_segments == 0) {
+      // This object has no "r-x" LOAD segments. That's unexpected.
+      ABSL_RAW_LOG(WARNING, "%s: no executable LOAD segments", obj->filename);
+      return false;
+    }
+  }
+  return true;
+}
+
+// The implementation of our symbolization routine.  If it
+// successfully finds the symbol containing "pc" and obtains the
+// symbol name, returns pointer to that symbol. Otherwise, returns nullptr.
+// If any symbol decorators have been installed via InstallSymbolDecorator(),
+// they are called here as well.
+// To keep stack consumption low, we would like this function to not
+// get inlined.
+const char *Symbolizer::GetSymbol(const void *const pc) {
+  const char *entry = FindSymbolInCache(pc);
+  if (entry != nullptr) {
+    return entry;
+  }
+  symbol_buf_[0] = '\0';
+
+  ObjFile *const obj = FindObjFile(pc, 1);
+  ptrdiff_t relocation = 0;
+  int fd = -1;
+  if (obj != nullptr) {
+    if (MaybeInitializeObjFile(obj)) {
+      const size_t start_addr = reinterpret_cast<size_t>(obj->start_addr);
+      if (obj->elf_type == ET_DYN && start_addr >= obj->offset) {
+        // This object was relocated.
+        //
+        // For obj->offset > 0, adjust the relocation since a mapping at offset
+        // X in the file will have a start address of [true relocation]+X.
+        relocation = start_addr - obj->offset;
+
+        // Note: some binaries have multiple "rx" LOAD segments. We must
+        // find the right one.
+        ElfW(Phdr) *phdr = nullptr;
+        for (size_t j = 0; j < obj->phdr.size(); j++) {
+          ElfW(Phdr) &p = obj->phdr[j];
+          if (p.p_type != PT_LOAD) {
+            // We only expect PT_LOADs. This must be PT_NULL that we didn't
+            // write over (i.e. we exhausted all interesting PT_LOADs).
+            ABSL_RAW_CHECK(p.p_type == PT_NULL, "unexpected p_type");
+            break;
+          }
+          if (pc < reinterpret_cast<void *>(start_addr + p.p_memsz)) {
+            phdr = &p;
+            break;
+          }
+        }
+        if (phdr == nullptr) {
+          // That's unexpected. Hope for the best.
+          ABSL_RAW_LOG(
+              WARNING,
+              "%s: unable to find LOAD segment for pc: %p, start_addr: %zx",
+              obj->filename, pc, start_addr);
+        } else {
+          // Adjust relocation in case phdr.p_vaddr != 0.
+          // This happens for binaries linked with `lld --rosegment`, and for
+          // binaries linked with BFD `ld -z separate-code`.
+          relocation -= phdr->p_vaddr - phdr->p_offset;
+        }
+      }
+
+      fd = obj->fd;
+      if (GetSymbolFromObjectFile(*obj, pc, relocation, symbol_buf_,
+                                  sizeof(symbol_buf_), tmp_buf_,
+                                  sizeof(tmp_buf_)) == SYMBOL_FOUND) {
+        // Only try to demangle the symbol name if it fit into symbol_buf_.
+        DemangleInplace(symbol_buf_, sizeof(symbol_buf_), tmp_buf_,
+                        sizeof(tmp_buf_));
+      }
+    }
+  } else {
+#if ABSL_HAVE_VDSO_SUPPORT
+    VDSOSupport vdso;
+    if (vdso.IsPresent()) {
+      VDSOSupport::SymbolInfo symbol_info;
+      if (vdso.LookupSymbolByAddress(pc, &symbol_info)) {
+        // All VDSO symbols are known to be short.
+        size_t len = strlen(symbol_info.name);
+        ABSL_RAW_CHECK(len + 1 < sizeof(symbol_buf_),
+                       "VDSO symbol unexpectedly long");
+        memcpy(symbol_buf_, symbol_info.name, len + 1);
+      }
+    }
+#endif
+  }
+
+  if (g_decorators_mu.TryLock()) {
+    if (g_num_decorators > 0) {
+      SymbolDecoratorArgs decorator_args = {
+          pc,       relocation,       fd,     symbol_buf_, sizeof(symbol_buf_),
+          tmp_buf_, sizeof(tmp_buf_), nullptr};
+      for (int i = 0; i < g_num_decorators; ++i) {
+        decorator_args.arg = g_decorators[i].arg;
+        g_decorators[i].fn(&decorator_args);
+      }
+    }
+    g_decorators_mu.Unlock();
+  }
+  if (symbol_buf_[0] == '\0') {
+    return nullptr;
+  }
+  symbol_buf_[sizeof(symbol_buf_) - 1] = '\0';  // Paranoia.
+  return InsertSymbolInCache(pc, symbol_buf_);
+}
+
+bool RemoveAllSymbolDecorators(void) {
+  if (!g_decorators_mu.TryLock()) {
+    // Someone else is using decorators. Get out.
+    return false;
+  }
+  g_num_decorators = 0;
+  g_decorators_mu.Unlock();
+  return true;
+}
+
+bool RemoveSymbolDecorator(int ticket) {
+  if (!g_decorators_mu.TryLock()) {
+    // Someone else is using decorators. Get out.
+    return false;
+  }
+  for (int i = 0; i < g_num_decorators; ++i) {
+    if (g_decorators[i].ticket == ticket) {
+      while (i < g_num_decorators - 1) {
+        g_decorators[i] = g_decorators[i + 1];
+        ++i;
+      }
+      g_num_decorators = i;
+      break;
+    }
+  }
+  g_decorators_mu.Unlock();
+  return true;  // Decorator is known to be removed.
+}
+
+int InstallSymbolDecorator(SymbolDecorator decorator, void *arg) {
+  static int ticket = 0;
+
+  if (!g_decorators_mu.TryLock()) {
+    // Someone else is using decorators. Get out.
+    return -2;
+  }
+  int ret = ticket;
+  if (g_num_decorators >= kMaxDecorators) {
+    ret = -1;
+  } else {
+    g_decorators[g_num_decorators] = {decorator, arg, ticket++};
+    ++g_num_decorators;
+  }
+  g_decorators_mu.Unlock();
+  return ret;
+}
+
+bool RegisterFileMappingHint(const void *start, const void *end, uint64_t offset,
+                             const char *filename) {
+  SAFE_ASSERT(start <= end);
+  SAFE_ASSERT(filename != nullptr);
+
+  InitSigSafeArena();
+
+  if (!g_file_mapping_mu.TryLock()) {
+    return false;
+  }
+
+  bool ret = true;
+  if (g_num_file_mapping_hints >= kMaxFileMappingHints) {
+    ret = false;
+  } else {
+    // TODO(ckennelly): Move this into a string copy routine.
+    int len = strlen(filename);
+    char *dst = static_cast<char *>(
+        base_internal::LowLevelAlloc::AllocWithArena(len + 1, SigSafeArena()));
+    ABSL_RAW_CHECK(dst != nullptr, "out of memory");
+    memcpy(dst, filename, len + 1);
+
+    auto &hint = g_file_mapping_hints[g_num_file_mapping_hints++];
+    hint.start = start;
+    hint.end = end;
+    hint.offset = offset;
+    hint.filename = dst;
+  }
+
+  g_file_mapping_mu.Unlock();
+  return ret;
+}
+
+bool GetFileMappingHint(const void **start, const void **end, uint64_t *offset,
+                        const char **filename) {
+  if (!g_file_mapping_mu.TryLock()) {
+    return false;
+  }
+  bool found = false;
+  for (int i = 0; i < g_num_file_mapping_hints; i++) {
+    if (g_file_mapping_hints[i].start <= *start &&
+        *end <= g_file_mapping_hints[i].end) {
+      // We assume that the start_address for the mapping is the base
+      // address of the ELF section, but when [start_address,end_address) is
+      // not strictly equal to [hint.start, hint.end), that assumption is
+      // invalid.
+      //
+      // This uses the hint's start address (even though hint.start is not
+      // necessarily equal to start_address) to ensure the correct
+      // relocation is computed later.
+      *start = g_file_mapping_hints[i].start;
+      *end = g_file_mapping_hints[i].end;
+      *offset = g_file_mapping_hints[i].offset;
+      *filename = g_file_mapping_hints[i].filename;
+      found = true;
+      break;
+    }
+  }
+  g_file_mapping_mu.Unlock();
+  return found;
+}
+
+}  // namespace debugging_internal
+
+bool Symbolize(const void *pc, char *out, int out_size) {
+  // Symbolization is very slow under tsan.
+  ABSL_ANNOTATE_IGNORE_READS_AND_WRITES_BEGIN();
+  SAFE_ASSERT(out_size >= 0);
+  debugging_internal::Symbolizer *s = debugging_internal::AllocateSymbolizer();
+  const char *name = s->GetSymbol(pc);
+  bool ok = false;
+  if (name != nullptr && out_size > 0) {
+    strncpy(out, name, out_size);
+    ok = true;
+    if (out[out_size - 1] != '\0') {
+      // strncpy() does not '\0' terminate when it truncates.  Do so, with
+      // trailing ellipsis.
+      static constexpr char kEllipsis[] = "...";
+      int ellipsis_size =
+          std::min(implicit_cast<int>(strlen(kEllipsis)), out_size - 1);
+      memcpy(out + out_size - ellipsis_size - 1, kEllipsis, ellipsis_size);
+      out[out_size - 1] = '\0';
+    }
+  }
+  debugging_internal::FreeSymbolizer(s);
+  ABSL_ANNOTATE_IGNORE_READS_AND_WRITES_END();
+  return ok;
+}
+
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+extern "C" bool AbslInternalGetFileMappingHint(const void **start,
+                                               const void **end, uint64_t *offset,
+                                               const char **filename) {
+  return absl::debugging_internal::GetFileMappingHint(start, end, offset,
+                                                      filename);
+}
diff --git a/src/absl/debugging/symbolize_unimplemented.inc b/src/absl/debugging/symbolize_unimplemented.inc
new file mode 100644 (file)
index 0000000..db24456
--- /dev/null
@@ -0,0 +1,40 @@
+// Copyright 2018 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <cstdint>
+
+#include "absl/base/internal/raw_logging.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+
+namespace debugging_internal {
+
+int InstallSymbolDecorator(SymbolDecorator, void*) { return -1; }
+bool RemoveSymbolDecorator(int) { return false; }
+bool RemoveAllSymbolDecorators(void) { return false; }
+bool RegisterFileMappingHint(const void *, const void *, uint64_t, const char *) {
+  return false;
+}
+bool GetFileMappingHint(const void **, const void **, uint64_t *, const char **) {
+  return false;
+}
+
+}  // namespace debugging_internal
+
+void InitializeSymbolizer(const char*) {}
+bool Symbolize(const void *, char *, int) { return false; }
+
+ABSL_NAMESPACE_END
+}  // namespace absl
diff --git a/src/absl/debugging/symbolize_win32.inc b/src/absl/debugging/symbolize_win32.inc
new file mode 100644 (file)
index 0000000..6e2650d
--- /dev/null
@@ -0,0 +1,82 @@
+// Copyright 2018 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// See "Retrieving Symbol Information by Address":
+// https://msdn.microsoft.com/en-us/library/windows/desktop/ms680578(v=vs.85).aspx
+
+#include <windows.h>
+
+// MSVC header dbghelp.h has a warning for an ignored typedef.
+// #pragma warning(push)
+// #pragma warning(disable:4091)
+#include <dbghelp.h>
+// #pragma warning(pop)
+
+#pragma comment(lib, "dbghelp.lib")
+
+#include <algorithm>
+#include <cstring>
+
+#include "absl/base/internal/raw_logging.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+
+static HANDLE process = NULL;
+
+void InitializeSymbolizer(const char*) {
+  if (process != nullptr) {
+    return;
+  }
+  process = GetCurrentProcess();
+
+  // Symbols are not loaded until a reference is made requiring the
+  // symbols be loaded. This is the fastest, most efficient way to use
+  // the symbol handler.
+  //SymSetOptions(SYMOPT_DEFERRED_LOADS | SYMOPT_UNDNAME);
+  //if (!SymInitialize(process, nullptr, true)) {
+  //  // GetLastError() returns a Win32 DWORD, but we assign to
+  //  // unsigned long long to simplify the ABSL_RAW_LOG case below.  The uniform
+  //  // initialization guarantees this is not a narrowing conversion.
+  //  const unsigned long long error{GetLastError()};  // NOLINT(runtime/int)
+  //  ABSL_RAW_LOG(FATAL, "SymInitialize() failed: %llu", error);
+  //}
+}
+
+bool Symbolize(const void* pc, char* out, int out_size) {
+  if (out_size <= 0) {
+    return false;
+  }
+  alignas(SYMBOL_INFO) char buf[sizeof(SYMBOL_INFO) + MAX_SYM_NAME];
+  SYMBOL_INFO* symbol = reinterpret_cast<SYMBOL_INFO*>(buf);
+  symbol->SizeOfStruct = sizeof(SYMBOL_INFO);
+  symbol->MaxNameLen = MAX_SYM_NAME;
+  // if (!SymFromAddr(process, reinterpret_cast<DWORD64>(pc), nullptr, symbol)) {
+  //   return false;
+  // }
+  // strncpy(out, symbol->Name, out_size);
+  // if (out[out_size - 1] != '\0') {
+  //   // strncpy() does not '\0' terminate when it truncates.
+  //   static constexpr char kEllipsis[] = "...";
+  //   int ellipsis_size =
+  //       std::min<int>(sizeof(kEllipsis) - 1, out_size - 1);
+  //   memcpy(out + out_size - ellipsis_size - 1, kEllipsis, ellipsis_size);
+  //   out[out_size - 1] = '\0';
+  // }
+  // return true;
+  return false;
+}
+
+ABSL_NAMESPACE_END
+}  // namespace absl
diff --git a/src/absl/functional/bind_front.h b/src/absl/functional/bind_front.h
new file mode 100644 (file)
index 0000000..5b47970
--- /dev/null
@@ -0,0 +1,184 @@
+// Copyright 2018 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// -----------------------------------------------------------------------------
+// File: bind_front.h
+// -----------------------------------------------------------------------------
+//
+// `absl::bind_front()` returns a functor by binding a number of arguments to
+// the front of a provided (usually more generic) functor. Unlike `std::bind`,
+// it does not require the use of argument placeholders. The simpler syntax of
+// `absl::bind_front()` allows you to avoid known misuses with `std::bind()`.
+//
+// `absl::bind_front()` is meant as a drop-in replacement for C++20's upcoming
+// `std::bind_front()`, which similarly resolves these issues with
+// `std::bind()`. Both `bind_front()` alternatives, unlike `std::bind()`, allow
+// partial function application. (See
+// https://en.wikipedia.org/wiki/Partial_application).
+
+#ifndef ABSL_FUNCTIONAL_BIND_FRONT_H_
+#define ABSL_FUNCTIONAL_BIND_FRONT_H_
+
+#include "absl/functional/internal/front_binder.h"
+#include "absl/utility/utility.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+
+// bind_front()
+//
+// Binds the first N arguments of an invocable object and stores them by value.
+//
+// Like `std::bind()`, `absl::bind_front()` is implicitly convertible to
+// `std::function`.  In particular, it may be used as a simpler replacement for
+// `std::bind()` in most cases, as it does not require  placeholders to be
+// specified. More importantly, it provides more reliable correctness guarantees
+// than `std::bind()`; while `std::bind()` will silently ignore passing more
+// parameters than expected, for example, `absl::bind_front()` will report such
+// mis-uses as errors.
+//
+// absl::bind_front(a...) can be seen as storing the results of
+// std::make_tuple(a...).
+//
+// Example: Binding a free function.
+//
+//   int Minus(int a, int b) { return a - b; }
+//
+//   assert(absl::bind_front(Minus)(3, 2) == 3 - 2);
+//   assert(absl::bind_front(Minus, 3)(2) == 3 - 2);
+//   assert(absl::bind_front(Minus, 3, 2)() == 3 - 2);
+//
+// Example: Binding a member function.
+//
+//   struct Math {
+//     int Double(int a) const { return 2 * a; }
+//   };
+//
+//   Math math;
+//
+//   assert(absl::bind_front(&Math::Double)(&math, 3) == 2 * 3);
+//   // Stores a pointer to math inside the functor.
+//   assert(absl::bind_front(&Math::Double, &math)(3) == 2 * 3);
+//   // Stores a copy of math inside the functor.
+//   assert(absl::bind_front(&Math::Double, math)(3) == 2 * 3);
+//   // Stores std::unique_ptr<Math> inside the functor.
+//   assert(absl::bind_front(&Math::Double,
+//                           std::unique_ptr<Math>(new Math))(3) == 2 * 3);
+//
+// Example: Using `absl::bind_front()`, instead of `std::bind()`, with
+//          `std::function`.
+//
+//   class FileReader {
+//    public:
+//     void ReadFileAsync(const std::string& filename, std::string* content,
+//                        const std::function<void()>& done) {
+//       // Calls Executor::Schedule(std::function<void()>).
+//       Executor::DefaultExecutor()->Schedule(
+//           absl::bind_front(&FileReader::BlockingRead, this,
+//                            filename, content, done));
+//     }
+//
+//    private:
+//     void BlockingRead(const std::string& filename, std::string* content,
+//                       const std::function<void()>& done) {
+//       CHECK_OK(file::GetContents(filename, content, {}));
+//       done();
+//     }
+//   };
+//
+// `absl::bind_front()` stores bound arguments explicitly using the type passed
+// rather than implicitly based on the type accepted by its functor.
+//
+// Example: Binding arguments explicitly.
+//
+//   void LogStringView(absl::string_view sv) {
+//     LOG(INFO) << sv;
+//   }
+//
+//   Executor* e = Executor::DefaultExecutor();
+//   std::string s = "hello";
+//   absl::string_view sv = s;
+//
+//   // absl::bind_front(LogStringView, arg) makes a copy of arg and stores it.
+//   e->Schedule(absl::bind_front(LogStringView, sv)); // ERROR: dangling
+//                                                     // string_view.
+//
+//   e->Schedule(absl::bind_front(LogStringView, s));  // OK: stores a copy of
+//                                                     // s.
+//
+// To store some of the arguments passed to `absl::bind_front()` by reference,
+//  use std::ref()` and `std::cref()`.
+//
+// Example: Storing some of the bound arguments by reference.
+//
+//   class Service {
+//    public:
+//     void Serve(const Request& req, std::function<void()>* done) {
+//       // The request protocol buffer won't be deleted until done is called.
+//       // It's safe to store a reference to it inside the functor.
+//       Executor::DefaultExecutor()->Schedule(
+//           absl::bind_front(&Service::BlockingServe, this, std::cref(req),
+//           done));
+//     }
+//
+//    private:
+//     void BlockingServe(const Request& req, std::function<void()>* done);
+//   };
+//
+// Example: Storing bound arguments by reference.
+//
+//   void Print(const std::string& a, const std::string& b) {
+//     std::cerr << a << b;
+//   }
+//
+//   std::string hi = "Hello, ";
+//   std::vector<std::string> names = {"Chuk", "Gek"};
+//   // Doesn't copy hi.
+//   for_each(names.begin(), names.end(),
+//            absl::bind_front(Print, std::ref(hi)));
+//
+//   // DO NOT DO THIS: the functor may outlive "hi", resulting in
+//   // dangling references.
+//   foo->DoInFuture(absl::bind_front(Print, std::ref(hi), "Guest"));  // BAD!
+//   auto f = absl::bind_front(Print, std::ref(hi), "Guest"); // BAD!
+//
+// Example: Storing reference-like types.
+//
+//   void Print(absl::string_view a, const std::string& b) {
+//     std::cerr << a << b;
+//   }
+//
+//   std::string hi = "Hello, ";
+//   // Copies "hi".
+//   absl::bind_front(Print, hi)("Chuk");
+//
+//   // Compile error: std::reference_wrapper<const string> is not implicitly
+//   // convertible to string_view.
+//   // absl::bind_front(Print, std::cref(hi))("Chuk");
+//
+//   // Doesn't copy "hi".
+//   absl::bind_front(Print, absl::string_view(hi))("Chuk");
+//
+template <class F, class... BoundArgs>
+constexpr functional_internal::bind_front_t<F, BoundArgs...> bind_front(
+    F&& func, BoundArgs&&... args) {
+  return functional_internal::bind_front_t<F, BoundArgs...>(
+      absl::in_place, absl::forward<F>(func),
+      absl::forward<BoundArgs>(args)...);
+}
+
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#endif  // ABSL_FUNCTIONAL_BIND_FRONT_H_
diff --git a/src/absl/functional/function_ref.h b/src/absl/functional/function_ref.h
new file mode 100644 (file)
index 0000000..6e03ac2
--- /dev/null
@@ -0,0 +1,139 @@
+// Copyright 2019 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// -----------------------------------------------------------------------------
+// File: function_ref.h
+// -----------------------------------------------------------------------------
+//
+// This header file defines the `absl::FunctionRef` type for holding a
+// non-owning reference to an object of any invocable type. This function
+// reference is typically most useful as a type-erased argument type for
+// accepting function types that neither take ownership nor copy the type; using
+// the reference type in this case avoids a copy and an allocation. Best
+// practices of other non-owning reference-like objects (such as
+// `absl::string_view`) apply here.
+//
+//  An `absl::FunctionRef` is similar in usage to a `std::function` but has the
+//  following differences:
+//
+//  * It doesn't own the underlying object.
+//  * It doesn't have a null or empty state.
+//  * It never performs deep copies or allocations.
+//  * It's much faster and cheaper to construct.
+//  * It's trivially copyable and destructable.
+//
+// Generally, `absl::FunctionRef` should not be used as a return value, data
+// member, or to initialize a `std::function`. Such usages will often lead to
+// problematic lifetime issues. Once you convert something to an
+// `absl::FunctionRef` you cannot make a deep copy later.
+//
+// This class is suitable for use wherever a "const std::function<>&"
+// would be used without making a copy. ForEach functions and other versions of
+// the visitor pattern are a good example of when this class should be used.
+//
+// This class is trivial to copy and should be passed by value.
+#ifndef ABSL_FUNCTIONAL_FUNCTION_REF_H_
+#define ABSL_FUNCTIONAL_FUNCTION_REF_H_
+
+#include <cassert>
+#include <functional>
+#include <type_traits>
+
+#include "absl/functional/internal/function_ref.h"
+#include "absl/meta/type_traits.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+
+// FunctionRef
+//
+// Dummy class declaration to allow the partial specialization based on function
+// types below.
+template <typename T>
+class FunctionRef;
+
+// FunctionRef
+//
+// An `absl::FunctionRef` is a lightweight wrapper to any invokable object with
+// a compatible signature. Generally, an `absl::FunctionRef` should only be used
+// as an argument type and should be preferred as an argument over a const
+// reference to a `std::function`.
+//
+// Example:
+//
+//   // The following function takes a function callback by const reference
+//   bool Visitor(const std::function<void(my_proto&,
+//                                         absl::string_view)>& callback);
+//
+//   // Assuming that the function is not stored or otherwise copied, it can be
+//   // replaced by an `absl::FunctionRef`:
+//   bool Visitor(absl::FunctionRef<void(my_proto&, absl::string_view)>
+//                  callback);
+//
+// Note: the assignment operator within an `absl::FunctionRef` is intentionally
+// deleted to prevent misuse; because the `absl::FunctionRef` does not own the
+// underlying type, assignment likely indicates misuse.
+template <typename R, typename... Args>
+class FunctionRef<R(Args...)> {
+ private:
+  // Used to disable constructors for objects that are not compatible with the
+  // signature of this FunctionRef.
+  template <typename F,
+            typename FR = absl::base_internal::invoke_result_t<F, Args&&...>>
+  using EnableIfCompatible =
+      typename std::enable_if<std::is_void<R>::value ||
+                              std::is_convertible<FR, R>::value>::type;
+
+ public:
+  // Constructs a FunctionRef from any invokable type.
+  template <typename F, typename = EnableIfCompatible<const F&>>
+  FunctionRef(const F& f)  // NOLINT(runtime/explicit)
+      : invoker_(&absl::functional_internal::InvokeObject<F, R, Args...>) {
+    absl::functional_internal::AssertNonNull(f);
+    ptr_.obj = &f;
+  }
+
+  // Overload for function pointers. This eliminates a level of indirection that
+  // would happen if the above overload was used (it lets us store the pointer
+  // instead of a pointer to a pointer).
+  //
+  // This overload is also used for references to functions, since references to
+  // functions can decay to function pointers implicitly.
+  template <
+      typename F, typename = EnableIfCompatible<F*>,
+      absl::functional_internal::EnableIf<absl::is_function<F>::value> = 0>
+  FunctionRef(F* f)  // NOLINT(runtime/explicit)
+      : invoker_(&absl::functional_internal::InvokeFunction<F*, R, Args...>) {
+    assert(f != nullptr);
+    ptr_.fun = reinterpret_cast<decltype(ptr_.fun)>(f);
+  }
+
+  // To help prevent subtle lifetime bugs, FunctionRef is not assignable.
+  // Typically, it should only be used as an argument type.
+  FunctionRef& operator=(const FunctionRef& rhs) = delete;
+
+  // Call the underlying object.
+  R operator()(Args... args) const {
+    return invoker_(ptr_, std::forward<Args>(args)...);
+  }
+
+ private:
+  absl::functional_internal::VoidPtr ptr_;
+  absl::functional_internal::Invoker<R, Args...> invoker_;
+};
+
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#endif  // ABSL_FUNCTIONAL_FUNCTION_REF_H_
diff --git a/src/absl/functional/internal/front_binder.h b/src/absl/functional/internal/front_binder.h
new file mode 100644 (file)
index 0000000..45f52de
--- /dev/null
@@ -0,0 +1,95 @@
+// Copyright 2018 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// Implementation details for `absl::bind_front()`.
+
+#ifndef ABSL_FUNCTIONAL_INTERNAL_FRONT_BINDER_H_
+#define ABSL_FUNCTIONAL_INTERNAL_FRONT_BINDER_H_
+
+#include <cstddef>
+#include <type_traits>
+#include <utility>
+
+#include "absl/base/internal/invoke.h"
+#include "absl/container/internal/compressed_tuple.h"
+#include "absl/meta/type_traits.h"
+#include "absl/utility/utility.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace functional_internal {
+
+// Invoke the method, expanding the tuple of bound arguments.
+template <class R, class Tuple, size_t... Idx, class... Args>
+R Apply(Tuple&& bound, absl::index_sequence<Idx...>, Args&&... free) {
+  return base_internal::invoke(
+      absl::forward<Tuple>(bound).template get<Idx>()...,
+      absl::forward<Args>(free)...);
+}
+
+template <class F, class... BoundArgs>
+class FrontBinder {
+  using BoundArgsT = absl::container_internal::CompressedTuple<F, BoundArgs...>;
+  using Idx = absl::make_index_sequence<sizeof...(BoundArgs) + 1>;
+
+  BoundArgsT bound_args_;
+
+ public:
+  template <class... Ts>
+  constexpr explicit FrontBinder(absl::in_place_t, Ts&&... ts)
+      : bound_args_(absl::forward<Ts>(ts)...) {}
+
+  template <class... FreeArgs, class R = base_internal::invoke_result_t<
+                                   F&, BoundArgs&..., FreeArgs&&...>>
+  R operator()(FreeArgs&&... free_args) & {
+    return functional_internal::Apply<R>(bound_args_, Idx(),
+                                         absl::forward<FreeArgs>(free_args)...);
+  }
+
+  template <class... FreeArgs,
+            class R = base_internal::invoke_result_t<
+                const F&, const BoundArgs&..., FreeArgs&&...>>
+  R operator()(FreeArgs&&... free_args) const& {
+    return functional_internal::Apply<R>(bound_args_, Idx(),
+                                         absl::forward<FreeArgs>(free_args)...);
+  }
+
+  template <class... FreeArgs, class R = base_internal::invoke_result_t<
+                                   F&&, BoundArgs&&..., FreeArgs&&...>>
+  R operator()(FreeArgs&&... free_args) && {
+    // This overload is called when *this is an rvalue. If some of the bound
+    // arguments are stored by value or rvalue reference, we move them.
+    return functional_internal::Apply<R>(absl::move(bound_args_), Idx(),
+                                         absl::forward<FreeArgs>(free_args)...);
+  }
+
+  template <class... FreeArgs,
+            class R = base_internal::invoke_result_t<
+                const F&&, const BoundArgs&&..., FreeArgs&&...>>
+  R operator()(FreeArgs&&... free_args) const&& {
+    // This overload is called when *this is an rvalue. If some of the bound
+    // arguments are stored by value or rvalue reference, we move them.
+    return functional_internal::Apply<R>(absl::move(bound_args_), Idx(),
+                                         absl::forward<FreeArgs>(free_args)...);
+  }
+};
+
+template <class F, class... BoundArgs>
+using bind_front_t = FrontBinder<decay_t<F>, absl::decay_t<BoundArgs>...>;
+
+}  // namespace functional_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#endif  // ABSL_FUNCTIONAL_INTERNAL_FRONT_BINDER_H_
diff --git a/src/absl/functional/internal/function_ref.h b/src/absl/functional/internal/function_ref.h
new file mode 100644 (file)
index 0000000..b5bb8b4
--- /dev/null
@@ -0,0 +1,106 @@
+// Copyright 2019 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef ABSL_FUNCTIONAL_INTERNAL_FUNCTION_REF_H_
+#define ABSL_FUNCTIONAL_INTERNAL_FUNCTION_REF_H_
+
+#include <cassert>
+#include <functional>
+#include <type_traits>
+
+#include "absl/base/internal/invoke.h"
+#include "absl/meta/type_traits.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace functional_internal {
+
+// Like a void* that can handle function pointers as well. The standard does not
+// allow function pointers to round-trip through void*, but void(*)() is fine.
+//
+// Note: It's important that this class remains trivial and is the same size as
+// a pointer, since this allows the compiler to perform tail-call optimizations
+// when the underlying function is a callable object with a matching signature.
+union VoidPtr {
+  const void* obj;
+  void (*fun)();
+};
+
+// Chooses the best type for passing T as an argument.
+// Attempt to be close to SystemV AMD64 ABI. Objects with trivial copy ctor are
+// passed by value.
+template <typename T>
+constexpr bool PassByValue() {
+  return !std::is_lvalue_reference<T>::value &&
+         absl::is_trivially_copy_constructible<T>::value &&
+         absl::is_trivially_copy_assignable<
+             typename std::remove_cv<T>::type>::value &&
+         std::is_trivially_destructible<T>::value &&
+         sizeof(T) <= 2 * sizeof(void*);
+}
+
+template <typename T>
+struct ForwardT : std::conditional<PassByValue<T>(), T, T&&> {};
+
+// An Invoker takes a pointer to the type-erased invokable object, followed by
+// the arguments that the invokable object expects.
+//
+// Note: The order of arguments here is an optimization, since member functions
+// have an implicit "this" pointer as their first argument, putting VoidPtr
+// first allows the compiler to perform tail-call optimization in many cases.
+template <typename R, typename... Args>
+using Invoker = R (*)(VoidPtr, typename ForwardT<Args>::type...);
+
+//
+// InvokeObject and InvokeFunction provide static "Invoke" functions that can be
+// used as Invokers for objects or functions respectively.
+//
+// static_cast<R> handles the case the return type is void.
+template <typename Obj, typename R, typename... Args>
+R InvokeObject(VoidPtr ptr, typename ForwardT<Args>::type... args) {
+  auto o = static_cast<const Obj*>(ptr.obj);
+  return static_cast<R>(
+      absl::base_internal::invoke(*o, std::forward<Args>(args)...));
+}
+
+template <typename Fun, typename R, typename... Args>
+R InvokeFunction(VoidPtr ptr, typename ForwardT<Args>::type... args) {
+  auto f = reinterpret_cast<Fun>(ptr.fun);
+  return static_cast<R>(
+      absl::base_internal::invoke(f, std::forward<Args>(args)...));
+}
+
+template <typename Sig>
+void AssertNonNull(const std::function<Sig>& f) {
+  assert(f != nullptr);
+  (void)f;
+}
+
+template <typename F>
+void AssertNonNull(const F&) {}
+
+template <typename F, typename C>
+void AssertNonNull(F C::*f) {
+  assert(f != nullptr);
+  (void)f;
+}
+
+template <bool C>
+using EnableIf = typename ::std::enable_if<C, int>::type;
+
+}  // namespace functional_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#endif  // ABSL_FUNCTIONAL_INTERNAL_FUNCTION_REF_H_
diff --git a/src/absl/memory/memory.h b/src/absl/memory/memory.h
new file mode 100644 (file)
index 0000000..2b5ff62
--- /dev/null
@@ -0,0 +1,699 @@
+// Copyright 2017 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// -----------------------------------------------------------------------------
+// File: memory.h
+// -----------------------------------------------------------------------------
+//
+// This header file contains utility functions for managing the creation and
+// conversion of smart pointers. This file is an extension to the C++
+// standard <memory> library header file.
+
+#ifndef ABSL_MEMORY_MEMORY_H_
+#define ABSL_MEMORY_MEMORY_H_
+
+#include <cstddef>
+#include <limits>
+#include <memory>
+#include <new>
+#include <type_traits>
+#include <utility>
+
+#include "absl/base/macros.h"
+#include "absl/meta/type_traits.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+
+// -----------------------------------------------------------------------------
+// Function Template: WrapUnique()
+// -----------------------------------------------------------------------------
+//
+// Adopts ownership from a raw pointer and transfers it to the returned
+// `std::unique_ptr`, whose type is deduced. Because of this deduction, *do not*
+// specify the template type `T` when calling `WrapUnique`.
+//
+// Example:
+//   X* NewX(int, int);
+//   auto x = WrapUnique(NewX(1, 2));  // 'x' is std::unique_ptr<X>.
+//
+// Do not call WrapUnique with an explicit type, as in
+// `WrapUnique<X>(NewX(1, 2))`.  The purpose of WrapUnique is to automatically
+// deduce the pointer type. If you wish to make the type explicit, just use
+// `std::unique_ptr` directly.
+//
+//   auto x = std::unique_ptr<X>(NewX(1, 2));
+//                  - or -
+//   std::unique_ptr<X> x(NewX(1, 2));
+//
+// While `absl::WrapUnique` is useful for capturing the output of a raw
+// pointer factory, prefer 'absl::make_unique<T>(args...)' over
+// 'absl::WrapUnique(new T(args...))'.
+//
+//   auto x = WrapUnique(new X(1, 2));  // works, but nonideal.
+//   auto x = make_unique<X>(1, 2);     // safer, standard, avoids raw 'new'.
+//
+// Note that `absl::WrapUnique(p)` is valid only if `delete p` is a valid
+// expression. In particular, `absl::WrapUnique()` cannot wrap pointers to
+// arrays, functions or void, and it must not be used to capture pointers
+// obtained from array-new expressions (even though that would compile!).
+template <typename T>
+std::unique_ptr<T> WrapUnique(T* ptr) {
+  static_assert(!std::is_array<T>::value, "array types are unsupported");
+  static_assert(std::is_object<T>::value, "non-object types are unsupported");
+  return std::unique_ptr<T>(ptr);
+}
+
+namespace memory_internal {
+
+// Traits to select proper overload and return type for `absl::make_unique<>`.
+template <typename T>
+struct MakeUniqueResult {
+  using scalar = std::unique_ptr<T>;
+};
+template <typename T>
+struct MakeUniqueResult<T[]> {
+  using array = std::unique_ptr<T[]>;
+};
+template <typename T, size_t N>
+struct MakeUniqueResult<T[N]> {
+  using invalid = void;
+};
+
+}  // namespace memory_internal
+
+// gcc 4.8 has __cplusplus at 201301 but the libstdc++ shipped with it doesn't
+// define make_unique.  Other supported compilers either just define __cplusplus
+// as 201103 but have make_unique (msvc), or have make_unique whenever
+// __cplusplus > 201103 (clang).
+#if (__cplusplus > 201103L || defined(_MSC_VER)) && \
+    !(defined(__GLIBCXX__) && !defined(__cpp_lib_make_unique))
+using std::make_unique;
+#else
+// -----------------------------------------------------------------------------
+// Function Template: make_unique<T>()
+// -----------------------------------------------------------------------------
+//
+// Creates a `std::unique_ptr<>`, while avoiding issues creating temporaries
+// during the construction process. `absl::make_unique<>` also avoids redundant
+// type declarations, by avoiding the need to explicitly use the `new` operator.
+//
+// This implementation of `absl::make_unique<>` is designed for C++11 code and
+// will be replaced in C++14 by the equivalent `std::make_unique<>` abstraction.
+// `absl::make_unique<>` is designed to be 100% compatible with
+// `std::make_unique<>` so that the eventual migration will involve a simple
+// rename operation.
+//
+// For more background on why `std::unique_ptr<T>(new T(a,b))` is problematic,
+// see Herb Sutter's explanation on
+// (Exception-Safe Function Calls)[https://herbsutter.com/gotw/_102/].
+// (In general, reviewers should treat `new T(a,b)` with scrutiny.)
+//
+// Example usage:
+//
+//    auto p = make_unique<X>(args...);  // 'p'  is a std::unique_ptr<X>
+//    auto pa = make_unique<X[]>(5);     // 'pa' is a std::unique_ptr<X[]>
+//
+// Three overloads of `absl::make_unique` are required:
+//
+//   - For non-array T:
+//
+//       Allocates a T with `new T(std::forward<Args> args...)`,
+//       forwarding all `args` to T's constructor.
+//       Returns a `std::unique_ptr<T>` owning that object.
+//
+//   - For an array of unknown bounds T[]:
+//
+//       `absl::make_unique<>` will allocate an array T of type U[] with
+//       `new U[n]()` and return a `std::unique_ptr<U[]>` owning that array.
+//
+//       Note that 'U[n]()' is different from 'U[n]', and elements will be
+//       value-initialized. Note as well that `std::unique_ptr` will perform its
+//       own destruction of the array elements upon leaving scope, even though
+//       the array [] does not have a default destructor.
+//
+//       NOTE: an array of unknown bounds T[] may still be (and often will be)
+//       initialized to have a size, and will still use this overload. E.g:
+//
+//         auto my_array = absl::make_unique<int[]>(10);
+//
+//   - For an array of known bounds T[N]:
+//
+//       `absl::make_unique<>` is deleted (like with `std::make_unique<>`) as
+//       this overload is not useful.
+//
+//       NOTE: an array of known bounds T[N] is not considered a useful
+//       construction, and may cause undefined behavior in templates. E.g:
+//
+//         auto my_array = absl::make_unique<int[10]>();
+//
+//       In those cases, of course, you can still use the overload above and
+//       simply initialize it to its desired size:
+//
+//         auto my_array = absl::make_unique<int[]>(10);
+
+// `absl::make_unique` overload for non-array types.
+template <typename T, typename... Args>
+typename memory_internal::MakeUniqueResult<T>::scalar make_unique(
+    Args&&... args) {
+  return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
+}
+
+// `absl::make_unique` overload for an array T[] of unknown bounds.
+// The array allocation needs to use the `new T[size]` form and cannot take
+// element constructor arguments. The `std::unique_ptr` will manage destructing
+// these array elements.
+template <typename T>
+typename memory_internal::MakeUniqueResult<T>::array make_unique(size_t n) {
+  return std::unique_ptr<T>(new typename absl::remove_extent_t<T>[n]());
+}
+
+// `absl::make_unique` overload for an array T[N] of known bounds.
+// This construction will be rejected.
+template <typename T, typename... Args>
+typename memory_internal::MakeUniqueResult<T>::invalid make_unique(
+    Args&&... /* args */) = delete;
+#endif
+
+// -----------------------------------------------------------------------------
+// Function Template: RawPtr()
+// -----------------------------------------------------------------------------
+//
+// Extracts the raw pointer from a pointer-like value `ptr`. `absl::RawPtr` is
+// useful within templates that need to handle a complement of raw pointers,
+// `std::nullptr_t`, and smart pointers.
+template <typename T>
+auto RawPtr(T&& ptr) -> decltype(std::addressof(*ptr)) {
+  // ptr is a forwarding reference to support Ts with non-const operators.
+  return (ptr != nullptr) ? std::addressof(*ptr) : nullptr;
+}
+inline std::nullptr_t RawPtr(std::nullptr_t) { return nullptr; }
+
+// -----------------------------------------------------------------------------
+// Function Template: ShareUniquePtr()
+// -----------------------------------------------------------------------------
+//
+// Adopts a `std::unique_ptr` rvalue and returns a `std::shared_ptr` of deduced
+// type. Ownership (if any) of the held value is transferred to the returned
+// shared pointer.
+//
+// Example:
+//
+//     auto up = absl::make_unique<int>(10);
+//     auto sp = absl::ShareUniquePtr(std::move(up));  // shared_ptr<int>
+//     CHECK_EQ(*sp, 10);
+//     CHECK(up == nullptr);
+//
+// Note that this conversion is correct even when T is an array type, and more
+// generally it works for *any* deleter of the `unique_ptr` (single-object
+// deleter, array deleter, or any custom deleter), since the deleter is adopted
+// by the shared pointer as well. The deleter is copied (unless it is a
+// reference).
+//
+// Implements the resolution of [LWG 2415](http://wg21.link/lwg2415), by which a
+// null shared pointer does not attempt to call the deleter.
+template <typename T, typename D>
+std::shared_ptr<T> ShareUniquePtr(std::unique_ptr<T, D>&& ptr) {
+  return ptr ? std::shared_ptr<T>(std::move(ptr)) : std::shared_ptr<T>();
+}
+
+// -----------------------------------------------------------------------------
+// Function Template: WeakenPtr()
+// -----------------------------------------------------------------------------
+//
+// Creates a weak pointer associated with a given shared pointer. The returned
+// value is a `std::weak_ptr` of deduced type.
+//
+// Example:
+//
+//    auto sp = std::make_shared<int>(10);
+//    auto wp = absl::WeakenPtr(sp);
+//    CHECK_EQ(sp.get(), wp.lock().get());
+//    sp.reset();
+//    CHECK(wp.lock() == nullptr);
+//
+template <typename T>
+std::weak_ptr<T> WeakenPtr(const std::shared_ptr<T>& ptr) {
+  return std::weak_ptr<T>(ptr);
+}
+
+namespace memory_internal {
+
+// ExtractOr<E, O, D>::type evaluates to E<O> if possible. Otherwise, D.
+template <template <typename> class Extract, typename Obj, typename Default,
+          typename>
+struct ExtractOr {
+  using type = Default;
+};
+
+template <template <typename> class Extract, typename Obj, typename Default>
+struct ExtractOr<Extract, Obj, Default, void_t<Extract<Obj>>> {
+  using type = Extract<Obj>;
+};
+
+template <template <typename> class Extract, typename Obj, typename Default>
+using ExtractOrT = typename ExtractOr<Extract, Obj, Default, void>::type;
+
+// Extractors for the features of allocators.
+template <typename T>
+using GetPointer = typename T::pointer;
+
+template <typename T>
+using GetConstPointer = typename T::const_pointer;
+
+template <typename T>
+using GetVoidPointer = typename T::void_pointer;
+
+template <typename T>
+using GetConstVoidPointer = typename T::const_void_pointer;
+
+template <typename T>
+using GetDifferenceType = typename T::difference_type;
+
+template <typename T>
+using GetSizeType = typename T::size_type;
+
+template <typename T>
+using GetPropagateOnContainerCopyAssignment =
+    typename T::propagate_on_container_copy_assignment;
+
+template <typename T>
+using GetPropagateOnContainerMoveAssignment =
+    typename T::propagate_on_container_move_assignment;
+
+template <typename T>
+using GetPropagateOnContainerSwap = typename T::propagate_on_container_swap;
+
+template <typename T>
+using GetIsAlwaysEqual = typename T::is_always_equal;
+
+template <typename T>
+struct GetFirstArg;
+
+template <template <typename...> class Class, typename T, typename... Args>
+struct GetFirstArg<Class<T, Args...>> {
+  using type = T;
+};
+
+template <typename Ptr, typename = void>
+struct ElementType {
+  using type = typename GetFirstArg<Ptr>::type;
+};
+
+template <typename T>
+struct ElementType<T, void_t<typename T::element_type>> {
+  using type = typename T::element_type;
+};
+
+template <typename T, typename U>
+struct RebindFirstArg;
+
+template <template <typename...> class Class, typename T, typename... Args,
+          typename U>
+struct RebindFirstArg<Class<T, Args...>, U> {
+  using type = Class<U, Args...>;
+};
+
+template <typename T, typename U, typename = void>
+struct RebindPtr {
+  using type = typename RebindFirstArg<T, U>::type;
+};
+
+template <typename T, typename U>
+struct RebindPtr<T, U, void_t<typename T::template rebind<U>>> {
+  using type = typename T::template rebind<U>;
+};
+
+template <typename T, typename U>
+constexpr bool HasRebindAlloc(...) {
+  return false;
+}
+
+template <typename T, typename U>
+constexpr bool HasRebindAlloc(typename T::template rebind<U>::other*) {
+  return true;
+}
+
+template <typename T, typename U, bool = HasRebindAlloc<T, U>(nullptr)>
+struct RebindAlloc {
+  using type = typename RebindFirstArg<T, U>::type;
+};
+
+template <typename T, typename U>
+struct RebindAlloc<T, U, true> {
+  using type = typename T::template rebind<U>::other;
+};
+
+}  // namespace memory_internal
+
+// -----------------------------------------------------------------------------
+// Class Template: pointer_traits
+// -----------------------------------------------------------------------------
+//
+// An implementation of C++11's std::pointer_traits.
+//
+// Provided for portability on toolchains that have a working C++11 compiler,
+// but the standard library is lacking in C++11 support. For example, some
+// version of the Android NDK.
+//
+
+template <typename Ptr>
+struct pointer_traits {
+  using pointer = Ptr;
+
+  // element_type:
+  // Ptr::element_type if present. Otherwise T if Ptr is a template
+  // instantiation Template<T, Args...>
+  using element_type = typename memory_internal::ElementType<Ptr>::type;
+
+  // difference_type:
+  // Ptr::difference_type if present, otherwise std::ptrdiff_t
+  using difference_type =
+      memory_internal::ExtractOrT<memory_internal::GetDifferenceType, Ptr,
+                                  std::ptrdiff_t>;
+
+  // rebind:
+  // Ptr::rebind<U> if exists, otherwise Template<U, Args...> if Ptr is a
+  // template instantiation Template<T, Args...>
+  template <typename U>
+  using rebind = typename memory_internal::RebindPtr<Ptr, U>::type;
+
+  // pointer_to:
+  // Calls Ptr::pointer_to(r)
+  static pointer pointer_to(element_type& r) {  // NOLINT(runtime/references)
+    return Ptr::pointer_to(r);
+  }
+};
+
+// Specialization for T*.
+template <typename T>
+struct pointer_traits<T*> {
+  using pointer = T*;
+  using element_type = T;
+  using difference_type = std::ptrdiff_t;
+
+  template <typename U>
+  using rebind = U*;
+
+  // pointer_to:
+  // Calls std::addressof(r)
+  static pointer pointer_to(
+      element_type& r) noexcept {  // NOLINT(runtime/references)
+    return std::addressof(r);
+  }
+};
+
+// -----------------------------------------------------------------------------
+// Class Template: allocator_traits
+// -----------------------------------------------------------------------------
+//
+// A C++11 compatible implementation of C++17's std::allocator_traits.
+//
+#if __cplusplus >= 201703L
+using std::allocator_traits;
+#else  // __cplusplus >= 201703L
+template <typename Alloc>
+struct allocator_traits {
+  using allocator_type = Alloc;
+
+  // value_type:
+  // Alloc::value_type
+  using value_type = typename Alloc::value_type;
+
+  // pointer:
+  // Alloc::pointer if present, otherwise value_type*
+  using pointer = memory_internal::ExtractOrT<memory_internal::GetPointer,
+                                              Alloc, value_type*>;
+
+  // const_pointer:
+  // Alloc::const_pointer if present, otherwise
+  // absl::pointer_traits<pointer>::rebind<const value_type>
+  using const_pointer =
+      memory_internal::ExtractOrT<memory_internal::GetConstPointer, Alloc,
+                                  typename absl::pointer_traits<pointer>::
+                                      template rebind<const value_type>>;
+
+  // void_pointer:
+  // Alloc::void_pointer if present, otherwise
+  // absl::pointer_traits<pointer>::rebind<void>
+  using void_pointer = memory_internal::ExtractOrT<
+      memory_internal::GetVoidPointer, Alloc,
+      typename absl::pointer_traits<pointer>::template rebind<void>>;
+
+  // const_void_pointer:
+  // Alloc::const_void_pointer if present, otherwise
+  // absl::pointer_traits<pointer>::rebind<const void>
+  using const_void_pointer = memory_internal::ExtractOrT<
+      memory_internal::GetConstVoidPointer, Alloc,
+      typename absl::pointer_traits<pointer>::template rebind<const void>>;
+
+  // difference_type:
+  // Alloc::difference_type if present, otherwise
+  // absl::pointer_traits<pointer>::difference_type
+  using difference_type = memory_internal::ExtractOrT<
+      memory_internal::GetDifferenceType, Alloc,
+      typename absl::pointer_traits<pointer>::difference_type>;
+
+  // size_type:
+  // Alloc::size_type if present, otherwise
+  // std::make_unsigned<difference_type>::type
+  using size_type = memory_internal::ExtractOrT<
+      memory_internal::GetSizeType, Alloc,
+      typename std::make_unsigned<difference_type>::type>;
+
+  // propagate_on_container_copy_assignment:
+  // Alloc::propagate_on_container_copy_assignment if present, otherwise
+  // std::false_type
+  using propagate_on_container_copy_assignment = memory_internal::ExtractOrT<
+      memory_internal::GetPropagateOnContainerCopyAssignment, Alloc,
+      std::false_type>;
+
+  // propagate_on_container_move_assignment:
+  // Alloc::propagate_on_container_move_assignment if present, otherwise
+  // std::false_type
+  using propagate_on_container_move_assignment = memory_internal::ExtractOrT<
+      memory_internal::GetPropagateOnContainerMoveAssignment, Alloc,
+      std::false_type>;
+
+  // propagate_on_container_swap:
+  // Alloc::propagate_on_container_swap if present, otherwise std::false_type
+  using propagate_on_container_swap =
+      memory_internal::ExtractOrT<memory_internal::GetPropagateOnContainerSwap,
+                                  Alloc, std::false_type>;
+
+  // is_always_equal:
+  // Alloc::is_always_equal if present, otherwise std::is_empty<Alloc>::type
+  using is_always_equal =
+      memory_internal::ExtractOrT<memory_internal::GetIsAlwaysEqual, Alloc,
+                                  typename std::is_empty<Alloc>::type>;
+
+  // rebind_alloc:
+  // Alloc::rebind<T>::other if present, otherwise Alloc<T, Args> if this Alloc
+  // is Alloc<U, Args>
+  template <typename T>
+  using rebind_alloc = typename memory_internal::RebindAlloc<Alloc, T>::type;
+
+  // rebind_traits:
+  // absl::allocator_traits<rebind_alloc<T>>
+  template <typename T>
+  using rebind_traits = absl::allocator_traits<rebind_alloc<T>>;
+
+  // allocate(Alloc& a, size_type n):
+  // Calls a.allocate(n)
+  static pointer allocate(Alloc& a,  // NOLINT(runtime/references)
+                          size_type n) {
+    return a.allocate(n);
+  }
+
+  // allocate(Alloc& a, size_type n, const_void_pointer hint):
+  // Calls a.allocate(n, hint) if possible.
+  // If not possible, calls a.allocate(n)
+  static pointer allocate(Alloc& a, size_type n,  // NOLINT(runtime/references)
+                          const_void_pointer hint) {
+    return allocate_impl(0, a, n, hint);
+  }
+
+  // deallocate(Alloc& a, pointer p, size_type n):
+  // Calls a.deallocate(p, n)
+  static void deallocate(Alloc& a, pointer p,  // NOLINT(runtime/references)
+                         size_type n) {
+    a.deallocate(p, n);
+  }
+
+  // construct(Alloc& a, T* p, Args&&... args):
+  // Calls a.construct(p, std::forward<Args>(args)...) if possible.
+  // If not possible, calls
+  //   ::new (static_cast<void*>(p)) T(std::forward<Args>(args)...)
+  template <typename T, typename... Args>
+  static void construct(Alloc& a, T* p,  // NOLINT(runtime/references)
+                        Args&&... args) {
+    construct_impl(0, a, p, std::forward<Args>(args)...);
+  }
+
+  // destroy(Alloc& a, T* p):
+  // Calls a.destroy(p) if possible. If not possible, calls p->~T().
+  template <typename T>
+  static void destroy(Alloc& a, T* p) {  // NOLINT(runtime/references)
+    destroy_impl(0, a, p);
+  }
+
+  // max_size(const Alloc& a):
+  // Returns a.max_size() if possible. If not possible, returns
+  //   std::numeric_limits<size_type>::max() / sizeof(value_type)
+  static size_type max_size(const Alloc& a) { return max_size_impl(0, a); }
+
+  // select_on_container_copy_construction(const Alloc& a):
+  // Returns a.select_on_container_copy_construction() if possible.
+  // If not possible, returns a.
+  static Alloc select_on_container_copy_construction(const Alloc& a) {
+    return select_on_container_copy_construction_impl(0, a);
+  }
+
+ private:
+  template <typename A>
+  static auto allocate_impl(int, A& a,  // NOLINT(runtime/references)
+                            size_type n, const_void_pointer hint)
+      -> decltype(a.allocate(n, hint)) {
+    return a.allocate(n, hint);
+  }
+  static pointer allocate_impl(char, Alloc& a,  // NOLINT(runtime/references)
+                               size_type n, const_void_pointer) {
+    return a.allocate(n);
+  }
+
+  template <typename A, typename... Args>
+  static auto construct_impl(int, A& a,  // NOLINT(runtime/references)
+                             Args&&... args)
+      -> decltype(a.construct(std::forward<Args>(args)...)) {
+    a.construct(std::forward<Args>(args)...);
+  }
+
+  template <typename T, typename... Args>
+  static void construct_impl(char, Alloc&, T* p, Args&&... args) {
+    ::new (static_cast<void*>(p)) T(std::forward<Args>(args)...);
+  }
+
+  template <typename A, typename T>
+  static auto destroy_impl(int, A& a,  // NOLINT(runtime/references)
+                           T* p) -> decltype(a.destroy(p)) {
+    a.destroy(p);
+  }
+  template <typename T>
+  static void destroy_impl(char, Alloc&, T* p) {
+    p->~T();
+  }
+
+  template <typename A>
+  static auto max_size_impl(int, const A& a) -> decltype(a.max_size()) {
+    return a.max_size();
+  }
+  static size_type max_size_impl(char, const Alloc&) {
+    return (std::numeric_limits<size_type>::max)() / sizeof(value_type);
+  }
+
+  template <typename A>
+  static auto select_on_container_copy_construction_impl(int, const A& a)
+      -> decltype(a.select_on_container_copy_construction()) {
+    return a.select_on_container_copy_construction();
+  }
+  static Alloc select_on_container_copy_construction_impl(char,
+                                                          const Alloc& a) {
+    return a;
+  }
+};
+#endif  // __cplusplus >= 201703L
+
+namespace memory_internal {
+
+// This template alias transforms Alloc::is_nothrow into a metafunction with
+// Alloc as a parameter so it can be used with ExtractOrT<>.
+template <typename Alloc>
+using GetIsNothrow = typename Alloc::is_nothrow;
+
+}  // namespace memory_internal
+
+// ABSL_ALLOCATOR_NOTHROW is a build time configuration macro for user to
+// specify whether the default allocation function can throw or never throws.
+// If the allocation function never throws, user should define it to a non-zero
+// value (e.g. via `-DABSL_ALLOCATOR_NOTHROW`).
+// If the allocation function can throw, user should leave it undefined or
+// define it to zero.
+//
+// allocator_is_nothrow<Alloc> is a traits class that derives from
+// Alloc::is_nothrow if present, otherwise std::false_type. It's specialized
+// for Alloc = std::allocator<T> for any type T according to the state of
+// ABSL_ALLOCATOR_NOTHROW.
+//
+// default_allocator_is_nothrow is a class that derives from std::true_type
+// when the default allocator (global operator new) never throws, and
+// std::false_type when it can throw. It is a convenience shorthand for writing
+// allocator_is_nothrow<std::allocator<T>> (T can be any type).
+// NOTE: allocator_is_nothrow<std::allocator<T>> is guaranteed to derive from
+// the same type for all T, because users should specialize neither
+// allocator_is_nothrow nor std::allocator.
+template <typename Alloc>
+struct allocator_is_nothrow
+    : memory_internal::ExtractOrT<memory_internal::GetIsNothrow, Alloc,
+                                  std::false_type> {};
+
+#if defined(ABSL_ALLOCATOR_NOTHROW) && ABSL_ALLOCATOR_NOTHROW
+template <typename T>
+struct allocator_is_nothrow<std::allocator<T>> : std::true_type {};
+struct default_allocator_is_nothrow : std::true_type {};
+#else
+struct default_allocator_is_nothrow : std::false_type {};
+#endif
+
+namespace memory_internal {
+template <typename Allocator, typename Iterator, typename... Args>
+void ConstructRange(Allocator& alloc, Iterator first, Iterator last,
+                    const Args&... args) {
+  for (Iterator cur = first; cur != last; ++cur) {
+    ABSL_INTERNAL_TRY {
+      std::allocator_traits<Allocator>::construct(alloc, std::addressof(*cur),
+                                                  args...);
+    }
+    ABSL_INTERNAL_CATCH_ANY {
+      while (cur != first) {
+        --cur;
+        std::allocator_traits<Allocator>::destroy(alloc, std::addressof(*cur));
+      }
+      ABSL_INTERNAL_RETHROW;
+    }
+  }
+}
+
+template <typename Allocator, typename Iterator, typename InputIterator>
+void CopyRange(Allocator& alloc, Iterator destination, InputIterator first,
+               InputIterator last) {
+  for (Iterator cur = destination; first != last;
+       static_cast<void>(++cur), static_cast<void>(++first)) {
+    ABSL_INTERNAL_TRY {
+      std::allocator_traits<Allocator>::construct(alloc, std::addressof(*cur),
+                                                  *first);
+    }
+    ABSL_INTERNAL_CATCH_ANY {
+      while (cur != destination) {
+        --cur;
+        std::allocator_traits<Allocator>::destroy(alloc, std::addressof(*cur));
+      }
+      ABSL_INTERNAL_RETHROW;
+    }
+  }
+}
+}  // namespace memory_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#endif  // ABSL_MEMORY_MEMORY_H_
diff --git a/src/absl/meta/type_traits.h b/src/absl/meta/type_traits.h
new file mode 100644 (file)
index 0000000..d5cb5f3
--- /dev/null
@@ -0,0 +1,767 @@
+//
+// Copyright 2017 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// -----------------------------------------------------------------------------
+// type_traits.h
+// -----------------------------------------------------------------------------
+//
+// This file contains C++11-compatible versions of standard <type_traits> API
+// functions for determining the characteristics of types. Such traits can
+// support type inference, classification, and transformation, as well as
+// make it easier to write templates based on generic type behavior.
+//
+// See https://en.cppreference.com/w/cpp/header/type_traits
+//
+// WARNING: use of many of the constructs in this header will count as "complex
+// template metaprogramming", so before proceeding, please carefully consider
+// https://google.github.io/styleguide/cppguide.html#Template_metaprogramming
+//
+// WARNING: using template metaprogramming to detect or depend on API
+// features is brittle and not guaranteed. Neither the standard library nor
+// Abseil provides any guarantee that APIs are stable in the face of template
+// metaprogramming. Use with caution.
+#ifndef ABSL_META_TYPE_TRAITS_H_
+#define ABSL_META_TYPE_TRAITS_H_
+
+#include <stddef.h>
+#include <functional>
+#include <type_traits>
+
+#include "absl/base/config.h"
+
+// MSVC constructibility traits do not detect destructor properties and so our
+// implementations should not use them as a source-of-truth.
+#if defined(_MSC_VER) && !defined(__clang__) && !defined(__GNUC__)
+#define ABSL_META_INTERNAL_STD_CONSTRUCTION_TRAITS_DONT_CHECK_DESTRUCTION 1
+#endif
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+
+// Defined and documented later on in this file.
+template <typename T>
+struct is_trivially_destructible;
+
+// Defined and documented later on in this file.
+template <typename T>
+struct is_trivially_move_assignable;
+
+namespace type_traits_internal {
+
+// Silence MSVC warnings about the destructor being defined as deleted.
+#if defined(_MSC_VER) && !defined(__GNUC__)
+#pragma warning(push)
+#pragma warning(disable : 4624)
+#endif  // defined(_MSC_VER) && !defined(__GNUC__)
+
+template <class T>
+union SingleMemberUnion {
+  T t;
+};
+
+// Restore the state of the destructor warning that was silenced above.
+#if defined(_MSC_VER) && !defined(__GNUC__)
+#pragma warning(pop)
+#endif  // defined(_MSC_VER) && !defined(__GNUC__)
+
+template <class T>
+struct IsTriviallyMoveConstructibleObject
+    : std::integral_constant<
+          bool, std::is_move_constructible<
+                    type_traits_internal::SingleMemberUnion<T>>::value &&
+                    absl::is_trivially_destructible<T>::value> {};
+
+template <class T>
+struct IsTriviallyCopyConstructibleObject
+    : std::integral_constant<
+          bool, std::is_copy_constructible<
+                    type_traits_internal::SingleMemberUnion<T>>::value &&
+                    absl::is_trivially_destructible<T>::value> {};
+
+template <class T>
+struct IsTriviallyMoveAssignableReference : std::false_type {};
+
+template <class T>
+struct IsTriviallyMoveAssignableReference<T&>
+    : absl::is_trivially_move_assignable<T>::type {};
+
+template <class T>
+struct IsTriviallyMoveAssignableReference<T&&>
+    : absl::is_trivially_move_assignable<T>::type {};
+
+template <typename... Ts>
+struct VoidTImpl {
+  using type = void;
+};
+
+// This trick to retrieve a default alignment is necessary for our
+// implementation of aligned_storage_t to be consistent with any implementation
+// of std::aligned_storage.
+template <size_t Len, typename T = std::aligned_storage<Len>>
+struct default_alignment_of_aligned_storage;
+
+template <size_t Len, size_t Align>
+struct default_alignment_of_aligned_storage<Len,
+                                            std::aligned_storage<Len, Align>> {
+  static constexpr size_t value = Align;
+};
+
+////////////////////////////////
+// Library Fundamentals V2 TS //
+////////////////////////////////
+
+// NOTE: The `is_detected` family of templates here differ from the library
+// fundamentals specification in that for library fundamentals, `Op<Args...>` is
+// evaluated as soon as the type `is_detected<Op, Args...>` undergoes
+// substitution, regardless of whether or not the `::value` is accessed. That
+// is inconsistent with all other standard traits and prevents lazy evaluation
+// in larger contexts (such as if the `is_detected` check is a trailing argument
+// of a `conjunction`. This implementation opts to instead be lazy in the same
+// way that the standard traits are (this "defect" of the detection idiom
+// specifications has been reported).
+
+template <class Enabler, template <class...> class Op, class... Args>
+struct is_detected_impl {
+  using type = std::false_type;
+};
+
+template <template <class...> class Op, class... Args>
+struct is_detected_impl<typename VoidTImpl<Op<Args...>>::type, Op, Args...> {
+  using type = std::true_type;
+};
+
+template <template <class...> class Op, class... Args>
+struct is_detected : is_detected_impl<void, Op, Args...>::type {};
+
+template <class Enabler, class To, template <class...> class Op, class... Args>
+struct is_detected_convertible_impl {
+  using type = std::false_type;
+};
+
+template <class To, template <class...> class Op, class... Args>
+struct is_detected_convertible_impl<
+    typename std::enable_if<std::is_convertible<Op<Args...>, To>::value>::type,
+    To, Op, Args...> {
+  using type = std::true_type;
+};
+
+template <class To, template <class...> class Op, class... Args>
+struct is_detected_convertible
+    : is_detected_convertible_impl<void, To, Op, Args...>::type {};
+
+template <typename T>
+using IsCopyAssignableImpl =
+    decltype(std::declval<T&>() = std::declval<const T&>());
+
+template <typename T>
+using IsMoveAssignableImpl = decltype(std::declval<T&>() = std::declval<T&&>());
+
+}  // namespace type_traits_internal
+
+// MSVC 19.20 has a regression that causes our workarounds to fail, but their
+// std forms now appear to be compliant.
+#if defined(_MSC_VER) && !defined(__clang__) && (_MSC_VER >= 1920)
+
+template <typename T>
+using is_copy_assignable = std::is_copy_assignable<T>;
+
+template <typename T>
+using is_move_assignable = std::is_move_assignable<T>;
+
+#else
+
+template <typename T>
+struct is_copy_assignable : type_traits_internal::is_detected<
+                                type_traits_internal::IsCopyAssignableImpl, T> {
+};
+
+template <typename T>
+struct is_move_assignable : type_traits_internal::is_detected<
+                                type_traits_internal::IsMoveAssignableImpl, T> {
+};
+
+#endif
+
+// void_t()
+//
+// Ignores the type of any its arguments and returns `void`. In general, this
+// metafunction allows you to create a general case that maps to `void` while
+// allowing specializations that map to specific types.
+//
+// This metafunction is designed to be a drop-in replacement for the C++17
+// `std::void_t` metafunction.
+//
+// NOTE: `absl::void_t` does not use the standard-specified implementation so
+// that it can remain compatible with gcc < 5.1. This can introduce slightly
+// different behavior, such as when ordering partial specializations.
+template <typename... Ts>
+using void_t = typename type_traits_internal::VoidTImpl<Ts...>::type;
+
+// conjunction
+//
+// Performs a compile-time logical AND operation on the passed types (which
+// must have  `::value` members convertible to `bool`. Short-circuits if it
+// encounters any `false` members (and does not compare the `::value` members
+// of any remaining arguments).
+//
+// This metafunction is designed to be a drop-in replacement for the C++17
+// `std::conjunction` metafunction.
+template <typename... Ts>
+struct conjunction : std::true_type {};
+
+template <typename T, typename... Ts>
+struct conjunction<T, Ts...>
+    : std::conditional<T::value, conjunction<Ts...>, T>::type {};
+
+template <typename T>
+struct conjunction<T> : T {};
+
+// disjunction
+//
+// Performs a compile-time logical OR operation on the passed types (which
+// must have  `::value` members convertible to `bool`. Short-circuits if it
+// encounters any `true` members (and does not compare the `::value` members
+// of any remaining arguments).
+//
+// This metafunction is designed to be a drop-in replacement for the C++17
+// `std::disjunction` metafunction.
+template <typename... Ts>
+struct disjunction : std::false_type {};
+
+template <typename T, typename... Ts>
+struct disjunction<T, Ts...> :
+      std::conditional<T::value, T, disjunction<Ts...>>::type {};
+
+template <typename T>
+struct disjunction<T> : T {};
+
+// negation
+//
+// Performs a compile-time logical NOT operation on the passed type (which
+// must have  `::value` members convertible to `bool`.
+//
+// This metafunction is designed to be a drop-in replacement for the C++17
+// `std::negation` metafunction.
+template <typename T>
+struct negation : std::integral_constant<bool, !T::value> {};
+
+// is_function()
+//
+// Determines whether the passed type `T` is a function type.
+//
+// This metafunction is designed to be a drop-in replacement for the C++11
+// `std::is_function()` metafunction for platforms that have incomplete C++11
+// support (such as libstdc++ 4.x).
+//
+// This metafunction works because appending `const` to a type does nothing to
+// function types and reference types (and forms a const-qualified type
+// otherwise).
+template <typename T>
+struct is_function
+    : std::integral_constant<
+          bool, !(std::is_reference<T>::value ||
+                  std::is_const<typename std::add_const<T>::type>::value)> {};
+
+// is_trivially_destructible()
+//
+// Determines whether the passed type `T` is trivially destructible.
+//
+// This metafunction is designed to be a drop-in replacement for the C++11
+// `std::is_trivially_destructible()` metafunction for platforms that have
+// incomplete C++11 support (such as libstdc++ 4.x). On any platforms that do
+// fully support C++11, we check whether this yields the same result as the std
+// implementation.
+//
+// NOTE: the extensions (__has_trivial_xxx) are implemented in gcc (version >=
+// 4.3) and clang. Since we are supporting libstdc++ > 4.7, they should always
+// be present. These  extensions are documented at
+// https://gcc.gnu.org/onlinedocs/gcc/Type-Traits.html#Type-Traits.
+template <typename T>
+struct is_trivially_destructible
+    : std::integral_constant<bool, __has_trivial_destructor(T) &&
+                                   std::is_destructible<T>::value> {
+#ifdef ABSL_HAVE_STD_IS_TRIVIALLY_DESTRUCTIBLE
+ private:
+  static constexpr bool compliant = std::is_trivially_destructible<T>::value ==
+                                    is_trivially_destructible::value;
+  static_assert(compliant || std::is_trivially_destructible<T>::value,
+                "Not compliant with std::is_trivially_destructible; "
+                "Standard: false, Implementation: true");
+  static_assert(compliant || !std::is_trivially_destructible<T>::value,
+                "Not compliant with std::is_trivially_destructible; "
+                "Standard: true, Implementation: false");
+#endif  // ABSL_HAVE_STD_IS_TRIVIALLY_DESTRUCTIBLE
+};
+
+// is_trivially_default_constructible()
+//
+// Determines whether the passed type `T` is trivially default constructible.
+//
+// This metafunction is designed to be a drop-in replacement for the C++11
+// `std::is_trivially_default_constructible()` metafunction for platforms that
+// have incomplete C++11 support (such as libstdc++ 4.x). On any platforms that
+// do fully support C++11, we check whether this yields the same result as the
+// std implementation.
+//
+// NOTE: according to the C++ standard, Section: 20.15.4.3 [meta.unary.prop]
+// "The predicate condition for a template specialization is_constructible<T,
+// Args...> shall be satisfied if and only if the following variable
+// definition would be well-formed for some invented variable t:
+//
+// T t(declval<Args>()...);
+//
+// is_trivially_constructible<T, Args...> additionally requires that the
+// variable definition does not call any operation that is not trivial.
+// For the purposes of this check, the call to std::declval is considered
+// trivial."
+//
+// Notes from https://en.cppreference.com/w/cpp/types/is_constructible:
+// In many implementations, is_nothrow_constructible also checks if the
+// destructor throws because it is effectively noexcept(T(arg)). Same
+// applies to is_trivially_constructible, which, in these implementations, also
+// requires that the destructor is trivial.
+// GCC bug 51452: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=51452
+// LWG issue 2116: http://cplusplus.github.io/LWG/lwg-active.html#2116.
+//
+// "T obj();" need to be well-formed and not call any nontrivial operation.
+// Nontrivially destructible types will cause the expression to be nontrivial.
+template <typename T>
+struct is_trivially_default_constructible
+    : std::integral_constant<bool, __has_trivial_constructor(T) &&
+                                   std::is_default_constructible<T>::value &&
+                                   is_trivially_destructible<T>::value> {
+#if defined(ABSL_HAVE_STD_IS_TRIVIALLY_CONSTRUCTIBLE) && \
+    !defined(                                            \
+        ABSL_META_INTERNAL_STD_CONSTRUCTION_TRAITS_DONT_CHECK_DESTRUCTION)
+ private:
+  static constexpr bool compliant =
+      std::is_trivially_default_constructible<T>::value ==
+      is_trivially_default_constructible::value;
+  static_assert(compliant || std::is_trivially_default_constructible<T>::value,
+                "Not compliant with std::is_trivially_default_constructible; "
+                "Standard: false, Implementation: true");
+  static_assert(compliant || !std::is_trivially_default_constructible<T>::value,
+                "Not compliant with std::is_trivially_default_constructible; "
+                "Standard: true, Implementation: false");
+#endif  // ABSL_HAVE_STD_IS_TRIVIALLY_CONSTRUCTIBLE
+};
+
+// is_trivially_move_constructible()
+//
+// Determines whether the passed type `T` is trivially move constructible.
+//
+// This metafunction is designed to be a drop-in replacement for the C++11
+// `std::is_trivially_move_constructible()` metafunction for platforms that have
+// incomplete C++11 support (such as libstdc++ 4.x). On any platforms that do
+// fully support C++11, we check whether this yields the same result as the std
+// implementation.
+//
+// NOTE: `T obj(declval<T>());` needs to be well-formed and not call any
+// nontrivial operation.  Nontrivially destructible types will cause the
+// expression to be nontrivial.
+template <typename T>
+struct is_trivially_move_constructible
+    : std::conditional<
+          std::is_object<T>::value && !std::is_array<T>::value,
+          type_traits_internal::IsTriviallyMoveConstructibleObject<T>,
+          std::is_reference<T>>::type::type {
+#if defined(ABSL_HAVE_STD_IS_TRIVIALLY_CONSTRUCTIBLE) && \
+    !defined(                                            \
+        ABSL_META_INTERNAL_STD_CONSTRUCTION_TRAITS_DONT_CHECK_DESTRUCTION)
+ private:
+  static constexpr bool compliant =
+      std::is_trivially_move_constructible<T>::value ==
+      is_trivially_move_constructible::value;
+  static_assert(compliant || std::is_trivially_move_constructible<T>::value,
+                "Not compliant with std::is_trivially_move_constructible; "
+                "Standard: false, Implementation: true");
+  static_assert(compliant || !std::is_trivially_move_constructible<T>::value,
+                "Not compliant with std::is_trivially_move_constructible; "
+                "Standard: true, Implementation: false");
+#endif  // ABSL_HAVE_STD_IS_TRIVIALLY_CONSTRUCTIBLE
+};
+
+// is_trivially_copy_constructible()
+//
+// Determines whether the passed type `T` is trivially copy constructible.
+//
+// This metafunction is designed to be a drop-in replacement for the C++11
+// `std::is_trivially_copy_constructible()` metafunction for platforms that have
+// incomplete C++11 support (such as libstdc++ 4.x). On any platforms that do
+// fully support C++11, we check whether this yields the same result as the std
+// implementation.
+//
+// NOTE: `T obj(declval<const T&>());` needs to be well-formed and not call any
+// nontrivial operation.  Nontrivially destructible types will cause the
+// expression to be nontrivial.
+template <typename T>
+struct is_trivially_copy_constructible
+    : std::conditional<
+          std::is_object<T>::value && !std::is_array<T>::value,
+          type_traits_internal::IsTriviallyCopyConstructibleObject<T>,
+          std::is_lvalue_reference<T>>::type::type {
+#if defined(ABSL_HAVE_STD_IS_TRIVIALLY_CONSTRUCTIBLE) && \
+    !defined(                                            \
+        ABSL_META_INTERNAL_STD_CONSTRUCTION_TRAITS_DONT_CHECK_DESTRUCTION)
+ private:
+  static constexpr bool compliant =
+      std::is_trivially_copy_constructible<T>::value ==
+      is_trivially_copy_constructible::value;
+  static_assert(compliant || std::is_trivially_copy_constructible<T>::value,
+                "Not compliant with std::is_trivially_copy_constructible; "
+                "Standard: false, Implementation: true");
+  static_assert(compliant || !std::is_trivially_copy_constructible<T>::value,
+                "Not compliant with std::is_trivially_copy_constructible; "
+                "Standard: true, Implementation: false");
+#endif  // ABSL_HAVE_STD_IS_TRIVIALLY_CONSTRUCTIBLE
+};
+
+// is_trivially_move_assignable()
+//
+// Determines whether the passed type `T` is trivially move assignable.
+//
+// This metafunction is designed to be a drop-in replacement for the C++11
+// `std::is_trivially_move_assignable()` metafunction for platforms that have
+// incomplete C++11 support (such as libstdc++ 4.x). On any platforms that do
+// fully support C++11, we check whether this yields the same result as the std
+// implementation.
+//
+// NOTE: `is_assignable<T, U>::value` is `true` if the expression
+// `declval<T>() = declval<U>()` is well-formed when treated as an unevaluated
+// operand. `is_trivially_assignable<T, U>` requires the assignment to call no
+// operation that is not trivial. `is_trivially_copy_assignable<T>` is simply
+// `is_trivially_assignable<T&, T>`.
+template <typename T>
+struct is_trivially_move_assignable
+    : std::conditional<
+          std::is_object<T>::value && !std::is_array<T>::value &&
+              std::is_move_assignable<T>::value,
+          std::is_move_assignable<type_traits_internal::SingleMemberUnion<T>>,
+          type_traits_internal::IsTriviallyMoveAssignableReference<T>>::type::
+          type {
+#ifdef ABSL_HAVE_STD_IS_TRIVIALLY_ASSIGNABLE
+ private:
+  static constexpr bool compliant =
+      std::is_trivially_move_assignable<T>::value ==
+      is_trivially_move_assignable::value;
+  static_assert(compliant || std::is_trivially_move_assignable<T>::value,
+                "Not compliant with std::is_trivially_move_assignable; "
+                "Standard: false, Implementation: true");
+  static_assert(compliant || !std::is_trivially_move_assignable<T>::value,
+                "Not compliant with std::is_trivially_move_assignable; "
+                "Standard: true, Implementation: false");
+#endif  // ABSL_HAVE_STD_IS_TRIVIALLY_ASSIGNABLE
+};
+
+// is_trivially_copy_assignable()
+//
+// Determines whether the passed type `T` is trivially copy assignable.
+//
+// This metafunction is designed to be a drop-in replacement for the C++11
+// `std::is_trivially_copy_assignable()` metafunction for platforms that have
+// incomplete C++11 support (such as libstdc++ 4.x). On any platforms that do
+// fully support C++11, we check whether this yields the same result as the std
+// implementation.
+//
+// NOTE: `is_assignable<T, U>::value` is `true` if the expression
+// `declval<T>() = declval<U>()` is well-formed when treated as an unevaluated
+// operand. `is_trivially_assignable<T, U>` requires the assignment to call no
+// operation that is not trivial. `is_trivially_copy_assignable<T>` is simply
+// `is_trivially_assignable<T&, const T&>`.
+template <typename T>
+struct is_trivially_copy_assignable
+    : std::integral_constant<
+          bool, __has_trivial_assign(typename std::remove_reference<T>::type) &&
+                    absl::is_copy_assignable<T>::value> {
+#ifdef ABSL_HAVE_STD_IS_TRIVIALLY_ASSIGNABLE
+ private:
+  static constexpr bool compliant =
+      std::is_trivially_copy_assignable<T>::value ==
+      is_trivially_copy_assignable::value;
+  static_assert(compliant || std::is_trivially_copy_assignable<T>::value,
+                "Not compliant with std::is_trivially_copy_assignable; "
+                "Standard: false, Implementation: true");
+  static_assert(compliant || !std::is_trivially_copy_assignable<T>::value,
+                "Not compliant with std::is_trivially_copy_assignable; "
+                "Standard: true, Implementation: false");
+#endif  // ABSL_HAVE_STD_IS_TRIVIALLY_ASSIGNABLE
+};
+
+namespace type_traits_internal {
+// is_trivially_copyable()
+//
+// Determines whether the passed type `T` is trivially copyable.
+//
+// This metafunction is designed to be a drop-in replacement for the C++11
+// `std::is_trivially_copyable()` metafunction for platforms that have
+// incomplete C++11 support (such as libstdc++ 4.x). We use the C++17 definition
+// of TriviallyCopyable.
+//
+// NOTE: `is_trivially_copyable<T>::value` is `true` if all of T's copy/move
+// constructors/assignment operators are trivial or deleted, T has at least
+// one non-deleted copy/move constructor/assignment operator, and T is trivially
+// destructible. Arrays of trivially copyable types are trivially copyable.
+//
+// We expose this metafunction only for internal use within absl.
+template <typename T>
+class is_trivially_copyable_impl {
+  using ExtentsRemoved = typename std::remove_all_extents<T>::type;
+  static constexpr bool kIsCopyOrMoveConstructible =
+      std::is_copy_constructible<ExtentsRemoved>::value ||
+      std::is_move_constructible<ExtentsRemoved>::value;
+  static constexpr bool kIsCopyOrMoveAssignable =
+      absl::is_copy_assignable<ExtentsRemoved>::value ||
+      absl::is_move_assignable<ExtentsRemoved>::value;
+
+ public:
+  static constexpr bool kValue =
+      (__has_trivial_copy(ExtentsRemoved) || !kIsCopyOrMoveConstructible) &&
+      (__has_trivial_assign(ExtentsRemoved) || !kIsCopyOrMoveAssignable) &&
+      (kIsCopyOrMoveConstructible || kIsCopyOrMoveAssignable) &&
+      is_trivially_destructible<ExtentsRemoved>::value &&
+      // We need to check for this explicitly because otherwise we'll say
+      // references are trivial copyable when compiled by MSVC.
+      !std::is_reference<ExtentsRemoved>::value;
+};
+
+template <typename T>
+struct is_trivially_copyable
+    : std::integral_constant<
+          bool, type_traits_internal::is_trivially_copyable_impl<T>::kValue> {};
+}  // namespace type_traits_internal
+
+// -----------------------------------------------------------------------------
+// C++14 "_t" trait aliases
+// -----------------------------------------------------------------------------
+
+template <typename T>
+using remove_cv_t = typename std::remove_cv<T>::type;
+
+template <typename T>
+using remove_const_t = typename std::remove_const<T>::type;
+
+template <typename T>
+using remove_volatile_t = typename std::remove_volatile<T>::type;
+
+template <typename T>
+using add_cv_t = typename std::add_cv<T>::type;
+
+template <typename T>
+using add_const_t = typename std::add_const<T>::type;
+
+template <typename T>
+using add_volatile_t = typename std::add_volatile<T>::type;
+
+template <typename T>
+using remove_reference_t = typename std::remove_reference<T>::type;
+
+template <typename T>
+using add_lvalue_reference_t = typename std::add_lvalue_reference<T>::type;
+
+template <typename T>
+using add_rvalue_reference_t = typename std::add_rvalue_reference<T>::type;
+
+template <typename T>
+using remove_pointer_t = typename std::remove_pointer<T>::type;
+
+template <typename T>
+using add_pointer_t = typename std::add_pointer<T>::type;
+
+template <typename T>
+using make_signed_t = typename std::make_signed<T>::type;
+
+template <typename T>
+using make_unsigned_t = typename std::make_unsigned<T>::type;
+
+template <typename T>
+using remove_extent_t = typename std::remove_extent<T>::type;
+
+template <typename T>
+using remove_all_extents_t = typename std::remove_all_extents<T>::type;
+
+template <size_t Len, size_t Align = type_traits_internal::
+                          default_alignment_of_aligned_storage<Len>::value>
+using aligned_storage_t = typename std::aligned_storage<Len, Align>::type;
+
+template <typename T>
+using decay_t = typename std::decay<T>::type;
+
+template <bool B, typename T = void>
+using enable_if_t = typename std::enable_if<B, T>::type;
+
+template <bool B, typename T, typename F>
+using conditional_t = typename std::conditional<B, T, F>::type;
+
+template <typename... T>
+using common_type_t = typename std::common_type<T...>::type;
+
+template <typename T>
+using underlying_type_t = typename std::underlying_type<T>::type;
+
+
+namespace type_traits_internal {
+
+#if __cplusplus >= 201703L
+// std::result_of is deprecated (C++17) or removed (C++20)
+template<typename> struct result_of;
+template<typename F, typename... Args>
+struct result_of<F(Args...)> : std::invoke_result<F, Args...> {};
+#else
+template<typename F> using result_of = std::result_of<F>;
+#endif
+
+}  // namespace type_traits_internal
+
+template<typename F>
+using result_of_t = typename type_traits_internal::result_of<F>::type;
+
+namespace type_traits_internal {
+// In MSVC we can't probe std::hash or stdext::hash because it triggers a
+// static_assert instead of failing substitution. Libc++ prior to 4.0
+// also used a static_assert.
+//
+#if defined(_MSC_VER) || (defined(_LIBCPP_VERSION) && \
+                          _LIBCPP_VERSION < 4000 && _LIBCPP_STD_VER > 11)
+#define ABSL_META_INTERNAL_STD_HASH_SFINAE_FRIENDLY_ 0
+#else
+#define ABSL_META_INTERNAL_STD_HASH_SFINAE_FRIENDLY_ 1
+#endif
+
+#if !ABSL_META_INTERNAL_STD_HASH_SFINAE_FRIENDLY_
+template <typename Key, typename = size_t>
+struct IsHashable : std::true_type {};
+#else   // ABSL_META_INTERNAL_STD_HASH_SFINAE_FRIENDLY_
+template <typename Key, typename = void>
+struct IsHashable : std::false_type {};
+
+template <typename Key>
+struct IsHashable<
+    Key,
+    absl::enable_if_t<std::is_convertible<
+        decltype(std::declval<std::hash<Key>&>()(std::declval<Key const&>())),
+        std::size_t>::value>> : std::true_type {};
+#endif  // !ABSL_META_INTERNAL_STD_HASH_SFINAE_FRIENDLY_
+
+struct AssertHashEnabledHelper {
+ private:
+  static void Sink(...) {}
+  struct NAT {};
+
+  template <class Key>
+  static auto GetReturnType(int)
+      -> decltype(std::declval<std::hash<Key>>()(std::declval<Key const&>()));
+  template <class Key>
+  static NAT GetReturnType(...);
+
+  template <class Key>
+  static std::nullptr_t DoIt() {
+    static_assert(IsHashable<Key>::value,
+                  "std::hash<Key> does not provide a call operator");
+    static_assert(
+        std::is_default_constructible<std::hash<Key>>::value,
+        "std::hash<Key> must be default constructible when it is enabled");
+    static_assert(
+        std::is_copy_constructible<std::hash<Key>>::value,
+        "std::hash<Key> must be copy constructible when it is enabled");
+    static_assert(absl::is_copy_assignable<std::hash<Key>>::value,
+                  "std::hash<Key> must be copy assignable when it is enabled");
+    // is_destructible is unchecked as it's implied by each of the
+    // is_constructible checks.
+    using ReturnType = decltype(GetReturnType<Key>(0));
+    static_assert(std::is_same<ReturnType, NAT>::value ||
+                      std::is_same<ReturnType, size_t>::value,
+                  "std::hash<Key> must return size_t");
+    return nullptr;
+  }
+
+  template <class... Ts>
+  friend void AssertHashEnabled();
+};
+
+template <class... Ts>
+inline void AssertHashEnabled() {
+  using Helper = AssertHashEnabledHelper;
+  Helper::Sink(Helper::DoIt<Ts>()...);
+}
+
+}  // namespace type_traits_internal
+
+// An internal namespace that is required to implement the C++17 swap traits.
+// It is not further nested in type_traits_internal to avoid long symbol names.
+namespace swap_internal {
+
+// Necessary for the traits.
+using std::swap;
+
+// This declaration prevents global `swap` and `absl::swap` overloads from being
+// considered unless ADL picks them up.
+void swap();
+
+template <class T>
+using IsSwappableImpl = decltype(swap(std::declval<T&>(), std::declval<T&>()));
+
+// NOTE: This dance with the default template parameter is for MSVC.
+template <class T,
+          class IsNoexcept = std::integral_constant<
+              bool, noexcept(swap(std::declval<T&>(), std::declval<T&>()))>>
+using IsNothrowSwappableImpl = typename std::enable_if<IsNoexcept::value>::type;
+
+// IsSwappable
+//
+// Determines whether the standard swap idiom is a valid expression for
+// arguments of type `T`.
+template <class T>
+struct IsSwappable
+    : absl::type_traits_internal::is_detected<IsSwappableImpl, T> {};
+
+// IsNothrowSwappable
+//
+// Determines whether the standard swap idiom is a valid expression for
+// arguments of type `T` and is noexcept.
+template <class T>
+struct IsNothrowSwappable
+    : absl::type_traits_internal::is_detected<IsNothrowSwappableImpl, T> {};
+
+// Swap()
+//
+// Performs the swap idiom from a namespace where valid candidates may only be
+// found in `std` or via ADL.
+template <class T, absl::enable_if_t<IsSwappable<T>::value, int> = 0>
+void Swap(T& lhs, T& rhs) noexcept(IsNothrowSwappable<T>::value) {
+  swap(lhs, rhs);
+}
+
+// StdSwapIsUnconstrained
+//
+// Some standard library implementations are broken in that they do not
+// constrain `std::swap`. This will effectively tell us if we are dealing with
+// one of those implementations.
+using StdSwapIsUnconstrained = IsSwappable<void()>;
+
+}  // namespace swap_internal
+
+namespace type_traits_internal {
+
+// Make the swap-related traits/function accessible from this namespace.
+using swap_internal::IsNothrowSwappable;
+using swap_internal::IsSwappable;
+using swap_internal::Swap;
+using swap_internal::StdSwapIsUnconstrained;
+
+}  // namespace type_traits_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#endif  // ABSL_META_TYPE_TRAITS_H_
diff --git a/src/absl/numeric/bits.h b/src/absl/numeric/bits.h
new file mode 100644 (file)
index 0000000..52013ad
--- /dev/null
@@ -0,0 +1,177 @@
+// Copyright 2020 The Abseil Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// -----------------------------------------------------------------------------
+// File: bits.h
+// -----------------------------------------------------------------------------
+//
+// This file contains implementations of C++20's bitwise math functions, as
+// defined by:
+//
+// P0553R4:
+//  http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p0553r4.html
+// P0556R3:
+//  http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p0556r3.html
+// P1355R2:
+//  http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p1355r2.html
+// P1956R1:
+//  http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2020/p1956r1.pdf
+//
+// When using a standard library that implements these functions, we use the
+// standard library's implementation.
+
+#ifndef ABSL_NUMERIC_BITS_H_
+#define ABSL_NUMERIC_BITS_H_
+
+#include <cstdint>
+#include <limits>
+#include <type_traits>
+
+#if (defined(__cpp_lib_int_pow2) && __cpp_lib_int_pow2 >= 202002L) || \
+    (defined(__cpp_lib_bitops) && __cpp_lib_bitops >= 201907L)
+#include <bit>
+#endif
+
+#include "absl/base/attributes.h"
+#include "absl/base/config.h"
+#include "absl/numeric/internal/bits.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+
+#if !(defined(__cpp_lib_bitops) && __cpp_lib_bitops >= 201907L)
+// rotating
+template <class T>
+ABSL_MUST_USE_RESULT constexpr
+    typename std::enable_if<std::is_unsigned<T>::value, T>::type
+    rotl(T x, int s) noexcept {
+  return numeric_internal::RotateLeft(x, s);
+}
+
+template <class T>
+ABSL_MUST_USE_RESULT constexpr
+    typename std::enable_if<std::is_unsigned<T>::value, T>::type
+    rotr(T x, int s) noexcept {
+  return numeric_internal::RotateRight(x, s);
+}
+
+// Counting functions
+//
+// While these functions are typically constexpr, on some platforms, they may
+// not be marked as constexpr due to constraints of the compiler/available
+// intrinsics.
+template <class T>
+ABSL_INTERNAL_CONSTEXPR_CLZ inline
+    typename std::enable_if<std::is_unsigned<T>::value, int>::type
+    countl_zero(T x) noexcept {
+  return numeric_internal::CountLeadingZeroes(x);
+}
+
+template <class T>
+ABSL_INTERNAL_CONSTEXPR_CLZ inline
+    typename std::enable_if<std::is_unsigned<T>::value, int>::type
+    countl_one(T x) noexcept {
+  // Avoid integer promotion to a wider type
+  return countl_zero(static_cast<T>(~x));
+}
+
+template <class T>
+ABSL_INTERNAL_CONSTEXPR_CTZ inline
+    typename std::enable_if<std::is_unsigned<T>::value, int>::type
+    countr_zero(T x) noexcept {
+  return numeric_internal::CountTrailingZeroes(x);
+}
+
+template <class T>
+ABSL_INTERNAL_CONSTEXPR_CTZ inline
+    typename std::enable_if<std::is_unsigned<T>::value, int>::type
+    countr_one(T x) noexcept {
+  // Avoid integer promotion to a wider type
+  return countr_zero(static_cast<T>(~x));
+}
+
+template <class T>
+ABSL_INTERNAL_CONSTEXPR_POPCOUNT inline
+    typename std::enable_if<std::is_unsigned<T>::value, int>::type
+    popcount(T x) noexcept {
+  return numeric_internal::Popcount(x);
+}
+#else  // defined(__cpp_lib_bitops) && __cpp_lib_bitops >= 201907L
+
+using std::countl_one;
+using std::countl_zero;
+using std::countr_one;
+using std::countr_zero;
+using std::popcount;
+using std::rotl;
+using std::rotr;
+
+#endif
+
+#if !(defined(__cpp_lib_int_pow2) && __cpp_lib_int_pow2 >= 202002L)
+// Returns: true if x is an integral power of two; false otherwise.
+template <class T>
+constexpr inline typename std::enable_if<std::is_unsigned<T>::value, bool>::type
+has_single_bit(T x) noexcept {
+  return x != 0 && (x & (x - 1)) == 0;
+}
+
+// Returns: If x == 0, 0; otherwise one plus the base-2 logarithm of x, with any
+// fractional part discarded.
+template <class T>
+ABSL_INTERNAL_CONSTEXPR_CLZ inline
+    typename std::enable_if<std::is_unsigned<T>::value, T>::type
+    bit_width(T x) noexcept {
+  return std::numeric_limits<T>::digits - countl_zero(x);
+}
+
+// Returns: If x == 0, 0; otherwise the maximal value y such that
+// has_single_bit(y) is true and y <= x.
+template <class T>
+ABSL_INTERNAL_CONSTEXPR_CLZ inline
+    typename std::enable_if<std::is_unsigned<T>::value, T>::type
+    bit_floor(T x) noexcept {
+  return x == 0 ? 0 : T{1} << (bit_width(x) - 1);
+}
+
+// Returns: N, where N is the smallest power of 2 greater than or equal to x.
+//
+// Preconditions: N is representable as a value of type T.
+template <class T>
+ABSL_INTERNAL_CONSTEXPR_CLZ inline
+    typename std::enable_if<std::is_unsigned<T>::value, T>::type
+    bit_ceil(T x) {
+  // If T is narrower than unsigned, T{1} << bit_width will be promoted.  We
+  // want to force it to wraparound so that bit_ceil of an invalid value are not
+  // core constant expressions.
+  //
+  // BitCeilNonPowerOf2 triggers an overflow in constexpr contexts if we would
+  // undergo promotion to unsigned but not fit the result into T without
+  // truncation.
+  return has_single_bit(x) ? T{1} << (bit_width(x) - 1)
+                           : numeric_internal::BitCeilNonPowerOf2(x);
+}
+#else  // defined(__cpp_lib_int_pow2) && __cpp_lib_int_pow2 >= 202002L
+
+using std::bit_ceil;
+using std::bit_floor;
+using std::bit_width;
+using std::has_single_bit;
+
+#endif
+
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#endif  // ABSL_NUMERIC_BITS_H_
diff --git a/src/absl/numeric/int128.cc b/src/absl/numeric/int128.cc
new file mode 100644 (file)
index 0000000..5160df7
--- /dev/null
@@ -0,0 +1,390 @@
+// Copyright 2017 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "absl/numeric/int128.h"
+
+#include <stddef.h>
+
+#include <cassert>
+#include <iomanip>
+#include <ostream>  // NOLINT(readability/streams)
+#include <sstream>
+#include <string>
+#include <type_traits>
+
+#include "absl/base/optimization.h"
+#include "absl/numeric/bits.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+
+ABSL_DLL const uint128 kuint128max = MakeUint128(
+    std::numeric_limits<uint64_t>::max(), std::numeric_limits<uint64_t>::max());
+
+namespace {
+
+// Returns the 0-based position of the last set bit (i.e., most significant bit)
+// in the given uint128. The argument is not 0.
+//
+// For example:
+//   Given: 5 (decimal) == 101 (binary)
+//   Returns: 2
+inline ABSL_ATTRIBUTE_ALWAYS_INLINE int Fls128(uint128 n) {
+  if (uint64_t hi = Uint128High64(n)) {
+    ABSL_INTERNAL_ASSUME(hi != 0);
+    return 127 - countl_zero(hi);
+  }
+  const uint64_t low = Uint128Low64(n);
+  ABSL_INTERNAL_ASSUME(low != 0);
+  return 63 - countl_zero(low);
+}
+
+// Long division/modulo for uint128 implemented using the shift-subtract
+// division algorithm adapted from:
+// https://stackoverflow.com/questions/5386377/division-without-using
+inline void DivModImpl(uint128 dividend, uint128 divisor, uint128* quotient_ret,
+                       uint128* remainder_ret) {
+  assert(divisor != 0);
+
+  if (divisor > dividend) {
+    *quotient_ret = 0;
+    *remainder_ret = dividend;
+    return;
+  }
+
+  if (divisor == dividend) {
+    *quotient_ret = 1;
+    *remainder_ret = 0;
+    return;
+  }
+
+  uint128 denominator = divisor;
+  uint128 quotient = 0;
+
+  // Left aligns the MSB of the denominator and the dividend.
+  const int shift = Fls128(dividend) - Fls128(denominator);
+  denominator <<= shift;
+
+  // Uses shift-subtract algorithm to divide dividend by denominator. The
+  // remainder will be left in dividend.
+  for (int i = 0; i <= shift; ++i) {
+    quotient <<= 1;
+    if (dividend >= denominator) {
+      dividend -= denominator;
+      quotient |= 1;
+    }
+    denominator >>= 1;
+  }
+
+  *quotient_ret = quotient;
+  *remainder_ret = dividend;
+}
+
+template <typename T>
+uint128 MakeUint128FromFloat(T v) {
+  static_assert(std::is_floating_point<T>::value, "");
+
+  // Rounding behavior is towards zero, same as for built-in types.
+
+  // Undefined behavior if v is NaN or cannot fit into uint128.
+  assert(std::isfinite(v) && v > -1 &&
+         (std::numeric_limits<T>::max_exponent <= 128 ||
+          v < std::ldexp(static_cast<T>(1), 128)));
+
+  if (v >= std::ldexp(static_cast<T>(1), 64)) {
+    uint64_t hi = static_cast<uint64_t>(std::ldexp(v, -64));
+    uint64_t lo = static_cast<uint64_t>(v - std::ldexp(static_cast<T>(hi), 64));
+    return MakeUint128(hi, lo);
+  }
+
+  return MakeUint128(0, static_cast<uint64_t>(v));
+}
+
+#if defined(__clang__) && !defined(__SSE3__)
+// Workaround for clang bug: https://bugs.llvm.org/show_bug.cgi?id=38289
+// Casting from long double to uint64_t is miscompiled and drops bits.
+// It is more work, so only use when we need the workaround.
+uint128 MakeUint128FromFloat(long double v) {
+  // Go 50 bits at a time, that fits in a double
+  static_assert(std::numeric_limits<double>::digits >= 50, "");
+  static_assert(std::numeric_limits<long double>::digits <= 150, "");
+  // Undefined behavior if v is not finite or cannot fit into uint128.
+  assert(std::isfinite(v) && v > -1 && v < std::ldexp(1.0L, 128));
+
+  v = std::ldexp(v, -100);
+  uint64_t w0 = static_cast<uint64_t>(static_cast<double>(std::trunc(v)));
+  v = std::ldexp(v - static_cast<double>(w0), 50);
+  uint64_t w1 = static_cast<uint64_t>(static_cast<double>(std::trunc(v)));
+  v = std::ldexp(v - static_cast<double>(w1), 50);
+  uint64_t w2 = static_cast<uint64_t>(static_cast<double>(std::trunc(v)));
+  return (static_cast<uint128>(w0) << 100) | (static_cast<uint128>(w1) << 50) |
+         static_cast<uint128>(w2);
+}
+#endif  // __clang__ && !__SSE3__
+}  // namespace
+
+uint128::uint128(float v) : uint128(MakeUint128FromFloat(v)) {}
+uint128::uint128(double v) : uint128(MakeUint128FromFloat(v)) {}
+uint128::uint128(long double v) : uint128(MakeUint128FromFloat(v)) {}
+
+uint128 operator/(uint128 lhs, uint128 rhs) {
+#if defined(ABSL_HAVE_INTRINSIC_INT128)
+  return static_cast<unsigned __int128>(lhs) /
+         static_cast<unsigned __int128>(rhs);
+#else  // ABSL_HAVE_INTRINSIC_INT128
+  uint128 quotient = 0;
+  uint128 remainder = 0;
+  DivModImpl(lhs, rhs, &quotient, &remainder);
+  return quotient;
+#endif  // ABSL_HAVE_INTRINSIC_INT128
+}
+uint128 operator%(uint128 lhs, uint128 rhs) {
+#if defined(ABSL_HAVE_INTRINSIC_INT128)
+  return static_cast<unsigned __int128>(lhs) %
+         static_cast<unsigned __int128>(rhs);
+#else  // ABSL_HAVE_INTRINSIC_INT128
+  uint128 quotient = 0;
+  uint128 remainder = 0;
+  DivModImpl(lhs, rhs, &quotient, &remainder);
+  return remainder;
+#endif  // ABSL_HAVE_INTRINSIC_INT128
+}
+
+namespace {
+
+std::string Uint128ToFormattedString(uint128 v, std::ios_base::fmtflags flags) {
+  // Select a divisor which is the largest power of the base < 2^64.
+  uint128 div;
+  int div_base_log;
+  switch (flags & std::ios::basefield) {
+    case std::ios::hex:
+      div = 0x1000000000000000;  // 16^15
+      div_base_log = 15;
+      break;
+    case std::ios::oct:
+      div = 01000000000000000000000;  // 8^21
+      div_base_log = 21;
+      break;
+    default:  // std::ios::dec
+      div = 10000000000000000000u;  // 10^19
+      div_base_log = 19;
+      break;
+  }
+
+  // Now piece together the uint128 representation from three chunks of the
+  // original value, each less than "div" and therefore representable as a
+  // uint64_t.
+  std::ostringstream os;
+  std::ios_base::fmtflags copy_mask =
+      std::ios::basefield | std::ios::showbase | std::ios::uppercase;
+  os.setf(flags & copy_mask, copy_mask);
+  uint128 high = v;
+  uint128 low;
+  DivModImpl(high, div, &high, &low);
+  uint128 mid;
+  DivModImpl(high, div, &high, &mid);
+  if (Uint128Low64(high) != 0) {
+    os << Uint128Low64(high);
+    os << std::noshowbase << std::setfill('0') << std::setw(div_base_log);
+    os << Uint128Low64(mid);
+    os << std::setw(div_base_log);
+  } else if (Uint128Low64(mid) != 0) {
+    os << Uint128Low64(mid);
+    os << std::noshowbase << std::setfill('0') << std::setw(div_base_log);
+  }
+  os << Uint128Low64(low);
+  return os.str();
+}
+
+}  // namespace
+
+std::ostream& operator<<(std::ostream& os, uint128 v) {
+  std::ios_base::fmtflags flags = os.flags();
+  std::string rep = Uint128ToFormattedString(v, flags);
+
+  // Add the requisite padding.
+  std::streamsize width = os.width(0);
+  if (static_cast<size_t>(width) > rep.size()) {
+    std::ios::fmtflags adjustfield = flags & std::ios::adjustfield;
+    if (adjustfield == std::ios::left) {
+      rep.append(width - rep.size(), os.fill());
+    } else if (adjustfield == std::ios::internal &&
+               (flags & std::ios::showbase) &&
+               (flags & std::ios::basefield) == std::ios::hex && v != 0) {
+      rep.insert(2, width - rep.size(), os.fill());
+    } else {
+      rep.insert(0, width - rep.size(), os.fill());
+    }
+  }
+
+  return os << rep;
+}
+
+namespace {
+
+uint128 UnsignedAbsoluteValue(int128 v) {
+  // Cast to uint128 before possibly negating because -Int128Min() is undefined.
+  return Int128High64(v) < 0 ? -uint128(v) : uint128(v);
+}
+
+}  // namespace
+
+#if !defined(ABSL_HAVE_INTRINSIC_INT128)
+namespace {
+
+template <typename T>
+int128 MakeInt128FromFloat(T v) {
+  // Conversion when v is NaN or cannot fit into int128 would be undefined
+  // behavior if using an intrinsic 128-bit integer.
+  assert(std::isfinite(v) && (std::numeric_limits<T>::max_exponent <= 127 ||
+                              (v >= -std::ldexp(static_cast<T>(1), 127) &&
+                               v < std::ldexp(static_cast<T>(1), 127))));
+
+  // We must convert the absolute value and then negate as needed, because
+  // floating point types are typically sign-magnitude. Otherwise, the
+  // difference between the high and low 64 bits when interpreted as two's
+  // complement overwhelms the precision of the mantissa.
+  uint128 result = v < 0 ? -MakeUint128FromFloat(-v) : MakeUint128FromFloat(v);
+  return MakeInt128(int128_internal::BitCastToSigned(Uint128High64(result)),
+                    Uint128Low64(result));
+}
+
+}  // namespace
+
+int128::int128(float v) : int128(MakeInt128FromFloat(v)) {}
+int128::int128(double v) : int128(MakeInt128FromFloat(v)) {}
+int128::int128(long double v) : int128(MakeInt128FromFloat(v)) {}
+
+int128 operator/(int128 lhs, int128 rhs) {
+  assert(lhs != Int128Min() || rhs != -1);  // UB on two's complement.
+
+  uint128 quotient = 0;
+  uint128 remainder = 0;
+  DivModImpl(UnsignedAbsoluteValue(lhs), UnsignedAbsoluteValue(rhs),
+             &quotient, &remainder);
+  if ((Int128High64(lhs) < 0) != (Int128High64(rhs) < 0)) quotient = -quotient;
+  return MakeInt128(int128_internal::BitCastToSigned(Uint128High64(quotient)),
+                    Uint128Low64(quotient));
+}
+
+int128 operator%(int128 lhs, int128 rhs) {
+  assert(lhs != Int128Min() || rhs != -1);  // UB on two's complement.
+
+  uint128 quotient = 0;
+  uint128 remainder = 0;
+  DivModImpl(UnsignedAbsoluteValue(lhs), UnsignedAbsoluteValue(rhs),
+             &quotient, &remainder);
+  if (Int128High64(lhs) < 0) remainder = -remainder;
+  return MakeInt128(int128_internal::BitCastToSigned(Uint128High64(remainder)),
+                    Uint128Low64(remainder));
+}
+#endif  // ABSL_HAVE_INTRINSIC_INT128
+
+std::ostream& operator<<(std::ostream& os, int128 v) {
+  std::ios_base::fmtflags flags = os.flags();
+  std::string rep;
+
+  // Add the sign if needed.
+  bool print_as_decimal =
+      (flags & std::ios::basefield) == std::ios::dec ||
+      (flags & std::ios::basefield) == std::ios_base::fmtflags();
+  if (print_as_decimal) {
+    if (Int128High64(v) < 0) {
+      rep = "-";
+    } else if (flags & std::ios::showpos) {
+      rep = "+";
+    }
+  }
+
+  rep.append(Uint128ToFormattedString(
+      print_as_decimal ? UnsignedAbsoluteValue(v) : uint128(v), os.flags()));
+
+  // Add the requisite padding.
+  std::streamsize width = os.width(0);
+  if (static_cast<size_t>(width) > rep.size()) {
+    switch (flags & std::ios::adjustfield) {
+      case std::ios::left:
+        rep.append(width - rep.size(), os.fill());
+        break;
+      case std::ios::internal:
+        if (print_as_decimal && (rep[0] == '+' || rep[0] == '-')) {
+          rep.insert(1, width - rep.size(), os.fill());
+        } else if ((flags & std::ios::basefield) == std::ios::hex &&
+                   (flags & std::ios::showbase) && v != 0) {
+          rep.insert(2, width - rep.size(), os.fill());
+        } else {
+          rep.insert(0, width - rep.size(), os.fill());
+        }
+        break;
+      default:  // std::ios::right
+        rep.insert(0, width - rep.size(), os.fill());
+        break;
+    }
+  }
+
+  return os << rep;
+}
+
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+namespace std {
+constexpr bool numeric_limits<absl::uint128>::is_specialized;
+constexpr bool numeric_limits<absl::uint128>::is_signed;
+constexpr bool numeric_limits<absl::uint128>::is_integer;
+constexpr bool numeric_limits<absl::uint128>::is_exact;
+constexpr bool numeric_limits<absl::uint128>::has_infinity;
+constexpr bool numeric_limits<absl::uint128>::has_quiet_NaN;
+constexpr bool numeric_limits<absl::uint128>::has_signaling_NaN;
+constexpr float_denorm_style numeric_limits<absl::uint128>::has_denorm;
+constexpr bool numeric_limits<absl::uint128>::has_denorm_loss;
+constexpr float_round_style numeric_limits<absl::uint128>::round_style;
+constexpr bool numeric_limits<absl::uint128>::is_iec559;
+constexpr bool numeric_limits<absl::uint128>::is_bounded;
+constexpr bool numeric_limits<absl::uint128>::is_modulo;
+constexpr int numeric_limits<absl::uint128>::digits;
+constexpr int numeric_limits<absl::uint128>::digits10;
+constexpr int numeric_limits<absl::uint128>::max_digits10;
+constexpr int numeric_limits<absl::uint128>::radix;
+constexpr int numeric_limits<absl::uint128>::min_exponent;
+constexpr int numeric_limits<absl::uint128>::min_exponent10;
+constexpr int numeric_limits<absl::uint128>::max_exponent;
+constexpr int numeric_limits<absl::uint128>::max_exponent10;
+constexpr bool numeric_limits<absl::uint128>::traps;
+constexpr bool numeric_limits<absl::uint128>::tinyness_before;
+
+constexpr bool numeric_limits<absl::int128>::is_specialized;
+constexpr bool numeric_limits<absl::int128>::is_signed;
+constexpr bool numeric_limits<absl::int128>::is_integer;
+constexpr bool numeric_limits<absl::int128>::is_exact;
+constexpr bool numeric_limits<absl::int128>::has_infinity;
+constexpr bool numeric_limits<absl::int128>::has_quiet_NaN;
+constexpr bool numeric_limits<absl::int128>::has_signaling_NaN;
+constexpr float_denorm_style numeric_limits<absl::int128>::has_denorm;
+constexpr bool numeric_limits<absl::int128>::has_denorm_loss;
+constexpr float_round_style numeric_limits<absl::int128>::round_style;
+constexpr bool numeric_limits<absl::int128>::is_iec559;
+constexpr bool numeric_limits<absl::int128>::is_bounded;
+constexpr bool numeric_limits<absl::int128>::is_modulo;
+constexpr int numeric_limits<absl::int128>::digits;
+constexpr int numeric_limits<absl::int128>::digits10;
+constexpr int numeric_limits<absl::int128>::max_digits10;
+constexpr int numeric_limits<absl::int128>::radix;
+constexpr int numeric_limits<absl::int128>::min_exponent;
+constexpr int numeric_limits<absl::int128>::min_exponent10;
+constexpr int numeric_limits<absl::int128>::max_exponent;
+constexpr int numeric_limits<absl::int128>::max_exponent10;
+constexpr bool numeric_limits<absl::int128>::traps;
+constexpr bool numeric_limits<absl::int128>::tinyness_before;
+}  // namespace std
diff --git a/src/absl/numeric/int128.h b/src/absl/numeric/int128.h
new file mode 100644 (file)
index 0000000..0dd814a
--- /dev/null
@@ -0,0 +1,1092 @@
+//
+// Copyright 2017 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// -----------------------------------------------------------------------------
+// File: int128.h
+// -----------------------------------------------------------------------------
+//
+// This header file defines 128-bit integer types, `uint128` and `int128`.
+
+#ifndef ABSL_NUMERIC_INT128_H_
+#define ABSL_NUMERIC_INT128_H_
+
+#include <cassert>
+#include <cmath>
+#include <cstdint>
+#include <cstring>
+#include <iosfwd>
+#include <limits>
+#include <utility>
+
+#include "absl/base/config.h"
+#include "absl/base/macros.h"
+#include "absl/base/port.h"
+
+#if defined(_MSC_VER)
+// In very old versions of MSVC and when the /Zc:wchar_t flag is off, wchar_t is
+// a typedef for unsigned short.  Otherwise wchar_t is mapped to the __wchar_t
+// builtin type.  We need to make sure not to define operator wchar_t()
+// alongside operator unsigned short() in these instances.
+#define ABSL_INTERNAL_WCHAR_T __wchar_t
+#if defined(_M_X64)
+#include <intrin.h>
+#pragma intrinsic(_umul128)
+#endif  // defined(_M_X64)
+#else   // defined(_MSC_VER)
+#define ABSL_INTERNAL_WCHAR_T wchar_t
+#endif  // defined(_MSC_VER)
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+
+class int128;
+
+// uint128
+//
+// An unsigned 128-bit integer type. The API is meant to mimic an intrinsic type
+// as closely as is practical, including exhibiting undefined behavior in
+// analogous cases (e.g. division by zero). This type is intended to be a
+// drop-in replacement once C++ supports an intrinsic `uint128_t` type; when
+// that occurs, existing well-behaved uses of `uint128` will continue to work
+// using that new type.
+//
+// Note: code written with this type will continue to compile once `uint128_t`
+// is introduced, provided the replacement helper functions
+// `Uint128(Low|High)64()` and `MakeUint128()` are made.
+//
+// A `uint128` supports the following:
+//
+//   * Implicit construction from integral types
+//   * Explicit conversion to integral types
+//
+// Additionally, if your compiler supports `__int128`, `uint128` is
+// interoperable with that type. (Abseil checks for this compatibility through
+// the `ABSL_HAVE_INTRINSIC_INT128` macro.)
+//
+// However, a `uint128` differs from intrinsic integral types in the following
+// ways:
+//
+//   * Errors on implicit conversions that do not preserve value (such as
+//     loss of precision when converting to float values).
+//   * Requires explicit construction from and conversion to floating point
+//     types.
+//   * Conversion to integral types requires an explicit static_cast() to
+//     mimic use of the `-Wnarrowing` compiler flag.
+//   * The alignment requirement of `uint128` may differ from that of an
+//     intrinsic 128-bit integer type depending on platform and build
+//     configuration.
+//
+// Example:
+//
+//     float y = absl::Uint128Max();  // Error. uint128 cannot be implicitly
+//                                    // converted to float.
+//
+//     absl::uint128 v;
+//     uint64_t i = v;                         // Error
+//     uint64_t i = static_cast<uint64_t>(v);  // OK
+//
+class
+#if defined(ABSL_HAVE_INTRINSIC_INT128)
+    alignas(unsigned __int128)
+#endif  // ABSL_HAVE_INTRINSIC_INT128
+        uint128 {
+ public:
+  uint128() = default;
+
+  // Constructors from arithmetic types
+  constexpr uint128(int v);                 // NOLINT(runtime/explicit)
+  constexpr uint128(unsigned int v);        // NOLINT(runtime/explicit)
+  constexpr uint128(long v);                // NOLINT(runtime/int)
+  constexpr uint128(unsigned long v);       // NOLINT(runtime/int)
+  constexpr uint128(long long v);           // NOLINT(runtime/int)
+  constexpr uint128(unsigned long long v);  // NOLINT(runtime/int)
+#ifdef ABSL_HAVE_INTRINSIC_INT128
+  constexpr uint128(__int128 v);           // NOLINT(runtime/explicit)
+  constexpr uint128(unsigned __int128 v);  // NOLINT(runtime/explicit)
+#endif  // ABSL_HAVE_INTRINSIC_INT128
+  constexpr uint128(int128 v);  // NOLINT(runtime/explicit)
+  explicit uint128(float v);
+  explicit uint128(double v);
+  explicit uint128(long double v);
+
+  // Assignment operators from arithmetic types
+  uint128& operator=(int v);
+  uint128& operator=(unsigned int v);
+  uint128& operator=(long v);                // NOLINT(runtime/int)
+  uint128& operator=(unsigned long v);       // NOLINT(runtime/int)
+  uint128& operator=(long long v);           // NOLINT(runtime/int)
+  uint128& operator=(unsigned long long v);  // NOLINT(runtime/int)
+#ifdef ABSL_HAVE_INTRINSIC_INT128
+  uint128& operator=(__int128 v);
+  uint128& operator=(unsigned __int128 v);
+#endif  // ABSL_HAVE_INTRINSIC_INT128
+  uint128& operator=(int128 v);
+
+  // Conversion operators to other arithmetic types
+  constexpr explicit operator bool() const;
+  constexpr explicit operator char() const;
+  constexpr explicit operator signed char() const;
+  constexpr explicit operator unsigned char() const;
+  constexpr explicit operator char16_t() const;
+  constexpr explicit operator char32_t() const;
+  constexpr explicit operator ABSL_INTERNAL_WCHAR_T() const;
+  constexpr explicit operator short() const;  // NOLINT(runtime/int)
+  // NOLINTNEXTLINE(runtime/int)
+  constexpr explicit operator unsigned short() const;
+  constexpr explicit operator int() const;
+  constexpr explicit operator unsigned int() const;
+  constexpr explicit operator long() const;  // NOLINT(runtime/int)
+  // NOLINTNEXTLINE(runtime/int)
+  constexpr explicit operator unsigned long() const;
+  // NOLINTNEXTLINE(runtime/int)
+  constexpr explicit operator long long() const;
+  // NOLINTNEXTLINE(runtime/int)
+  constexpr explicit operator unsigned long long() const;
+#ifdef ABSL_HAVE_INTRINSIC_INT128
+  constexpr explicit operator __int128() const;
+  constexpr explicit operator unsigned __int128() const;
+#endif  // ABSL_HAVE_INTRINSIC_INT128
+  explicit operator float() const;
+  explicit operator double() const;
+  explicit operator long double() const;
+
+  // Trivial copy constructor, assignment operator and destructor.
+
+  // Arithmetic operators.
+  uint128& operator+=(uint128 other);
+  uint128& operator-=(uint128 other);
+  uint128& operator*=(uint128 other);
+  // Long division/modulo for uint128.
+  uint128& operator/=(uint128 other);
+  uint128& operator%=(uint128 other);
+  uint128 operator++(int);
+  uint128 operator--(int);
+  uint128& operator<<=(int);
+  uint128& operator>>=(int);
+  uint128& operator&=(uint128 other);
+  uint128& operator|=(uint128 other);
+  uint128& operator^=(uint128 other);
+  uint128& operator++();
+  uint128& operator--();
+
+  // Uint128Low64()
+  //
+  // Returns the lower 64-bit value of a `uint128` value.
+  friend constexpr uint64_t Uint128Low64(uint128 v);
+
+  // Uint128High64()
+  //
+  // Returns the higher 64-bit value of a `uint128` value.
+  friend constexpr uint64_t Uint128High64(uint128 v);
+
+  // MakeUInt128()
+  //
+  // Constructs a `uint128` numeric value from two 64-bit unsigned integers.
+  // Note that this factory function is the only way to construct a `uint128`
+  // from integer values greater than 2^64.
+  //
+  // Example:
+  //
+  //   absl::uint128 big = absl::MakeUint128(1, 0);
+  friend constexpr uint128 MakeUint128(uint64_t high, uint64_t low);
+
+  // Uint128Max()
+  //
+  // Returns the highest value for a 128-bit unsigned integer.
+  friend constexpr uint128 Uint128Max();
+
+  // Support for absl::Hash.
+  template <typename H>
+  friend H AbslHashValue(H h, uint128 v) {
+    return H::combine(std::move(h), Uint128High64(v), Uint128Low64(v));
+  }
+
+ private:
+  constexpr uint128(uint64_t high, uint64_t low);
+
+  // TODO(strel) Update implementation to use __int128 once all users of
+  // uint128 are fixed to not depend on alignof(uint128) == 8. Also add
+  // alignas(16) to class definition to keep alignment consistent across
+  // platforms.
+#if defined(ABSL_IS_LITTLE_ENDIAN)
+  uint64_t lo_;
+  uint64_t hi_;
+#elif defined(ABSL_IS_BIG_ENDIAN)
+  uint64_t hi_;
+  uint64_t lo_;
+#else  // byte order
+#error "Unsupported byte order: must be little-endian or big-endian."
+#endif  // byte order
+};
+
+// Prefer to use the constexpr `Uint128Max()`.
+//
+// TODO(absl-team) deprecate kuint128max once migration tool is released.
+ABSL_DLL extern const uint128 kuint128max;
+
+// allow uint128 to be logged
+std::ostream& operator<<(std::ostream& os, uint128 v);
+
+// TODO(strel) add operator>>(std::istream&, uint128)
+
+constexpr uint128 Uint128Max() {
+  return uint128((std::numeric_limits<uint64_t>::max)(),
+                 (std::numeric_limits<uint64_t>::max)());
+}
+
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+// Specialized numeric_limits for uint128.
+namespace std {
+template <>
+class numeric_limits<absl::uint128> {
+ public:
+  static constexpr bool is_specialized = true;
+  static constexpr bool is_signed = false;
+  static constexpr bool is_integer = true;
+  static constexpr bool is_exact = true;
+  static constexpr bool has_infinity = false;
+  static constexpr bool has_quiet_NaN = false;
+  static constexpr bool has_signaling_NaN = false;
+  static constexpr float_denorm_style has_denorm = denorm_absent;
+  static constexpr bool has_denorm_loss = false;
+  static constexpr float_round_style round_style = round_toward_zero;
+  static constexpr bool is_iec559 = false;
+  static constexpr bool is_bounded = true;
+  static constexpr bool is_modulo = true;
+  static constexpr int digits = 128;
+  static constexpr int digits10 = 38;
+  static constexpr int max_digits10 = 0;
+  static constexpr int radix = 2;
+  static constexpr int min_exponent = 0;
+  static constexpr int min_exponent10 = 0;
+  static constexpr int max_exponent = 0;
+  static constexpr int max_exponent10 = 0;
+#ifdef ABSL_HAVE_INTRINSIC_INT128
+  static constexpr bool traps = numeric_limits<unsigned __int128>::traps;
+#else   // ABSL_HAVE_INTRINSIC_INT128
+  static constexpr bool traps = numeric_limits<uint64_t>::traps;
+#endif  // ABSL_HAVE_INTRINSIC_INT128
+  static constexpr bool tinyness_before = false;
+
+  static constexpr absl::uint128 (min)() { return 0; }
+  static constexpr absl::uint128 lowest() { return 0; }
+  static constexpr absl::uint128 (max)() { return absl::Uint128Max(); }
+  static constexpr absl::uint128 epsilon() { return 0; }
+  static constexpr absl::uint128 round_error() { return 0; }
+  static constexpr absl::uint128 infinity() { return 0; }
+  static constexpr absl::uint128 quiet_NaN() { return 0; }
+  static constexpr absl::uint128 signaling_NaN() { return 0; }
+  static constexpr absl::uint128 denorm_min() { return 0; }
+};
+}  // namespace std
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+
+// int128
+//
+// A signed 128-bit integer type. The API is meant to mimic an intrinsic
+// integral type as closely as is practical, including exhibiting undefined
+// behavior in analogous cases (e.g. division by zero).
+//
+// An `int128` supports the following:
+//
+//   * Implicit construction from integral types
+//   * Explicit conversion to integral types
+//
+// However, an `int128` differs from intrinsic integral types in the following
+// ways:
+//
+//   * It is not implicitly convertible to other integral types.
+//   * Requires explicit construction from and conversion to floating point
+//     types.
+
+// Additionally, if your compiler supports `__int128`, `int128` is
+// interoperable with that type. (Abseil checks for this compatibility through
+// the `ABSL_HAVE_INTRINSIC_INT128` macro.)
+//
+// The design goal for `int128` is that it will be compatible with a future
+// `int128_t`, if that type becomes a part of the standard.
+//
+// Example:
+//
+//     float y = absl::int128(17);  // Error. int128 cannot be implicitly
+//                                  // converted to float.
+//
+//     absl::int128 v;
+//     int64_t i = v;                        // Error
+//     int64_t i = static_cast<int64_t>(v);  // OK
+//
+class int128 {
+ public:
+  int128() = default;
+
+  // Constructors from arithmetic types
+  constexpr int128(int v);                 // NOLINT(runtime/explicit)
+  constexpr int128(unsigned int v);        // NOLINT(runtime/explicit)
+  constexpr int128(long v);                // NOLINT(runtime/int)
+  constexpr int128(unsigned long v);       // NOLINT(runtime/int)
+  constexpr int128(long long v);           // NOLINT(runtime/int)
+  constexpr int128(unsigned long long v);  // NOLINT(runtime/int)
+#ifdef ABSL_HAVE_INTRINSIC_INT128
+  constexpr int128(__int128 v);  // NOLINT(runtime/explicit)
+  constexpr explicit int128(unsigned __int128 v);
+#endif  // ABSL_HAVE_INTRINSIC_INT128
+  constexpr explicit int128(uint128 v);
+  explicit int128(float v);
+  explicit int128(double v);
+  explicit int128(long double v);
+
+  // Assignment operators from arithmetic types
+  int128& operator=(int v);
+  int128& operator=(unsigned int v);
+  int128& operator=(long v);                // NOLINT(runtime/int)
+  int128& operator=(unsigned long v);       // NOLINT(runtime/int)
+  int128& operator=(long long v);           // NOLINT(runtime/int)
+  int128& operator=(unsigned long long v);  // NOLINT(runtime/int)
+#ifdef ABSL_HAVE_INTRINSIC_INT128
+  int128& operator=(__int128 v);
+#endif  // ABSL_HAVE_INTRINSIC_INT128
+
+  // Conversion operators to other arithmetic types
+  constexpr explicit operator bool() const;
+  constexpr explicit operator char() const;
+  constexpr explicit operator signed char() const;
+  constexpr explicit operator unsigned char() const;
+  constexpr explicit operator char16_t() const;
+  constexpr explicit operator char32_t() const;
+  constexpr explicit operator ABSL_INTERNAL_WCHAR_T() const;
+  constexpr explicit operator short() const;  // NOLINT(runtime/int)
+  // NOLINTNEXTLINE(runtime/int)
+  constexpr explicit operator unsigned short() const;
+  constexpr explicit operator int() const;
+  constexpr explicit operator unsigned int() const;
+  constexpr explicit operator long() const;  // NOLINT(runtime/int)
+  // NOLINTNEXTLINE(runtime/int)
+  constexpr explicit operator unsigned long() const;
+  // NOLINTNEXTLINE(runtime/int)
+  constexpr explicit operator long long() const;
+  // NOLINTNEXTLINE(runtime/int)
+  constexpr explicit operator unsigned long long() const;
+#ifdef ABSL_HAVE_INTRINSIC_INT128
+  constexpr explicit operator __int128() const;
+  constexpr explicit operator unsigned __int128() const;
+#endif  // ABSL_HAVE_INTRINSIC_INT128
+  explicit operator float() const;
+  explicit operator double() const;
+  explicit operator long double() const;
+
+  // Trivial copy constructor, assignment operator and destructor.
+
+  // Arithmetic operators
+  int128& operator+=(int128 other);
+  int128& operator-=(int128 other);
+  int128& operator*=(int128 other);
+  int128& operator/=(int128 other);
+  int128& operator%=(int128 other);
+  int128 operator++(int);  // postfix increment: i++
+  int128 operator--(int);  // postfix decrement: i--
+  int128& operator++();    // prefix increment:  ++i
+  int128& operator--();    // prefix decrement:  --i
+  int128& operator&=(int128 other);
+  int128& operator|=(int128 other);
+  int128& operator^=(int128 other);
+  int128& operator<<=(int amount);
+  int128& operator>>=(int amount);
+
+  // Int128Low64()
+  //
+  // Returns the lower 64-bit value of a `int128` value.
+  friend constexpr uint64_t Int128Low64(int128 v);
+
+  // Int128High64()
+  //
+  // Returns the higher 64-bit value of a `int128` value.
+  friend constexpr int64_t Int128High64(int128 v);
+
+  // MakeInt128()
+  //
+  // Constructs a `int128` numeric value from two 64-bit integers. Note that
+  // signedness is conveyed in the upper `high` value.
+  //
+  //   (absl::int128(1) << 64) * high + low
+  //
+  // Note that this factory function is the only way to construct a `int128`
+  // from integer values greater than 2^64 or less than -2^64.
+  //
+  // Example:
+  //
+  //   absl::int128 big = absl::MakeInt128(1, 0);
+  //   absl::int128 big_n = absl::MakeInt128(-1, 0);
+  friend constexpr int128 MakeInt128(int64_t high, uint64_t low);
+
+  // Int128Max()
+  //
+  // Returns the maximum value for a 128-bit signed integer.
+  friend constexpr int128 Int128Max();
+
+  // Int128Min()
+  //
+  // Returns the minimum value for a 128-bit signed integer.
+  friend constexpr int128 Int128Min();
+
+  // Support for absl::Hash.
+  template <typename H>
+  friend H AbslHashValue(H h, int128 v) {
+    return H::combine(std::move(h), Int128High64(v), Int128Low64(v));
+  }
+
+ private:
+  constexpr int128(int64_t high, uint64_t low);
+
+#if defined(ABSL_HAVE_INTRINSIC_INT128)
+  __int128 v_;
+#else  // ABSL_HAVE_INTRINSIC_INT128
+#if defined(ABSL_IS_LITTLE_ENDIAN)
+  uint64_t lo_;
+  int64_t hi_;
+#elif defined(ABSL_IS_BIG_ENDIAN)
+  int64_t hi_;
+  uint64_t lo_;
+#else  // byte order
+#error "Unsupported byte order: must be little-endian or big-endian."
+#endif  // byte order
+#endif  // ABSL_HAVE_INTRINSIC_INT128
+};
+
+std::ostream& operator<<(std::ostream& os, int128 v);
+
+// TODO(absl-team) add operator>>(std::istream&, int128)
+
+constexpr int128 Int128Max() {
+  return int128((std::numeric_limits<int64_t>::max)(),
+                (std::numeric_limits<uint64_t>::max)());
+}
+
+constexpr int128 Int128Min() {
+  return int128((std::numeric_limits<int64_t>::min)(), 0);
+}
+
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+// Specialized numeric_limits for int128.
+namespace std {
+template <>
+class numeric_limits<absl::int128> {
+ public:
+  static constexpr bool is_specialized = true;
+  static constexpr bool is_signed = true;
+  static constexpr bool is_integer = true;
+  static constexpr bool is_exact = true;
+  static constexpr bool has_infinity = false;
+  static constexpr bool has_quiet_NaN = false;
+  static constexpr bool has_signaling_NaN = false;
+  static constexpr float_denorm_style has_denorm = denorm_absent;
+  static constexpr bool has_denorm_loss = false;
+  static constexpr float_round_style round_style = round_toward_zero;
+  static constexpr bool is_iec559 = false;
+  static constexpr bool is_bounded = true;
+  static constexpr bool is_modulo = false;
+  static constexpr int digits = 127;
+  static constexpr int digits10 = 38;
+  static constexpr int max_digits10 = 0;
+  static constexpr int radix = 2;
+  static constexpr int min_exponent = 0;
+  static constexpr int min_exponent10 = 0;
+  static constexpr int max_exponent = 0;
+  static constexpr int max_exponent10 = 0;
+#ifdef ABSL_HAVE_INTRINSIC_INT128
+  static constexpr bool traps = numeric_limits<__int128>::traps;
+#else   // ABSL_HAVE_INTRINSIC_INT128
+  static constexpr bool traps = numeric_limits<uint64_t>::traps;
+#endif  // ABSL_HAVE_INTRINSIC_INT128
+  static constexpr bool tinyness_before = false;
+
+  static constexpr absl::int128 (min)() { return absl::Int128Min(); }
+  static constexpr absl::int128 lowest() { return absl::Int128Min(); }
+  static constexpr absl::int128 (max)() { return absl::Int128Max(); }
+  static constexpr absl::int128 epsilon() { return 0; }
+  static constexpr absl::int128 round_error() { return 0; }
+  static constexpr absl::int128 infinity() { return 0; }
+  static constexpr absl::int128 quiet_NaN() { return 0; }
+  static constexpr absl::int128 signaling_NaN() { return 0; }
+  static constexpr absl::int128 denorm_min() { return 0; }
+};
+}  // namespace std
+
+// --------------------------------------------------------------------------
+//                      Implementation details follow
+// --------------------------------------------------------------------------
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+
+constexpr uint128 MakeUint128(uint64_t high, uint64_t low) {
+  return uint128(high, low);
+}
+
+// Assignment from integer types.
+
+inline uint128& uint128::operator=(int v) { return *this = uint128(v); }
+
+inline uint128& uint128::operator=(unsigned int v) {
+  return *this = uint128(v);
+}
+
+inline uint128& uint128::operator=(long v) {  // NOLINT(runtime/int)
+  return *this = uint128(v);
+}
+
+// NOLINTNEXTLINE(runtime/int)
+inline uint128& uint128::operator=(unsigned long v) {
+  return *this = uint128(v);
+}
+
+// NOLINTNEXTLINE(runtime/int)
+inline uint128& uint128::operator=(long long v) {
+  return *this = uint128(v);
+}
+
+// NOLINTNEXTLINE(runtime/int)
+inline uint128& uint128::operator=(unsigned long long v) {
+  return *this = uint128(v);
+}
+
+#ifdef ABSL_HAVE_INTRINSIC_INT128
+inline uint128& uint128::operator=(__int128 v) {
+  return *this = uint128(v);
+}
+
+inline uint128& uint128::operator=(unsigned __int128 v) {
+  return *this = uint128(v);
+}
+#endif  // ABSL_HAVE_INTRINSIC_INT128
+
+inline uint128& uint128::operator=(int128 v) {
+  return *this = uint128(v);
+}
+
+// Arithmetic operators.
+
+uint128 operator<<(uint128 lhs, int amount);
+uint128 operator>>(uint128 lhs, int amount);
+uint128 operator+(uint128 lhs, uint128 rhs);
+uint128 operator-(uint128 lhs, uint128 rhs);
+uint128 operator*(uint128 lhs, uint128 rhs);
+uint128 operator/(uint128 lhs, uint128 rhs);
+uint128 operator%(uint128 lhs, uint128 rhs);
+
+inline uint128& uint128::operator<<=(int amount) {
+  *this = *this << amount;
+  return *this;
+}
+
+inline uint128& uint128::operator>>=(int amount) {
+  *this = *this >> amount;
+  return *this;
+}
+
+inline uint128& uint128::operator+=(uint128 other) {
+  *this = *this + other;
+  return *this;
+}
+
+inline uint128& uint128::operator-=(uint128 other) {
+  *this = *this - other;
+  return *this;
+}
+
+inline uint128& uint128::operator*=(uint128 other) {
+  *this = *this * other;
+  return *this;
+}
+
+inline uint128& uint128::operator/=(uint128 other) {
+  *this = *this / other;
+  return *this;
+}
+
+inline uint128& uint128::operator%=(uint128 other) {
+  *this = *this % other;
+  return *this;
+}
+
+constexpr uint64_t Uint128Low64(uint128 v) { return v.lo_; }
+
+constexpr uint64_t Uint128High64(uint128 v) { return v.hi_; }
+
+// Constructors from integer types.
+
+#if defined(ABSL_IS_LITTLE_ENDIAN)
+
+constexpr uint128::uint128(uint64_t high, uint64_t low)
+    : lo_{low}, hi_{high} {}
+
+constexpr uint128::uint128(int v)
+    : lo_{static_cast<uint64_t>(v)},
+      hi_{v < 0 ? (std::numeric_limits<uint64_t>::max)() : 0} {}
+constexpr uint128::uint128(long v)  // NOLINT(runtime/int)
+    : lo_{static_cast<uint64_t>(v)},
+      hi_{v < 0 ? (std::numeric_limits<uint64_t>::max)() : 0} {}
+constexpr uint128::uint128(long long v)  // NOLINT(runtime/int)
+    : lo_{static_cast<uint64_t>(v)},
+      hi_{v < 0 ? (std::numeric_limits<uint64_t>::max)() : 0} {}
+
+constexpr uint128::uint128(unsigned int v) : lo_{v}, hi_{0} {}
+// NOLINTNEXTLINE(runtime/int)
+constexpr uint128::uint128(unsigned long v) : lo_{v}, hi_{0} {}
+// NOLINTNEXTLINE(runtime/int)
+constexpr uint128::uint128(unsigned long long v) : lo_{v}, hi_{0} {}
+
+#ifdef ABSL_HAVE_INTRINSIC_INT128
+constexpr uint128::uint128(__int128 v)
+    : lo_{static_cast<uint64_t>(v & ~uint64_t{0})},
+      hi_{static_cast<uint64_t>(static_cast<unsigned __int128>(v) >> 64)} {}
+constexpr uint128::uint128(unsigned __int128 v)
+    : lo_{static_cast<uint64_t>(v & ~uint64_t{0})},
+      hi_{static_cast<uint64_t>(v >> 64)} {}
+#endif  // ABSL_HAVE_INTRINSIC_INT128
+
+constexpr uint128::uint128(int128 v)
+    : lo_{Int128Low64(v)}, hi_{static_cast<uint64_t>(Int128High64(v))} {}
+
+#elif defined(ABSL_IS_BIG_ENDIAN)
+
+constexpr uint128::uint128(uint64_t high, uint64_t low)
+    : hi_{high}, lo_{low} {}
+
+constexpr uint128::uint128(int v)
+    : hi_{v < 0 ? (std::numeric_limits<uint64_t>::max)() : 0},
+      lo_{static_cast<uint64_t>(v)} {}
+constexpr uint128::uint128(long v)  // NOLINT(runtime/int)
+    : hi_{v < 0 ? (std::numeric_limits<uint64_t>::max)() : 0},
+      lo_{static_cast<uint64_t>(v)} {}
+constexpr uint128::uint128(long long v)  // NOLINT(runtime/int)
+    : hi_{v < 0 ? (std::numeric_limits<uint64_t>::max)() : 0},
+      lo_{static_cast<uint64_t>(v)} {}
+
+constexpr uint128::uint128(unsigned int v) : hi_{0}, lo_{v} {}
+// NOLINTNEXTLINE(runtime/int)
+constexpr uint128::uint128(unsigned long v) : hi_{0}, lo_{v} {}
+// NOLINTNEXTLINE(runtime/int)
+constexpr uint128::uint128(unsigned long long v) : hi_{0}, lo_{v} {}
+
+#ifdef ABSL_HAVE_INTRINSIC_INT128
+constexpr uint128::uint128(__int128 v)
+    : hi_{static_cast<uint64_t>(static_cast<unsigned __int128>(v) >> 64)},
+      lo_{static_cast<uint64_t>(v & ~uint64_t{0})} {}
+constexpr uint128::uint128(unsigned __int128 v)
+    : hi_{static_cast<uint64_t>(v >> 64)},
+      lo_{static_cast<uint64_t>(v & ~uint64_t{0})} {}
+#endif  // ABSL_HAVE_INTRINSIC_INT128
+
+constexpr uint128::uint128(int128 v)
+    : hi_{static_cast<uint64_t>(Int128High64(v))}, lo_{Int128Low64(v)} {}
+
+#else  // byte order
+#error "Unsupported byte order: must be little-endian or big-endian."
+#endif  // byte order
+
+// Conversion operators to integer types.
+
+constexpr uint128::operator bool() const { return lo_ || hi_; }
+
+constexpr uint128::operator char() const { return static_cast<char>(lo_); }
+
+constexpr uint128::operator signed char() const {
+  return static_cast<signed char>(lo_);
+}
+
+constexpr uint128::operator unsigned char() const {
+  return static_cast<unsigned char>(lo_);
+}
+
+constexpr uint128::operator char16_t() const {
+  return static_cast<char16_t>(lo_);
+}
+
+constexpr uint128::operator char32_t() const {
+  return static_cast<char32_t>(lo_);
+}
+
+constexpr uint128::operator ABSL_INTERNAL_WCHAR_T() const {
+  return static_cast<ABSL_INTERNAL_WCHAR_T>(lo_);
+}
+
+// NOLINTNEXTLINE(runtime/int)
+constexpr uint128::operator short() const { return static_cast<short>(lo_); }
+
+constexpr uint128::operator unsigned short() const {  // NOLINT(runtime/int)
+  return static_cast<unsigned short>(lo_);            // NOLINT(runtime/int)
+}
+
+constexpr uint128::operator int() const { return static_cast<int>(lo_); }
+
+constexpr uint128::operator unsigned int() const {
+  return static_cast<unsigned int>(lo_);
+}
+
+// NOLINTNEXTLINE(runtime/int)
+constexpr uint128::operator long() const { return static_cast<long>(lo_); }
+
+constexpr uint128::operator unsigned long() const {  // NOLINT(runtime/int)
+  return static_cast<unsigned long>(lo_);            // NOLINT(runtime/int)
+}
+
+constexpr uint128::operator long long() const {  // NOLINT(runtime/int)
+  return static_cast<long long>(lo_);            // NOLINT(runtime/int)
+}
+
+constexpr uint128::operator unsigned long long() const {  // NOLINT(runtime/int)
+  return static_cast<unsigned long long>(lo_);            // NOLINT(runtime/int)
+}
+
+#ifdef ABSL_HAVE_INTRINSIC_INT128
+constexpr uint128::operator __int128() const {
+  return (static_cast<__int128>(hi_) << 64) + lo_;
+}
+
+constexpr uint128::operator unsigned __int128() const {
+  return (static_cast<unsigned __int128>(hi_) << 64) + lo_;
+}
+#endif  // ABSL_HAVE_INTRINSIC_INT128
+
+// Conversion operators to floating point types.
+
+inline uint128::operator float() const {
+  return static_cast<float>(lo_) + std::ldexp(static_cast<float>(hi_), 64);
+}
+
+inline uint128::operator double() const {
+  return static_cast<double>(lo_) + std::ldexp(static_cast<double>(hi_), 64);
+}
+
+inline uint128::operator long double() const {
+  return static_cast<long double>(lo_) +
+         std::ldexp(static_cast<long double>(hi_), 64);
+}
+
+// Comparison operators.
+
+inline bool operator==(uint128 lhs, uint128 rhs) {
+  return (Uint128Low64(lhs) == Uint128Low64(rhs) &&
+          Uint128High64(lhs) == Uint128High64(rhs));
+}
+
+inline bool operator!=(uint128 lhs, uint128 rhs) {
+  return !(lhs == rhs);
+}
+
+inline bool operator<(uint128 lhs, uint128 rhs) {
+#ifdef ABSL_HAVE_INTRINSIC_INT128
+  return static_cast<unsigned __int128>(lhs) <
+         static_cast<unsigned __int128>(rhs);
+#else
+  return (Uint128High64(lhs) == Uint128High64(rhs))
+             ? (Uint128Low64(lhs) < Uint128Low64(rhs))
+             : (Uint128High64(lhs) < Uint128High64(rhs));
+#endif
+}
+
+inline bool operator>(uint128 lhs, uint128 rhs) { return rhs < lhs; }
+
+inline bool operator<=(uint128 lhs, uint128 rhs) { return !(rhs < lhs); }
+
+inline bool operator>=(uint128 lhs, uint128 rhs) { return !(lhs < rhs); }
+
+// Unary operators.
+
+inline uint128 operator-(uint128 val) {
+  uint64_t hi = ~Uint128High64(val);
+  uint64_t lo = ~Uint128Low64(val) + 1;
+  if (lo == 0) ++hi;  // carry
+  return MakeUint128(hi, lo);
+}
+
+inline bool operator!(uint128 val) {
+  return !Uint128High64(val) && !Uint128Low64(val);
+}
+
+// Logical operators.
+
+inline uint128 operator~(uint128 val) {
+  return MakeUint128(~Uint128High64(val), ~Uint128Low64(val));
+}
+
+inline uint128 operator|(uint128 lhs, uint128 rhs) {
+  return MakeUint128(Uint128High64(lhs) | Uint128High64(rhs),
+                           Uint128Low64(lhs) | Uint128Low64(rhs));
+}
+
+inline uint128 operator&(uint128 lhs, uint128 rhs) {
+  return MakeUint128(Uint128High64(lhs) & Uint128High64(rhs),
+                           Uint128Low64(lhs) & Uint128Low64(rhs));
+}
+
+inline uint128 operator^(uint128 lhs, uint128 rhs) {
+  return MakeUint128(Uint128High64(lhs) ^ Uint128High64(rhs),
+                           Uint128Low64(lhs) ^ Uint128Low64(rhs));
+}
+
+inline uint128& uint128::operator|=(uint128 other) {
+  hi_ |= other.hi_;
+  lo_ |= other.lo_;
+  return *this;
+}
+
+inline uint128& uint128::operator&=(uint128 other) {
+  hi_ &= other.hi_;
+  lo_ &= other.lo_;
+  return *this;
+}
+
+inline uint128& uint128::operator^=(uint128 other) {
+  hi_ ^= other.hi_;
+  lo_ ^= other.lo_;
+  return *this;
+}
+
+// Arithmetic operators.
+
+inline uint128 operator<<(uint128 lhs, int amount) {
+#ifdef ABSL_HAVE_INTRINSIC_INT128
+  return static_cast<unsigned __int128>(lhs) << amount;
+#else
+  // uint64_t shifts of >= 64 are undefined, so we will need some
+  // special-casing.
+  if (amount < 64) {
+    if (amount != 0) {
+      return MakeUint128(
+          (Uint128High64(lhs) << amount) | (Uint128Low64(lhs) >> (64 - amount)),
+          Uint128Low64(lhs) << amount);
+    }
+    return lhs;
+  }
+  return MakeUint128(Uint128Low64(lhs) << (amount - 64), 0);
+#endif
+}
+
+inline uint128 operator>>(uint128 lhs, int amount) {
+#ifdef ABSL_HAVE_INTRINSIC_INT128
+  return static_cast<unsigned __int128>(lhs) >> amount;
+#else
+  // uint64_t shifts of >= 64 are undefined, so we will need some
+  // special-casing.
+  if (amount < 64) {
+    if (amount != 0) {
+      return MakeUint128(Uint128High64(lhs) >> amount,
+                         (Uint128Low64(lhs) >> amount) |
+                             (Uint128High64(lhs) << (64 - amount)));
+    }
+    return lhs;
+  }
+  return MakeUint128(0, Uint128High64(lhs) >> (amount - 64));
+#endif
+}
+
+inline uint128 operator+(uint128 lhs, uint128 rhs) {
+  uint128 result = MakeUint128(Uint128High64(lhs) + Uint128High64(rhs),
+                               Uint128Low64(lhs) + Uint128Low64(rhs));
+  if (Uint128Low64(result) < Uint128Low64(lhs)) {  // check for carry
+    return MakeUint128(Uint128High64(result) + 1, Uint128Low64(result));
+  }
+  return result;
+}
+
+inline uint128 operator-(uint128 lhs, uint128 rhs) {
+  uint128 result = MakeUint128(Uint128High64(lhs) - Uint128High64(rhs),
+                               Uint128Low64(lhs) - Uint128Low64(rhs));
+  if (Uint128Low64(lhs) < Uint128Low64(rhs)) {  // check for carry
+    return MakeUint128(Uint128High64(result) - 1, Uint128Low64(result));
+  }
+  return result;
+}
+
+inline uint128 operator*(uint128 lhs, uint128 rhs) {
+#if defined(ABSL_HAVE_INTRINSIC_INT128)
+  // TODO(strel) Remove once alignment issues are resolved and unsigned __int128
+  // can be used for uint128 storage.
+  return static_cast<unsigned __int128>(lhs) *
+         static_cast<unsigned __int128>(rhs);
+#elif defined(_MSC_VER) && defined(_M_X64)
+  uint64_t carry;
+  uint64_t low = _umul128(Uint128Low64(lhs), Uint128Low64(rhs), &carry);
+  return MakeUint128(Uint128Low64(lhs) * Uint128High64(rhs) +
+                         Uint128High64(lhs) * Uint128Low64(rhs) + carry,
+                     low);
+#else   // ABSL_HAVE_INTRINSIC128
+  uint64_t a32 = Uint128Low64(lhs) >> 32;
+  uint64_t a00 = Uint128Low64(lhs) & 0xffffffff;
+  uint64_t b32 = Uint128Low64(rhs) >> 32;
+  uint64_t b00 = Uint128Low64(rhs) & 0xffffffff;
+  uint128 result =
+      MakeUint128(Uint128High64(lhs) * Uint128Low64(rhs) +
+                      Uint128Low64(lhs) * Uint128High64(rhs) + a32 * b32,
+                  a00 * b00);
+  result += uint128(a32 * b00) << 32;
+  result += uint128(a00 * b32) << 32;
+  return result;
+#endif  // ABSL_HAVE_INTRINSIC128
+}
+
+// Increment/decrement operators.
+
+inline uint128 uint128::operator++(int) {
+  uint128 tmp(*this);
+  *this += 1;
+  return tmp;
+}
+
+inline uint128 uint128::operator--(int) {
+  uint128 tmp(*this);
+  *this -= 1;
+  return tmp;
+}
+
+inline uint128& uint128::operator++() {
+  *this += 1;
+  return *this;
+}
+
+inline uint128& uint128::operator--() {
+  *this -= 1;
+  return *this;
+}
+
+constexpr int128 MakeInt128(int64_t high, uint64_t low) {
+  return int128(high, low);
+}
+
+// Assignment from integer types.
+inline int128& int128::operator=(int v) {
+  return *this = int128(v);
+}
+
+inline int128& int128::operator=(unsigned int v) {
+  return *this = int128(v);
+}
+
+inline int128& int128::operator=(long v) {  // NOLINT(runtime/int)
+  return *this = int128(v);
+}
+
+// NOLINTNEXTLINE(runtime/int)
+inline int128& int128::operator=(unsigned long v) {
+  return *this = int128(v);
+}
+
+// NOLINTNEXTLINE(runtime/int)
+inline int128& int128::operator=(long long v) {
+  return *this = int128(v);
+}
+
+// NOLINTNEXTLINE(runtime/int)
+inline int128& int128::operator=(unsigned long long v) {
+  return *this = int128(v);
+}
+
+// Arithmetic operators.
+
+int128 operator+(int128 lhs, int128 rhs);
+int128 operator-(int128 lhs, int128 rhs);
+int128 operator*(int128 lhs, int128 rhs);
+int128 operator/(int128 lhs, int128 rhs);
+int128 operator%(int128 lhs, int128 rhs);
+int128 operator|(int128 lhs, int128 rhs);
+int128 operator&(int128 lhs, int128 rhs);
+int128 operator^(int128 lhs, int128 rhs);
+int128 operator<<(int128 lhs, int amount);
+int128 operator>>(int128 lhs, int amount);
+
+inline int128& int128::operator+=(int128 other) {
+  *this = *this + other;
+  return *this;
+}
+
+inline int128& int128::operator-=(int128 other) {
+  *this = *this - other;
+  return *this;
+}
+
+inline int128& int128::operator*=(int128 other) {
+  *this = *this * other;
+  return *this;
+}
+
+inline int128& int128::operator/=(int128 other) {
+  *this = *this / other;
+  return *this;
+}
+
+inline int128& int128::operator%=(int128 other) {
+  *this = *this % other;
+  return *this;
+}
+
+inline int128& int128::operator|=(int128 other) {
+  *this = *this | other;
+  return *this;
+}
+
+inline int128& int128::operator&=(int128 other) {
+  *this = *this & other;
+  return *this;
+}
+
+inline int128& int128::operator^=(int128 other) {
+  *this = *this ^ other;
+  return *this;
+}
+
+inline int128& int128::operator<<=(int amount) {
+  *this = *this << amount;
+  return *this;
+}
+
+inline int128& int128::operator>>=(int amount) {
+  *this = *this >> amount;
+  return *this;
+}
+
+namespace int128_internal {
+
+// Casts from unsigned to signed while preserving the underlying binary
+// representation.
+constexpr int64_t BitCastToSigned(uint64_t v) {
+  // Casting an unsigned integer to a signed integer of the same
+  // width is implementation defined behavior if the source value would not fit
+  // in the destination type. We step around it with a roundtrip bitwise not
+  // operation to make sure this function remains constexpr. Clang, GCC, and
+  // MSVC optimize this to a no-op on x86-64.
+  return v & (uint64_t{1} << 63) ? ~static_cast<int64_t>(~v)
+                                 : static_cast<int64_t>(v);
+}
+
+}  // namespace int128_internal
+
+#if defined(ABSL_HAVE_INTRINSIC_INT128)
+#include "absl/numeric/int128_have_intrinsic.inc"  // IWYU pragma: export
+#else  // ABSL_HAVE_INTRINSIC_INT128
+#include "absl/numeric/int128_no_intrinsic.inc"  // IWYU pragma: export
+#endif  // ABSL_HAVE_INTRINSIC_INT128
+
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#undef ABSL_INTERNAL_WCHAR_T
+
+#endif  // ABSL_NUMERIC_INT128_H_
diff --git a/src/absl/numeric/int128_have_intrinsic.inc b/src/absl/numeric/int128_have_intrinsic.inc
new file mode 100644 (file)
index 0000000..d6c76dd
--- /dev/null
@@ -0,0 +1,302 @@
+//
+// Copyright 2017 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// This file contains :int128 implementation details that depend on internal
+// representation when ABSL_HAVE_INTRINSIC_INT128 is defined. This file is
+// included by int128.h and relies on ABSL_INTERNAL_WCHAR_T being defined.
+
+namespace int128_internal {
+
+// Casts from unsigned to signed while preserving the underlying binary
+// representation.
+constexpr __int128 BitCastToSigned(unsigned __int128 v) {
+  // Casting an unsigned integer to a signed integer of the same
+  // width is implementation defined behavior if the source value would not fit
+  // in the destination type. We step around it with a roundtrip bitwise not
+  // operation to make sure this function remains constexpr. Clang and GCC
+  // optimize this to a no-op on x86-64.
+  return v & (static_cast<unsigned __int128>(1) << 127)
+             ? ~static_cast<__int128>(~v)
+             : static_cast<__int128>(v);
+}
+
+}  // namespace int128_internal
+
+inline int128& int128::operator=(__int128 v) {
+  v_ = v;
+  return *this;
+}
+
+constexpr uint64_t Int128Low64(int128 v) {
+  return static_cast<uint64_t>(v.v_ & ~uint64_t{0});
+}
+
+constexpr int64_t Int128High64(int128 v) {
+  // Initially cast to unsigned to prevent a right shift on a negative value.
+  return int128_internal::BitCastToSigned(
+      static_cast<uint64_t>(static_cast<unsigned __int128>(v.v_) >> 64));
+}
+
+constexpr int128::int128(int64_t high, uint64_t low)
+    // Initially cast to unsigned to prevent a left shift that overflows.
+    : v_(int128_internal::BitCastToSigned(static_cast<unsigned __int128>(high)
+                                           << 64) |
+         low) {}
+
+
+constexpr int128::int128(int v) : v_{v} {}
+
+constexpr int128::int128(long v) : v_{v} {}       // NOLINT(runtime/int)
+
+constexpr int128::int128(long long v) : v_{v} {}  // NOLINT(runtime/int)
+
+constexpr int128::int128(__int128 v) : v_{v} {}
+
+constexpr int128::int128(unsigned int v) : v_{v} {}
+
+constexpr int128::int128(unsigned long v) : v_{v} {}  // NOLINT(runtime/int)
+
+// NOLINTNEXTLINE(runtime/int)
+constexpr int128::int128(unsigned long long v) : v_{v} {}
+
+constexpr int128::int128(unsigned __int128 v) : v_{static_cast<__int128>(v)} {}
+
+inline int128::int128(float v) {
+  v_ = static_cast<__int128>(v);
+}
+
+inline int128::int128(double v) {
+  v_ = static_cast<__int128>(v);
+}
+
+inline int128::int128(long double v) {
+  v_ = static_cast<__int128>(v);
+}
+
+constexpr int128::int128(uint128 v) : v_{static_cast<__int128>(v)} {}
+
+constexpr int128::operator bool() const { return static_cast<bool>(v_); }
+
+constexpr int128::operator char() const { return static_cast<char>(v_); }
+
+constexpr int128::operator signed char() const {
+  return static_cast<signed char>(v_);
+}
+
+constexpr int128::operator unsigned char() const {
+  return static_cast<unsigned char>(v_);
+}
+
+constexpr int128::operator char16_t() const {
+  return static_cast<char16_t>(v_);
+}
+
+constexpr int128::operator char32_t() const {
+  return static_cast<char32_t>(v_);
+}
+
+constexpr int128::operator ABSL_INTERNAL_WCHAR_T() const {
+  return static_cast<ABSL_INTERNAL_WCHAR_T>(v_);
+}
+
+constexpr int128::operator short() const {  // NOLINT(runtime/int)
+  return static_cast<short>(v_);            // NOLINT(runtime/int)
+}
+
+constexpr int128::operator unsigned short() const {  // NOLINT(runtime/int)
+  return static_cast<unsigned short>(v_);            // NOLINT(runtime/int)
+}
+
+constexpr int128::operator int() const {
+  return static_cast<int>(v_);
+}
+
+constexpr int128::operator unsigned int() const {
+  return static_cast<unsigned int>(v_);
+}
+
+constexpr int128::operator long() const {  // NOLINT(runtime/int)
+  return static_cast<long>(v_);            // NOLINT(runtime/int)
+}
+
+constexpr int128::operator unsigned long() const {  // NOLINT(runtime/int)
+  return static_cast<unsigned long>(v_);            // NOLINT(runtime/int)
+}
+
+constexpr int128::operator long long() const {  // NOLINT(runtime/int)
+  return static_cast<long long>(v_);            // NOLINT(runtime/int)
+}
+
+constexpr int128::operator unsigned long long() const {  // NOLINT(runtime/int)
+  return static_cast<unsigned long long>(v_);            // NOLINT(runtime/int)
+}
+
+constexpr int128::operator __int128() const { return v_; }
+
+constexpr int128::operator unsigned __int128() const {
+  return static_cast<unsigned __int128>(v_);
+}
+
+// Clang on PowerPC sometimes produces incorrect __int128 to floating point
+// conversions. In that case, we do the conversion with a similar implementation
+// to the conversion operators in int128_no_intrinsic.inc.
+#if defined(__clang__) && !defined(__ppc64__)
+inline int128::operator float() const { return static_cast<float>(v_); }
+
+inline int128::operator double () const { return static_cast<double>(v_); }
+
+inline int128::operator long double() const {
+  return static_cast<long double>(v_);
+}
+
+#else  // Clang on PowerPC
+// Forward declaration for conversion operators to floating point types.
+int128 operator-(int128 v);
+bool operator!=(int128 lhs, int128 rhs);
+
+inline int128::operator float() const {
+  // We must convert the absolute value and then negate as needed, because
+  // floating point types are typically sign-magnitude. Otherwise, the
+  // difference between the high and low 64 bits when interpreted as two's
+  // complement overwhelms the precision of the mantissa.
+  //
+  // Also check to make sure we don't negate Int128Min()
+  return v_ < 0 && *this != Int128Min()
+             ? -static_cast<float>(-*this)
+             : static_cast<float>(Int128Low64(*this)) +
+                   std::ldexp(static_cast<float>(Int128High64(*this)), 64);
+}
+
+inline int128::operator double() const {
+  // See comment in int128::operator float() above.
+  return v_ < 0 && *this != Int128Min()
+             ? -static_cast<double>(-*this)
+             : static_cast<double>(Int128Low64(*this)) +
+                   std::ldexp(static_cast<double>(Int128High64(*this)), 64);
+}
+
+inline int128::operator long double() const {
+  // See comment in int128::operator float() above.
+  return v_ < 0 && *this != Int128Min()
+             ? -static_cast<long double>(-*this)
+             : static_cast<long double>(Int128Low64(*this)) +
+                   std::ldexp(static_cast<long double>(Int128High64(*this)),
+                              64);
+}
+#endif  // Clang on PowerPC
+
+// Comparison operators.
+
+inline bool operator==(int128 lhs, int128 rhs) {
+  return static_cast<__int128>(lhs) == static_cast<__int128>(rhs);
+}
+
+inline bool operator!=(int128 lhs, int128 rhs) {
+  return static_cast<__int128>(lhs) != static_cast<__int128>(rhs);
+}
+
+inline bool operator<(int128 lhs, int128 rhs) {
+  return static_cast<__int128>(lhs) < static_cast<__int128>(rhs);
+}
+
+inline bool operator>(int128 lhs, int128 rhs) {
+  return static_cast<__int128>(lhs) > static_cast<__int128>(rhs);
+}
+
+inline bool operator<=(int128 lhs, int128 rhs) {
+  return static_cast<__int128>(lhs) <= static_cast<__int128>(rhs);
+}
+
+inline bool operator>=(int128 lhs, int128 rhs) {
+  return static_cast<__int128>(lhs) >= static_cast<__int128>(rhs);
+}
+
+// Unary operators.
+
+inline int128 operator-(int128 v) {
+  return -static_cast<__int128>(v);
+}
+
+inline bool operator!(int128 v) {
+  return !static_cast<__int128>(v);
+}
+
+inline int128 operator~(int128 val) {
+  return ~static_cast<__int128>(val);
+}
+
+// Arithmetic operators.
+
+inline int128 operator+(int128 lhs, int128 rhs) {
+  return static_cast<__int128>(lhs) + static_cast<__int128>(rhs);
+}
+
+inline int128 operator-(int128 lhs, int128 rhs) {
+  return static_cast<__int128>(lhs) - static_cast<__int128>(rhs);
+}
+
+inline int128 operator*(int128 lhs, int128 rhs) {
+  return static_cast<__int128>(lhs) * static_cast<__int128>(rhs);
+}
+
+inline int128 operator/(int128 lhs, int128 rhs) {
+  return static_cast<__int128>(lhs) / static_cast<__int128>(rhs);
+}
+
+inline int128 operator%(int128 lhs, int128 rhs) {
+  return static_cast<__int128>(lhs) % static_cast<__int128>(rhs);
+}
+
+inline int128 int128::operator++(int) {
+  int128 tmp(*this);
+  ++v_;
+  return tmp;
+}
+
+inline int128 int128::operator--(int) {
+  int128 tmp(*this);
+  --v_;
+  return tmp;
+}
+
+inline int128& int128::operator++() {
+  ++v_;
+  return *this;
+}
+
+inline int128& int128::operator--() {
+  --v_;
+  return *this;
+}
+
+inline int128 operator|(int128 lhs, int128 rhs) {
+  return static_cast<__int128>(lhs) | static_cast<__int128>(rhs);
+}
+
+inline int128 operator&(int128 lhs, int128 rhs) {
+  return static_cast<__int128>(lhs) & static_cast<__int128>(rhs);
+}
+
+inline int128 operator^(int128 lhs, int128 rhs) {
+  return static_cast<__int128>(lhs) ^ static_cast<__int128>(rhs);
+}
+
+inline int128 operator<<(int128 lhs, int amount) {
+  return static_cast<__int128>(lhs) << amount;
+}
+
+inline int128 operator>>(int128 lhs, int amount) {
+  return static_cast<__int128>(lhs) >> amount;
+}
diff --git a/src/absl/numeric/int128_no_intrinsic.inc b/src/absl/numeric/int128_no_intrinsic.inc
new file mode 100644 (file)
index 0000000..c753771
--- /dev/null
@@ -0,0 +1,308 @@
+//
+// Copyright 2017 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// This file contains :int128 implementation details that depend on internal
+// representation when ABSL_HAVE_INTRINSIC_INT128 is *not* defined. This file
+// is included by int128.h and relies on ABSL_INTERNAL_WCHAR_T being defined.
+
+constexpr uint64_t Int128Low64(int128 v) { return v.lo_; }
+
+constexpr int64_t Int128High64(int128 v) { return v.hi_; }
+
+#if defined(ABSL_IS_LITTLE_ENDIAN)
+
+constexpr int128::int128(int64_t high, uint64_t low) :
+    lo_(low), hi_(high) {}
+
+constexpr int128::int128(int v)
+    : lo_{static_cast<uint64_t>(v)}, hi_{v < 0 ? ~int64_t{0} : 0} {}
+constexpr int128::int128(long v)  // NOLINT(runtime/int)
+    : lo_{static_cast<uint64_t>(v)}, hi_{v < 0 ? ~int64_t{0} : 0} {}
+constexpr int128::int128(long long v)  // NOLINT(runtime/int)
+    : lo_{static_cast<uint64_t>(v)}, hi_{v < 0 ? ~int64_t{0} : 0} {}
+
+constexpr int128::int128(unsigned int v) : lo_{v}, hi_{0} {}
+// NOLINTNEXTLINE(runtime/int)
+constexpr int128::int128(unsigned long v) : lo_{v}, hi_{0} {}
+// NOLINTNEXTLINE(runtime/int)
+constexpr int128::int128(unsigned long long v) : lo_{v}, hi_{0} {}
+
+constexpr int128::int128(uint128 v)
+    : lo_{Uint128Low64(v)}, hi_{static_cast<int64_t>(Uint128High64(v))} {}
+
+#elif defined(ABSL_IS_BIG_ENDIAN)
+
+constexpr int128::int128(int64_t high, uint64_t low) :
+    hi_{high}, lo_{low} {}
+
+constexpr int128::int128(int v)
+    : hi_{v < 0 ? ~int64_t{0} : 0}, lo_{static_cast<uint64_t>(v)} {}
+constexpr int128::int128(long v)  // NOLINT(runtime/int)
+    : hi_{v < 0 ? ~int64_t{0} : 0}, lo_{static_cast<uint64_t>(v)} {}
+constexpr int128::int128(long long v)  // NOLINT(runtime/int)
+    : hi_{v < 0 ? ~int64_t{0} : 0}, lo_{static_cast<uint64_t>(v)} {}
+
+constexpr int128::int128(unsigned int v) : hi_{0}, lo_{v} {}
+// NOLINTNEXTLINE(runtime/int)
+constexpr int128::int128(unsigned long v) : hi_{0}, lo_{v} {}
+// NOLINTNEXTLINE(runtime/int)
+constexpr int128::int128(unsigned long long v) : hi_{0}, lo_{v} {}
+
+constexpr int128::int128(uint128 v)
+    : hi_{static_cast<int64_t>(Uint128High64(v))}, lo_{Uint128Low64(v)} {}
+
+#else  // byte order
+#error "Unsupported byte order: must be little-endian or big-endian."
+#endif  // byte order
+
+constexpr int128::operator bool() const { return lo_ || hi_; }
+
+constexpr int128::operator char() const {
+  // NOLINTNEXTLINE(runtime/int)
+  return static_cast<char>(static_cast<long long>(*this));
+}
+
+constexpr int128::operator signed char() const {
+  // NOLINTNEXTLINE(runtime/int)
+  return static_cast<signed char>(static_cast<long long>(*this));
+}
+
+constexpr int128::operator unsigned char() const {
+  return static_cast<unsigned char>(lo_);
+}
+
+constexpr int128::operator char16_t() const {
+  return static_cast<char16_t>(lo_);
+}
+
+constexpr int128::operator char32_t() const {
+  return static_cast<char32_t>(lo_);
+}
+
+constexpr int128::operator ABSL_INTERNAL_WCHAR_T() const {
+  // NOLINTNEXTLINE(runtime/int)
+  return static_cast<ABSL_INTERNAL_WCHAR_T>(static_cast<long long>(*this));
+}
+
+constexpr int128::operator short() const {  // NOLINT(runtime/int)
+  // NOLINTNEXTLINE(runtime/int)
+  return static_cast<short>(static_cast<long long>(*this));
+}
+
+constexpr int128::operator unsigned short() const {  // NOLINT(runtime/int)
+  return static_cast<unsigned short>(lo_);           // NOLINT(runtime/int)
+}
+
+constexpr int128::operator int() const {
+  // NOLINTNEXTLINE(runtime/int)
+  return static_cast<int>(static_cast<long long>(*this));
+}
+
+constexpr int128::operator unsigned int() const {
+  return static_cast<unsigned int>(lo_);
+}
+
+constexpr int128::operator long() const {  // NOLINT(runtime/int)
+  // NOLINTNEXTLINE(runtime/int)
+  return static_cast<long>(static_cast<long long>(*this));
+}
+
+constexpr int128::operator unsigned long() const {  // NOLINT(runtime/int)
+  return static_cast<unsigned long>(lo_);           // NOLINT(runtime/int)
+}
+
+constexpr int128::operator long long() const {  // NOLINT(runtime/int)
+  // We don't bother checking the value of hi_. If *this < 0, lo_'s high bit
+  // must be set in order for the value to fit into a long long. Conversely, if
+  // lo_'s high bit is set, *this must be < 0 for the value to fit.
+  return int128_internal::BitCastToSigned(lo_);
+}
+
+constexpr int128::operator unsigned long long() const {  // NOLINT(runtime/int)
+  return static_cast<unsigned long long>(lo_);           // NOLINT(runtime/int)
+}
+
+// Forward declaration for conversion operators to floating point types.
+int128 operator-(int128 v);
+bool operator!=(int128 lhs, int128 rhs);
+
+inline int128::operator float() const {
+  // We must convert the absolute value and then negate as needed, because
+  // floating point types are typically sign-magnitude. Otherwise, the
+  // difference between the high and low 64 bits when interpreted as two's
+  // complement overwhelms the precision of the mantissa.
+  //
+  // Also check to make sure we don't negate Int128Min()
+  return hi_ < 0 && *this != Int128Min()
+             ? -static_cast<float>(-*this)
+             : static_cast<float>(lo_) +
+                   std::ldexp(static_cast<float>(hi_), 64);
+}
+
+inline int128::operator double() const {
+  // See comment in int128::operator float() above.
+  return hi_ < 0 && *this != Int128Min()
+             ? -static_cast<double>(-*this)
+             : static_cast<double>(lo_) +
+                   std::ldexp(static_cast<double>(hi_), 64);
+}
+
+inline int128::operator long double() const {
+  // See comment in int128::operator float() above.
+  return hi_ < 0 && *this != Int128Min()
+             ? -static_cast<long double>(-*this)
+             : static_cast<long double>(lo_) +
+                   std::ldexp(static_cast<long double>(hi_), 64);
+}
+
+// Comparison operators.
+
+inline bool operator==(int128 lhs, int128 rhs) {
+  return (Int128Low64(lhs) == Int128Low64(rhs) &&
+          Int128High64(lhs) == Int128High64(rhs));
+}
+
+inline bool operator!=(int128 lhs, int128 rhs) {
+  return !(lhs == rhs);
+}
+
+inline bool operator<(int128 lhs, int128 rhs) {
+  return (Int128High64(lhs) == Int128High64(rhs))
+             ? (Int128Low64(lhs) < Int128Low64(rhs))
+             : (Int128High64(lhs) < Int128High64(rhs));
+}
+
+inline bool operator>(int128 lhs, int128 rhs) {
+  return (Int128High64(lhs) == Int128High64(rhs))
+             ? (Int128Low64(lhs) > Int128Low64(rhs))
+             : (Int128High64(lhs) > Int128High64(rhs));
+}
+
+inline bool operator<=(int128 lhs, int128 rhs) {
+  return !(lhs > rhs);
+}
+
+inline bool operator>=(int128 lhs, int128 rhs) {
+  return !(lhs < rhs);
+}
+
+// Unary operators.
+
+inline int128 operator-(int128 v) {
+  int64_t hi = ~Int128High64(v);
+  uint64_t lo = ~Int128Low64(v) + 1;
+  if (lo == 0) ++hi;  // carry
+  return MakeInt128(hi, lo);
+}
+
+inline bool operator!(int128 v) {
+  return !Int128Low64(v) && !Int128High64(v);
+}
+
+inline int128 operator~(int128 val) {
+  return MakeInt128(~Int128High64(val), ~Int128Low64(val));
+}
+
+// Arithmetic operators.
+
+inline int128 operator+(int128 lhs, int128 rhs) {
+  int128 result = MakeInt128(Int128High64(lhs) + Int128High64(rhs),
+                             Int128Low64(lhs) + Int128Low64(rhs));
+  if (Int128Low64(result) < Int128Low64(lhs)) {  // check for carry
+    return MakeInt128(Int128High64(result) + 1, Int128Low64(result));
+  }
+  return result;
+}
+
+inline int128 operator-(int128 lhs, int128 rhs) {
+  int128 result = MakeInt128(Int128High64(lhs) - Int128High64(rhs),
+                             Int128Low64(lhs) - Int128Low64(rhs));
+  if (Int128Low64(lhs) < Int128Low64(rhs)) {  // check for carry
+    return MakeInt128(Int128High64(result) - 1, Int128Low64(result));
+  }
+  return result;
+}
+
+inline int128 operator*(int128 lhs, int128 rhs) {
+  uint128 result = uint128(lhs) * rhs;
+  return MakeInt128(int128_internal::BitCastToSigned(Uint128High64(result)),
+                    Uint128Low64(result));
+}
+
+inline int128 int128::operator++(int) {
+  int128 tmp(*this);
+  *this += 1;
+  return tmp;
+}
+
+inline int128 int128::operator--(int) {
+  int128 tmp(*this);
+  *this -= 1;
+  return tmp;
+}
+
+inline int128& int128::operator++() {
+  *this += 1;
+  return *this;
+}
+
+inline int128& int128::operator--() {
+  *this -= 1;
+  return *this;
+}
+
+inline int128 operator|(int128 lhs, int128 rhs) {
+  return MakeInt128(Int128High64(lhs) | Int128High64(rhs),
+                    Int128Low64(lhs) | Int128Low64(rhs));
+}
+
+inline int128 operator&(int128 lhs, int128 rhs) {
+  return MakeInt128(Int128High64(lhs) & Int128High64(rhs),
+                    Int128Low64(lhs) & Int128Low64(rhs));
+}
+
+inline int128 operator^(int128 lhs, int128 rhs) {
+  return MakeInt128(Int128High64(lhs) ^ Int128High64(rhs),
+                    Int128Low64(lhs) ^ Int128Low64(rhs));
+}
+
+inline int128 operator<<(int128 lhs, int amount) {
+  // uint64_t shifts of >= 64 are undefined, so we need some special-casing.
+  if (amount < 64) {
+    if (amount != 0) {
+      return MakeInt128(
+          (Int128High64(lhs) << amount) |
+              static_cast<int64_t>(Int128Low64(lhs) >> (64 - amount)),
+          Int128Low64(lhs) << amount);
+    }
+    return lhs;
+  }
+  return MakeInt128(static_cast<int64_t>(Int128Low64(lhs) << (amount - 64)), 0);
+}
+
+inline int128 operator>>(int128 lhs, int amount) {
+  // uint64_t shifts of >= 64 are undefined, so we need some special-casing.
+  if (amount < 64) {
+    if (amount != 0) {
+      return MakeInt128(
+          Int128High64(lhs) >> amount,
+          (Int128Low64(lhs) >> amount) |
+              (static_cast<uint64_t>(Int128High64(lhs)) << (64 - amount)));
+    }
+    return lhs;
+  }
+  return MakeInt128(0,
+                    static_cast<uint64_t>(Int128High64(lhs) >> (amount - 64)));
+}
diff --git a/src/absl/numeric/internal/bits.h b/src/absl/numeric/internal/bits.h
new file mode 100644 (file)
index 0000000..bfef06b
--- /dev/null
@@ -0,0 +1,358 @@
+// Copyright 2020 The Abseil Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef ABSL_NUMERIC_INTERNAL_BITS_H_
+#define ABSL_NUMERIC_INTERNAL_BITS_H_
+
+#include <cstdint>
+#include <limits>
+#include <type_traits>
+
+// Clang on Windows has __builtin_clzll; otherwise we need to use the
+// windows intrinsic functions.
+#if defined(_MSC_VER) && !defined(__clang__)
+#include <intrin.h>
+#endif
+
+#include "absl/base/attributes.h"
+#include "absl/base/config.h"
+
+#if defined(__GNUC__) && !defined(__clang__)
+// GCC
+#define ABSL_NUMERIC_INTERNAL_HAVE_BUILTIN_OR_GCC(x) 1
+#else
+#define ABSL_NUMERIC_INTERNAL_HAVE_BUILTIN_OR_GCC(x) ABSL_HAVE_BUILTIN(x)
+#endif
+
+#if ABSL_NUMERIC_INTERNAL_HAVE_BUILTIN_OR_GCC(__builtin_popcountl) && \
+    ABSL_NUMERIC_INTERNAL_HAVE_BUILTIN_OR_GCC(__builtin_popcountll)
+#define ABSL_INTERNAL_CONSTEXPR_POPCOUNT constexpr
+#define ABSL_INTERNAL_HAS_CONSTEXPR_POPCOUNT 1
+#else
+#define ABSL_INTERNAL_CONSTEXPR_POPCOUNT
+#define ABSL_INTERNAL_HAS_CONSTEXPR_POPCOUNT 0
+#endif
+
+#if ABSL_NUMERIC_INTERNAL_HAVE_BUILTIN_OR_GCC(__builtin_clz) && \
+    ABSL_NUMERIC_INTERNAL_HAVE_BUILTIN_OR_GCC(__builtin_clzll)
+#define ABSL_INTERNAL_CONSTEXPR_CLZ constexpr
+#define ABSL_INTERNAL_HAS_CONSTEXPR_CLZ 1
+#else
+#define ABSL_INTERNAL_CONSTEXPR_CLZ
+#define ABSL_INTERNAL_HAS_CONSTEXPR_CLZ 0
+#endif
+
+#if ABSL_NUMERIC_INTERNAL_HAVE_BUILTIN_OR_GCC(__builtin_ctz) && \
+    ABSL_NUMERIC_INTERNAL_HAVE_BUILTIN_OR_GCC(__builtin_ctzll)
+#define ABSL_INTERNAL_CONSTEXPR_CTZ constexpr
+#define ABSL_INTERNAL_HAS_CONSTEXPR_CTZ 1
+#else
+#define ABSL_INTERNAL_CONSTEXPR_CTZ
+#define ABSL_INTERNAL_HAS_CONSTEXPR_CTZ 0
+#endif
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace numeric_internal {
+
+constexpr bool IsPowerOf2(unsigned int x) noexcept {
+  return x != 0 && (x & (x - 1)) == 0;
+}
+
+template <class T>
+ABSL_MUST_USE_RESULT ABSL_ATTRIBUTE_ALWAYS_INLINE constexpr T RotateRight(
+    T x, int s) noexcept {
+  static_assert(std::is_unsigned<T>::value, "T must be unsigned");
+  static_assert(IsPowerOf2(std::numeric_limits<T>::digits),
+                "T must have a power-of-2 size");
+
+  return static_cast<T>(x >> (s & (std::numeric_limits<T>::digits - 1))) |
+         static_cast<T>(x << ((-s) & (std::numeric_limits<T>::digits - 1)));
+}
+
+template <class T>
+ABSL_MUST_USE_RESULT ABSL_ATTRIBUTE_ALWAYS_INLINE constexpr T RotateLeft(
+    T x, int s) noexcept {
+  static_assert(std::is_unsigned<T>::value, "T must be unsigned");
+  static_assert(IsPowerOf2(std::numeric_limits<T>::digits),
+                "T must have a power-of-2 size");
+
+  return static_cast<T>(x << (s & (std::numeric_limits<T>::digits - 1))) |
+         static_cast<T>(x >> ((-s) & (std::numeric_limits<T>::digits - 1)));
+}
+
+ABSL_ATTRIBUTE_ALWAYS_INLINE ABSL_INTERNAL_CONSTEXPR_POPCOUNT inline int
+Popcount32(uint32_t x) noexcept {
+#if ABSL_NUMERIC_INTERNAL_HAVE_BUILTIN_OR_GCC(__builtin_popcount)
+  static_assert(sizeof(unsigned int) == sizeof(x),
+                "__builtin_popcount does not take 32-bit arg");
+  return __builtin_popcount(x);
+#else
+  x -= ((x >> 1) & 0x55555555);
+  x = ((x >> 2) & 0x33333333) + (x & 0x33333333);
+  return static_cast<int>((((x + (x >> 4)) & 0xF0F0F0F) * 0x1010101) >> 24);
+#endif
+}
+
+ABSL_ATTRIBUTE_ALWAYS_INLINE ABSL_INTERNAL_CONSTEXPR_POPCOUNT inline int
+Popcount64(uint64_t x) noexcept {
+#if ABSL_NUMERIC_INTERNAL_HAVE_BUILTIN_OR_GCC(__builtin_popcountll)
+  static_assert(sizeof(unsigned long long) == sizeof(x),  // NOLINT(runtime/int)
+                "__builtin_popcount does not take 64-bit arg");
+  return __builtin_popcountll(x);
+#else
+  x -= (x >> 1) & 0x5555555555555555ULL;
+  x = ((x >> 2) & 0x3333333333333333ULL) + (x & 0x3333333333333333ULL);
+  return static_cast<int>(
+      (((x + (x >> 4)) & 0xF0F0F0F0F0F0F0FULL) * 0x101010101010101ULL) >> 56);
+#endif
+}
+
+template <class T>
+ABSL_ATTRIBUTE_ALWAYS_INLINE ABSL_INTERNAL_CONSTEXPR_POPCOUNT inline int
+Popcount(T x) noexcept {
+  static_assert(std::is_unsigned<T>::value, "T must be unsigned");
+  static_assert(IsPowerOf2(std::numeric_limits<T>::digits),
+                "T must have a power-of-2 size");
+  static_assert(sizeof(x) <= sizeof(uint64_t), "T is too large");
+  return sizeof(x) <= sizeof(uint32_t) ? Popcount32(x) : Popcount64(x);
+}
+
+ABSL_ATTRIBUTE_ALWAYS_INLINE ABSL_INTERNAL_CONSTEXPR_CLZ inline int
+CountLeadingZeroes32(uint32_t x) {
+#if ABSL_NUMERIC_INTERNAL_HAVE_BUILTIN_OR_GCC(__builtin_clz)
+  // Use __builtin_clz, which uses the following instructions:
+  //  x86: bsr, lzcnt
+  //  ARM64: clz
+  //  PPC: cntlzd
+
+  static_assert(sizeof(unsigned int) == sizeof(x),
+                "__builtin_clz does not take 32-bit arg");
+  // Handle 0 as a special case because __builtin_clz(0) is undefined.
+  return x == 0 ? 32 : __builtin_clz(x);
+#elif defined(_MSC_VER) && !defined(__clang__)
+  unsigned long result = 0;  // NOLINT(runtime/int)
+  if (_BitScanReverse(&result, x)) {
+    return 31 - result;
+  }
+  return 32;
+#else
+  int zeroes = 28;
+  if (x >> 16) {
+    zeroes -= 16;
+    x >>= 16;
+  }
+  if (x >> 8) {
+    zeroes -= 8;
+    x >>= 8;
+  }
+  if (x >> 4) {
+    zeroes -= 4;
+    x >>= 4;
+  }
+  return "\4\3\2\2\1\1\1\1\0\0\0\0\0\0\0"[x] + zeroes;
+#endif
+}
+
+ABSL_ATTRIBUTE_ALWAYS_INLINE ABSL_INTERNAL_CONSTEXPR_CLZ inline int
+CountLeadingZeroes16(uint16_t x) {
+#if ABSL_HAVE_BUILTIN(__builtin_clzs)
+  static_assert(sizeof(unsigned short) == sizeof(x),  // NOLINT(runtime/int)
+                "__builtin_clzs does not take 16-bit arg");
+  return x == 0 ? 16 : __builtin_clzs(x);
+#else
+  return CountLeadingZeroes32(x) - 16;
+#endif
+}
+
+ABSL_ATTRIBUTE_ALWAYS_INLINE ABSL_INTERNAL_CONSTEXPR_CLZ inline int
+CountLeadingZeroes64(uint64_t x) {
+#if ABSL_NUMERIC_INTERNAL_HAVE_BUILTIN_OR_GCC(__builtin_clzll)
+  // Use __builtin_clzll, which uses the following instructions:
+  //  x86: bsr, lzcnt
+  //  ARM64: clz
+  //  PPC: cntlzd
+  static_assert(sizeof(unsigned long long) == sizeof(x),  // NOLINT(runtime/int)
+                "__builtin_clzll does not take 64-bit arg");
+
+  // Handle 0 as a special case because __builtin_clzll(0) is undefined.
+  return x == 0 ? 64 : __builtin_clzll(x);
+#elif defined(_MSC_VER) && !defined(__clang__) && \
+    (defined(_M_X64) || defined(_M_ARM64))
+  // MSVC does not have __buitin_clzll. Use _BitScanReverse64.
+  unsigned long result = 0;  // NOLINT(runtime/int)
+  if (_BitScanReverse64(&result, x)) {
+    return 63 - result;
+  }
+  return 64;
+#elif defined(_MSC_VER) && !defined(__clang__)
+  // MSVC does not have __buitin_clzll. Compose two calls to _BitScanReverse
+  unsigned long result = 0;  // NOLINT(runtime/int)
+  if ((x >> 32) &&
+      _BitScanReverse(&result, static_cast<unsigned long>(x >> 32))) {
+    return 31 - result;
+  }
+  if (_BitScanReverse(&result, static_cast<unsigned long>(x))) {
+    return 63 - result;
+  }
+  return 64;
+#else
+  int zeroes = 60;
+  if (x >> 32) {
+    zeroes -= 32;
+    x >>= 32;
+  }
+  if (x >> 16) {
+    zeroes -= 16;
+    x >>= 16;
+  }
+  if (x >> 8) {
+    zeroes -= 8;
+    x >>= 8;
+  }
+  if (x >> 4) {
+    zeroes -= 4;
+    x >>= 4;
+  }
+  return "\4\3\2\2\1\1\1\1\0\0\0\0\0\0\0"[x] + zeroes;
+#endif
+}
+
+template <typename T>
+ABSL_ATTRIBUTE_ALWAYS_INLINE ABSL_INTERNAL_CONSTEXPR_CLZ inline int
+CountLeadingZeroes(T x) {
+  static_assert(std::is_unsigned<T>::value, "T must be unsigned");
+  static_assert(IsPowerOf2(std::numeric_limits<T>::digits),
+                "T must have a power-of-2 size");
+  static_assert(sizeof(T) <= sizeof(uint64_t), "T too large");
+  return sizeof(T) <= sizeof(uint16_t)
+             ? CountLeadingZeroes16(static_cast<uint16_t>(x)) -
+                   (std::numeric_limits<uint16_t>::digits -
+                    std::numeric_limits<T>::digits)
+             : (sizeof(T) <= sizeof(uint32_t)
+                    ? CountLeadingZeroes32(static_cast<uint32_t>(x)) -
+                          (std::numeric_limits<uint32_t>::digits -
+                           std::numeric_limits<T>::digits)
+                    : CountLeadingZeroes64(x));
+}
+
+ABSL_ATTRIBUTE_ALWAYS_INLINE ABSL_INTERNAL_CONSTEXPR_CTZ inline int
+CountTrailingZeroesNonzero32(uint32_t x) {
+#if ABSL_NUMERIC_INTERNAL_HAVE_BUILTIN_OR_GCC(__builtin_ctz)
+  static_assert(sizeof(unsigned int) == sizeof(x),
+                "__builtin_ctz does not take 32-bit arg");
+  return __builtin_ctz(x);
+#elif defined(_MSC_VER) && !defined(__clang__)
+  unsigned long result = 0;  // NOLINT(runtime/int)
+  _BitScanForward(&result, x);
+  return result;
+#else
+  int c = 31;
+  x &= ~x + 1;
+  if (x & 0x0000FFFF) c -= 16;
+  if (x & 0x00FF00FF) c -= 8;
+  if (x & 0x0F0F0F0F) c -= 4;
+  if (x & 0x33333333) c -= 2;
+  if (x & 0x55555555) c -= 1;
+  return c;
+#endif
+}
+
+ABSL_ATTRIBUTE_ALWAYS_INLINE ABSL_INTERNAL_CONSTEXPR_CTZ inline int
+CountTrailingZeroesNonzero64(uint64_t x) {
+#if ABSL_NUMERIC_INTERNAL_HAVE_BUILTIN_OR_GCC(__builtin_ctzll)
+  static_assert(sizeof(unsigned long long) == sizeof(x),  // NOLINT(runtime/int)
+                "__builtin_ctzll does not take 64-bit arg");
+  return __builtin_ctzll(x);
+#elif defined(_MSC_VER) && !defined(__clang__) && \
+    (defined(_M_X64) || defined(_M_ARM64))
+  unsigned long result = 0;  // NOLINT(runtime/int)
+  _BitScanForward64(&result, x);
+  return result;
+#elif defined(_MSC_VER) && !defined(__clang__)
+  unsigned long result = 0;  // NOLINT(runtime/int)
+  if (static_cast<uint32_t>(x) == 0) {
+    _BitScanForward(&result, static_cast<unsigned long>(x >> 32));
+    return result + 32;
+  }
+  _BitScanForward(&result, static_cast<unsigned long>(x));
+  return result;
+#else
+  int c = 63;
+  x &= ~x + 1;
+  if (x & 0x00000000FFFFFFFF) c -= 32;
+  if (x & 0x0000FFFF0000FFFF) c -= 16;
+  if (x & 0x00FF00FF00FF00FF) c -= 8;
+  if (x & 0x0F0F0F0F0F0F0F0F) c -= 4;
+  if (x & 0x3333333333333333) c -= 2;
+  if (x & 0x5555555555555555) c -= 1;
+  return c;
+#endif
+}
+
+ABSL_ATTRIBUTE_ALWAYS_INLINE ABSL_INTERNAL_CONSTEXPR_CTZ inline int
+CountTrailingZeroesNonzero16(uint16_t x) {
+#if ABSL_HAVE_BUILTIN(__builtin_ctzs)
+  static_assert(sizeof(unsigned short) == sizeof(x),  // NOLINT(runtime/int)
+                "__builtin_ctzs does not take 16-bit arg");
+  return __builtin_ctzs(x);
+#else
+  return CountTrailingZeroesNonzero32(x);
+#endif
+}
+
+template <class T>
+ABSL_ATTRIBUTE_ALWAYS_INLINE ABSL_INTERNAL_CONSTEXPR_CTZ inline int
+CountTrailingZeroes(T x) noexcept {
+  static_assert(std::is_unsigned<T>::value, "T must be unsigned");
+  static_assert(IsPowerOf2(std::numeric_limits<T>::digits),
+                "T must have a power-of-2 size");
+  static_assert(sizeof(T) <= sizeof(uint64_t), "T too large");
+  return x == 0 ? std::numeric_limits<T>::digits
+                : (sizeof(T) <= sizeof(uint16_t)
+                       ? CountTrailingZeroesNonzero16(static_cast<uint16_t>(x))
+                       : (sizeof(T) <= sizeof(uint32_t)
+                              ? CountTrailingZeroesNonzero32(
+                                    static_cast<uint32_t>(x))
+                              : CountTrailingZeroesNonzero64(x)));
+}
+
+// If T is narrower than unsigned, T{1} << bit_width will be promoted.  We
+// want to force it to wraparound so that bit_ceil of an invalid value are not
+// core constant expressions.
+template <class T>
+ABSL_ATTRIBUTE_ALWAYS_INLINE ABSL_INTERNAL_CONSTEXPR_CLZ inline
+    typename std::enable_if<std::is_unsigned<T>::value, T>::type
+    BitCeilPromotionHelper(T x, T promotion) {
+  return (T{1} << (x + promotion)) >> promotion;
+}
+
+template <class T>
+ABSL_ATTRIBUTE_ALWAYS_INLINE ABSL_INTERNAL_CONSTEXPR_CLZ inline
+    typename std::enable_if<std::is_unsigned<T>::value, T>::type
+    BitCeilNonPowerOf2(T x) {
+  // If T is narrower than unsigned, it undergoes promotion to unsigned when we
+  // shift.  We calculate the number of bits added by the wider type.
+  return BitCeilPromotionHelper(
+      static_cast<T>(std::numeric_limits<T>::digits - CountLeadingZeroes(x)),
+      T{sizeof(T) >= sizeof(unsigned) ? 0
+                                      : std::numeric_limits<unsigned>::digits -
+                                            std::numeric_limits<T>::digits});
+}
+
+}  // namespace numeric_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#endif  // ABSL_NUMERIC_INTERNAL_BITS_H_
diff --git a/src/absl/numeric/internal/representation.h b/src/absl/numeric/internal/representation.h
new file mode 100644 (file)
index 0000000..82d332f
--- /dev/null
@@ -0,0 +1,55 @@
+// Copyright 2021 The Abseil Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef ABSL_NUMERIC_INTERNAL_REPRESENTATION_H_
+#define ABSL_NUMERIC_INTERNAL_REPRESENTATION_H_
+
+#include <limits>
+
+#include "absl/base/config.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace numeric_internal {
+
+// Returns true iff long double is represented as a pair of doubles added
+// together.
+inline constexpr bool IsDoubleDouble() {
+  // A double-double value always has exactly twice the precision of a double
+  // value--one double carries the high digits and one double carries the low
+  // digits. This property is not shared with any other common floating-point
+  // representation, so this test won't trigger false positives. For reference,
+  // this table gives the number of bits of precision of each common
+  // floating-point representation:
+  //
+  //                type     precision
+  //         IEEE single          24 b
+  //         IEEE double          53
+  //     x86 long double          64
+  //       double-double         106
+  //      IEEE quadruple         113
+  //
+  // Note in particular that a quadruple-precision float has greater precision
+  // than a double-double float despite taking up the same amount of memory; the
+  // quad has more of its bits allocated to the mantissa than the double-double
+  // has.
+  return std::numeric_limits<long double>::digits ==
+         2 * std::numeric_limits<double>::digits;
+}
+
+}  // namespace numeric_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#endif  // ABSL_NUMERIC_INTERNAL_REPRESENTATION_H_
diff --git a/src/absl/strings/ascii.cc b/src/absl/strings/ascii.cc
new file mode 100644 (file)
index 0000000..93bb03e
--- /dev/null
@@ -0,0 +1,200 @@
+// Copyright 2017 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "absl/strings/ascii.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace ascii_internal {
+
+// # Table generated by this Python code (bit 0x02 is currently unused):
+// TODO(mbar) Move Python code for generation of table to BUILD and link here.
+
+// NOTE: The kAsciiPropertyBits table used within this code was generated by
+// Python code of the following form. (Bit 0x02 is currently unused and
+// available.)
+//
+// def Hex2(n):
+//   return '0x' + hex(n/16)[2:] + hex(n%16)[2:]
+// def IsPunct(ch):
+//   return (ord(ch) >= 32 and ord(ch) < 127 and
+//           not ch.isspace() and not ch.isalnum())
+// def IsBlank(ch):
+//   return ch in ' \t'
+// def IsCntrl(ch):
+//   return ord(ch) < 32 or ord(ch) == 127
+// def IsXDigit(ch):
+//   return ch.isdigit() or ch.lower() in 'abcdef'
+// for i in range(128):
+//   ch = chr(i)
+//   mask = ((ch.isalpha() and 0x01 or 0) |
+//           (ch.isalnum() and 0x04 or 0) |
+//           (ch.isspace() and 0x08 or 0) |
+//           (IsPunct(ch) and 0x10 or 0) |
+//           (IsBlank(ch) and 0x20 or 0) |
+//           (IsCntrl(ch) and 0x40 or 0) |
+//           (IsXDigit(ch) and 0x80 or 0))
+//   print Hex2(mask) + ',',
+//   if i % 16 == 7:
+//     print ' //', Hex2(i & 0x78)
+//   elif i % 16 == 15:
+//     print
+
+// clang-format off
+// Array of bitfields holding character information. Each bit value corresponds
+// to a particular character feature. For readability, and because the value
+// of these bits is tightly coupled to this implementation, the individual bits
+// are not named. Note that bitfields for all characters above ASCII 127 are
+// zero-initialized.
+ABSL_DLL const unsigned char kPropertyBits[256] = {
+    0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,  // 0x00
+    0x40, 0x68, 0x48, 0x48, 0x48, 0x48, 0x40, 0x40,
+    0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,  // 0x10
+    0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
+    0x28, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,  // 0x20
+    0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
+    0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84,  // 0x30
+    0x84, 0x84, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
+    0x10, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x05,  // 0x40
+    0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
+    0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,  // 0x50
+    0x05, 0x05, 0x05, 0x10, 0x10, 0x10, 0x10, 0x10,
+    0x10, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x05,  // 0x60
+    0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
+    0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,  // 0x70
+    0x05, 0x05, 0x05, 0x10, 0x10, 0x10, 0x10, 0x40,
+};
+
+// Array of characters for the ascii_tolower() function. For values 'A'
+// through 'Z', return the lower-case character; otherwise, return the
+// identity of the passed character.
+ABSL_DLL const char kToLower[256] = {
+  '\x00', '\x01', '\x02', '\x03', '\x04', '\x05', '\x06', '\x07',
+  '\x08', '\x09', '\x0a', '\x0b', '\x0c', '\x0d', '\x0e', '\x0f',
+  '\x10', '\x11', '\x12', '\x13', '\x14', '\x15', '\x16', '\x17',
+  '\x18', '\x19', '\x1a', '\x1b', '\x1c', '\x1d', '\x1e', '\x1f',
+  '\x20', '\x21', '\x22', '\x23', '\x24', '\x25', '\x26', '\x27',
+  '\x28', '\x29', '\x2a', '\x2b', '\x2c', '\x2d', '\x2e', '\x2f',
+  '\x30', '\x31', '\x32', '\x33', '\x34', '\x35', '\x36', '\x37',
+  '\x38', '\x39', '\x3a', '\x3b', '\x3c', '\x3d', '\x3e', '\x3f',
+  '\x40',    'a',    'b',    'c',    'd',    'e',    'f',    'g',
+     'h',    'i',    'j',    'k',    'l',    'm',    'n',    'o',
+     'p',    'q',    'r',    's',    't',    'u',    'v',    'w',
+     'x',    'y',    'z', '\x5b', '\x5c', '\x5d', '\x5e', '\x5f',
+  '\x60', '\x61', '\x62', '\x63', '\x64', '\x65', '\x66', '\x67',
+  '\x68', '\x69', '\x6a', '\x6b', '\x6c', '\x6d', '\x6e', '\x6f',
+  '\x70', '\x71', '\x72', '\x73', '\x74', '\x75', '\x76', '\x77',
+  '\x78', '\x79', '\x7a', '\x7b', '\x7c', '\x7d', '\x7e', '\x7f',
+  '\x80', '\x81', '\x82', '\x83', '\x84', '\x85', '\x86', '\x87',
+  '\x88', '\x89', '\x8a', '\x8b', '\x8c', '\x8d', '\x8e', '\x8f',
+  '\x90', '\x91', '\x92', '\x93', '\x94', '\x95', '\x96', '\x97',
+  '\x98', '\x99', '\x9a', '\x9b', '\x9c', '\x9d', '\x9e', '\x9f',
+  '\xa0', '\xa1', '\xa2', '\xa3', '\xa4', '\xa5', '\xa6', '\xa7',
+  '\xa8', '\xa9', '\xaa', '\xab', '\xac', '\xad', '\xae', '\xaf',
+  '\xb0', '\xb1', '\xb2', '\xb3', '\xb4', '\xb5', '\xb6', '\xb7',
+  '\xb8', '\xb9', '\xba', '\xbb', '\xbc', '\xbd', '\xbe', '\xbf',
+  '\xc0', '\xc1', '\xc2', '\xc3', '\xc4', '\xc5', '\xc6', '\xc7',
+  '\xc8', '\xc9', '\xca', '\xcb', '\xcc', '\xcd', '\xce', '\xcf',
+  '\xd0', '\xd1', '\xd2', '\xd3', '\xd4', '\xd5', '\xd6', '\xd7',
+  '\xd8', '\xd9', '\xda', '\xdb', '\xdc', '\xdd', '\xde', '\xdf',
+  '\xe0', '\xe1', '\xe2', '\xe3', '\xe4', '\xe5', '\xe6', '\xe7',
+  '\xe8', '\xe9', '\xea', '\xeb', '\xec', '\xed', '\xee', '\xef',
+  '\xf0', '\xf1', '\xf2', '\xf3', '\xf4', '\xf5', '\xf6', '\xf7',
+  '\xf8', '\xf9', '\xfa', '\xfb', '\xfc', '\xfd', '\xfe', '\xff',
+};
+
+// Array of characters for the ascii_toupper() function. For values 'a'
+// through 'z', return the upper-case character; otherwise, return the
+// identity of the passed character.
+ABSL_DLL const char kToUpper[256] = {
+  '\x00', '\x01', '\x02', '\x03', '\x04', '\x05', '\x06', '\x07',
+  '\x08', '\x09', '\x0a', '\x0b', '\x0c', '\x0d', '\x0e', '\x0f',
+  '\x10', '\x11', '\x12', '\x13', '\x14', '\x15', '\x16', '\x17',
+  '\x18', '\x19', '\x1a', '\x1b', '\x1c', '\x1d', '\x1e', '\x1f',
+  '\x20', '\x21', '\x22', '\x23', '\x24', '\x25', '\x26', '\x27',
+  '\x28', '\x29', '\x2a', '\x2b', '\x2c', '\x2d', '\x2e', '\x2f',
+  '\x30', '\x31', '\x32', '\x33', '\x34', '\x35', '\x36', '\x37',
+  '\x38', '\x39', '\x3a', '\x3b', '\x3c', '\x3d', '\x3e', '\x3f',
+  '\x40', '\x41', '\x42', '\x43', '\x44', '\x45', '\x46', '\x47',
+  '\x48', '\x49', '\x4a', '\x4b', '\x4c', '\x4d', '\x4e', '\x4f',
+  '\x50', '\x51', '\x52', '\x53', '\x54', '\x55', '\x56', '\x57',
+  '\x58', '\x59', '\x5a', '\x5b', '\x5c', '\x5d', '\x5e', '\x5f',
+  '\x60',    'A',    'B',    'C',    'D',    'E',    'F',    'G',
+     'H',    'I',    'J',    'K',    'L',    'M',    'N',    'O',
+     'P',    'Q',    'R',    'S',    'T',    'U',    'V',    'W',
+     'X',    'Y',    'Z', '\x7b', '\x7c', '\x7d', '\x7e', '\x7f',
+  '\x80', '\x81', '\x82', '\x83', '\x84', '\x85', '\x86', '\x87',
+  '\x88', '\x89', '\x8a', '\x8b', '\x8c', '\x8d', '\x8e', '\x8f',
+  '\x90', '\x91', '\x92', '\x93', '\x94', '\x95', '\x96', '\x97',
+  '\x98', '\x99', '\x9a', '\x9b', '\x9c', '\x9d', '\x9e', '\x9f',
+  '\xa0', '\xa1', '\xa2', '\xa3', '\xa4', '\xa5', '\xa6', '\xa7',
+  '\xa8', '\xa9', '\xaa', '\xab', '\xac', '\xad', '\xae', '\xaf',
+  '\xb0', '\xb1', '\xb2', '\xb3', '\xb4', '\xb5', '\xb6', '\xb7',
+  '\xb8', '\xb9', '\xba', '\xbb', '\xbc', '\xbd', '\xbe', '\xbf',
+  '\xc0', '\xc1', '\xc2', '\xc3', '\xc4', '\xc5', '\xc6', '\xc7',
+  '\xc8', '\xc9', '\xca', '\xcb', '\xcc', '\xcd', '\xce', '\xcf',
+  '\xd0', '\xd1', '\xd2', '\xd3', '\xd4', '\xd5', '\xd6', '\xd7',
+  '\xd8', '\xd9', '\xda', '\xdb', '\xdc', '\xdd', '\xde', '\xdf',
+  '\xe0', '\xe1', '\xe2', '\xe3', '\xe4', '\xe5', '\xe6', '\xe7',
+  '\xe8', '\xe9', '\xea', '\xeb', '\xec', '\xed', '\xee', '\xef',
+  '\xf0', '\xf1', '\xf2', '\xf3', '\xf4', '\xf5', '\xf6', '\xf7',
+  '\xf8', '\xf9', '\xfa', '\xfb', '\xfc', '\xfd', '\xfe', '\xff',
+};
+// clang-format on
+
+}  // namespace ascii_internal
+
+void AsciiStrToLower(std::string* s) {
+  for (auto& ch : *s) {
+    ch = absl::ascii_tolower(ch);
+  }
+}
+
+void AsciiStrToUpper(std::string* s) {
+  for (auto& ch : *s) {
+    ch = absl::ascii_toupper(ch);
+  }
+}
+
+void RemoveExtraAsciiWhitespace(std::string* str) {
+  auto stripped = StripAsciiWhitespace(*str);
+
+  if (stripped.empty()) {
+    str->clear();
+    return;
+  }
+
+  auto input_it = stripped.begin();
+  auto input_end = stripped.end();
+  auto output_it = &(*str)[0];
+  bool is_ws = false;
+
+  for (; input_it < input_end; ++input_it) {
+    if (is_ws) {
+      // Consecutive whitespace?  Keep only the last.
+      is_ws = absl::ascii_isspace(*input_it);
+      if (is_ws) --output_it;
+    } else {
+      is_ws = absl::ascii_isspace(*input_it);
+    }
+
+    *output_it = *input_it;
+    ++output_it;
+  }
+
+  str->erase(output_it - &(*str)[0]);
+}
+
+ABSL_NAMESPACE_END
+}  // namespace absl
diff --git a/src/absl/strings/ascii.h b/src/absl/strings/ascii.h
new file mode 100644 (file)
index 0000000..b46bc71
--- /dev/null
@@ -0,0 +1,242 @@
+//
+// Copyright 2017 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// -----------------------------------------------------------------------------
+// File: ascii.h
+// -----------------------------------------------------------------------------
+//
+// This package contains functions operating on characters and strings
+// restricted to standard ASCII. These include character classification
+// functions analogous to those found in the ANSI C Standard Library <ctype.h>
+// header file.
+//
+// C++ implementations provide <ctype.h> functionality based on their
+// C environment locale. In general, reliance on such a locale is not ideal, as
+// the locale standard is problematic (and may not return invariant information
+// for the same character set, for example). These `ascii_*()` functions are
+// hard-wired for standard ASCII, much faster, and guaranteed to behave
+// consistently.  They will never be overloaded, nor will their function
+// signature change.
+//
+// `ascii_isalnum()`, `ascii_isalpha()`, `ascii_isascii()`, `ascii_isblank()`,
+// `ascii_iscntrl()`, `ascii_isdigit()`, `ascii_isgraph()`, `ascii_islower()`,
+// `ascii_isprint()`, `ascii_ispunct()`, `ascii_isspace()`, `ascii_isupper()`,
+// `ascii_isxdigit()`
+//   Analogous to the <ctype.h> functions with similar names, these
+//   functions take an unsigned char and return a bool, based on whether the
+//   character matches the condition specified.
+//
+//   If the input character has a numerical value greater than 127, these
+//   functions return `false`.
+//
+// `ascii_tolower()`, `ascii_toupper()`
+//   Analogous to the <ctype.h> functions with similar names, these functions
+//   take an unsigned char and return a char.
+//
+//   If the input character is not an ASCII {lower,upper}-case letter (including
+//   numerical values greater than 127) then the functions return the same value
+//   as the input character.
+
+#ifndef ABSL_STRINGS_ASCII_H_
+#define ABSL_STRINGS_ASCII_H_
+
+#include <algorithm>
+#include <string>
+
+#include "absl/base/attributes.h"
+#include "absl/base/config.h"
+#include "absl/strings/string_view.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace ascii_internal {
+
+// Declaration for an array of bitfields holding character information.
+ABSL_DLL extern const unsigned char kPropertyBits[256];
+
+// Declaration for the array of characters to upper-case characters.
+ABSL_DLL extern const char kToUpper[256];
+
+// Declaration for the array of characters to lower-case characters.
+ABSL_DLL extern const char kToLower[256];
+
+}  // namespace ascii_internal
+
+// ascii_isalpha()
+//
+// Determines whether the given character is an alphabetic character.
+inline bool ascii_isalpha(unsigned char c) {
+  return (ascii_internal::kPropertyBits[c] & 0x01) != 0;
+}
+
+// ascii_isalnum()
+//
+// Determines whether the given character is an alphanumeric character.
+inline bool ascii_isalnum(unsigned char c) {
+  return (ascii_internal::kPropertyBits[c] & 0x04) != 0;
+}
+
+// ascii_isspace()
+//
+// Determines whether the given character is a whitespace character (space,
+// tab, vertical tab, formfeed, linefeed, or carriage return).
+inline bool ascii_isspace(unsigned char c) {
+  return (ascii_internal::kPropertyBits[c] & 0x08) != 0;
+}
+
+// ascii_ispunct()
+//
+// Determines whether the given character is a punctuation character.
+inline bool ascii_ispunct(unsigned char c) {
+  return (ascii_internal::kPropertyBits[c] & 0x10) != 0;
+}
+
+// ascii_isblank()
+//
+// Determines whether the given character is a blank character (tab or space).
+inline bool ascii_isblank(unsigned char c) {
+  return (ascii_internal::kPropertyBits[c] & 0x20) != 0;
+}
+
+// ascii_iscntrl()
+//
+// Determines whether the given character is a control character.
+inline bool ascii_iscntrl(unsigned char c) {
+  return (ascii_internal::kPropertyBits[c] & 0x40) != 0;
+}
+
+// ascii_isxdigit()
+//
+// Determines whether the given character can be represented as a hexadecimal
+// digit character (i.e. {0-9} or {A-F}).
+inline bool ascii_isxdigit(unsigned char c) {
+  return (ascii_internal::kPropertyBits[c] & 0x80) != 0;
+}
+
+// ascii_isdigit()
+//
+// Determines whether the given character can be represented as a decimal
+// digit character (i.e. {0-9}).
+inline bool ascii_isdigit(unsigned char c) { return c >= '0' && c <= '9'; }
+
+// ascii_isprint()
+//
+// Determines whether the given character is printable, including whitespace.
+inline bool ascii_isprint(unsigned char c) { return c >= 32 && c < 127; }
+
+// ascii_isgraph()
+//
+// Determines whether the given character has a graphical representation.
+inline bool ascii_isgraph(unsigned char c) { return c > 32 && c < 127; }
+
+// ascii_isupper()
+//
+// Determines whether the given character is uppercase.
+inline bool ascii_isupper(unsigned char c) { return c >= 'A' && c <= 'Z'; }
+
+// ascii_islower()
+//
+// Determines whether the given character is lowercase.
+inline bool ascii_islower(unsigned char c) { return c >= 'a' && c <= 'z'; }
+
+// ascii_isascii()
+//
+// Determines whether the given character is ASCII.
+inline bool ascii_isascii(unsigned char c) { return c < 128; }
+
+// ascii_tolower()
+//
+// Returns an ASCII character, converting to lowercase if uppercase is
+// passed. Note that character values > 127 are simply returned.
+inline char ascii_tolower(unsigned char c) {
+  return ascii_internal::kToLower[c];
+}
+
+// Converts the characters in `s` to lowercase, changing the contents of `s`.
+void AsciiStrToLower(std::string* s);
+
+// Creates a lowercase string from a given absl::string_view.
+ABSL_MUST_USE_RESULT inline std::string AsciiStrToLower(absl::string_view s) {
+  std::string result(s);
+  absl::AsciiStrToLower(&result);
+  return result;
+}
+
+// ascii_toupper()
+//
+// Returns the ASCII character, converting to upper-case if lower-case is
+// passed. Note that characters values > 127 are simply returned.
+inline char ascii_toupper(unsigned char c) {
+  return ascii_internal::kToUpper[c];
+}
+
+// Converts the characters in `s` to uppercase, changing the contents of `s`.
+void AsciiStrToUpper(std::string* s);
+
+// Creates an uppercase string from a given absl::string_view.
+ABSL_MUST_USE_RESULT inline std::string AsciiStrToUpper(absl::string_view s) {
+  std::string result(s);
+  absl::AsciiStrToUpper(&result);
+  return result;
+}
+
+// Returns absl::string_view with whitespace stripped from the beginning of the
+// given string_view.
+ABSL_MUST_USE_RESULT inline absl::string_view StripLeadingAsciiWhitespace(
+    absl::string_view str) {
+  auto it = std::find_if_not(str.begin(), str.end(), absl::ascii_isspace);
+  return str.substr(it - str.begin());
+}
+
+// Strips in place whitespace from the beginning of the given string.
+inline void StripLeadingAsciiWhitespace(std::string* str) {
+  auto it = std::find_if_not(str->begin(), str->end(), absl::ascii_isspace);
+  str->erase(str->begin(), it);
+}
+
+// Returns absl::string_view with whitespace stripped from the end of the given
+// string_view.
+ABSL_MUST_USE_RESULT inline absl::string_view StripTrailingAsciiWhitespace(
+    absl::string_view str) {
+  auto it = std::find_if_not(str.rbegin(), str.rend(), absl::ascii_isspace);
+  return str.substr(0, str.rend() - it);
+}
+
+// Strips in place whitespace from the end of the given string
+inline void StripTrailingAsciiWhitespace(std::string* str) {
+  auto it = std::find_if_not(str->rbegin(), str->rend(), absl::ascii_isspace);
+  str->erase(str->rend() - it);
+}
+
+// Returns absl::string_view with whitespace stripped from both ends of the
+// given string_view.
+ABSL_MUST_USE_RESULT inline absl::string_view StripAsciiWhitespace(
+    absl::string_view str) {
+  return StripTrailingAsciiWhitespace(StripLeadingAsciiWhitespace(str));
+}
+
+// Strips in place whitespace from both ends of the given string
+inline void StripAsciiWhitespace(std::string* str) {
+  StripTrailingAsciiWhitespace(str);
+  StripLeadingAsciiWhitespace(str);
+}
+
+// Removes leading, trailing, and consecutive internal whitespace.
+void RemoveExtraAsciiWhitespace(std::string*);
+
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#endif  // ABSL_STRINGS_ASCII_H_
diff --git a/src/absl/strings/charconv.cc b/src/absl/strings/charconv.cc
new file mode 100644 (file)
index 0000000..b8674c2
--- /dev/null
@@ -0,0 +1,984 @@
+// Copyright 2018 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "absl/strings/charconv.h"
+
+#include <algorithm>
+#include <cassert>
+#include <cmath>
+#include <cstring>
+
+#include "absl/base/casts.h"
+#include "absl/numeric/bits.h"
+#include "absl/numeric/int128.h"
+#include "absl/strings/internal/charconv_bigint.h"
+#include "absl/strings/internal/charconv_parse.h"
+
+// The macro ABSL_BIT_PACK_FLOATS is defined on x86-64, where IEEE floating
+// point numbers have the same endianness in memory as a bitfield struct
+// containing the corresponding parts.
+//
+// When set, we replace calls to ldexp() with manual bit packing, which is
+// faster and is unaffected by floating point environment.
+#ifdef ABSL_BIT_PACK_FLOATS
+#error ABSL_BIT_PACK_FLOATS cannot be directly set
+#elif defined(__x86_64__) || defined(_M_X64)
+#define ABSL_BIT_PACK_FLOATS 1
+#endif
+
+// A note about subnormals:
+//
+// The code below talks about "normals" and "subnormals".  A normal IEEE float
+// has a fixed-width mantissa and power of two exponent.  For example, a normal
+// `double` has a 53-bit mantissa.  Because the high bit is always 1, it is not
+// stored in the representation.  The implicit bit buys an extra bit of
+// resolution in the datatype.
+//
+// The downside of this scheme is that there is a large gap between DBL_MIN and
+// zero.  (Large, at least, relative to the different between DBL_MIN and the
+// next representable number).  This gap is softened by the "subnormal" numbers,
+// which have the same power-of-two exponent as DBL_MIN, but no implicit 53rd
+// bit.  An all-bits-zero exponent in the encoding represents subnormals.  (Zero
+// is represented as a subnormal with an all-bits-zero mantissa.)
+//
+// The code below, in calculations, represents the mantissa as a uint64_t.  The
+// end result normally has the 53rd bit set.  It represents subnormals by using
+// narrower mantissas.
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace {
+
+template <typename FloatType>
+struct FloatTraits;
+
+template <>
+struct FloatTraits<double> {
+  // The number of mantissa bits in the given float type.  This includes the
+  // implied high bit.
+  static constexpr int kTargetMantissaBits = 53;
+
+  // The largest supported IEEE exponent, in our integral mantissa
+  // representation.
+  //
+  // If `m` is the largest possible int kTargetMantissaBits bits wide, then
+  // m * 2**kMaxExponent is exactly equal to DBL_MAX.
+  static constexpr int kMaxExponent = 971;
+
+  // The smallest supported IEEE normal exponent, in our integral mantissa
+  // representation.
+  //
+  // If `m` is the smallest possible int kTargetMantissaBits bits wide, then
+  // m * 2**kMinNormalExponent is exactly equal to DBL_MIN.
+  static constexpr int kMinNormalExponent = -1074;
+
+  static double MakeNan(const char* tagp) {
+    // Support nan no matter which namespace it's in.  Some platforms
+    // incorrectly don't put it in namespace std.
+    using namespace std;  // NOLINT
+    return nan(tagp);
+  }
+
+  // Builds a nonzero floating point number out of the provided parts.
+  //
+  // This is intended to do the same operation as ldexp(mantissa, exponent),
+  // but using purely integer math, to avoid -ffastmath and floating
+  // point environment issues.  Using type punning is also faster. We fall back
+  // to ldexp on a per-platform basis for portability.
+  //
+  // `exponent` must be between kMinNormalExponent and kMaxExponent.
+  //
+  // `mantissa` must either be exactly kTargetMantissaBits wide, in which case
+  // a normal value is made, or it must be less narrow than that, in which case
+  // `exponent` must be exactly kMinNormalExponent, and a subnormal value is
+  // made.
+  static double Make(uint64_t mantissa, int exponent, bool sign) {
+#ifndef ABSL_BIT_PACK_FLOATS
+    // Support ldexp no matter which namespace it's in.  Some platforms
+    // incorrectly don't put it in namespace std.
+    using namespace std;  // NOLINT
+    return sign ? -ldexp(mantissa, exponent) : ldexp(mantissa, exponent);
+#else
+    constexpr uint64_t kMantissaMask =
+        (uint64_t(1) << (kTargetMantissaBits - 1)) - 1;
+    uint64_t dbl = static_cast<uint64_t>(sign) << 63;
+    if (mantissa > kMantissaMask) {
+      // Normal value.
+      // Adjust by 1023 for the exponent representation bias, and an additional
+      // 52 due to the implied decimal point in the IEEE mantissa represenation.
+      dbl += uint64_t{exponent + 1023u + kTargetMantissaBits - 1} << 52;
+      mantissa &= kMantissaMask;
+    } else {
+      // subnormal value
+      assert(exponent == kMinNormalExponent);
+    }
+    dbl += mantissa;
+    return absl::bit_cast<double>(dbl);
+#endif  // ABSL_BIT_PACK_FLOATS
+  }
+};
+
+// Specialization of floating point traits for the `float` type.  See the
+// FloatTraits<double> specialization above for meaning of each of the following
+// members and methods.
+template <>
+struct FloatTraits<float> {
+  static constexpr int kTargetMantissaBits = 24;
+  static constexpr int kMaxExponent = 104;
+  static constexpr int kMinNormalExponent = -149;
+  static float MakeNan(const char* tagp) {
+    // Support nanf no matter which namespace it's in.  Some platforms
+    // incorrectly don't put it in namespace std.
+    using namespace std;  // NOLINT
+    return nanf(tagp);
+  }
+  static float Make(uint32_t mantissa, int exponent, bool sign) {
+#ifndef ABSL_BIT_PACK_FLOATS
+    // Support ldexpf no matter which namespace it's in.  Some platforms
+    // incorrectly don't put it in namespace std.
+    using namespace std;  // NOLINT
+    return sign ? -ldexpf(mantissa, exponent) : ldexpf(mantissa, exponent);
+#else
+    constexpr uint32_t kMantissaMask =
+        (uint32_t(1) << (kTargetMantissaBits - 1)) - 1;
+    uint32_t flt = static_cast<uint32_t>(sign) << 31;
+    if (mantissa > kMantissaMask) {
+      // Normal value.
+      // Adjust by 127 for the exponent representation bias, and an additional
+      // 23 due to the implied decimal point in the IEEE mantissa represenation.
+      flt += uint32_t{exponent + 127u + kTargetMantissaBits - 1} << 23;
+      mantissa &= kMantissaMask;
+    } else {
+      // subnormal value
+      assert(exponent == kMinNormalExponent);
+    }
+    flt += mantissa;
+    return absl::bit_cast<float>(flt);
+#endif  // ABSL_BIT_PACK_FLOATS
+  }
+};
+
+// Decimal-to-binary conversions require coercing powers of 10 into a mantissa
+// and a power of 2.  The two helper functions Power10Mantissa(n) and
+// Power10Exponent(n) perform this task.  Together, these represent a hand-
+// rolled floating point value which is equal to or just less than 10**n.
+//
+// The return values satisfy two range guarantees:
+//
+//   Power10Mantissa(n) * 2**Power10Exponent(n) <= 10**n
+//     < (Power10Mantissa(n) + 1) * 2**Power10Exponent(n)
+//
+//   2**63 <= Power10Mantissa(n) < 2**64.
+//
+// Lookups into the power-of-10 table must first check the Power10Overflow() and
+// Power10Underflow() functions, to avoid out-of-bounds table access.
+//
+// Indexes into these tables are biased by -kPower10TableMin, and the table has
+// values in the range [kPower10TableMin, kPower10TableMax].
+extern const uint64_t kPower10MantissaTable[];
+extern const int16_t kPower10ExponentTable[];
+
+// The smallest allowed value for use with the Power10Mantissa() and
+// Power10Exponent() functions below.  (If a smaller exponent is needed in
+// calculations, the end result is guaranteed to underflow.)
+constexpr int kPower10TableMin = -342;
+
+// The largest allowed value for use with the Power10Mantissa() and
+// Power10Exponent() functions below.  (If a smaller exponent is needed in
+// calculations, the end result is guaranteed to overflow.)
+constexpr int kPower10TableMax = 308;
+
+uint64_t Power10Mantissa(int n) {
+  return kPower10MantissaTable[n - kPower10TableMin];
+}
+
+int Power10Exponent(int n) {
+  return kPower10ExponentTable[n - kPower10TableMin];
+}
+
+// Returns true if n is large enough that 10**n always results in an IEEE
+// overflow.
+bool Power10Overflow(int n) { return n > kPower10TableMax; }
+
+// Returns true if n is small enough that 10**n times a ParsedFloat mantissa
+// always results in an IEEE underflow.
+bool Power10Underflow(int n) { return n < kPower10TableMin; }
+
+// Returns true if Power10Mantissa(n) * 2**Power10Exponent(n) is exactly equal
+// to 10**n numerically.  Put another way, this returns true if there is no
+// truncation error in Power10Mantissa(n).
+bool Power10Exact(int n) { return n >= 0 && n <= 27; }
+
+// Sentinel exponent values for representing numbers too large or too close to
+// zero to represent in a double.
+constexpr int kOverflow = 99999;
+constexpr int kUnderflow = -99999;
+
+// Struct representing the calculated conversion result of a positive (nonzero)
+// floating point number.
+//
+// The calculated number is mantissa * 2**exponent (mantissa is treated as an
+// integer.)  `mantissa` is chosen to be the correct width for the IEEE float
+// representation being calculated.  (`mantissa` will always have the same bit
+// width for normal values, and narrower bit widths for subnormals.)
+//
+// If the result of conversion was an underflow or overflow, exponent is set
+// to kUnderflow or kOverflow.
+struct CalculatedFloat {
+  uint64_t mantissa = 0;
+  int exponent = 0;
+};
+
+// Returns the bit width of the given uint128.  (Equivalently, returns 128
+// minus the number of leading zero bits.)
+unsigned BitWidth(uint128 value) {
+  if (Uint128High64(value) == 0) {
+    return static_cast<unsigned>(bit_width(Uint128Low64(value)));
+  }
+  return 128 - countl_zero(Uint128High64(value));
+}
+
+// Calculates how far to the right a mantissa needs to be shifted to create a
+// properly adjusted mantissa for an IEEE floating point number.
+//
+// `mantissa_width` is the bit width of the mantissa to be shifted, and
+// `binary_exponent` is the exponent of the number before the shift.
+//
+// This accounts for subnormal values, and will return a larger-than-normal
+// shift if binary_exponent would otherwise be too low.
+template <typename FloatType>
+int NormalizedShiftSize(int mantissa_width, int binary_exponent) {
+  const int normal_shift =
+      mantissa_width - FloatTraits<FloatType>::kTargetMantissaBits;
+  const int minimum_shift =
+      FloatTraits<FloatType>::kMinNormalExponent - binary_exponent;
+  return std::max(normal_shift, minimum_shift);
+}
+
+// Right shifts a uint128 so that it has the requested bit width.  (The
+// resulting value will have 128 - bit_width leading zeroes.)  The initial
+// `value` must be wider than the requested bit width.
+//
+// Returns the number of bits shifted.
+int TruncateToBitWidth(int bit_width, uint128* value) {
+  const int current_bit_width = BitWidth(*value);
+  const int shift = current_bit_width - bit_width;
+  *value >>= shift;
+  return shift;
+}
+
+// Checks if the given ParsedFloat represents one of the edge cases that are
+// not dependent on number base: zero, infinity, or NaN.  If so, sets *value
+// the appropriate double, and returns true.
+template <typename FloatType>
+bool HandleEdgeCase(const strings_internal::ParsedFloat& input, bool negative,
+                    FloatType* value) {
+  if (input.type == strings_internal::FloatType::kNan) {
+    // A bug in both clang and gcc would cause the compiler to optimize away the
+    // buffer we are building below.  Declaring the buffer volatile avoids the
+    // issue, and has no measurable performance impact in microbenchmarks.
+    //
+    // https://bugs.llvm.org/show_bug.cgi?id=37778
+    // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=86113
+    constexpr ptrdiff_t kNanBufferSize = 128;
+    volatile char n_char_sequence[kNanBufferSize];
+    if (input.subrange_begin == nullptr) {
+      n_char_sequence[0] = '\0';
+    } else {
+      ptrdiff_t nan_size = input.subrange_end - input.subrange_begin;
+      nan_size = std::min(nan_size, kNanBufferSize - 1);
+      std::copy_n(input.subrange_begin, nan_size, n_char_sequence);
+      n_char_sequence[nan_size] = '\0';
+    }
+    char* nan_argument = const_cast<char*>(n_char_sequence);
+    *value = negative ? -FloatTraits<FloatType>::MakeNan(nan_argument)
+                      : FloatTraits<FloatType>::MakeNan(nan_argument);
+    return true;
+  }
+  if (input.type == strings_internal::FloatType::kInfinity) {
+    *value = negative ? -std::numeric_limits<FloatType>::infinity()
+                      : std::numeric_limits<FloatType>::infinity();
+    return true;
+  }
+  if (input.mantissa == 0) {
+    *value = negative ? -0.0 : 0.0;
+    return true;
+  }
+  return false;
+}
+
+// Given a CalculatedFloat result of a from_chars conversion, generate the
+// correct output values.
+//
+// CalculatedFloat can represent an underflow or overflow, in which case the
+// error code in *result is set.  Otherwise, the calculated floating point
+// number is stored in *value.
+template <typename FloatType>
+void EncodeResult(const CalculatedFloat& calculated, bool negative,
+                  absl::from_chars_result* result, FloatType* value) {
+  if (calculated.exponent == kOverflow) {
+    result->ec = std::errc::result_out_of_range;
+    *value = negative ? -std::numeric_limits<FloatType>::max()
+                      : std::numeric_limits<FloatType>::max();
+    return;
+  } else if (calculated.mantissa == 0 || calculated.exponent == kUnderflow) {
+    result->ec = std::errc::result_out_of_range;
+    *value = negative ? -0.0 : 0.0;
+    return;
+  }
+  *value = FloatTraits<FloatType>::Make(calculated.mantissa,
+                                        calculated.exponent, negative);
+}
+
+// Returns the given uint128 shifted to the right by `shift` bits, and rounds
+// the remaining bits using round_to_nearest logic.  The value is returned as a
+// uint64_t, since this is the type used by this library for storing calculated
+// floating point mantissas.
+//
+// It is expected that the width of the input value shifted by `shift` will
+// be the correct bit-width for the target mantissa, which is strictly narrower
+// than a uint64_t.
+//
+// If `input_exact` is false, then a nonzero error epsilon is assumed.  For
+// rounding purposes, the true value being rounded is strictly greater than the
+// input value.  The error may represent a single lost carry bit.
+//
+// When input_exact, shifted bits of the form 1000000... represent a tie, which
+// is broken by rounding to even -- the rounding direction is chosen so the low
+// bit of the returned value is 0.
+//
+// When !input_exact, shifted bits of the form 10000000... represent a value
+// strictly greater than one half (due to the error epsilon), and so ties are
+// always broken by rounding up.
+//
+// When !input_exact, shifted bits of the form 01111111... are uncertain;
+// the true value may or may not be greater than 10000000..., due to the
+// possible lost carry bit.  The correct rounding direction is unknown.  In this
+// case, the result is rounded down, and `output_exact` is set to false.
+//
+// Zero and negative values of `shift` are accepted, in which case the word is
+// shifted left, as necessary.
+uint64_t ShiftRightAndRound(uint128 value, int shift, bool input_exact,
+                            bool* output_exact) {
+  if (shift <= 0) {
+    *output_exact = input_exact;
+    return static_cast<uint64_t>(value << -shift);
+  }
+  if (shift >= 128) {
+    // Exponent is so small that we are shifting away all significant bits.
+    // Answer will not be representable, even as a subnormal, so return a zero
+    // mantissa (which represents underflow).
+    *output_exact = true;
+    return 0;
+  }
+
+  *output_exact = true;
+  const uint128 shift_mask = (uint128(1) << shift) - 1;
+  const uint128 halfway_point = uint128(1) << (shift - 1);
+
+  const uint128 shifted_bits = value & shift_mask;
+  value >>= shift;
+  if (shifted_bits > halfway_point) {
+    // Shifted bits greater than 10000... require rounding up.
+    return static_cast<uint64_t>(value + 1);
+  }
+  if (shifted_bits == halfway_point) {
+    // In exact mode, shifted bits of 10000... mean we're exactly halfway
+    // between two numbers, and we must round to even.  So only round up if
+    // the low bit of `value` is set.
+    //
+    // In inexact mode, the nonzero error means the actual value is greater
+    // than the halfway point and we must alway round up.
+    if ((value & 1) == 1 || !input_exact) {
+      ++value;
+    }
+    return static_cast<uint64_t>(value);
+  }
+  if (!input_exact && shifted_bits == halfway_point - 1) {
+    // Rounding direction is unclear, due to error.
+    *output_exact = false;
+  }
+  // Otherwise, round down.
+  return static_cast<uint64_t>(value);
+}
+
+// Checks if a floating point guess needs to be rounded up, using high precision
+// math.
+//
+// `guess_mantissa` and `guess_exponent` represent a candidate guess for the
+// number represented by `parsed_decimal`.
+//
+// The exact number represented by `parsed_decimal` must lie between the two
+// numbers:
+//   A = `guess_mantissa * 2**guess_exponent`
+//   B = `(guess_mantissa + 1) * 2**guess_exponent`
+//
+// This function returns false if `A` is the better guess, and true if `B` is
+// the better guess, with rounding ties broken by rounding to even.
+bool MustRoundUp(uint64_t guess_mantissa, int guess_exponent,
+                 const strings_internal::ParsedFloat& parsed_decimal) {
+  // 768 is the number of digits needed in the worst case.  We could determine a
+  // better limit dynamically based on the value of parsed_decimal.exponent.
+  // This would optimize pathological input cases only.  (Sane inputs won't have
+  // hundreds of digits of mantissa.)
+  absl::strings_internal::BigUnsigned<84> exact_mantissa;
+  int exact_exponent = exact_mantissa.ReadFloatMantissa(parsed_decimal, 768);
+
+  // Adjust the `guess` arguments to be halfway between A and B.
+  guess_mantissa = guess_mantissa * 2 + 1;
+  guess_exponent -= 1;
+
+  // In our comparison:
+  // lhs = exact = exact_mantissa * 10**exact_exponent
+  //             = exact_mantissa * 5**exact_exponent * 2**exact_exponent
+  // rhs = guess = guess_mantissa * 2**guess_exponent
+  //
+  // Because we are doing integer math, we can't directly deal with negative
+  // exponents.  We instead move these to the other side of the inequality.
+  absl::strings_internal::BigUnsigned<84>& lhs = exact_mantissa;
+  int comparison;
+  if (exact_exponent >= 0) {
+    lhs.MultiplyByFiveToTheNth(exact_exponent);
+    absl::strings_internal::BigUnsigned<84> rhs(guess_mantissa);
+    // There are powers of 2 on both sides of the inequality; reduce this to
+    // a single bit-shift.
+    if (exact_exponent > guess_exponent) {
+      lhs.ShiftLeft(exact_exponent - guess_exponent);
+    } else {
+      rhs.ShiftLeft(guess_exponent - exact_exponent);
+    }
+    comparison = Compare(lhs, rhs);
+  } else {
+    // Move the power of 5 to the other side of the equation, giving us:
+    // lhs = exact_mantissa * 2**exact_exponent
+    // rhs = guess_mantissa * 5**(-exact_exponent) * 2**guess_exponent
+    absl::strings_internal::BigUnsigned<84> rhs =
+        absl::strings_internal::BigUnsigned<84>::FiveToTheNth(-exact_exponent);
+    rhs.MultiplyBy(guess_mantissa);
+    if (exact_exponent > guess_exponent) {
+      lhs.ShiftLeft(exact_exponent - guess_exponent);
+    } else {
+      rhs.ShiftLeft(guess_exponent - exact_exponent);
+    }
+    comparison = Compare(lhs, rhs);
+  }
+  if (comparison < 0) {
+    return false;
+  } else if (comparison > 0) {
+    return true;
+  } else {
+    // When lhs == rhs, the decimal input is exactly between A and B.
+    // Round towards even -- round up only if the low bit of the initial
+    // `guess_mantissa` was a 1.  We shifted guess_mantissa left 1 bit at
+    // the beginning of this function, so test the 2nd bit here.
+    return (guess_mantissa & 2) == 2;
+  }
+}
+
+// Constructs a CalculatedFloat from a given mantissa and exponent, but
+// with the following normalizations applied:
+//
+// If rounding has caused mantissa to increase just past the allowed bit
+// width, shift and adjust exponent.
+//
+// If exponent is too high, sets kOverflow.
+//
+// If mantissa is zero (representing a non-zero value not representable, even
+// as a subnormal), sets kUnderflow.
+template <typename FloatType>
+CalculatedFloat CalculatedFloatFromRawValues(uint64_t mantissa, int exponent) {
+  CalculatedFloat result;
+  if (mantissa == uint64_t(1) << FloatTraits<FloatType>::kTargetMantissaBits) {
+    mantissa >>= 1;
+    exponent += 1;
+  }
+  if (exponent > FloatTraits<FloatType>::kMaxExponent) {
+    result.exponent = kOverflow;
+  } else if (mantissa == 0) {
+    result.exponent = kUnderflow;
+  } else {
+    result.exponent = exponent;
+    result.mantissa = mantissa;
+  }
+  return result;
+}
+
+template <typename FloatType>
+CalculatedFloat CalculateFromParsedHexadecimal(
+    const strings_internal::ParsedFloat& parsed_hex) {
+  uint64_t mantissa = parsed_hex.mantissa;
+  int exponent = parsed_hex.exponent;
+  auto mantissa_width = static_cast<unsigned>(bit_width(mantissa));
+  const int shift = NormalizedShiftSize<FloatType>(mantissa_width, exponent);
+  bool result_exact;
+  exponent += shift;
+  mantissa = ShiftRightAndRound(mantissa, shift,
+                                /* input exact= */ true, &result_exact);
+  // ParseFloat handles rounding in the hexadecimal case, so we don't have to
+  // check `result_exact` here.
+  return CalculatedFloatFromRawValues<FloatType>(mantissa, exponent);
+}
+
+template <typename FloatType>
+CalculatedFloat CalculateFromParsedDecimal(
+    const strings_internal::ParsedFloat& parsed_decimal) {
+  CalculatedFloat result;
+
+  // Large or small enough decimal exponents will always result in overflow
+  // or underflow.
+  if (Power10Underflow(parsed_decimal.exponent)) {
+    result.exponent = kUnderflow;
+    return result;
+  } else if (Power10Overflow(parsed_decimal.exponent)) {
+    result.exponent = kOverflow;
+    return result;
+  }
+
+  // Otherwise convert our power of 10 into a power of 2 times an integer
+  // mantissa, and multiply this by our parsed decimal mantissa.
+  uint128 wide_binary_mantissa = parsed_decimal.mantissa;
+  wide_binary_mantissa *= Power10Mantissa(parsed_decimal.exponent);
+  int binary_exponent = Power10Exponent(parsed_decimal.exponent);
+
+  // Discard bits that are inaccurate due to truncation error.  The magic
+  // `mantissa_width` constants below are justified in
+  // https://abseil.io/about/design/charconv. They represent the number of bits
+  // in `wide_binary_mantissa` that are guaranteed to be unaffected by error
+  // propagation.
+  bool mantissa_exact;
+  int mantissa_width;
+  if (parsed_decimal.subrange_begin) {
+    // Truncated mantissa
+    mantissa_width = 58;
+    mantissa_exact = false;
+    binary_exponent +=
+        TruncateToBitWidth(mantissa_width, &wide_binary_mantissa);
+  } else if (!Power10Exact(parsed_decimal.exponent)) {
+    // Exact mantissa, truncated power of ten
+    mantissa_width = 63;
+    mantissa_exact = false;
+    binary_exponent +=
+        TruncateToBitWidth(mantissa_width, &wide_binary_mantissa);
+  } else {
+    // Product is exact
+    mantissa_width = BitWidth(wide_binary_mantissa);
+    mantissa_exact = true;
+  }
+
+  // Shift into an FloatType-sized mantissa, and round to nearest.
+  const int shift =
+      NormalizedShiftSize<FloatType>(mantissa_width, binary_exponent);
+  bool result_exact;
+  binary_exponent += shift;
+  uint64_t binary_mantissa = ShiftRightAndRound(wide_binary_mantissa, shift,
+                                                mantissa_exact, &result_exact);
+  if (!result_exact) {
+    // We could not determine the rounding direction using int128 math.  Use
+    // full resolution math instead.
+    if (MustRoundUp(binary_mantissa, binary_exponent, parsed_decimal)) {
+      binary_mantissa += 1;
+    }
+  }
+
+  return CalculatedFloatFromRawValues<FloatType>(binary_mantissa,
+                                                 binary_exponent);
+}
+
+template <typename FloatType>
+from_chars_result FromCharsImpl(const char* first, const char* last,
+                                FloatType& value, chars_format fmt_flags) {
+  from_chars_result result;
+  result.ptr = first;  // overwritten on successful parse
+  result.ec = std::errc();
+
+  bool negative = false;
+  if (first != last && *first == '-') {
+    ++first;
+    negative = true;
+  }
+  // If the `hex` flag is *not* set, then we will accept a 0x prefix and try
+  // to parse a hexadecimal float.
+  if ((fmt_flags & chars_format::hex) == chars_format{} && last - first >= 2 &&
+      *first == '0' && (first[1] == 'x' || first[1] == 'X')) {
+    const char* hex_first = first + 2;
+    strings_internal::ParsedFloat hex_parse =
+        strings_internal::ParseFloat<16>(hex_first, last, fmt_flags);
+    if (hex_parse.end == nullptr ||
+        hex_parse.type != strings_internal::FloatType::kNumber) {
+      // Either we failed to parse a hex float after the "0x", or we read
+      // "0xinf" or "0xnan" which we don't want to match.
+      //
+      // However, a string that begins with "0x" also begins with "0", which
+      // is normally a valid match for the number zero.  So we want these
+      // strings to match zero unless fmt_flags is `scientific`.  (This flag
+      // means an exponent is required, which the string "0" does not have.)
+      if (fmt_flags == chars_format::scientific) {
+        result.ec = std::errc::invalid_argument;
+      } else {
+        result.ptr = first + 1;
+        value = negative ? -0.0 : 0.0;
+      }
+      return result;
+    }
+    // We matched a value.
+    result.ptr = hex_parse.end;
+    if (HandleEdgeCase(hex_parse, negative, &value)) {
+      return result;
+    }
+    CalculatedFloat calculated =
+        CalculateFromParsedHexadecimal<FloatType>(hex_parse);
+    EncodeResult(calculated, negative, &result, &value);
+    return result;
+  }
+  // Otherwise, we choose the number base based on the flags.
+  if ((fmt_flags & chars_format::hex) == chars_format::hex) {
+    strings_internal::ParsedFloat hex_parse =
+        strings_internal::ParseFloat<16>(first, last, fmt_flags);
+    if (hex_parse.end == nullptr) {
+      result.ec = std::errc::invalid_argument;
+      return result;
+    }
+    result.ptr = hex_parse.end;
+    if (HandleEdgeCase(hex_parse, negative, &value)) {
+      return result;
+    }
+    CalculatedFloat calculated =
+        CalculateFromParsedHexadecimal<FloatType>(hex_parse);
+    EncodeResult(calculated, negative, &result, &value);
+    return result;
+  } else {
+    strings_internal::ParsedFloat decimal_parse =
+        strings_internal::ParseFloat<10>(first, last, fmt_flags);
+    if (decimal_parse.end == nullptr) {
+      result.ec = std::errc::invalid_argument;
+      return result;
+    }
+    result.ptr = decimal_parse.end;
+    if (HandleEdgeCase(decimal_parse, negative, &value)) {
+      return result;
+    }
+    CalculatedFloat calculated =
+        CalculateFromParsedDecimal<FloatType>(decimal_parse);
+    EncodeResult(calculated, negative, &result, &value);
+    return result;
+  }
+}
+}  // namespace
+
+from_chars_result from_chars(const char* first, const char* last, double& value,
+                             chars_format fmt) {
+  return FromCharsImpl(first, last, value, fmt);
+}
+
+from_chars_result from_chars(const char* first, const char* last, float& value,
+                             chars_format fmt) {
+  return FromCharsImpl(first, last, value, fmt);
+}
+
+namespace {
+
+// Table of powers of 10, from kPower10TableMin to kPower10TableMax.
+//
+// kPower10MantissaTable[i - kPower10TableMin] stores the 64-bit mantissa (high
+// bit always on), and kPower10ExponentTable[i - kPower10TableMin] stores the
+// power-of-two exponent.  For a given number i, this gives the unique mantissa
+// and exponent such that mantissa * 2**exponent <= 10**i < (mantissa + 1) *
+// 2**exponent.
+
+const uint64_t kPower10MantissaTable[] = {
+    0xeef453d6923bd65aU, 0x9558b4661b6565f8U, 0xbaaee17fa23ebf76U,
+    0xe95a99df8ace6f53U, 0x91d8a02bb6c10594U, 0xb64ec836a47146f9U,
+    0xe3e27a444d8d98b7U, 0x8e6d8c6ab0787f72U, 0xb208ef855c969f4fU,
+    0xde8b2b66b3bc4723U, 0x8b16fb203055ac76U, 0xaddcb9e83c6b1793U,
+    0xd953e8624b85dd78U, 0x87d4713d6f33aa6bU, 0xa9c98d8ccb009506U,
+    0xd43bf0effdc0ba48U, 0x84a57695fe98746dU, 0xa5ced43b7e3e9188U,
+    0xcf42894a5dce35eaU, 0x818995ce7aa0e1b2U, 0xa1ebfb4219491a1fU,
+    0xca66fa129f9b60a6U, 0xfd00b897478238d0U, 0x9e20735e8cb16382U,
+    0xc5a890362fddbc62U, 0xf712b443bbd52b7bU, 0x9a6bb0aa55653b2dU,
+    0xc1069cd4eabe89f8U, 0xf148440a256e2c76U, 0x96cd2a865764dbcaU,
+    0xbc807527ed3e12bcU, 0xeba09271e88d976bU, 0x93445b8731587ea3U,
+    0xb8157268fdae9e4cU, 0xe61acf033d1a45dfU, 0x8fd0c16206306babU,
+    0xb3c4f1ba87bc8696U, 0xe0b62e2929aba83cU, 0x8c71dcd9ba0b4925U,
+    0xaf8e5410288e1b6fU, 0xdb71e91432b1a24aU, 0x892731ac9faf056eU,
+    0xab70fe17c79ac6caU, 0xd64d3d9db981787dU, 0x85f0468293f0eb4eU,
+    0xa76c582338ed2621U, 0xd1476e2c07286faaU, 0x82cca4db847945caU,
+    0xa37fce126597973cU, 0xcc5fc196fefd7d0cU, 0xff77b1fcbebcdc4fU,
+    0x9faacf3df73609b1U, 0xc795830d75038c1dU, 0xf97ae3d0d2446f25U,
+    0x9becce62836ac577U, 0xc2e801fb244576d5U, 0xf3a20279ed56d48aU,
+    0x9845418c345644d6U, 0xbe5691ef416bd60cU, 0xedec366b11c6cb8fU,
+    0x94b3a202eb1c3f39U, 0xb9e08a83a5e34f07U, 0xe858ad248f5c22c9U,
+    0x91376c36d99995beU, 0xb58547448ffffb2dU, 0xe2e69915b3fff9f9U,
+    0x8dd01fad907ffc3bU, 0xb1442798f49ffb4aU, 0xdd95317f31c7fa1dU,
+    0x8a7d3eef7f1cfc52U, 0xad1c8eab5ee43b66U, 0xd863b256369d4a40U,
+    0x873e4f75e2224e68U, 0xa90de3535aaae202U, 0xd3515c2831559a83U,
+    0x8412d9991ed58091U, 0xa5178fff668ae0b6U, 0xce5d73ff402d98e3U,
+    0x80fa687f881c7f8eU, 0xa139029f6a239f72U, 0xc987434744ac874eU,
+    0xfbe9141915d7a922U, 0x9d71ac8fada6c9b5U, 0xc4ce17b399107c22U,
+    0xf6019da07f549b2bU, 0x99c102844f94e0fbU, 0xc0314325637a1939U,
+    0xf03d93eebc589f88U, 0x96267c7535b763b5U, 0xbbb01b9283253ca2U,
+    0xea9c227723ee8bcbU, 0x92a1958a7675175fU, 0xb749faed14125d36U,
+    0xe51c79a85916f484U, 0x8f31cc0937ae58d2U, 0xb2fe3f0b8599ef07U,
+    0xdfbdcece67006ac9U, 0x8bd6a141006042bdU, 0xaecc49914078536dU,
+    0xda7f5bf590966848U, 0x888f99797a5e012dU, 0xaab37fd7d8f58178U,
+    0xd5605fcdcf32e1d6U, 0x855c3be0a17fcd26U, 0xa6b34ad8c9dfc06fU,
+    0xd0601d8efc57b08bU, 0x823c12795db6ce57U, 0xa2cb1717b52481edU,
+    0xcb7ddcdda26da268U, 0xfe5d54150b090b02U, 0x9efa548d26e5a6e1U,
+    0xc6b8e9b0709f109aU, 0xf867241c8cc6d4c0U, 0x9b407691d7fc44f8U,
+    0xc21094364dfb5636U, 0xf294b943e17a2bc4U, 0x979cf3ca6cec5b5aU,
+    0xbd8430bd08277231U, 0xece53cec4a314ebdU, 0x940f4613ae5ed136U,
+    0xb913179899f68584U, 0xe757dd7ec07426e5U, 0x9096ea6f3848984fU,
+    0xb4bca50b065abe63U, 0xe1ebce4dc7f16dfbU, 0x8d3360f09cf6e4bdU,
+    0xb080392cc4349decU, 0xdca04777f541c567U, 0x89e42caaf9491b60U,
+    0xac5d37d5b79b6239U, 0xd77485cb25823ac7U, 0x86a8d39ef77164bcU,
+    0xa8530886b54dbdebU, 0xd267caa862a12d66U, 0x8380dea93da4bc60U,
+    0xa46116538d0deb78U, 0xcd795be870516656U, 0x806bd9714632dff6U,
+    0xa086cfcd97bf97f3U, 0xc8a883c0fdaf7df0U, 0xfad2a4b13d1b5d6cU,
+    0x9cc3a6eec6311a63U, 0xc3f490aa77bd60fcU, 0xf4f1b4d515acb93bU,
+    0x991711052d8bf3c5U, 0xbf5cd54678eef0b6U, 0xef340a98172aace4U,
+    0x9580869f0e7aac0eU, 0xbae0a846d2195712U, 0xe998d258869facd7U,
+    0x91ff83775423cc06U, 0xb67f6455292cbf08U, 0xe41f3d6a7377eecaU,
+    0x8e938662882af53eU, 0xb23867fb2a35b28dU, 0xdec681f9f4c31f31U,
+    0x8b3c113c38f9f37eU, 0xae0b158b4738705eU, 0xd98ddaee19068c76U,
+    0x87f8a8d4cfa417c9U, 0xa9f6d30a038d1dbcU, 0xd47487cc8470652bU,
+    0x84c8d4dfd2c63f3bU, 0xa5fb0a17c777cf09U, 0xcf79cc9db955c2ccU,
+    0x81ac1fe293d599bfU, 0xa21727db38cb002fU, 0xca9cf1d206fdc03bU,
+    0xfd442e4688bd304aU, 0x9e4a9cec15763e2eU, 0xc5dd44271ad3cdbaU,
+    0xf7549530e188c128U, 0x9a94dd3e8cf578b9U, 0xc13a148e3032d6e7U,
+    0xf18899b1bc3f8ca1U, 0x96f5600f15a7b7e5U, 0xbcb2b812db11a5deU,
+    0xebdf661791d60f56U, 0x936b9fcebb25c995U, 0xb84687c269ef3bfbU,
+    0xe65829b3046b0afaU, 0x8ff71a0fe2c2e6dcU, 0xb3f4e093db73a093U,
+    0xe0f218b8d25088b8U, 0x8c974f7383725573U, 0xafbd2350644eeacfU,
+    0xdbac6c247d62a583U, 0x894bc396ce5da772U, 0xab9eb47c81f5114fU,
+    0xd686619ba27255a2U, 0x8613fd0145877585U, 0xa798fc4196e952e7U,
+    0xd17f3b51fca3a7a0U, 0x82ef85133de648c4U, 0xa3ab66580d5fdaf5U,
+    0xcc963fee10b7d1b3U, 0xffbbcfe994e5c61fU, 0x9fd561f1fd0f9bd3U,
+    0xc7caba6e7c5382c8U, 0xf9bd690a1b68637bU, 0x9c1661a651213e2dU,
+    0xc31bfa0fe5698db8U, 0xf3e2f893dec3f126U, 0x986ddb5c6b3a76b7U,
+    0xbe89523386091465U, 0xee2ba6c0678b597fU, 0x94db483840b717efU,
+    0xba121a4650e4ddebU, 0xe896a0d7e51e1566U, 0x915e2486ef32cd60U,
+    0xb5b5ada8aaff80b8U, 0xe3231912d5bf60e6U, 0x8df5efabc5979c8fU,
+    0xb1736b96b6fd83b3U, 0xddd0467c64bce4a0U, 0x8aa22c0dbef60ee4U,
+    0xad4ab7112eb3929dU, 0xd89d64d57a607744U, 0x87625f056c7c4a8bU,
+    0xa93af6c6c79b5d2dU, 0xd389b47879823479U, 0x843610cb4bf160cbU,
+    0xa54394fe1eedb8feU, 0xce947a3da6a9273eU, 0x811ccc668829b887U,
+    0xa163ff802a3426a8U, 0xc9bcff6034c13052U, 0xfc2c3f3841f17c67U,
+    0x9d9ba7832936edc0U, 0xc5029163f384a931U, 0xf64335bcf065d37dU,
+    0x99ea0196163fa42eU, 0xc06481fb9bcf8d39U, 0xf07da27a82c37088U,
+    0x964e858c91ba2655U, 0xbbe226efb628afeaU, 0xeadab0aba3b2dbe5U,
+    0x92c8ae6b464fc96fU, 0xb77ada0617e3bbcbU, 0xe55990879ddcaabdU,
+    0x8f57fa54c2a9eab6U, 0xb32df8e9f3546564U, 0xdff9772470297ebdU,
+    0x8bfbea76c619ef36U, 0xaefae51477a06b03U, 0xdab99e59958885c4U,
+    0x88b402f7fd75539bU, 0xaae103b5fcd2a881U, 0xd59944a37c0752a2U,
+    0x857fcae62d8493a5U, 0xa6dfbd9fb8e5b88eU, 0xd097ad07a71f26b2U,
+    0x825ecc24c873782fU, 0xa2f67f2dfa90563bU, 0xcbb41ef979346bcaU,
+    0xfea126b7d78186bcU, 0x9f24b832e6b0f436U, 0xc6ede63fa05d3143U,
+    0xf8a95fcf88747d94U, 0x9b69dbe1b548ce7cU, 0xc24452da229b021bU,
+    0xf2d56790ab41c2a2U, 0x97c560ba6b0919a5U, 0xbdb6b8e905cb600fU,
+    0xed246723473e3813U, 0x9436c0760c86e30bU, 0xb94470938fa89bceU,
+    0xe7958cb87392c2c2U, 0x90bd77f3483bb9b9U, 0xb4ecd5f01a4aa828U,
+    0xe2280b6c20dd5232U, 0x8d590723948a535fU, 0xb0af48ec79ace837U,
+    0xdcdb1b2798182244U, 0x8a08f0f8bf0f156bU, 0xac8b2d36eed2dac5U,
+    0xd7adf884aa879177U, 0x86ccbb52ea94baeaU, 0xa87fea27a539e9a5U,
+    0xd29fe4b18e88640eU, 0x83a3eeeef9153e89U, 0xa48ceaaab75a8e2bU,
+    0xcdb02555653131b6U, 0x808e17555f3ebf11U, 0xa0b19d2ab70e6ed6U,
+    0xc8de047564d20a8bU, 0xfb158592be068d2eU, 0x9ced737bb6c4183dU,
+    0xc428d05aa4751e4cU, 0xf53304714d9265dfU, 0x993fe2c6d07b7fabU,
+    0xbf8fdb78849a5f96U, 0xef73d256a5c0f77cU, 0x95a8637627989aadU,
+    0xbb127c53b17ec159U, 0xe9d71b689dde71afU, 0x9226712162ab070dU,
+    0xb6b00d69bb55c8d1U, 0xe45c10c42a2b3b05U, 0x8eb98a7a9a5b04e3U,
+    0xb267ed1940f1c61cU, 0xdf01e85f912e37a3U, 0x8b61313bbabce2c6U,
+    0xae397d8aa96c1b77U, 0xd9c7dced53c72255U, 0x881cea14545c7575U,
+    0xaa242499697392d2U, 0xd4ad2dbfc3d07787U, 0x84ec3c97da624ab4U,
+    0xa6274bbdd0fadd61U, 0xcfb11ead453994baU, 0x81ceb32c4b43fcf4U,
+    0xa2425ff75e14fc31U, 0xcad2f7f5359a3b3eU, 0xfd87b5f28300ca0dU,
+    0x9e74d1b791e07e48U, 0xc612062576589ddaU, 0xf79687aed3eec551U,
+    0x9abe14cd44753b52U, 0xc16d9a0095928a27U, 0xf1c90080baf72cb1U,
+    0x971da05074da7beeU, 0xbce5086492111aeaU, 0xec1e4a7db69561a5U,
+    0x9392ee8e921d5d07U, 0xb877aa3236a4b449U, 0xe69594bec44de15bU,
+    0x901d7cf73ab0acd9U, 0xb424dc35095cd80fU, 0xe12e13424bb40e13U,
+    0x8cbccc096f5088cbU, 0xafebff0bcb24aafeU, 0xdbe6fecebdedd5beU,
+    0x89705f4136b4a597U, 0xabcc77118461cefcU, 0xd6bf94d5e57a42bcU,
+    0x8637bd05af6c69b5U, 0xa7c5ac471b478423U, 0xd1b71758e219652bU,
+    0x83126e978d4fdf3bU, 0xa3d70a3d70a3d70aU, 0xccccccccccccccccU,
+    0x8000000000000000U, 0xa000000000000000U, 0xc800000000000000U,
+    0xfa00000000000000U, 0x9c40000000000000U, 0xc350000000000000U,
+    0xf424000000000000U, 0x9896800000000000U, 0xbebc200000000000U,
+    0xee6b280000000000U, 0x9502f90000000000U, 0xba43b74000000000U,
+    0xe8d4a51000000000U, 0x9184e72a00000000U, 0xb5e620f480000000U,
+    0xe35fa931a0000000U, 0x8e1bc9bf04000000U, 0xb1a2bc2ec5000000U,
+    0xde0b6b3a76400000U, 0x8ac7230489e80000U, 0xad78ebc5ac620000U,
+    0xd8d726b7177a8000U, 0x878678326eac9000U, 0xa968163f0a57b400U,
+    0xd3c21bcecceda100U, 0x84595161401484a0U, 0xa56fa5b99019a5c8U,
+    0xcecb8f27f4200f3aU, 0x813f3978f8940984U, 0xa18f07d736b90be5U,
+    0xc9f2c9cd04674edeU, 0xfc6f7c4045812296U, 0x9dc5ada82b70b59dU,
+    0xc5371912364ce305U, 0xf684df56c3e01bc6U, 0x9a130b963a6c115cU,
+    0xc097ce7bc90715b3U, 0xf0bdc21abb48db20U, 0x96769950b50d88f4U,
+    0xbc143fa4e250eb31U, 0xeb194f8e1ae525fdU, 0x92efd1b8d0cf37beU,
+    0xb7abc627050305adU, 0xe596b7b0c643c719U, 0x8f7e32ce7bea5c6fU,
+    0xb35dbf821ae4f38bU, 0xe0352f62a19e306eU, 0x8c213d9da502de45U,
+    0xaf298d050e4395d6U, 0xdaf3f04651d47b4cU, 0x88d8762bf324cd0fU,
+    0xab0e93b6efee0053U, 0xd5d238a4abe98068U, 0x85a36366eb71f041U,
+    0xa70c3c40a64e6c51U, 0xd0cf4b50cfe20765U, 0x82818f1281ed449fU,
+    0xa321f2d7226895c7U, 0xcbea6f8ceb02bb39U, 0xfee50b7025c36a08U,
+    0x9f4f2726179a2245U, 0xc722f0ef9d80aad6U, 0xf8ebad2b84e0d58bU,
+    0x9b934c3b330c8577U, 0xc2781f49ffcfa6d5U, 0xf316271c7fc3908aU,
+    0x97edd871cfda3a56U, 0xbde94e8e43d0c8ecU, 0xed63a231d4c4fb27U,
+    0x945e455f24fb1cf8U, 0xb975d6b6ee39e436U, 0xe7d34c64a9c85d44U,
+    0x90e40fbeea1d3a4aU, 0xb51d13aea4a488ddU, 0xe264589a4dcdab14U,
+    0x8d7eb76070a08aecU, 0xb0de65388cc8ada8U, 0xdd15fe86affad912U,
+    0x8a2dbf142dfcc7abU, 0xacb92ed9397bf996U, 0xd7e77a8f87daf7fbU,
+    0x86f0ac99b4e8dafdU, 0xa8acd7c0222311bcU, 0xd2d80db02aabd62bU,
+    0x83c7088e1aab65dbU, 0xa4b8cab1a1563f52U, 0xcde6fd5e09abcf26U,
+    0x80b05e5ac60b6178U, 0xa0dc75f1778e39d6U, 0xc913936dd571c84cU,
+    0xfb5878494ace3a5fU, 0x9d174b2dcec0e47bU, 0xc45d1df942711d9aU,
+    0xf5746577930d6500U, 0x9968bf6abbe85f20U, 0xbfc2ef456ae276e8U,
+    0xefb3ab16c59b14a2U, 0x95d04aee3b80ece5U, 0xbb445da9ca61281fU,
+    0xea1575143cf97226U, 0x924d692ca61be758U, 0xb6e0c377cfa2e12eU,
+    0xe498f455c38b997aU, 0x8edf98b59a373fecU, 0xb2977ee300c50fe7U,
+    0xdf3d5e9bc0f653e1U, 0x8b865b215899f46cU, 0xae67f1e9aec07187U,
+    0xda01ee641a708de9U, 0x884134fe908658b2U, 0xaa51823e34a7eedeU,
+    0xd4e5e2cdc1d1ea96U, 0x850fadc09923329eU, 0xa6539930bf6bff45U,
+    0xcfe87f7cef46ff16U, 0x81f14fae158c5f6eU, 0xa26da3999aef7749U,
+    0xcb090c8001ab551cU, 0xfdcb4fa002162a63U, 0x9e9f11c4014dda7eU,
+    0xc646d63501a1511dU, 0xf7d88bc24209a565U, 0x9ae757596946075fU,
+    0xc1a12d2fc3978937U, 0xf209787bb47d6b84U, 0x9745eb4d50ce6332U,
+    0xbd176620a501fbffU, 0xec5d3fa8ce427affU, 0x93ba47c980e98cdfU,
+    0xb8a8d9bbe123f017U, 0xe6d3102ad96cec1dU, 0x9043ea1ac7e41392U,
+    0xb454e4a179dd1877U, 0xe16a1dc9d8545e94U, 0x8ce2529e2734bb1dU,
+    0xb01ae745b101e9e4U, 0xdc21a1171d42645dU, 0x899504ae72497ebaU,
+    0xabfa45da0edbde69U, 0xd6f8d7509292d603U, 0x865b86925b9bc5c2U,
+    0xa7f26836f282b732U, 0xd1ef0244af2364ffU, 0x8335616aed761f1fU,
+    0xa402b9c5a8d3a6e7U, 0xcd036837130890a1U, 0x802221226be55a64U,
+    0xa02aa96b06deb0fdU, 0xc83553c5c8965d3dU, 0xfa42a8b73abbf48cU,
+    0x9c69a97284b578d7U, 0xc38413cf25e2d70dU, 0xf46518c2ef5b8cd1U,
+    0x98bf2f79d5993802U, 0xbeeefb584aff8603U, 0xeeaaba2e5dbf6784U,
+    0x952ab45cfa97a0b2U, 0xba756174393d88dfU, 0xe912b9d1478ceb17U,
+    0x91abb422ccb812eeU, 0xb616a12b7fe617aaU, 0xe39c49765fdf9d94U,
+    0x8e41ade9fbebc27dU, 0xb1d219647ae6b31cU, 0xde469fbd99a05fe3U,
+    0x8aec23d680043beeU, 0xada72ccc20054ae9U, 0xd910f7ff28069da4U,
+    0x87aa9aff79042286U, 0xa99541bf57452b28U, 0xd3fa922f2d1675f2U,
+    0x847c9b5d7c2e09b7U, 0xa59bc234db398c25U, 0xcf02b2c21207ef2eU,
+    0x8161afb94b44f57dU, 0xa1ba1ba79e1632dcU, 0xca28a291859bbf93U,
+    0xfcb2cb35e702af78U, 0x9defbf01b061adabU, 0xc56baec21c7a1916U,
+    0xf6c69a72a3989f5bU, 0x9a3c2087a63f6399U, 0xc0cb28a98fcf3c7fU,
+    0xf0fdf2d3f3c30b9fU, 0x969eb7c47859e743U, 0xbc4665b596706114U,
+    0xeb57ff22fc0c7959U, 0x9316ff75dd87cbd8U, 0xb7dcbf5354e9beceU,
+    0xe5d3ef282a242e81U, 0x8fa475791a569d10U, 0xb38d92d760ec4455U,
+    0xe070f78d3927556aU, 0x8c469ab843b89562U, 0xaf58416654a6babbU,
+    0xdb2e51bfe9d0696aU, 0x88fcf317f22241e2U, 0xab3c2fddeeaad25aU,
+    0xd60b3bd56a5586f1U, 0x85c7056562757456U, 0xa738c6bebb12d16cU,
+    0xd106f86e69d785c7U, 0x82a45b450226b39cU, 0xa34d721642b06084U,
+    0xcc20ce9bd35c78a5U, 0xff290242c83396ceU, 0x9f79a169bd203e41U,
+    0xc75809c42c684dd1U, 0xf92e0c3537826145U, 0x9bbcc7a142b17ccbU,
+    0xc2abf989935ddbfeU, 0xf356f7ebf83552feU, 0x98165af37b2153deU,
+    0xbe1bf1b059e9a8d6U, 0xeda2ee1c7064130cU, 0x9485d4d1c63e8be7U,
+    0xb9a74a0637ce2ee1U, 0xe8111c87c5c1ba99U, 0x910ab1d4db9914a0U,
+    0xb54d5e4a127f59c8U, 0xe2a0b5dc971f303aU, 0x8da471a9de737e24U,
+    0xb10d8e1456105dadU, 0xdd50f1996b947518U, 0x8a5296ffe33cc92fU,
+    0xace73cbfdc0bfb7bU, 0xd8210befd30efa5aU, 0x8714a775e3e95c78U,
+    0xa8d9d1535ce3b396U, 0xd31045a8341ca07cU, 0x83ea2b892091e44dU,
+    0xa4e4b66b68b65d60U, 0xce1de40642e3f4b9U, 0x80d2ae83e9ce78f3U,
+    0xa1075a24e4421730U, 0xc94930ae1d529cfcU, 0xfb9b7cd9a4a7443cU,
+    0x9d412e0806e88aa5U, 0xc491798a08a2ad4eU, 0xf5b5d7ec8acb58a2U,
+    0x9991a6f3d6bf1765U, 0xbff610b0cc6edd3fU, 0xeff394dcff8a948eU,
+    0x95f83d0a1fb69cd9U, 0xbb764c4ca7a4440fU, 0xea53df5fd18d5513U,
+    0x92746b9be2f8552cU, 0xb7118682dbb66a77U, 0xe4d5e82392a40515U,
+    0x8f05b1163ba6832dU, 0xb2c71d5bca9023f8U, 0xdf78e4b2bd342cf6U,
+    0x8bab8eefb6409c1aU, 0xae9672aba3d0c320U, 0xda3c0f568cc4f3e8U,
+    0x8865899617fb1871U, 0xaa7eebfb9df9de8dU, 0xd51ea6fa85785631U,
+    0x8533285c936b35deU, 0xa67ff273b8460356U, 0xd01fef10a657842cU,
+    0x8213f56a67f6b29bU, 0xa298f2c501f45f42U, 0xcb3f2f7642717713U,
+    0xfe0efb53d30dd4d7U, 0x9ec95d1463e8a506U, 0xc67bb4597ce2ce48U,
+    0xf81aa16fdc1b81daU, 0x9b10a4e5e9913128U, 0xc1d4ce1f63f57d72U,
+    0xf24a01a73cf2dccfU, 0x976e41088617ca01U, 0xbd49d14aa79dbc82U,
+    0xec9c459d51852ba2U, 0x93e1ab8252f33b45U, 0xb8da1662e7b00a17U,
+    0xe7109bfba19c0c9dU, 0x906a617d450187e2U, 0xb484f9dc9641e9daU,
+    0xe1a63853bbd26451U, 0x8d07e33455637eb2U, 0xb049dc016abc5e5fU,
+    0xdc5c5301c56b75f7U, 0x89b9b3e11b6329baU, 0xac2820d9623bf429U,
+    0xd732290fbacaf133U, 0x867f59a9d4bed6c0U, 0xa81f301449ee8c70U,
+    0xd226fc195c6a2f8cU, 0x83585d8fd9c25db7U, 0xa42e74f3d032f525U,
+    0xcd3a1230c43fb26fU, 0x80444b5e7aa7cf85U, 0xa0555e361951c366U,
+    0xc86ab5c39fa63440U, 0xfa856334878fc150U, 0x9c935e00d4b9d8d2U,
+    0xc3b8358109e84f07U, 0xf4a642e14c6262c8U, 0x98e7e9cccfbd7dbdU,
+    0xbf21e44003acdd2cU, 0xeeea5d5004981478U, 0x95527a5202df0ccbU,
+    0xbaa718e68396cffdU, 0xe950df20247c83fdU, 0x91d28b7416cdd27eU,
+    0xb6472e511c81471dU, 0xe3d8f9e563a198e5U, 0x8e679c2f5e44ff8fU,
+};
+
+const int16_t kPower10ExponentTable[] = {
+    -1200, -1196, -1193, -1190, -1186, -1183, -1180, -1176, -1173, -1170, -1166,
+    -1163, -1160, -1156, -1153, -1150, -1146, -1143, -1140, -1136, -1133, -1130,
+    -1127, -1123, -1120, -1117, -1113, -1110, -1107, -1103, -1100, -1097, -1093,
+    -1090, -1087, -1083, -1080, -1077, -1073, -1070, -1067, -1063, -1060, -1057,
+    -1053, -1050, -1047, -1043, -1040, -1037, -1034, -1030, -1027, -1024, -1020,
+    -1017, -1014, -1010, -1007, -1004, -1000, -997,  -994,  -990,  -987,  -984,
+    -980,  -977,  -974,  -970,  -967,  -964,  -960,  -957,  -954,  -950,  -947,
+    -944,  -940,  -937,  -934,  -931,  -927,  -924,  -921,  -917,  -914,  -911,
+    -907,  -904,  -901,  -897,  -894,  -891,  -887,  -884,  -881,  -877,  -874,
+    -871,  -867,  -864,  -861,  -857,  -854,  -851,  -847,  -844,  -841,  -838,
+    -834,  -831,  -828,  -824,  -821,  -818,  -814,  -811,  -808,  -804,  -801,
+    -798,  -794,  -791,  -788,  -784,  -781,  -778,  -774,  -771,  -768,  -764,
+    -761,  -758,  -754,  -751,  -748,  -744,  -741,  -738,  -735,  -731,  -728,
+    -725,  -721,  -718,  -715,  -711,  -708,  -705,  -701,  -698,  -695,  -691,
+    -688,  -685,  -681,  -678,  -675,  -671,  -668,  -665,  -661,  -658,  -655,
+    -651,  -648,  -645,  -642,  -638,  -635,  -632,  -628,  -625,  -622,  -618,
+    -615,  -612,  -608,  -605,  -602,  -598,  -595,  -592,  -588,  -585,  -582,
+    -578,  -575,  -572,  -568,  -565,  -562,  -558,  -555,  -552,  -549,  -545,
+    -542,  -539,  -535,  -532,  -529,  -525,  -522,  -519,  -515,  -512,  -509,
+    -505,  -502,  -499,  -495,  -492,  -489,  -485,  -482,  -479,  -475,  -472,
+    -469,  -465,  -462,  -459,  -455,  -452,  -449,  -446,  -442,  -439,  -436,
+    -432,  -429,  -426,  -422,  -419,  -416,  -412,  -409,  -406,  -402,  -399,
+    -396,  -392,  -389,  -386,  -382,  -379,  -376,  -372,  -369,  -366,  -362,
+    -359,  -356,  -353,  -349,  -346,  -343,  -339,  -336,  -333,  -329,  -326,
+    -323,  -319,  -316,  -313,  -309,  -306,  -303,  -299,  -296,  -293,  -289,
+    -286,  -283,  -279,  -276,  -273,  -269,  -266,  -263,  -259,  -256,  -253,
+    -250,  -246,  -243,  -240,  -236,  -233,  -230,  -226,  -223,  -220,  -216,
+    -213,  -210,  -206,  -203,  -200,  -196,  -193,  -190,  -186,  -183,  -180,
+    -176,  -173,  -170,  -166,  -163,  -160,  -157,  -153,  -150,  -147,  -143,
+    -140,  -137,  -133,  -130,  -127,  -123,  -120,  -117,  -113,  -110,  -107,
+    -103,  -100,  -97,   -93,   -90,   -87,   -83,   -80,   -77,   -73,   -70,
+    -67,   -63,   -60,   -57,   -54,   -50,   -47,   -44,   -40,   -37,   -34,
+    -30,   -27,   -24,   -20,   -17,   -14,   -10,   -7,    -4,    0,     3,
+    6,     10,    13,    16,    20,    23,    26,    30,    33,    36,    39,
+    43,    46,    49,    53,    56,    59,    63,    66,    69,    73,    76,
+    79,    83,    86,    89,    93,    96,    99,    103,   106,   109,   113,
+    116,   119,   123,   126,   129,   132,   136,   139,   142,   146,   149,
+    152,   156,   159,   162,   166,   169,   172,   176,   179,   182,   186,
+    189,   192,   196,   199,   202,   206,   209,   212,   216,   219,   222,
+    226,   229,   232,   235,   239,   242,   245,   249,   252,   255,   259,
+    262,   265,   269,   272,   275,   279,   282,   285,   289,   292,   295,
+    299,   302,   305,   309,   312,   315,   319,   322,   325,   328,   332,
+    335,   338,   342,   345,   348,   352,   355,   358,   362,   365,   368,
+    372,   375,   378,   382,   385,   388,   392,   395,   398,   402,   405,
+    408,   412,   415,   418,   422,   425,   428,   431,   435,   438,   441,
+    445,   448,   451,   455,   458,   461,   465,   468,   471,   475,   478,
+    481,   485,   488,   491,   495,   498,   501,   505,   508,   511,   515,
+    518,   521,   524,   528,   531,   534,   538,   541,   544,   548,   551,
+    554,   558,   561,   564,   568,   571,   574,   578,   581,   584,   588,
+    591,   594,   598,   601,   604,   608,   611,   614,   617,   621,   624,
+    627,   631,   634,   637,   641,   644,   647,   651,   654,   657,   661,
+    664,   667,   671,   674,   677,   681,   684,   687,   691,   694,   697,
+    701,   704,   707,   711,   714,   717,   720,   724,   727,   730,   734,
+    737,   740,   744,   747,   750,   754,   757,   760,   764,   767,   770,
+    774,   777,   780,   784,   787,   790,   794,   797,   800,   804,   807,
+    810,   813,   817,   820,   823,   827,   830,   833,   837,   840,   843,
+    847,   850,   853,   857,   860,   863,   867,   870,   873,   877,   880,
+    883,   887,   890,   893,   897,   900,   903,   907,   910,   913,   916,
+    920,   923,   926,   930,   933,   936,   940,   943,   946,   950,   953,
+    956,   960,
+};
+
+}  // namespace
+ABSL_NAMESPACE_END
+}  // namespace absl
diff --git a/src/absl/strings/charconv.h b/src/absl/strings/charconv.h
new file mode 100644 (file)
index 0000000..e04be32
--- /dev/null
@@ -0,0 +1,119 @@
+// Copyright 2018 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef ABSL_STRINGS_CHARCONV_H_
+#define ABSL_STRINGS_CHARCONV_H_
+
+#include <system_error>  // NOLINT(build/c++11)
+
+#include "absl/base/config.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+
+// Workalike compatibilty version of std::chars_format from C++17.
+//
+// This is an bitfield enumerator which can be passed to absl::from_chars to
+// configure the string-to-float conversion.
+enum class chars_format {
+  scientific = 1,
+  fixed = 2,
+  hex = 4,
+  general = fixed | scientific,
+};
+
+// The return result of a string-to-number conversion.
+//
+// `ec` will be set to `invalid_argument` if a well-formed number was not found
+// at the start of the input range, `result_out_of_range` if a well-formed
+// number was found, but it was out of the representable range of the requested
+// type, or to std::errc() otherwise.
+//
+// If a well-formed number was found, `ptr` is set to one past the sequence of
+// characters that were successfully parsed.  If none was found, `ptr` is set
+// to the `first` argument to from_chars.
+struct from_chars_result {
+  const char* ptr;
+  std::errc ec;
+};
+
+// Workalike compatibilty version of std::from_chars from C++17.  Currently
+// this only supports the `double` and `float` types.
+//
+// This interface incorporates the proposed resolutions for library issues
+// DR 3080 and DR 3081.  If these are adopted with different wording,
+// Abseil's behavior will change to match the standard.  (The behavior most
+// likely to change is for DR 3081, which says what `value` will be set to in
+// the case of overflow and underflow.  Code that wants to avoid possible
+// breaking changes in this area should not depend on `value` when the returned
+// from_chars_result indicates a range error.)
+//
+// Searches the range [first, last) for the longest matching pattern beginning
+// at `first` that represents a floating point number.  If one is found, store
+// the result in `value`.
+//
+// The matching pattern format is almost the same as that of strtod(), except
+// that C locale is not respected, and an initial '+' character in the input
+// range will never be matched.
+//
+// If `fmt` is set, it must be one of the enumerator values of the chars_format.
+// (This is despite the fact that chars_format is a bitmask type.)  If set to
+// `scientific`, a matching number must contain an exponent.  If set to `fixed`,
+// then an exponent will never match.  (For example, the string "1e5" will be
+// parsed as "1".)  If set to `hex`, then a hexadecimal float is parsed in the
+// format that strtod() accepts, except that a "0x" prefix is NOT matched.
+// (In particular, in `hex` mode, the input "0xff" results in the largest
+// matching pattern "0".)
+absl::from_chars_result from_chars(const char* first, const char* last,
+                                   double& value,  // NOLINT
+                                   chars_format fmt = chars_format::general);
+
+absl::from_chars_result from_chars(const char* first, const char* last,
+                                   float& value,  // NOLINT
+                                   chars_format fmt = chars_format::general);
+
+// std::chars_format is specified as a bitmask type, which means the following
+// operations must be provided:
+inline constexpr chars_format operator&(chars_format lhs, chars_format rhs) {
+  return static_cast<chars_format>(static_cast<int>(lhs) &
+                                   static_cast<int>(rhs));
+}
+inline constexpr chars_format operator|(chars_format lhs, chars_format rhs) {
+  return static_cast<chars_format>(static_cast<int>(lhs) |
+                                   static_cast<int>(rhs));
+}
+inline constexpr chars_format operator^(chars_format lhs, chars_format rhs) {
+  return static_cast<chars_format>(static_cast<int>(lhs) ^
+                                   static_cast<int>(rhs));
+}
+inline constexpr chars_format operator~(chars_format arg) {
+  return static_cast<chars_format>(~static_cast<int>(arg));
+}
+inline chars_format& operator&=(chars_format& lhs, chars_format rhs) {
+  lhs = lhs & rhs;
+  return lhs;
+}
+inline chars_format& operator|=(chars_format& lhs, chars_format rhs) {
+  lhs = lhs | rhs;
+  return lhs;
+}
+inline chars_format& operator^=(chars_format& lhs, chars_format rhs) {
+  lhs = lhs ^ rhs;
+  return lhs;
+}
+
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#endif  // ABSL_STRINGS_CHARCONV_H_
diff --git a/src/absl/strings/cord.cc b/src/absl/strings/cord.cc
new file mode 100644 (file)
index 0000000..9353375
--- /dev/null
@@ -0,0 +1,1953 @@
+// Copyright 2020 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "absl/strings/cord.h"
+
+#include <algorithm>
+#include <atomic>
+#include <cstddef>
+#include <cstdio>
+#include <cstdlib>
+#include <iomanip>
+#include <iostream>
+#include <limits>
+#include <ostream>
+#include <sstream>
+#include <type_traits>
+#include <unordered_set>
+#include <vector>
+
+#include "absl/base/casts.h"
+#include "absl/base/internal/raw_logging.h"
+#include "absl/base/macros.h"
+#include "absl/base/port.h"
+#include "absl/container/fixed_array.h"
+#include "absl/container/inlined_vector.h"
+#include "absl/strings/escaping.h"
+#include "absl/strings/internal/cord_internal.h"
+#include "absl/strings/internal/cord_rep_flat.h"
+#include "absl/strings/internal/cord_rep_ring.h"
+#include "absl/strings/internal/resize_uninitialized.h"
+#include "absl/strings/str_cat.h"
+#include "absl/strings/str_format.h"
+#include "absl/strings/str_join.h"
+#include "absl/strings/string_view.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+
+using ::absl::cord_internal::CordRep;
+using ::absl::cord_internal::CordRepConcat;
+using ::absl::cord_internal::CordRepExternal;
+using ::absl::cord_internal::CordRepFlat;
+using ::absl::cord_internal::CordRepRing;
+using ::absl::cord_internal::CordRepSubstring;
+using ::absl::cord_internal::kMinFlatLength;
+using ::absl::cord_internal::kMaxFlatLength;
+
+using ::absl::cord_internal::CONCAT;
+using ::absl::cord_internal::EXTERNAL;
+using ::absl::cord_internal::FLAT;
+using ::absl::cord_internal::RING;
+using ::absl::cord_internal::SUBSTRING;
+
+using ::absl::cord_internal::kInlinedVectorSize;
+using ::absl::cord_internal::kMaxBytesToCopy;
+
+constexpr uint64_t Fibonacci(unsigned char n, uint64_t a = 0, uint64_t b = 1) {
+  return n == 0 ? a : Fibonacci(n - 1, b, a + b);
+}
+
+static_assert(Fibonacci(63) == 6557470319842,
+              "Fibonacci values computed incorrectly");
+
+// Minimum length required for a given depth tree -- a tree is considered
+// balanced if
+//      length(t) >= min_length[depth(t)]
+// The root node depth is allowed to become twice as large to reduce rebalancing
+// for larger strings (see IsRootBalanced).
+static constexpr uint64_t min_length[] = {
+    Fibonacci(2),          Fibonacci(3),  Fibonacci(4),  Fibonacci(5),
+    Fibonacci(6),          Fibonacci(7),  Fibonacci(8),  Fibonacci(9),
+    Fibonacci(10),         Fibonacci(11), Fibonacci(12), Fibonacci(13),
+    Fibonacci(14),         Fibonacci(15), Fibonacci(16), Fibonacci(17),
+    Fibonacci(18),         Fibonacci(19), Fibonacci(20), Fibonacci(21),
+    Fibonacci(22),         Fibonacci(23), Fibonacci(24), Fibonacci(25),
+    Fibonacci(26),         Fibonacci(27), Fibonacci(28), Fibonacci(29),
+    Fibonacci(30),         Fibonacci(31), Fibonacci(32), Fibonacci(33),
+    Fibonacci(34),         Fibonacci(35), Fibonacci(36), Fibonacci(37),
+    Fibonacci(38),         Fibonacci(39), Fibonacci(40), Fibonacci(41),
+    Fibonacci(42),         Fibonacci(43), Fibonacci(44), Fibonacci(45),
+    Fibonacci(46),         Fibonacci(47),
+    0xffffffffffffffffull,  // Avoid overflow
+};
+
+static const int kMinLengthSize = ABSL_ARRAYSIZE(min_length);
+
+static inline bool cord_ring_enabled() {
+  return cord_internal::cord_ring_buffer_enabled.load(
+      std::memory_order_relaxed);
+}
+
+static inline bool IsRootBalanced(CordRep* node) {
+  if (node->tag != CONCAT) {
+    return true;
+  } else if (node->concat()->depth() <= 15) {
+    return true;
+  } else if (node->concat()->depth() > kMinLengthSize) {
+    return false;
+  } else {
+    // Allow depth to become twice as large as implied by fibonacci rule to
+    // reduce rebalancing for larger strings.
+    return (node->length >= min_length[node->concat()->depth() / 2]);
+  }
+}
+
+static CordRep* Rebalance(CordRep* node);
+static void DumpNode(CordRep* rep, bool include_data, std::ostream* os,
+                     int indent = 0);
+static bool VerifyNode(CordRep* root, CordRep* start_node,
+                       bool full_validation);
+
+static inline CordRep* VerifyTree(CordRep* node) {
+  // Verification is expensive, so only do it in debug mode.
+  // Even in debug mode we normally do only light validation.
+  // If you are debugging Cord itself, you should define the
+  // macro EXTRA_CORD_VALIDATION, e.g. by adding
+  // --copt=-DEXTRA_CORD_VALIDATION to the blaze line.
+#ifdef EXTRA_CORD_VALIDATION
+  assert(node == nullptr || VerifyNode(node, node, /*full_validation=*/true));
+#else   // EXTRA_CORD_VALIDATION
+  assert(node == nullptr || VerifyNode(node, node, /*full_validation=*/false));
+#endif  // EXTRA_CORD_VALIDATION
+  static_cast<void>(&VerifyNode);
+
+  return node;
+}
+
+// Return the depth of a node
+static int Depth(const CordRep* rep) {
+  if (rep->tag == CONCAT) {
+    return rep->concat()->depth();
+  } else {
+    return 0;
+  }
+}
+
+static void SetConcatChildren(CordRepConcat* concat, CordRep* left,
+                              CordRep* right) {
+  concat->left = left;
+  concat->right = right;
+
+  concat->length = left->length + right->length;
+  concat->set_depth(1 + std::max(Depth(left), Depth(right)));
+}
+
+// Create a concatenation of the specified nodes.
+// Does not change the refcounts of "left" and "right".
+// The returned node has a refcount of 1.
+static CordRep* RawConcat(CordRep* left, CordRep* right) {
+  // Avoid making degenerate concat nodes (one child is empty)
+  if (left == nullptr) return right;
+  if (right == nullptr) return left;
+  if (left->length == 0) {
+    CordRep::Unref(left);
+    return right;
+  }
+  if (right->length == 0) {
+    CordRep::Unref(right);
+    return left;
+  }
+
+  CordRepConcat* rep = new CordRepConcat();
+  rep->tag = CONCAT;
+  SetConcatChildren(rep, left, right);
+
+  return rep;
+}
+
+static CordRep* Concat(CordRep* left, CordRep* right) {
+  CordRep* rep = RawConcat(left, right);
+  if (rep != nullptr && !IsRootBalanced(rep)) {
+    rep = Rebalance(rep);
+  }
+  return VerifyTree(rep);
+}
+
+// Make a balanced tree out of an array of leaf nodes.
+static CordRep* MakeBalancedTree(CordRep** reps, size_t n) {
+  // Make repeated passes over the array, merging adjacent pairs
+  // until we are left with just a single node.
+  while (n > 1) {
+    size_t dst = 0;
+    for (size_t src = 0; src < n; src += 2) {
+      if (src + 1 < n) {
+        reps[dst] = Concat(reps[src], reps[src + 1]);
+      } else {
+        reps[dst] = reps[src];
+      }
+      dst++;
+    }
+    n = dst;
+  }
+
+  return reps[0];
+}
+
+static CordRepFlat* CreateFlat(const char* data, size_t length,
+                            size_t alloc_hint) {
+  CordRepFlat* flat = CordRepFlat::New(length + alloc_hint);
+  flat->length = length;
+  memcpy(flat->Data(), data, length);
+  return flat;
+}
+
+// Creates a new flat or ringbuffer out of the specified array.
+// The returned node has a refcount of 1.
+static CordRep* RingNewTree(const char* data, size_t length,
+                            size_t alloc_hint) {
+  if (length <= kMaxFlatLength) {
+    return CreateFlat(data, length, alloc_hint);
+  }
+  CordRepFlat* flat = CreateFlat(data, kMaxFlatLength, 0);
+  data += kMaxFlatLength;
+  length -= kMaxFlatLength;
+  size_t extra = (length - 1) / kMaxFlatLength + 1;
+  auto* root = CordRepRing::Create(flat, extra);
+  return CordRepRing::Append(root, {data, length}, alloc_hint);
+}
+
+// Create a new tree out of the specified array.
+// The returned node has a refcount of 1.
+static CordRep* NewTree(const char* data,
+                        size_t length,
+                        size_t alloc_hint) {
+  if (length == 0) return nullptr;
+  if (cord_ring_enabled()) {
+    return RingNewTree(data, length, alloc_hint);
+  }
+  absl::FixedArray<CordRep*> reps((length - 1) / kMaxFlatLength + 1);
+  size_t n = 0;
+  do {
+    const size_t len = std::min(length, kMaxFlatLength);
+    CordRepFlat* rep = CordRepFlat::New(len + alloc_hint);
+    rep->length = len;
+    memcpy(rep->Data(), data, len);
+    reps[n++] = VerifyTree(rep);
+    data += len;
+    length -= len;
+  } while (length != 0);
+  return MakeBalancedTree(reps.data(), n);
+}
+
+namespace cord_internal {
+
+void InitializeCordRepExternal(absl::string_view data, CordRepExternal* rep) {
+  assert(!data.empty());
+  rep->length = data.size();
+  rep->tag = EXTERNAL;
+  rep->base = data.data();
+  VerifyTree(rep);
+}
+
+}  // namespace cord_internal
+
+static CordRep* NewSubstring(CordRep* child, size_t offset, size_t length) {
+  // Never create empty substring nodes
+  if (length == 0) {
+    CordRep::Unref(child);
+    return nullptr;
+  } else {
+    CordRepSubstring* rep = new CordRepSubstring();
+    assert((offset + length) <= child->length);
+    rep->length = length;
+    rep->tag = SUBSTRING;
+    rep->start = offset;
+    rep->child = child;
+    return VerifyTree(rep);
+  }
+}
+
+// --------------------------------------------------------------------
+// Cord::InlineRep functions
+
+constexpr unsigned char Cord::InlineRep::kMaxInline;
+
+inline void Cord::InlineRep::set_data(const char* data, size_t n,
+                                      bool nullify_tail) {
+  static_assert(kMaxInline == 15, "set_data is hard-coded for a length of 15");
+
+  cord_internal::SmallMemmove(data_.as_chars(), data, n, nullify_tail);
+  set_inline_size(n);
+}
+
+inline char* Cord::InlineRep::set_data(size_t n) {
+  assert(n <= kMaxInline);
+  ResetToEmpty();
+  set_inline_size(n);
+  return data_.as_chars();
+}
+
+inline CordRep* Cord::InlineRep::force_tree(size_t extra_hint) {
+  if (data_.is_tree()) {
+    return data_.as_tree();
+  }
+
+  size_t len = inline_size();
+  CordRepFlat* result = CordRepFlat::New(len + extra_hint);
+  result->length = len;
+  static_assert(kMinFlatLength >= sizeof(data_), "");
+  memcpy(result->Data(), data_.as_chars(), sizeof(data_));
+  set_tree(result);
+  return result;
+}
+
+inline void Cord::InlineRep::reduce_size(size_t n) {
+  size_t tag = inline_size();
+  assert(tag <= kMaxInline);
+  assert(tag >= n);
+  tag -= n;
+  memset(data_.as_chars() + tag, 0, n);
+  set_inline_size(static_cast<char>(tag));
+}
+
+inline void Cord::InlineRep::remove_prefix(size_t n) {
+  cord_internal::SmallMemmove(data_.as_chars(), data_.as_chars() + n,
+                              inline_size() - n);
+  reduce_size(n);
+}
+
+// Returns `rep` converted into a CordRepRing.
+// Directly returns `rep` if `rep` is already a CordRepRing.
+static CordRepRing* ForceRing(CordRep* rep, size_t extra) {
+  return (rep->tag == RING) ? rep->ring() : CordRepRing::Create(rep, extra);
+}
+
+void Cord::InlineRep::AppendTree(CordRep* tree) {
+  if (tree == nullptr) return;
+  if (data_.is_empty()) {
+    set_tree(tree);
+  } else if (cord_ring_enabled()) {
+    set_tree(CordRepRing::Append(ForceRing(force_tree(0), 1), tree));
+  } else {
+    set_tree(Concat(force_tree(0), tree));
+  }
+}
+
+void Cord::InlineRep::PrependTree(CordRep* tree) {
+  assert(tree != nullptr);
+  if (data_.is_empty()) {
+    set_tree(tree);
+  } else if (cord_ring_enabled()) {
+    set_tree(CordRepRing::Prepend(ForceRing(force_tree(0), 1), tree));
+  } else {
+    set_tree(Concat(tree, force_tree(0)));
+  }
+}
+
+// Searches for a non-full flat node at the rightmost leaf of the tree. If a
+// suitable leaf is found, the function will update the length field for all
+// nodes to account for the size increase. The append region address will be
+// written to region and the actual size increase will be written to size.
+static inline bool PrepareAppendRegion(CordRep* root, char** region,
+                                       size_t* size, size_t max_length) {
+  if (root->tag == RING && root->refcount.IsOne()) {
+    Span<char> span = root->ring()->GetAppendBuffer(max_length);
+    if (!span.empty()) {
+      *region = span.data();
+      *size = span.size();
+      return true;
+    }
+  }
+
+  // Search down the right-hand path for a non-full FLAT node.
+  CordRep* dst = root;
+  while (dst->tag == CONCAT && dst->refcount.IsOne()) {
+    dst = dst->concat()->right;
+  }
+
+  if (dst->tag < FLAT || !dst->refcount.IsOne()) {
+    *region = nullptr;
+    *size = 0;
+    return false;
+  }
+
+  const size_t in_use = dst->length;
+  const size_t capacity = dst->flat()->Capacity();
+  if (in_use == capacity) {
+    *region = nullptr;
+    *size = 0;
+    return false;
+  }
+
+  size_t size_increase = std::min(capacity - in_use, max_length);
+
+  // We need to update the length fields for all nodes, including the leaf node.
+  for (CordRep* rep = root; rep != dst; rep = rep->concat()->right) {
+    rep->length += size_increase;
+  }
+  dst->length += size_increase;
+
+  *region = dst->flat()->Data() + in_use;
+  *size = size_increase;
+  return true;
+}
+
+void Cord::InlineRep::GetAppendRegion(char** region, size_t* size,
+                                      size_t max_length) {
+  if (max_length == 0) {
+    *region = nullptr;
+    *size = 0;
+    return;
+  }
+
+  // Try to fit in the inline buffer if possible.
+  if (!is_tree()) {
+    size_t inline_length = inline_size();
+    if (max_length <= kMaxInline - inline_length) {
+      *region = data_.as_chars() + inline_length;
+      *size = max_length;
+      set_inline_size(inline_length + max_length);
+      return;
+    }
+  }
+
+  CordRep* root = force_tree(max_length);
+
+  if (PrepareAppendRegion(root, region, size, max_length)) {
+    return;
+  }
+
+  // Allocate new node.
+  CordRepFlat* new_node =
+      CordRepFlat::New(std::max(static_cast<size_t>(root->length), max_length));
+  new_node->length = std::min(new_node->Capacity(), max_length);
+  *region = new_node->Data();
+  *size = new_node->length;
+
+  if (cord_ring_enabled()) {
+    replace_tree(CordRepRing::Append(ForceRing(root, 1), new_node));
+    return;
+  }
+  replace_tree(Concat(root, new_node));
+}
+
+void Cord::InlineRep::GetAppendRegion(char** region, size_t* size) {
+  const size_t max_length = std::numeric_limits<size_t>::max();
+
+  // Try to fit in the inline buffer if possible.
+  if (!data_.is_tree()) {
+    size_t inline_length = inline_size();
+    if (inline_length < kMaxInline) {
+      *region = data_.as_chars() + inline_length;
+      *size = kMaxInline - inline_length;
+      set_inline_size(kMaxInline);
+      return;
+    }
+  }
+
+  CordRep* root = force_tree(max_length);
+
+  if (PrepareAppendRegion(root, region, size, max_length)) {
+    return;
+  }
+
+  // Allocate new node.
+  CordRepFlat* new_node = CordRepFlat::New(root->length);
+  new_node->length = new_node->Capacity();
+  *region = new_node->Data();
+  *size = new_node->length;
+
+  if (cord_ring_enabled()) {
+    replace_tree(CordRepRing::Append(ForceRing(root, 1), new_node));
+    return;
+  }
+  replace_tree(Concat(root, new_node));
+}
+
+// If the rep is a leaf, this will increment the value at total_mem_usage and
+// will return true.
+static bool RepMemoryUsageLeaf(const CordRep* rep, size_t* total_mem_usage) {
+  if (rep->tag >= FLAT) {
+    *total_mem_usage += rep->flat()->AllocatedSize();
+    return true;
+  }
+  if (rep->tag == EXTERNAL) {
+    *total_mem_usage += sizeof(CordRepConcat) + rep->length;
+    return true;
+  }
+  return false;
+}
+
+void Cord::InlineRep::AssignSlow(const Cord::InlineRep& src) {
+  ClearSlow();
+
+  data_ = src.data_;
+  if (is_tree()) {
+    data_.set_profiled(false);
+    CordRep::Ref(tree());
+    clear_cordz_info();
+  }
+}
+
+void Cord::InlineRep::ClearSlow() {
+  if (is_tree()) {
+    CordRep::Unref(tree());
+  }
+  ResetToEmpty();
+}
+
+// --------------------------------------------------------------------
+// Constructors and destructors
+
+Cord::Cord(absl::string_view src) {
+  const size_t n = src.size();
+  if (n <= InlineRep::kMaxInline) {
+    contents_.set_data(src.data(), n, false);
+  } else {
+    contents_.set_tree(NewTree(src.data(), n, 0));
+  }
+}
+
+template <typename T, Cord::EnableIfString<T>>
+Cord::Cord(T&& src) {
+  if (
+      // String is short: copy data to avoid external block overhead.
+      src.size() <= kMaxBytesToCopy ||
+      // String is wasteful: copy data to avoid pinning too much unused memory.
+      src.size() < src.capacity() / 2
+  ) {
+    if (src.size() <= InlineRep::kMaxInline) {
+      contents_.set_data(src.data(), src.size(), false);
+    } else {
+      contents_.set_tree(NewTree(src.data(), src.size(), 0));
+    }
+  } else {
+    struct StringReleaser {
+      void operator()(absl::string_view /* data */) {}
+      std::string data;
+    };
+    const absl::string_view original_data = src;
+    auto* rep = static_cast<
+        ::absl::cord_internal::CordRepExternalImpl<StringReleaser>*>(
+        absl::cord_internal::NewExternalRep(
+            original_data, StringReleaser{std::forward<T>(src)}));
+    // Moving src may have invalidated its data pointer, so adjust it.
+    rep->base = rep->template get<0>().data.data();
+    contents_.set_tree(rep);
+  }
+}
+
+template Cord::Cord(std::string&& src);
+
+// The destruction code is separate so that the compiler can determine
+// that it does not need to call the destructor on a moved-from Cord.
+void Cord::DestroyCordSlow() {
+  if (CordRep* tree = contents_.tree()) {
+    CordRep::Unref(VerifyTree(tree));
+  }
+}
+
+// --------------------------------------------------------------------
+// Mutators
+
+void Cord::Clear() {
+  if (CordRep* tree = contents_.clear()) {
+    CordRep::Unref(tree);
+  }
+}
+
+Cord& Cord::operator=(absl::string_view src) {
+
+  const char* data = src.data();
+  size_t length = src.size();
+  CordRep* tree = contents_.tree();
+  if (length <= InlineRep::kMaxInline) {
+    // Embed into this->contents_
+    contents_.set_data(data, length, true);
+    if (tree) CordRep::Unref(tree);
+    return *this;
+  }
+  if (tree != nullptr && tree->tag >= FLAT &&
+      tree->flat()->Capacity() >= length &&
+      tree->refcount.IsOne()) {
+    // Copy in place if the existing FLAT node is reusable.
+    memmove(tree->flat()->Data(), data, length);
+    tree->length = length;
+    VerifyTree(tree);
+    return *this;
+  }
+  contents_.set_tree(NewTree(data, length, 0));
+  if (tree) CordRep::Unref(tree);
+  return *this;
+}
+
+template <typename T, Cord::EnableIfString<T>>
+Cord& Cord::operator=(T&& src) {
+  if (src.size() <= kMaxBytesToCopy) {
+    *this = absl::string_view(src);
+  } else {
+    *this = Cord(std::forward<T>(src));
+  }
+  return *this;
+}
+
+template Cord& Cord::operator=(std::string&& src);
+
+// TODO(sanjay): Move to Cord::InlineRep section of file.  For now,
+// we keep it here to make diffs easier.
+void Cord::InlineRep::AppendArray(const char* src_data, size_t src_size) {
+  if (src_size == 0) return;  // memcpy(_, nullptr, 0) is undefined.
+
+  size_t appended = 0;
+  CordRep* root = nullptr;
+  if (is_tree()) {
+    root = data_.as_tree();
+    char* region;
+    if (PrepareAppendRegion(root, &region, &appended, src_size)) {
+      memcpy(region, src_data, appended);
+    }
+  } else {
+    // Try to fit in the inline buffer if possible.
+    size_t inline_length = inline_size();
+    if (src_size <= kMaxInline - inline_length) {
+      // Append new data to embedded array
+      memcpy(data_.as_chars() + inline_length, src_data, src_size);
+      set_inline_size(inline_length + src_size);
+      return;
+    }
+
+    // It is possible that src_data == data_, but when we transition from an
+    // InlineRep to a tree we need to assign data_ = root via set_tree. To
+    // avoid corrupting the source data before we copy it, delay calling
+    // set_tree until after we've copied data.
+    // We are going from an inline size to beyond inline size. Make the new size
+    // either double the inlined size, or the added size + 10%.
+    const size_t size1 = inline_length * 2 + src_size;
+    const size_t size2 = inline_length + src_size / 10;
+    root = CordRepFlat::New(std::max<size_t>(size1, size2));
+    appended = std::min(
+        src_size, root->flat()->Capacity() - inline_length);
+    memcpy(root->flat()->Data(), data_.as_chars(), inline_length);
+    memcpy(root->flat()->Data() + inline_length, src_data, appended);
+    root->length = inline_length + appended;
+    set_tree(root);
+  }
+
+  src_data += appended;
+  src_size -= appended;
+  if (src_size == 0) {
+    return;
+  }
+
+  if (cord_ring_enabled()) {
+    absl::string_view data(src_data, src_size);
+    root = ForceRing(root, (data.size() - 1) / kMaxFlatLength + 1);
+    replace_tree(CordRepRing::Append(root->ring(), data));
+    return;
+  }
+
+  // Use new block(s) for any remaining bytes that were not handled above.
+  // Alloc extra memory only if the right child of the root of the new tree is
+  // going to be a FLAT node, which will permit further inplace appends.
+  size_t length = src_size;
+  if (src_size < kMaxFlatLength) {
+    // The new length is either
+    // - old size + 10%
+    // - old_size + src_size
+    // This will cause a reasonable conservative step-up in size that is still
+    // large enough to avoid excessive amounts of small fragments being added.
+    length = std::max<size_t>(root->length / 10, src_size);
+  }
+  set_tree(Concat(root, NewTree(src_data, src_size, length - src_size)));
+}
+
+inline CordRep* Cord::TakeRep() const& {
+  return CordRep::Ref(contents_.tree());
+}
+
+inline CordRep* Cord::TakeRep() && {
+  CordRep* rep = contents_.tree();
+  contents_.clear();
+  return rep;
+}
+
+template <typename C>
+inline void Cord::AppendImpl(C&& src) {
+  if (empty()) {
+    // In case of an empty destination avoid allocating a new node, do not copy
+    // data.
+    *this = std::forward<C>(src);
+    return;
+  }
+
+  // For short cords, it is faster to copy data if there is room in dst.
+  const size_t src_size = src.contents_.size();
+  if (src_size <= kMaxBytesToCopy) {
+    CordRep* src_tree = src.contents_.tree();
+    if (src_tree == nullptr) {
+      // src has embedded data.
+      contents_.AppendArray(src.contents_.data(), src_size);
+      return;
+    }
+    if (src_tree->tag >= FLAT) {
+      // src tree just has one flat node.
+      contents_.AppendArray(src_tree->flat()->Data(), src_size);
+      return;
+    }
+    if (&src == this) {
+      // ChunkIterator below assumes that src is not modified during traversal.
+      Append(Cord(src));
+      return;
+    }
+    // TODO(mec): Should we only do this if "dst" has space?
+    for (absl::string_view chunk : src.Chunks()) {
+      Append(chunk);
+    }
+    return;
+  }
+
+  // Guaranteed to be a tree (kMaxBytesToCopy > kInlinedSize)
+  contents_.AppendTree(std::forward<C>(src).TakeRep());
+}
+
+void Cord::Append(const Cord& src) { AppendImpl(src); }
+
+void Cord::Append(Cord&& src) { AppendImpl(std::move(src)); }
+
+template <typename T, Cord::EnableIfString<T>>
+void Cord::Append(T&& src) {
+  if (src.size() <= kMaxBytesToCopy) {
+    Append(absl::string_view(src));
+  } else {
+    Append(Cord(std::forward<T>(src)));
+  }
+}
+
+template void Cord::Append(std::string&& src);
+
+void Cord::Prepend(const Cord& src) {
+  CordRep* src_tree = src.contents_.tree();
+  if (src_tree != nullptr) {
+    CordRep::Ref(src_tree);
+    contents_.PrependTree(src_tree);
+    return;
+  }
+
+  // `src` cord is inlined.
+  absl::string_view src_contents(src.contents_.data(), src.contents_.size());
+  return Prepend(src_contents);
+}
+
+void Cord::Prepend(absl::string_view src) {
+  if (src.empty()) return;  // memcpy(_, nullptr, 0) is undefined.
+  if (!contents_.is_tree()) {
+    size_t cur_size = contents_.inline_size();
+    if (cur_size + src.size() <= InlineRep::kMaxInline) {
+      // Use embedded storage.
+      char data[InlineRep::kMaxInline + 1] = {0};
+      memcpy(data, src.data(), src.size());
+      memcpy(data + src.size(), contents_.data(), cur_size);
+      memcpy(contents_.data_.as_chars(), data, InlineRep::kMaxInline + 1);
+      contents_.set_inline_size(cur_size + src.size());
+      return;
+    }
+  }
+  contents_.PrependTree(NewTree(src.data(), src.size(), 0));
+}
+
+template <typename T, Cord::EnableIfString<T>>
+inline void Cord::Prepend(T&& src) {
+  if (src.size() <= kMaxBytesToCopy) {
+    Prepend(absl::string_view(src));
+  } else {
+    Prepend(Cord(std::forward<T>(src)));
+  }
+}
+
+template void Cord::Prepend(std::string&& src);
+
+static CordRep* RemovePrefixFrom(CordRep* node, size_t n) {
+  if (n >= node->length) return nullptr;
+  if (n == 0) return CordRep::Ref(node);
+  absl::InlinedVector<CordRep*, kInlinedVectorSize> rhs_stack;
+
+  while (node->tag == CONCAT) {
+    assert(n <= node->length);
+    if (n < node->concat()->left->length) {
+      // Push right to stack, descend left.
+      rhs_stack.push_back(node->concat()->right);
+      node = node->concat()->left;
+    } else {
+      // Drop left, descend right.
+      n -= node->concat()->left->length;
+      node = node->concat()->right;
+    }
+  }
+  assert(n <= node->length);
+
+  if (n == 0) {
+    CordRep::Ref(node);
+  } else {
+    size_t start = n;
+    size_t len = node->length - n;
+    if (node->tag == SUBSTRING) {
+      // Consider in-place update of node, similar to in RemoveSuffixFrom().
+      start += node->substring()->start;
+      node = node->substring()->child;
+    }
+    node = NewSubstring(CordRep::Ref(node), start, len);
+  }
+  while (!rhs_stack.empty()) {
+    node = Concat(node, CordRep::Ref(rhs_stack.back()));
+    rhs_stack.pop_back();
+  }
+  return node;
+}
+
+// RemoveSuffixFrom() is very similar to RemovePrefixFrom(), with the
+// exception that removing a suffix has an optimization where a node may be
+// edited in place iff that node and all its ancestors have a refcount of 1.
+static CordRep* RemoveSuffixFrom(CordRep* node, size_t n) {
+  if (n >= node->length) return nullptr;
+  if (n == 0) return CordRep::Ref(node);
+  absl::InlinedVector<CordRep*, kInlinedVectorSize> lhs_stack;
+  bool inplace_ok = node->refcount.IsOne();
+
+  while (node->tag == CONCAT) {
+    assert(n <= node->length);
+    if (n < node->concat()->right->length) {
+      // Push left to stack, descend right.
+      lhs_stack.push_back(node->concat()->left);
+      node = node->concat()->right;
+    } else {
+      // Drop right, descend left.
+      n -= node->concat()->right->length;
+      node = node->concat()->left;
+    }
+    inplace_ok = inplace_ok && node->refcount.IsOne();
+  }
+  assert(n <= node->length);
+
+  if (n == 0) {
+    CordRep::Ref(node);
+  } else if (inplace_ok && node->tag != EXTERNAL) {
+    // Consider making a new buffer if the current node capacity is much
+    // larger than the new length.
+    CordRep::Ref(node);
+    node->length -= n;
+  } else {
+    size_t start = 0;
+    size_t len = node->length - n;
+    if (node->tag == SUBSTRING) {
+      start = node->substring()->start;
+      node = node->substring()->child;
+    }
+    node = NewSubstring(CordRep::Ref(node), start, len);
+  }
+  while (!lhs_stack.empty()) {
+    node = Concat(CordRep::Ref(lhs_stack.back()), node);
+    lhs_stack.pop_back();
+  }
+  return node;
+}
+
+void Cord::RemovePrefix(size_t n) {
+  ABSL_INTERNAL_CHECK(n <= size(),
+                      absl::StrCat("Requested prefix size ", n,
+                                   " exceeds Cord's size ", size()));
+  CordRep* tree = contents_.tree();
+  if (tree == nullptr) {
+    contents_.remove_prefix(n);
+  } else if (tree->tag == RING) {
+    contents_.replace_tree(CordRepRing::RemovePrefix(tree->ring(), n));
+  } else {
+    CordRep* newrep = RemovePrefixFrom(tree, n);
+    CordRep::Unref(tree);
+    contents_.replace_tree(VerifyTree(newrep));
+  }
+}
+
+void Cord::RemoveSuffix(size_t n) {
+  ABSL_INTERNAL_CHECK(n <= size(),
+                      absl::StrCat("Requested suffix size ", n,
+                                   " exceeds Cord's size ", size()));
+  CordRep* tree = contents_.tree();
+  if (tree == nullptr) {
+    contents_.reduce_size(n);
+  } else if (tree->tag == RING) {
+    contents_.replace_tree(CordRepRing::RemoveSuffix(tree->ring(), n));
+  } else {
+    CordRep* newrep = RemoveSuffixFrom(tree, n);
+    CordRep::Unref(tree);
+    contents_.replace_tree(VerifyTree(newrep));
+  }
+}
+
+// Work item for NewSubRange().
+struct SubRange {
+  SubRange(CordRep* a_node, size_t a_pos, size_t a_n)
+      : node(a_node), pos(a_pos), n(a_n) {}
+  CordRep* node;  // nullptr means concat last 2 results.
+  size_t pos;
+  size_t n;
+};
+
+static CordRep* NewSubRange(CordRep* node, size_t pos, size_t n) {
+  absl::InlinedVector<CordRep*, kInlinedVectorSize> results;
+  absl::InlinedVector<SubRange, kInlinedVectorSize> todo;
+  todo.push_back(SubRange(node, pos, n));
+  do {
+    const SubRange& sr = todo.back();
+    node = sr.node;
+    pos = sr.pos;
+    n = sr.n;
+    todo.pop_back();
+
+    if (node == nullptr) {
+      assert(results.size() >= 2);
+      CordRep* right = results.back();
+      results.pop_back();
+      CordRep* left = results.back();
+      results.pop_back();
+      results.push_back(Concat(left, right));
+    } else if (pos == 0 && n == node->length) {
+      results.push_back(CordRep::Ref(node));
+    } else if (node->tag != CONCAT) {
+      if (node->tag == SUBSTRING) {
+        pos += node->substring()->start;
+        node = node->substring()->child;
+      }
+      results.push_back(NewSubstring(CordRep::Ref(node), pos, n));
+    } else if (pos + n <= node->concat()->left->length) {
+      todo.push_back(SubRange(node->concat()->left, pos, n));
+    } else if (pos >= node->concat()->left->length) {
+      pos -= node->concat()->left->length;
+      todo.push_back(SubRange(node->concat()->right, pos, n));
+    } else {
+      size_t left_n = node->concat()->left->length - pos;
+      todo.push_back(SubRange(nullptr, 0, 0));  // Concat()
+      todo.push_back(SubRange(node->concat()->right, 0, n - left_n));
+      todo.push_back(SubRange(node->concat()->left, pos, left_n));
+    }
+  } while (!todo.empty());
+  assert(results.size() == 1);
+  return results[0];
+}
+
+Cord Cord::Subcord(size_t pos, size_t new_size) const {
+  Cord sub_cord;
+  size_t length = size();
+  if (pos > length) pos = length;
+  if (new_size > length - pos) new_size = length - pos;
+  CordRep* tree = contents_.tree();
+  if (tree == nullptr) {
+    // sub_cord is newly constructed, no need to re-zero-out the tail of
+    // contents_ memory.
+    sub_cord.contents_.set_data(contents_.data() + pos, new_size, false);
+  } else if (new_size == 0) {
+    // We want to return empty subcord, so nothing to do.
+  } else if (new_size <= InlineRep::kMaxInline) {
+    Cord::ChunkIterator it = chunk_begin();
+    it.AdvanceBytes(pos);
+    char* dest = sub_cord.contents_.data_.as_chars();
+    size_t remaining_size = new_size;
+    while (remaining_size > it->size()) {
+      cord_internal::SmallMemmove(dest, it->data(), it->size());
+      remaining_size -= it->size();
+      dest += it->size();
+      ++it;
+    }
+    cord_internal::SmallMemmove(dest, it->data(), remaining_size);
+    sub_cord.contents_.set_inline_size(new_size);
+  } else if (tree->tag == RING) {
+    tree = CordRepRing::SubRing(CordRep::Ref(tree)->ring(), pos, new_size);
+    sub_cord.contents_.set_tree(tree);
+  } else {
+    sub_cord.contents_.set_tree(NewSubRange(tree, pos, new_size));
+  }
+  return sub_cord;
+}
+
+// --------------------------------------------------------------------
+// Balancing
+
+class CordForest {
+ public:
+  explicit CordForest(size_t length)
+      : root_length_(length), trees_(kMinLengthSize, nullptr) {}
+
+  void Build(CordRep* cord_root) {
+    std::vector<CordRep*> pending = {cord_root};
+
+    while (!pending.empty()) {
+      CordRep* node = pending.back();
+      pending.pop_back();
+      CheckNode(node);
+      if (ABSL_PREDICT_FALSE(node->tag != CONCAT)) {
+        AddNode(node);
+        continue;
+      }
+
+      CordRepConcat* concat_node = node->concat();
+      if (concat_node->depth() >= kMinLengthSize ||
+          concat_node->length < min_length[concat_node->depth()]) {
+        pending.push_back(concat_node->right);
+        pending.push_back(concat_node->left);
+
+        if (concat_node->refcount.IsOne()) {
+          concat_node->left = concat_freelist_;
+          concat_freelist_ = concat_node;
+        } else {
+          CordRep::Ref(concat_node->right);
+          CordRep::Ref(concat_node->left);
+          CordRep::Unref(concat_node);
+        }
+      } else {
+        AddNode(node);
+      }
+    }
+  }
+
+  CordRep* ConcatNodes() {
+    CordRep* sum = nullptr;
+    for (auto* node : trees_) {
+      if (node == nullptr) continue;
+
+      sum = PrependNode(node, sum);
+      root_length_ -= node->length;
+      if (root_length_ == 0) break;
+    }
+    ABSL_INTERNAL_CHECK(sum != nullptr, "Failed to locate sum node");
+    return VerifyTree(sum);
+  }
+
+ private:
+  CordRep* AppendNode(CordRep* node, CordRep* sum) {
+    return (sum == nullptr) ? node : MakeConcat(sum, node);
+  }
+
+  CordRep* PrependNode(CordRep* node, CordRep* sum) {
+    return (sum == nullptr) ? node : MakeConcat(node, sum);
+  }
+
+  void AddNode(CordRep* node) {
+    CordRep* sum = nullptr;
+
+    // Collect together everything with which we will merge with node
+    int i = 0;
+    for (; node->length > min_length[i + 1]; ++i) {
+      auto& tree_at_i = trees_[i];
+
+      if (tree_at_i == nullptr) continue;
+      sum = PrependNode(tree_at_i, sum);
+      tree_at_i = nullptr;
+    }
+
+    sum = AppendNode(node, sum);
+
+    // Insert sum into appropriate place in the forest
+    for (; sum->length >= min_length[i]; ++i) {
+      auto& tree_at_i = trees_[i];
+      if (tree_at_i == nullptr) continue;
+
+      sum = MakeConcat(tree_at_i, sum);
+      tree_at_i = nullptr;
+    }
+
+    // min_length[0] == 1, which means sum->length >= min_length[0]
+    assert(i > 0);
+    trees_[i - 1] = sum;
+  }
+
+  // Make concat node trying to resue existing CordRepConcat nodes we
+  // already collected in the concat_freelist_.
+  CordRep* MakeConcat(CordRep* left, CordRep* right) {
+    if (concat_freelist_ == nullptr) return RawConcat(left, right);
+
+    CordRepConcat* rep = concat_freelist_;
+    if (concat_freelist_->left == nullptr) {
+      concat_freelist_ = nullptr;
+    } else {
+      concat_freelist_ = concat_freelist_->left->concat();
+    }
+    SetConcatChildren(rep, left, right);
+
+    return rep;
+  }
+
+  static void CheckNode(CordRep* node) {
+    ABSL_INTERNAL_CHECK(node->length != 0u, "");
+    if (node->tag == CONCAT) {
+      ABSL_INTERNAL_CHECK(node->concat()->left != nullptr, "");
+      ABSL_INTERNAL_CHECK(node->concat()->right != nullptr, "");
+      ABSL_INTERNAL_CHECK(node->length == (node->concat()->left->length +
+                                           node->concat()->right->length),
+                          "");
+    }
+  }
+
+  size_t root_length_;
+
+  // use an inlined vector instead of a flat array to get bounds checking
+  absl::InlinedVector<CordRep*, kInlinedVectorSize> trees_;
+
+  // List of concat nodes we can re-use for Cord balancing.
+  CordRepConcat* concat_freelist_ = nullptr;
+};
+
+static CordRep* Rebalance(CordRep* node) {
+  VerifyTree(node);
+  assert(node->tag == CONCAT);
+
+  if (node->length == 0) {
+    return nullptr;
+  }
+
+  CordForest forest(node->length);
+  forest.Build(node);
+  return forest.ConcatNodes();
+}
+
+// --------------------------------------------------------------------
+// Comparators
+
+namespace {
+
+int ClampResult(int memcmp_res) {
+  return static_cast<int>(memcmp_res > 0) - static_cast<int>(memcmp_res < 0);
+}
+
+int CompareChunks(absl::string_view* lhs, absl::string_view* rhs,
+                  size_t* size_to_compare) {
+  size_t compared_size = std::min(lhs->size(), rhs->size());
+  assert(*size_to_compare >= compared_size);
+  *size_to_compare -= compared_size;
+
+  int memcmp_res = ::memcmp(lhs->data(), rhs->data(), compared_size);
+  if (memcmp_res != 0) return memcmp_res;
+
+  lhs->remove_prefix(compared_size);
+  rhs->remove_prefix(compared_size);
+
+  return 0;
+}
+
+// This overload set computes comparison results from memcmp result. This
+// interface is used inside GenericCompare below. Differet implementations
+// are specialized for int and bool. For int we clamp result to {-1, 0, 1}
+// set. For bool we just interested in "value == 0".
+template <typename ResultType>
+ResultType ComputeCompareResult(int memcmp_res) {
+  return ClampResult(memcmp_res);
+}
+template <>
+bool ComputeCompareResult<bool>(int memcmp_res) {
+  return memcmp_res == 0;
+}
+
+}  // namespace
+
+// Helper routine. Locates the first flat chunk of the Cord without
+// initializing the iterator.
+inline absl::string_view Cord::InlineRep::FindFlatStartPiece() const {
+  if (!is_tree()) {
+    return absl::string_view(data_.as_chars(), data_.inline_size());
+  }
+
+  CordRep* node = tree();
+  if (node->tag >= FLAT) {
+    return absl::string_view(node->flat()->Data(), node->length);
+  }
+
+  if (node->tag == EXTERNAL) {
+    return absl::string_view(node->external()->base, node->length);
+  }
+
+  if (node->tag == RING) {
+    return node->ring()->entry_data(node->ring()->head());
+  }
+
+  // Walk down the left branches until we hit a non-CONCAT node.
+  while (node->tag == CONCAT) {
+    node = node->concat()->left;
+  }
+
+  // Get the child node if we encounter a SUBSTRING.
+  size_t offset = 0;
+  size_t length = node->length;
+  assert(length != 0);
+
+  if (node->tag == SUBSTRING) {
+    offset = node->substring()->start;
+    node = node->substring()->child;
+  }
+
+  if (node->tag >= FLAT) {
+    return absl::string_view(node->flat()->Data() + offset, length);
+  }
+
+  assert((node->tag == EXTERNAL) && "Expect FLAT or EXTERNAL node here");
+
+  return absl::string_view(node->external()->base + offset, length);
+}
+
+inline int Cord::CompareSlowPath(absl::string_view rhs, size_t compared_size,
+                                 size_t size_to_compare) const {
+  auto advance = [](Cord::ChunkIterator* it, absl::string_view* chunk) {
+    if (!chunk->empty()) return true;
+    ++*it;
+    if (it->bytes_remaining_ == 0) return false;
+    *chunk = **it;
+    return true;
+  };
+
+  Cord::ChunkIterator lhs_it = chunk_begin();
+
+  // compared_size is inside first chunk.
+  absl::string_view lhs_chunk =
+      (lhs_it.bytes_remaining_ != 0) ? *lhs_it : absl::string_view();
+  assert(compared_size <= lhs_chunk.size());
+  assert(compared_size <= rhs.size());
+  lhs_chunk.remove_prefix(compared_size);
+  rhs.remove_prefix(compared_size);
+  size_to_compare -= compared_size;  // skip already compared size.
+
+  while (advance(&lhs_it, &lhs_chunk) && !rhs.empty()) {
+    int comparison_result = CompareChunks(&lhs_chunk, &rhs, &size_to_compare);
+    if (comparison_result != 0) return comparison_result;
+    if (size_to_compare == 0) return 0;
+  }
+
+  return static_cast<int>(rhs.empty()) - static_cast<int>(lhs_chunk.empty());
+}
+
+inline int Cord::CompareSlowPath(const Cord& rhs, size_t compared_size,
+                                 size_t size_to_compare) const {
+  auto advance = [](Cord::ChunkIterator* it, absl::string_view* chunk) {
+    if (!chunk->empty()) return true;
+    ++*it;
+    if (it->bytes_remaining_ == 0) return false;
+    *chunk = **it;
+    return true;
+  };
+
+  Cord::ChunkIterator lhs_it = chunk_begin();
+  Cord::ChunkIterator rhs_it = rhs.chunk_begin();
+
+  // compared_size is inside both first chunks.
+  absl::string_view lhs_chunk =
+      (lhs_it.bytes_remaining_ != 0) ? *lhs_it : absl::string_view();
+  absl::string_view rhs_chunk =
+      (rhs_it.bytes_remaining_ != 0) ? *rhs_it : absl::string_view();
+  assert(compared_size <= lhs_chunk.size());
+  assert(compared_size <= rhs_chunk.size());
+  lhs_chunk.remove_prefix(compared_size);
+  rhs_chunk.remove_prefix(compared_size);
+  size_to_compare -= compared_size;  // skip already compared size.
+
+  while (advance(&lhs_it, &lhs_chunk) && advance(&rhs_it, &rhs_chunk)) {
+    int memcmp_res = CompareChunks(&lhs_chunk, &rhs_chunk, &size_to_compare);
+    if (memcmp_res != 0) return memcmp_res;
+    if (size_to_compare == 0) return 0;
+  }
+
+  return static_cast<int>(rhs_chunk.empty()) -
+         static_cast<int>(lhs_chunk.empty());
+}
+
+inline absl::string_view Cord::GetFirstChunk(const Cord& c) {
+  return c.contents_.FindFlatStartPiece();
+}
+inline absl::string_view Cord::GetFirstChunk(absl::string_view sv) {
+  return sv;
+}
+
+// Compares up to 'size_to_compare' bytes of 'lhs' with 'rhs'. It is assumed
+// that 'size_to_compare' is greater that size of smallest of first chunks.
+template <typename ResultType, typename RHS>
+ResultType GenericCompare(const Cord& lhs, const RHS& rhs,
+                          size_t size_to_compare) {
+  absl::string_view lhs_chunk = Cord::GetFirstChunk(lhs);
+  absl::string_view rhs_chunk = Cord::GetFirstChunk(rhs);
+
+  size_t compared_size = std::min(lhs_chunk.size(), rhs_chunk.size());
+  assert(size_to_compare >= compared_size);
+  int memcmp_res = ::memcmp(lhs_chunk.data(), rhs_chunk.data(), compared_size);
+  if (compared_size == size_to_compare || memcmp_res != 0) {
+    return ComputeCompareResult<ResultType>(memcmp_res);
+  }
+
+  return ComputeCompareResult<ResultType>(
+      lhs.CompareSlowPath(rhs, compared_size, size_to_compare));
+}
+
+bool Cord::EqualsImpl(absl::string_view rhs, size_t size_to_compare) const {
+  return GenericCompare<bool>(*this, rhs, size_to_compare);
+}
+
+bool Cord::EqualsImpl(const Cord& rhs, size_t size_to_compare) const {
+  return GenericCompare<bool>(*this, rhs, size_to_compare);
+}
+
+template <typename RHS>
+inline int SharedCompareImpl(const Cord& lhs, const RHS& rhs) {
+  size_t lhs_size = lhs.size();
+  size_t rhs_size = rhs.size();
+  if (lhs_size == rhs_size) {
+    return GenericCompare<int>(lhs, rhs, lhs_size);
+  }
+  if (lhs_size < rhs_size) {
+    auto data_comp_res = GenericCompare<int>(lhs, rhs, lhs_size);
+    return data_comp_res == 0 ? -1 : data_comp_res;
+  }
+
+  auto data_comp_res = GenericCompare<int>(lhs, rhs, rhs_size);
+  return data_comp_res == 0 ? +1 : data_comp_res;
+}
+
+int Cord::Compare(absl::string_view rhs) const {
+  return SharedCompareImpl(*this, rhs);
+}
+
+int Cord::CompareImpl(const Cord& rhs) const {
+  return SharedCompareImpl(*this, rhs);
+}
+
+bool Cord::EndsWith(absl::string_view rhs) const {
+  size_t my_size = size();
+  size_t rhs_size = rhs.size();
+
+  if (my_size < rhs_size) return false;
+
+  Cord tmp(*this);
+  tmp.RemovePrefix(my_size - rhs_size);
+  return tmp.EqualsImpl(rhs, rhs_size);
+}
+
+bool Cord::EndsWith(const Cord& rhs) const {
+  size_t my_size = size();
+  size_t rhs_size = rhs.size();
+
+  if (my_size < rhs_size) return false;
+
+  Cord tmp(*this);
+  tmp.RemovePrefix(my_size - rhs_size);
+  return tmp.EqualsImpl(rhs, rhs_size);
+}
+
+// --------------------------------------------------------------------
+// Misc.
+
+Cord::operator std::string() const {
+  std::string s;
+  absl::CopyCordToString(*this, &s);
+  return s;
+}
+
+void CopyCordToString(const Cord& src, std::string* dst) {
+  if (!src.contents_.is_tree()) {
+    src.contents_.CopyTo(dst);
+  } else {
+    absl::strings_internal::STLStringResizeUninitialized(dst, src.size());
+    src.CopyToArraySlowPath(&(*dst)[0]);
+  }
+}
+
+void Cord::CopyToArraySlowPath(char* dst) const {
+  assert(contents_.is_tree());
+  absl::string_view fragment;
+  if (GetFlatAux(contents_.tree(), &fragment)) {
+    memcpy(dst, fragment.data(), fragment.size());
+    return;
+  }
+  for (absl::string_view chunk : Chunks()) {
+    memcpy(dst, chunk.data(), chunk.size());
+    dst += chunk.size();
+  }
+}
+
+Cord::ChunkIterator& Cord::ChunkIterator::AdvanceStack() {
+  auto& stack_of_right_children = stack_of_right_children_;
+  if (stack_of_right_children.empty()) {
+    assert(!current_chunk_.empty());  // Called on invalid iterator.
+    // We have reached the end of the Cord.
+    return *this;
+  }
+
+  // Process the next node on the stack.
+  CordRep* node = stack_of_right_children.back();
+  stack_of_right_children.pop_back();
+
+  // Walk down the left branches until we hit a non-CONCAT node. Save the
+  // right children to the stack for subsequent traversal.
+  while (node->tag == CONCAT) {
+    stack_of_right_children.push_back(node->concat()->right);
+    node = node->concat()->left;
+  }
+
+  // Get the child node if we encounter a SUBSTRING.
+  size_t offset = 0;
+  size_t length = node->length;
+  if (node->tag == SUBSTRING) {
+    offset = node->substring()->start;
+    node = node->substring()->child;
+  }
+
+  assert(node->tag == EXTERNAL || node->tag >= FLAT);
+  assert(length != 0);
+  const char* data =
+      node->tag == EXTERNAL ? node->external()->base : node->flat()->Data();
+  current_chunk_ = absl::string_view(data + offset, length);
+  current_leaf_ = node;
+  return *this;
+}
+
+Cord Cord::ChunkIterator::AdvanceAndReadBytes(size_t n) {
+  ABSL_HARDENING_ASSERT(bytes_remaining_ >= n &&
+                        "Attempted to iterate past `end()`");
+  Cord subcord;
+
+  if (n <= InlineRep::kMaxInline) {
+    // Range to read fits in inline data. Flatten it.
+    char* data = subcord.contents_.set_data(n);
+    while (n > current_chunk_.size()) {
+      memcpy(data, current_chunk_.data(), current_chunk_.size());
+      data += current_chunk_.size();
+      n -= current_chunk_.size();
+      ++*this;
+    }
+    memcpy(data, current_chunk_.data(), n);
+    if (n < current_chunk_.size()) {
+      RemoveChunkPrefix(n);
+    } else if (n > 0) {
+      ++*this;
+    }
+    return subcord;
+  }
+
+  if (ring_reader_) {
+    size_t chunk_size = current_chunk_.size();
+    if (n <= chunk_size && n <= kMaxBytesToCopy) {
+      subcord = Cord(current_chunk_.substr(0, n));
+    } else {
+      auto* ring = CordRep::Ref(ring_reader_.ring())->ring();
+      size_t offset = ring_reader_.length() - bytes_remaining_;
+      subcord.contents_.set_tree(CordRepRing::SubRing(ring, offset, n));
+    }
+    if (n < chunk_size) {
+      bytes_remaining_ -= n;
+      current_chunk_.remove_prefix(n);
+    } else {
+      AdvanceBytesRing(n);
+    }
+    return subcord;
+  }
+
+  auto& stack_of_right_children = stack_of_right_children_;
+  if (n < current_chunk_.size()) {
+    // Range to read is a proper subrange of the current chunk.
+    assert(current_leaf_ != nullptr);
+    CordRep* subnode = CordRep::Ref(current_leaf_);
+    const char* data = subnode->tag == EXTERNAL ? subnode->external()->base
+                                                : subnode->flat()->Data();
+    subnode = NewSubstring(subnode, current_chunk_.data() - data, n);
+    subcord.contents_.set_tree(VerifyTree(subnode));
+    RemoveChunkPrefix(n);
+    return subcord;
+  }
+
+  // Range to read begins with a proper subrange of the current chunk.
+  assert(!current_chunk_.empty());
+  assert(current_leaf_ != nullptr);
+  CordRep* subnode = CordRep::Ref(current_leaf_);
+  if (current_chunk_.size() < subnode->length) {
+    const char* data = subnode->tag == EXTERNAL ? subnode->external()->base
+                                                : subnode->flat()->Data();
+    subnode = NewSubstring(subnode, current_chunk_.data() - data,
+                           current_chunk_.size());
+  }
+  n -= current_chunk_.size();
+  bytes_remaining_ -= current_chunk_.size();
+
+  // Process the next node(s) on the stack, reading whole subtrees depending on
+  // their length and how many bytes we are advancing.
+  CordRep* node = nullptr;
+  while (!stack_of_right_children.empty()) {
+    node = stack_of_right_children.back();
+    stack_of_right_children.pop_back();
+    if (node->length > n) break;
+    // TODO(qrczak): This might unnecessarily recreate existing concat nodes.
+    // Avoiding that would need pretty complicated logic (instead of
+    // current_leaf, keep current_subtree_ which points to the highest node
+    // such that the current leaf can be found on the path of left children
+    // starting from current_subtree_; delay creating subnode while node is
+    // below current_subtree_; find the proper node along the path of left
+    // children starting from current_subtree_ if this loop exits while staying
+    // below current_subtree_; etc.; alternatively, push parents instead of
+    // right children on the stack).
+    subnode = Concat(subnode, CordRep::Ref(node));
+    n -= node->length;
+    bytes_remaining_ -= node->length;
+    node = nullptr;
+  }
+
+  if (node == nullptr) {
+    // We have reached the end of the Cord.
+    assert(bytes_remaining_ == 0);
+    subcord.contents_.set_tree(VerifyTree(subnode));
+    return subcord;
+  }
+
+  // Walk down the appropriate branches until we hit a non-CONCAT node. Save the
+  // right children to the stack for subsequent traversal.
+  while (node->tag == CONCAT) {
+    if (node->concat()->left->length > n) {
+      // Push right, descend left.
+      stack_of_right_children.push_back(node->concat()->right);
+      node = node->concat()->left;
+    } else {
+      // Read left, descend right.
+      subnode = Concat(subnode, CordRep::Ref(node->concat()->left));
+      n -= node->concat()->left->length;
+      bytes_remaining_ -= node->concat()->left->length;
+      node = node->concat()->right;
+    }
+  }
+
+  // Get the child node if we encounter a SUBSTRING.
+  size_t offset = 0;
+  size_t length = node->length;
+  if (node->tag == SUBSTRING) {
+    offset = node->substring()->start;
+    node = node->substring()->child;
+  }
+
+  // Range to read ends with a proper (possibly empty) subrange of the current
+  // chunk.
+  assert(node->tag == EXTERNAL || node->tag >= FLAT);
+  assert(length > n);
+  if (n > 0) {
+    subnode = Concat(subnode, NewSubstring(CordRep::Ref(node), offset, n));
+  }
+  const char* data =
+      node->tag == EXTERNAL ? node->external()->base : node->flat()->Data();
+  current_chunk_ = absl::string_view(data + offset + n, length - n);
+  current_leaf_ = node;
+  bytes_remaining_ -= n;
+  subcord.contents_.set_tree(VerifyTree(subnode));
+  return subcord;
+}
+
+void Cord::ChunkIterator::AdvanceBytesSlowPath(size_t n) {
+  assert(bytes_remaining_ >= n && "Attempted to iterate past `end()`");
+  assert(n >= current_chunk_.size());  // This should only be called when
+                                       // iterating to a new node.
+
+  n -= current_chunk_.size();
+  bytes_remaining_ -= current_chunk_.size();
+
+  if (stack_of_right_children_.empty()) {
+    // We have reached the end of the Cord.
+    assert(bytes_remaining_ == 0);
+    return;
+  }
+
+  // Process the next node(s) on the stack, skipping whole subtrees depending on
+  // their length and how many bytes we are advancing.
+  CordRep* node = nullptr;
+  auto& stack_of_right_children = stack_of_right_children_;
+  while (!stack_of_right_children.empty()) {
+    node = stack_of_right_children.back();
+    stack_of_right_children.pop_back();
+    if (node->length > n) break;
+    n -= node->length;
+    bytes_remaining_ -= node->length;
+    node = nullptr;
+  }
+
+  if (node == nullptr) {
+    // We have reached the end of the Cord.
+    assert(bytes_remaining_ == 0);
+    return;
+  }
+
+  // Walk down the appropriate branches until we hit a non-CONCAT node. Save the
+  // right children to the stack for subsequent traversal.
+  while (node->tag == CONCAT) {
+    if (node->concat()->left->length > n) {
+      // Push right, descend left.
+      stack_of_right_children.push_back(node->concat()->right);
+      node = node->concat()->left;
+    } else {
+      // Skip left, descend right.
+      n -= node->concat()->left->length;
+      bytes_remaining_ -= node->concat()->left->length;
+      node = node->concat()->right;
+    }
+  }
+
+  // Get the child node if we encounter a SUBSTRING.
+  size_t offset = 0;
+  size_t length = node->length;
+  if (node->tag == SUBSTRING) {
+    offset = node->substring()->start;
+    node = node->substring()->child;
+  }
+
+  assert(node->tag == EXTERNAL || node->tag >= FLAT);
+  assert(length > n);
+  const char* data =
+      node->tag == EXTERNAL ? node->external()->base : node->flat()->Data();
+  current_chunk_ = absl::string_view(data + offset + n, length - n);
+  current_leaf_ = node;
+  bytes_remaining_ -= n;
+}
+
+char Cord::operator[](size_t i) const {
+  ABSL_HARDENING_ASSERT(i < size());
+  size_t offset = i;
+  const CordRep* rep = contents_.tree();
+  if (rep == nullptr) {
+    return contents_.data()[i];
+  }
+  while (true) {
+    assert(rep != nullptr);
+    assert(offset < rep->length);
+    if (rep->tag >= FLAT) {
+      // Get the "i"th character directly from the flat array.
+      return rep->flat()->Data()[offset];
+    } else if (rep->tag == RING) {
+      return rep->ring()->GetCharacter(offset);
+    } else if (rep->tag == EXTERNAL) {
+      // Get the "i"th character from the external array.
+      return rep->external()->base[offset];
+    } else if (rep->tag == CONCAT) {
+      // Recursively branch to the side of the concatenation that the "i"th
+      // character is on.
+      size_t left_length = rep->concat()->left->length;
+      if (offset < left_length) {
+        rep = rep->concat()->left;
+      } else {
+        offset -= left_length;
+        rep = rep->concat()->right;
+      }
+    } else {
+      // This must be a substring a node, so bypass it to get to the child.
+      assert(rep->tag == SUBSTRING);
+      offset += rep->substring()->start;
+      rep = rep->substring()->child;
+    }
+  }
+}
+
+absl::string_view Cord::FlattenSlowPath() {
+  size_t total_size = size();
+  CordRep* new_rep;
+  char* new_buffer;
+
+  // Try to put the contents into a new flat rep. If they won't fit in the
+  // biggest possible flat node, use an external rep instead.
+  if (total_size <= kMaxFlatLength) {
+    new_rep = CordRepFlat::New(total_size);
+    new_rep->length = total_size;
+    new_buffer = new_rep->flat()->Data();
+    CopyToArraySlowPath(new_buffer);
+  } else {
+    new_buffer = std::allocator<char>().allocate(total_size);
+    CopyToArraySlowPath(new_buffer);
+    new_rep = absl::cord_internal::NewExternalRep(
+        absl::string_view(new_buffer, total_size), [](absl::string_view s) {
+          std::allocator<char>().deallocate(const_cast<char*>(s.data()),
+                                            s.size());
+        });
+  }
+  if (CordRep* tree = contents_.tree()) {
+    CordRep::Unref(tree);
+  }
+  contents_.set_tree(new_rep);
+  return absl::string_view(new_buffer, total_size);
+}
+
+/* static */ bool Cord::GetFlatAux(CordRep* rep, absl::string_view* fragment) {
+  assert(rep != nullptr);
+  if (rep->tag >= FLAT) {
+    *fragment = absl::string_view(rep->flat()->Data(), rep->length);
+    return true;
+  } else if (rep->tag == EXTERNAL) {
+    *fragment = absl::string_view(rep->external()->base, rep->length);
+    return true;
+  } else if (rep->tag == SUBSTRING) {
+    CordRep* child = rep->substring()->child;
+    if (child->tag >= FLAT) {
+      *fragment = absl::string_view(
+          child->flat()->Data() + rep->substring()->start, rep->length);
+      return true;
+    } else if (child->tag == EXTERNAL) {
+      *fragment = absl::string_view(
+          child->external()->base + rep->substring()->start, rep->length);
+      return true;
+    }
+  }
+  return false;
+}
+
+/* static */ void Cord::ForEachChunkAux(
+    absl::cord_internal::CordRep* rep,
+    absl::FunctionRef<void(absl::string_view)> callback) {
+  if (rep->tag == RING) {
+    ChunkIterator it(rep), end;
+    while (it != end) {
+      callback(*it);
+      ++it;
+    }
+    return;
+  }
+
+  assert(rep != nullptr);
+  int stack_pos = 0;
+  constexpr int stack_max = 128;
+  // Stack of right branches for tree traversal
+  absl::cord_internal::CordRep* stack[stack_max];
+  absl::cord_internal::CordRep* current_node = rep;
+  while (true) {
+    if (current_node->tag == CONCAT) {
+      if (stack_pos == stack_max) {
+        // There's no more room on our stack array to add another right branch,
+        // and the idea is to avoid allocations, so call this function
+        // recursively to navigate this subtree further.  (This is not something
+        // we expect to happen in practice).
+        ForEachChunkAux(current_node, callback);
+
+        // Pop the next right branch and iterate.
+        current_node = stack[--stack_pos];
+        continue;
+      } else {
+        // Save the right branch for later traversal and continue down the left
+        // branch.
+        stack[stack_pos++] = current_node->concat()->right;
+        current_node = current_node->concat()->left;
+        continue;
+      }
+    }
+    // This is a leaf node, so invoke our callback.
+    absl::string_view chunk;
+    bool success = GetFlatAux(current_node, &chunk);
+    assert(success);
+    if (success) {
+      callback(chunk);
+    }
+    if (stack_pos == 0) {
+      // end of traversal
+      return;
+    }
+    current_node = stack[--stack_pos];
+  }
+}
+
+static void DumpNode(CordRep* rep, bool include_data, std::ostream* os,
+                     int indent) {
+  const int kIndentStep = 1;
+  absl::InlinedVector<CordRep*, kInlinedVectorSize> stack;
+  absl::InlinedVector<int, kInlinedVectorSize> indents;
+  for (;;) {
+    *os << std::setw(3) << rep->refcount.Get();
+    *os << " " << std::setw(7) << rep->length;
+    *os << " [";
+    if (include_data) *os << static_cast<void*>(rep);
+    *os << "]";
+    *os << " " << (IsRootBalanced(rep) ? 'b' : 'u');
+    *os << " " << std::setw(indent) << "";
+    if (rep->tag == CONCAT) {
+      *os << "CONCAT depth=" << Depth(rep) << "\n";
+      indent += kIndentStep;
+      indents.push_back(indent);
+      stack.push_back(rep->concat()->right);
+      rep = rep->concat()->left;
+    } else if (rep->tag == SUBSTRING) {
+      *os << "SUBSTRING @ " << rep->substring()->start << "\n";
+      indent += kIndentStep;
+      rep = rep->substring()->child;
+    } else {  // Leaf or ring
+      if (rep->tag == EXTERNAL) {
+        *os << "EXTERNAL [";
+        if (include_data)
+          *os << absl::CEscape(std::string(rep->external()->base, rep->length));
+        *os << "]\n";
+      } else if (rep->tag >= FLAT) {
+        *os << "FLAT cap=" << rep->flat()->Capacity()
+            << " [";
+        if (include_data)
+          *os << absl::CEscape(std::string(rep->flat()->Data(), rep->length));
+        *os << "]\n";
+      } else {
+        assert(rep->tag == RING);
+        auto* ring = rep->ring();
+        *os << "RING, entries = " << ring->entries() << "\n";
+        CordRepRing::index_type head = ring->head();
+        do {
+          DumpNode(ring->entry_child(head), include_data, os,
+                   indent + kIndentStep);
+          head = ring->advance(head);;
+        } while (head != ring->tail());
+      }
+      if (stack.empty()) break;
+      rep = stack.back();
+      stack.pop_back();
+      indent = indents.back();
+      indents.pop_back();
+    }
+  }
+  ABSL_INTERNAL_CHECK(indents.empty(), "");
+}
+
+static std::string ReportError(CordRep* root, CordRep* node) {
+  std::ostringstream buf;
+  buf << "Error at node " << node << " in:";
+  DumpNode(root, true, &buf);
+  return buf.str();
+}
+
+static bool VerifyNode(CordRep* root, CordRep* start_node,
+                       bool full_validation) {
+  absl::InlinedVector<CordRep*, 2> worklist;
+  worklist.push_back(start_node);
+  do {
+    CordRep* node = worklist.back();
+    worklist.pop_back();
+
+    ABSL_INTERNAL_CHECK(node != nullptr, ReportError(root, node));
+    if (node != root) {
+      ABSL_INTERNAL_CHECK(node->length != 0, ReportError(root, node));
+    }
+
+    if (node->tag == CONCAT) {
+      ABSL_INTERNAL_CHECK(node->concat()->left != nullptr,
+                          ReportError(root, node));
+      ABSL_INTERNAL_CHECK(node->concat()->right != nullptr,
+                          ReportError(root, node));
+      ABSL_INTERNAL_CHECK((node->length == node->concat()->left->length +
+                                               node->concat()->right->length),
+                          ReportError(root, node));
+      if (full_validation) {
+        worklist.push_back(node->concat()->right);
+        worklist.push_back(node->concat()->left);
+      }
+    } else if (node->tag >= FLAT) {
+      ABSL_INTERNAL_CHECK(
+          node->length <= node->flat()->Capacity(),
+          ReportError(root, node));
+    } else if (node->tag == EXTERNAL) {
+      ABSL_INTERNAL_CHECK(node->external()->base != nullptr,
+                          ReportError(root, node));
+    } else if (node->tag == SUBSTRING) {
+      ABSL_INTERNAL_CHECK(
+          node->substring()->start < node->substring()->child->length,
+          ReportError(root, node));
+      ABSL_INTERNAL_CHECK(node->substring()->start + node->length <=
+                              node->substring()->child->length,
+                          ReportError(root, node));
+    }
+  } while (!worklist.empty());
+  return true;
+}
+
+// Traverses the tree and computes the total memory allocated.
+/* static */ size_t Cord::MemoryUsageAux(const CordRep* rep) {
+  size_t total_mem_usage = 0;
+
+  // Allow a quick exit for the common case that the root is a leaf.
+  if (RepMemoryUsageLeaf(rep, &total_mem_usage)) {
+    return total_mem_usage;
+  }
+
+  // Iterate over the tree. cur_node is never a leaf node and leaf nodes will
+  // never be appended to tree_stack. This reduces overhead from manipulating
+  // tree_stack.
+  absl::InlinedVector<const CordRep*, kInlinedVectorSize> tree_stack;
+  const CordRep* cur_node = rep;
+  while (true) {
+    const CordRep* next_node = nullptr;
+
+    if (cur_node->tag == CONCAT) {
+      total_mem_usage += sizeof(CordRepConcat);
+      const CordRep* left = cur_node->concat()->left;
+      if (!RepMemoryUsageLeaf(left, &total_mem_usage)) {
+        next_node = left;
+      }
+
+      const CordRep* right = cur_node->concat()->right;
+      if (!RepMemoryUsageLeaf(right, &total_mem_usage)) {
+        if (next_node) {
+          tree_stack.push_back(next_node);
+        }
+        next_node = right;
+      }
+    } else if (cur_node->tag == RING) {
+      total_mem_usage += CordRepRing::AllocSize(cur_node->ring()->capacity());
+      const CordRepRing* ring = cur_node->ring();
+      CordRepRing::index_type pos = ring->head(), tail = ring->tail();
+      do {
+        CordRep* node = ring->entry_child(pos);
+        assert(node->tag >= FLAT || node->tag == EXTERNAL);
+        RepMemoryUsageLeaf(node, &total_mem_usage);
+      } while ((pos = ring->advance(pos)) != tail);
+    } else {
+      // Since cur_node is not a leaf or a concat node it must be a substring.
+      assert(cur_node->tag == SUBSTRING);
+      total_mem_usage += sizeof(CordRepSubstring);
+      next_node = cur_node->substring()->child;
+      if (RepMemoryUsageLeaf(next_node, &total_mem_usage)) {
+        next_node = nullptr;
+      }
+    }
+
+    if (!next_node) {
+      if (tree_stack.empty()) {
+        return total_mem_usage;
+      }
+      next_node = tree_stack.back();
+      tree_stack.pop_back();
+    }
+    cur_node = next_node;
+  }
+}
+
+std::ostream& operator<<(std::ostream& out, const Cord& cord) {
+  for (absl::string_view chunk : cord.Chunks()) {
+    out.write(chunk.data(), chunk.size());
+  }
+  return out;
+}
+
+namespace strings_internal {
+size_t CordTestAccess::FlatOverhead() { return cord_internal::kFlatOverhead; }
+size_t CordTestAccess::MaxFlatLength() { return cord_internal::kMaxFlatLength; }
+size_t CordTestAccess::FlatTagToLength(uint8_t tag) {
+  return cord_internal::TagToLength(tag);
+}
+uint8_t CordTestAccess::LengthToTag(size_t s) {
+  ABSL_INTERNAL_CHECK(s <= kMaxFlatLength, absl::StrCat("Invalid length ", s));
+  return cord_internal::AllocatedSizeToTag(s + cord_internal::kFlatOverhead);
+}
+size_t CordTestAccess::SizeofCordRepConcat() { return sizeof(CordRepConcat); }
+size_t CordTestAccess::SizeofCordRepExternal() {
+  return sizeof(CordRepExternal);
+}
+size_t CordTestAccess::SizeofCordRepSubstring() {
+  return sizeof(CordRepSubstring);
+}
+}  // namespace strings_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
diff --git a/src/absl/strings/cord.h b/src/absl/strings/cord.h
new file mode 100644 (file)
index 0000000..fa9cb91
--- /dev/null
@@ -0,0 +1,1394 @@
+// Copyright 2020 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// -----------------------------------------------------------------------------
+// File: cord.h
+// -----------------------------------------------------------------------------
+//
+// This file defines the `absl::Cord` data structure and operations on that data
+// structure. A Cord is a string-like sequence of characters optimized for
+// specific use cases. Unlike a `std::string`, which stores an array of
+// contiguous characters, Cord data is stored in a structure consisting of
+// separate, reference-counted "chunks." (Currently, this implementation is a
+// tree structure, though that implementation may change.)
+//
+// Because a Cord consists of these chunks, data can be added to or removed from
+// a Cord during its lifetime. Chunks may also be shared between Cords. Unlike a
+// `std::string`, a Cord can therefore accommodate data that changes over its
+// lifetime, though it's not quite "mutable"; it can change only in the
+// attachment, detachment, or rearrangement of chunks of its constituent data.
+//
+// A Cord provides some benefit over `std::string` under the following (albeit
+// narrow) circumstances:
+//
+//   * Cord data is designed to grow and shrink over a Cord's lifetime. Cord
+//     provides efficient insertions and deletions at the start and end of the
+//     character sequences, avoiding copies in those cases. Static data should
+//     generally be stored as strings.
+//   * External memory consisting of string-like data can be directly added to
+//     a Cord without requiring copies or allocations.
+//   * Cord data may be shared and copied cheaply. Cord provides a copy-on-write
+//     implementation and cheap sub-Cord operations. Copying a Cord is an O(1)
+//     operation.
+//
+// As a consequence to the above, Cord data is generally large. Small data
+// should generally use strings, as construction of a Cord requires some
+// overhead. Small Cords (<= 15 bytes) are represented inline, but most small
+// Cords are expected to grow over their lifetimes.
+//
+// Note that because a Cord is made up of separate chunked data, random access
+// to character data within a Cord is slower than within a `std::string`.
+//
+// Thread Safety
+//
+// Cord has the same thread-safety properties as many other types like
+// std::string, std::vector<>, int, etc -- it is thread-compatible. In
+// particular, if threads do not call non-const methods, then it is safe to call
+// const methods without synchronization. Copying a Cord produces a new instance
+// that can be used concurrently with the original in arbitrary ways.
+
+#ifndef ABSL_STRINGS_CORD_H_
+#define ABSL_STRINGS_CORD_H_
+
+#include <algorithm>
+#include <cstddef>
+#include <cstdint>
+#include <cstring>
+#include <iosfwd>
+#include <iterator>
+#include <string>
+#include <type_traits>
+
+#include "absl/base/internal/endian.h"
+#include "absl/base/internal/per_thread_tls.h"
+#include "absl/base/macros.h"
+#include "absl/base/port.h"
+#include "absl/container/inlined_vector.h"
+#include "absl/functional/function_ref.h"
+#include "absl/meta/type_traits.h"
+#include "absl/strings/internal/cord_internal.h"
+#include "absl/strings/internal/cord_rep_ring.h"
+#include "absl/strings/internal/cord_rep_ring_reader.h"
+#include "absl/strings/internal/resize_uninitialized.h"
+#include "absl/strings/internal/string_constant.h"
+#include "absl/strings/string_view.h"
+#include "absl/types/optional.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+class Cord;
+class CordTestPeer;
+template <typename Releaser>
+Cord MakeCordFromExternal(absl::string_view, Releaser&&);
+void CopyCordToString(const Cord& src, std::string* dst);
+
+// Cord
+//
+// A Cord is a sequence of characters, designed to be more efficient than a
+// `std::string` in certain circumstances: namely, large string data that needs
+// to change over its lifetime or shared, especially when such data is shared
+// across API boundaries.
+//
+// A Cord stores its character data in a structure that allows efficient prepend
+// and append operations. This makes a Cord useful for large string data sent
+// over in a wire format that may need to be prepended or appended at some point
+// during the data exchange (e.g. HTTP, protocol buffers). For example, a
+// Cord is useful for storing an HTTP request, and prepending an HTTP header to
+// such a request.
+//
+// Cords should not be used for storing general string data, however. They
+// require overhead to construct and are slower than strings for random access.
+//
+// The Cord API provides the following common API operations:
+//
+// * Create or assign Cords out of existing string data, memory, or other Cords
+// * Append and prepend data to an existing Cord
+// * Create new Sub-Cords from existing Cord data
+// * Swap Cord data and compare Cord equality
+// * Write out Cord data by constructing a `std::string`
+//
+// Additionally, the API provides iterator utilities to iterate through Cord
+// data via chunks or character bytes.
+//
+class Cord {
+ private:
+  template <typename T>
+  using EnableIfString =
+      absl::enable_if_t<std::is_same<T, std::string>::value, int>;
+
+ public:
+  // Cord::Cord() Constructors.
+
+  // Creates an empty Cord.
+  constexpr Cord() noexcept;
+
+  // Creates a Cord from an existing Cord. Cord is copyable and efficiently
+  // movable. The moved-from state is valid but unspecified.
+  Cord(const Cord& src);
+  Cord(Cord&& src) noexcept;
+  Cord& operator=(const Cord& x);
+  Cord& operator=(Cord&& x) noexcept;
+
+  // Creates a Cord from a `src` string. This constructor is marked explicit to
+  // prevent implicit Cord constructions from arguments convertible to an
+  // `absl::string_view`.
+  explicit Cord(absl::string_view src);
+  Cord& operator=(absl::string_view src);
+
+  // Creates a Cord from a `std::string&&` rvalue. These constructors are
+  // templated to avoid ambiguities for types that are convertible to both
+  // `absl::string_view` and `std::string`, such as `const char*`.
+  template <typename T, EnableIfString<T> = 0>
+  explicit Cord(T&& src);
+  template <typename T, EnableIfString<T> = 0>
+  Cord& operator=(T&& src);
+
+  // Cord::~Cord()
+  //
+  // Destructs the Cord.
+  ~Cord() {
+    if (contents_.is_tree()) DestroyCordSlow();
+  }
+
+  // MakeCordFromExternal()
+  //
+  // Creates a Cord that takes ownership of external string memory. The
+  // contents of `data` are not copied to the Cord; instead, the external
+  // memory is added to the Cord and reference-counted. This data may not be
+  // changed for the life of the Cord, though it may be prepended or appended
+  // to.
+  //
+  // `MakeCordFromExternal()` takes a callable "releaser" that is invoked when
+  // the reference count for `data` reaches zero. As noted above, this data must
+  // remain live until the releaser is invoked. The callable releaser also must:
+  //
+  //   * be move constructible
+  //   * support `void operator()(absl::string_view) const` or `void operator()`
+  //
+  // Example:
+  //
+  // Cord MakeCord(BlockPool* pool) {
+  //   Block* block = pool->NewBlock();
+  //   FillBlock(block);
+  //   return absl::MakeCordFromExternal(
+  //       block->ToStringView(),
+  //       [pool, block](absl::string_view v) {
+  //         pool->FreeBlock(block, v);
+  //       });
+  // }
+  //
+  // WARNING: Because a Cord can be reference-counted, it's likely a bug if your
+  // releaser doesn't do anything. For example, consider the following:
+  //
+  // void Foo(const char* buffer, int len) {
+  //   auto c = absl::MakeCordFromExternal(absl::string_view(buffer, len),
+  //                                       [](absl::string_view) {});
+  //
+  //   // BUG: If Bar() copies its cord for any reason, including keeping a
+  //   // substring of it, the lifetime of buffer might be extended beyond
+  //   // when Foo() returns.
+  //   Bar(c);
+  // }
+  template <typename Releaser>
+  friend Cord MakeCordFromExternal(absl::string_view data, Releaser&& releaser);
+
+  // Cord::Clear()
+  //
+  // Releases the Cord data. Any nodes that share data with other Cords, if
+  // applicable, will have their reference counts reduced by 1.
+  void Clear();
+
+  // Cord::Append()
+  //
+  // Appends data to the Cord, which may come from another Cord or other string
+  // data.
+  void Append(const Cord& src);
+  void Append(Cord&& src);
+  void Append(absl::string_view src);
+  template <typename T, EnableIfString<T> = 0>
+  void Append(T&& src);
+
+  // Cord::Prepend()
+  //
+  // Prepends data to the Cord, which may come from another Cord or other string
+  // data.
+  void Prepend(const Cord& src);
+  void Prepend(absl::string_view src);
+  template <typename T, EnableIfString<T> = 0>
+  void Prepend(T&& src);
+
+  // Cord::RemovePrefix()
+  //
+  // Removes the first `n` bytes of a Cord.
+  void RemovePrefix(size_t n);
+  void RemoveSuffix(size_t n);
+
+  // Cord::Subcord()
+  //
+  // Returns a new Cord representing the subrange [pos, pos + new_size) of
+  // *this. If pos >= size(), the result is empty(). If
+  // (pos + new_size) >= size(), the result is the subrange [pos, size()).
+  Cord Subcord(size_t pos, size_t new_size) const;
+
+  // Cord::swap()
+  //
+  // Swaps the contents of the Cord with `other`.
+  void swap(Cord& other) noexcept;
+
+  // swap()
+  //
+  // Swaps the contents of two Cords.
+  friend void swap(Cord& x, Cord& y) noexcept {
+    x.swap(y);
+  }
+
+  // Cord::size()
+  //
+  // Returns the size of the Cord.
+  size_t size() const;
+
+  // Cord::empty()
+  //
+  // Determines whether the given Cord is empty, returning `true` is so.
+  bool empty() const;
+
+  // Cord::EstimatedMemoryUsage()
+  //
+  // Returns the *approximate* number of bytes held in full or in part by this
+  // Cord (which may not remain the same between invocations).  Note that Cords
+  // that share memory could each be "charged" independently for the same shared
+  // memory.
+  size_t EstimatedMemoryUsage() const;
+
+  // Cord::Compare()
+  //
+  // Compares 'this' Cord with rhs. This function and its relatives treat Cords
+  // as sequences of unsigned bytes. The comparison is a straightforward
+  // lexicographic comparison. `Cord::Compare()` returns values as follows:
+  //
+  //   -1  'this' Cord is smaller
+  //    0  two Cords are equal
+  //    1  'this' Cord is larger
+  int Compare(absl::string_view rhs) const;
+  int Compare(const Cord& rhs) const;
+
+  // Cord::StartsWith()
+  //
+  // Determines whether the Cord starts with the passed string data `rhs`.
+  bool StartsWith(const Cord& rhs) const;
+  bool StartsWith(absl::string_view rhs) const;
+
+  // Cord::EndsWith()
+  //
+  // Determines whether the Cord ends with the passed string data `rhs`.
+  bool EndsWith(absl::string_view rhs) const;
+  bool EndsWith(const Cord& rhs) const;
+
+  // Cord::operator std::string()
+  //
+  // Converts a Cord into a `std::string()`. This operator is marked explicit to
+  // prevent unintended Cord usage in functions that take a string.
+  explicit operator std::string() const;
+
+  // CopyCordToString()
+  //
+  // Copies the contents of a `src` Cord into a `*dst` string.
+  //
+  // This function optimizes the case of reusing the destination string since it
+  // can reuse previously allocated capacity. However, this function does not
+  // guarantee that pointers previously returned by `dst->data()` remain valid
+  // even if `*dst` had enough capacity to hold `src`. If `*dst` is a new
+  // object, prefer to simply use the conversion operator to `std::string`.
+  friend void CopyCordToString(const Cord& src, std::string* dst);
+
+  class CharIterator;
+
+  //----------------------------------------------------------------------------
+  // Cord::ChunkIterator
+  //----------------------------------------------------------------------------
+  //
+  // A `Cord::ChunkIterator` allows iteration over the constituent chunks of its
+  // Cord. Such iteration allows you to perform non-const operatons on the data
+  // of a Cord without modifying it.
+  //
+  // Generally, you do not instantiate a `Cord::ChunkIterator` directly;
+  // instead, you create one implicitly through use of the `Cord::Chunks()`
+  // member function.
+  //
+  // The `Cord::ChunkIterator` has the following properties:
+  //
+  //   * The iterator is invalidated after any non-const operation on the
+  //     Cord object over which it iterates.
+  //   * The `string_view` returned by dereferencing a valid, non-`end()`
+  //     iterator is guaranteed to be non-empty.
+  //   * Two `ChunkIterator` objects can be compared equal if and only if they
+  //     remain valid and iterate over the same Cord.
+  //   * The iterator in this case is a proxy iterator; the `string_view`
+  //     returned by the iterator does not live inside the Cord, and its
+  //     lifetime is limited to the lifetime of the iterator itself. To help
+  //     prevent lifetime issues, `ChunkIterator::reference` is not a true
+  //     reference type and is equivalent to `value_type`.
+  //   * The iterator keeps state that can grow for Cords that contain many
+  //     nodes and are imbalanced due to sharing. Prefer to pass this type by
+  //     const reference instead of by value.
+  class ChunkIterator {
+   public:
+    using iterator_category = std::input_iterator_tag;
+    using value_type = absl::string_view;
+    using difference_type = ptrdiff_t;
+    using pointer = const value_type*;
+    using reference = value_type;
+
+    ChunkIterator() = default;
+
+    ChunkIterator& operator++();
+    ChunkIterator operator++(int);
+    bool operator==(const ChunkIterator& other) const;
+    bool operator!=(const ChunkIterator& other) const;
+    reference operator*() const;
+    pointer operator->() const;
+
+    friend class Cord;
+    friend class CharIterator;
+
+   private:
+    using CordRep = absl::cord_internal::CordRep;
+    using CordRepRing = absl::cord_internal::CordRepRing;
+    using CordRepRingReader = absl::cord_internal::CordRepRingReader;
+
+    // Stack of right children of concat nodes that we have to visit.
+    // Keep this at the end of the structure to avoid cache-thrashing.
+    // TODO(jgm): Benchmark to see if there's a more optimal value than 47 for
+    // the inlined vector size (47 exists for backward compatibility).
+    using Stack = absl::InlinedVector<absl::cord_internal::CordRep*, 47>;
+
+    // Constructs a `begin()` iterator from `tree`. `tree` must not be null.
+    explicit ChunkIterator(cord_internal::CordRep* tree);
+
+    // Constructs a `begin()` iterator from `cord`.
+    explicit ChunkIterator(const Cord* cord);
+
+    // Initializes this instance from a tree. Invoked by constructors.
+    void InitTree(cord_internal::CordRep* tree);
+
+    // Removes `n` bytes from `current_chunk_`. Expects `n` to be smaller than
+    // `current_chunk_.size()`.
+    void RemoveChunkPrefix(size_t n);
+    Cord AdvanceAndReadBytes(size_t n);
+    void AdvanceBytes(size_t n);
+
+    // Stack specific operator++
+    ChunkIterator& AdvanceStack();
+
+    // Ring buffer specific operator++
+    ChunkIterator& AdvanceRing();
+    void AdvanceBytesRing(size_t n);
+
+    // Iterates `n` bytes, where `n` is expected to be greater than or equal to
+    // `current_chunk_.size()`.
+    void AdvanceBytesSlowPath(size_t n);
+
+    // A view into bytes of the current `CordRep`. It may only be a view to a
+    // suffix of bytes if this is being used by `CharIterator`.
+    absl::string_view current_chunk_;
+    // The current leaf, or `nullptr` if the iterator points to short data.
+    // If the current chunk is a substring node, current_leaf_ points to the
+    // underlying flat or external node.
+    absl::cord_internal::CordRep* current_leaf_ = nullptr;
+    // The number of bytes left in the `Cord` over which we are iterating.
+    size_t bytes_remaining_ = 0;
+
+    // Cord reader for ring buffers. Empty if not traversing a ring buffer.
+    CordRepRingReader ring_reader_;
+
+    // See 'Stack' alias definition.
+    Stack stack_of_right_children_;
+  };
+
+  // Cord::ChunkIterator::chunk_begin()
+  //
+  // Returns an iterator to the first chunk of the `Cord`.
+  //
+  // Generally, prefer using `Cord::Chunks()` within a range-based for loop for
+  // iterating over the chunks of a Cord. This method may be useful for getting
+  // a `ChunkIterator` where range-based for-loops are not useful.
+  //
+  // Example:
+  //
+  //   absl::Cord::ChunkIterator FindAsChunk(const absl::Cord& c,
+  //                                         absl::string_view s) {
+  //     return std::find(c.chunk_begin(), c.chunk_end(), s);
+  //   }
+  ChunkIterator chunk_begin() const;
+
+  // Cord::ChunkItertator::chunk_end()
+  //
+  // Returns an iterator one increment past the last chunk of the `Cord`.
+  //
+  // Generally, prefer using `Cord::Chunks()` within a range-based for loop for
+  // iterating over the chunks of a Cord. This method may be useful for getting
+  // a `ChunkIterator` where range-based for-loops may not be available.
+  ChunkIterator chunk_end() const;
+
+  //----------------------------------------------------------------------------
+  // Cord::ChunkIterator::ChunkRange
+  //----------------------------------------------------------------------------
+  //
+  // `ChunkRange` is a helper class for iterating over the chunks of the `Cord`,
+  // producing an iterator which can be used within a range-based for loop.
+  // Construction of a `ChunkRange` will return an iterator pointing to the
+  // first chunk of the Cord. Generally, do not construct a `ChunkRange`
+  // directly; instead, prefer to use the `Cord::Chunks()` method.
+  //
+  // Implementation note: `ChunkRange` is simply a convenience wrapper over
+  // `Cord::chunk_begin()` and `Cord::chunk_end()`.
+  class ChunkRange {
+   public:
+    explicit ChunkRange(const Cord* cord) : cord_(cord) {}
+
+    ChunkIterator begin() const;
+    ChunkIterator end() const;
+
+   private:
+    const Cord* cord_;
+  };
+
+  // Cord::Chunks()
+  //
+  // Returns a `Cord::ChunkIterator::ChunkRange` for iterating over the chunks
+  // of a `Cord` with a range-based for-loop. For most iteration tasks on a
+  // Cord, use `Cord::Chunks()` to retrieve this iterator.
+  //
+  // Example:
+  //
+  //   void ProcessChunks(const Cord& cord) {
+  //     for (absl::string_view chunk : cord.Chunks()) { ... }
+  //   }
+  //
+  // Note that the ordinary caveats of temporary lifetime extension apply:
+  //
+  //   void Process() {
+  //     for (absl::string_view chunk : CordFactory().Chunks()) {
+  //       // The temporary Cord returned by CordFactory has been destroyed!
+  //     }
+  //   }
+  ChunkRange Chunks() const;
+
+  //----------------------------------------------------------------------------
+  // Cord::CharIterator
+  //----------------------------------------------------------------------------
+  //
+  // A `Cord::CharIterator` allows iteration over the constituent characters of
+  // a `Cord`.
+  //
+  // Generally, you do not instantiate a `Cord::CharIterator` directly; instead,
+  // you create one implicitly through use of the `Cord::Chars()` member
+  // function.
+  //
+  // A `Cord::CharIterator` has the following properties:
+  //
+  //   * The iterator is invalidated after any non-const operation on the
+  //     Cord object over which it iterates.
+  //   * Two `CharIterator` objects can be compared equal if and only if they
+  //     remain valid and iterate over the same Cord.
+  //   * The iterator keeps state that can grow for Cords that contain many
+  //     nodes and are imbalanced due to sharing. Prefer to pass this type by
+  //     const reference instead of by value.
+  //   * This type cannot act as a forward iterator because a `Cord` can reuse
+  //     sections of memory. This fact violates the requirement for forward
+  //     iterators to compare equal if dereferencing them returns the same
+  //     object.
+  class CharIterator {
+   public:
+    using iterator_category = std::input_iterator_tag;
+    using value_type = char;
+    using difference_type = ptrdiff_t;
+    using pointer = const char*;
+    using reference = const char&;
+
+    CharIterator() = default;
+
+    CharIterator& operator++();
+    CharIterator operator++(int);
+    bool operator==(const CharIterator& other) const;
+    bool operator!=(const CharIterator& other) const;
+    reference operator*() const;
+    pointer operator->() const;
+
+    friend Cord;
+
+   private:
+    explicit CharIterator(const Cord* cord) : chunk_iterator_(cord) {}
+
+    ChunkIterator chunk_iterator_;
+  };
+
+  // Cord::CharIterator::AdvanceAndRead()
+  //
+  // Advances the `Cord::CharIterator` by `n_bytes` and returns the bytes
+  // advanced as a separate `Cord`. `n_bytes` must be less than or equal to the
+  // number of bytes within the Cord; otherwise, behavior is undefined. It is
+  // valid to pass `char_end()` and `0`.
+  static Cord AdvanceAndRead(CharIterator* it, size_t n_bytes);
+
+  // Cord::CharIterator::Advance()
+  //
+  // Advances the `Cord::CharIterator` by `n_bytes`. `n_bytes` must be less than
+  // or equal to the number of bytes remaining within the Cord; otherwise,
+  // behavior is undefined. It is valid to pass `char_end()` and `0`.
+  static void Advance(CharIterator* it, size_t n_bytes);
+
+  // Cord::CharIterator::ChunkRemaining()
+  //
+  // Returns the longest contiguous view starting at the iterator's position.
+  //
+  // `it` must be dereferenceable.
+  static absl::string_view ChunkRemaining(const CharIterator& it);
+
+  // Cord::CharIterator::char_begin()
+  //
+  // Returns an iterator to the first character of the `Cord`.
+  //
+  // Generally, prefer using `Cord::Chars()` within a range-based for loop for
+  // iterating over the chunks of a Cord. This method may be useful for getting
+  // a `CharIterator` where range-based for-loops may not be available.
+  CharIterator char_begin() const;
+
+  // Cord::CharIterator::char_end()
+  //
+  // Returns an iterator to one past the last character of the `Cord`.
+  //
+  // Generally, prefer using `Cord::Chars()` within a range-based for loop for
+  // iterating over the chunks of a Cord. This method may be useful for getting
+  // a `CharIterator` where range-based for-loops are not useful.
+  CharIterator char_end() const;
+
+  // Cord::CharIterator::CharRange
+  //
+  // `CharRange` is a helper class for iterating over the characters of a
+  // producing an iterator which can be used within a range-based for loop.
+  // Construction of a `CharRange` will return an iterator pointing to the first
+  // character of the Cord. Generally, do not construct a `CharRange` directly;
+  // instead, prefer to use the `Cord::Chars()` method show below.
+  //
+  // Implementation note: `CharRange` is simply a convenience wrapper over
+  // `Cord::char_begin()` and `Cord::char_end()`.
+  class CharRange {
+   public:
+    explicit CharRange(const Cord* cord) : cord_(cord) {}
+
+    CharIterator begin() const;
+    CharIterator end() const;
+
+   private:
+    const Cord* cord_;
+  };
+
+  // Cord::CharIterator::Chars()
+  //
+  // Returns a `Cord::CharIterator` for iterating over the characters of a
+  // `Cord` with a range-based for-loop. For most character-based iteration
+  // tasks on a Cord, use `Cord::Chars()` to retrieve this iterator.
+  //
+  // Example:
+  //
+  //   void ProcessCord(const Cord& cord) {
+  //     for (char c : cord.Chars()) { ... }
+  //   }
+  //
+  // Note that the ordinary caveats of temporary lifetime extension apply:
+  //
+  //   void Process() {
+  //     for (char c : CordFactory().Chars()) {
+  //       // The temporary Cord returned by CordFactory has been destroyed!
+  //     }
+  //   }
+  CharRange Chars() const;
+
+  // Cord::operator[]
+  //
+  // Gets the "i"th character of the Cord and returns it, provided that
+  // 0 <= i < Cord.size().
+  //
+  // NOTE: This routine is reasonably efficient. It is roughly
+  // logarithmic based on the number of chunks that make up the cord. Still,
+  // if you need to iterate over the contents of a cord, you should
+  // use a CharIterator/ChunkIterator rather than call operator[] or Get()
+  // repeatedly in a loop.
+  char operator[](size_t i) const;
+
+  // Cord::TryFlat()
+  //
+  // If this cord's representation is a single flat array, returns a
+  // string_view referencing that array.  Otherwise returns nullopt.
+  absl::optional<absl::string_view> TryFlat() const;
+
+  // Cord::Flatten()
+  //
+  // Flattens the cord into a single array and returns a view of the data.
+  //
+  // If the cord was already flat, the contents are not modified.
+  absl::string_view Flatten();
+
+  // Supports absl::Cord as a sink object for absl::Format().
+  friend void AbslFormatFlush(absl::Cord* cord, absl::string_view part) {
+    cord->Append(part);
+  }
+
+  template <typename H>
+  friend H AbslHashValue(H hash_state, const absl::Cord& c) {
+    absl::optional<absl::string_view> maybe_flat = c.TryFlat();
+    if (maybe_flat.has_value()) {
+      return H::combine(std::move(hash_state), *maybe_flat);
+    }
+    return c.HashFragmented(std::move(hash_state));
+  }
+
+  // Create a Cord with the contents of StringConstant<T>::value.
+  // No allocations will be done and no data will be copied.
+  // This is an INTERNAL API and subject to change or removal. This API can only
+  // be used by spelling absl::strings_internal::MakeStringConstant, which is
+  // also an internal API.
+  template <typename T>
+  explicit constexpr Cord(strings_internal::StringConstant<T>);
+
+ private:
+  friend class CordTestPeer;
+  friend bool operator==(const Cord& lhs, const Cord& rhs);
+  friend bool operator==(const Cord& lhs, absl::string_view rhs);
+
+  // Calls the provided function once for each cord chunk, in order.  Unlike
+  // Chunks(), this API will not allocate memory.
+  void ForEachChunk(absl::FunctionRef<void(absl::string_view)>) const;
+
+  // Allocates new contiguous storage for the contents of the cord. This is
+  // called by Flatten() when the cord was not already flat.
+  absl::string_view FlattenSlowPath();
+
+  // Actual cord contents are hidden inside the following simple
+  // class so that we can isolate the bulk of cord.cc from changes
+  // to the representation.
+  //
+  // InlineRep holds either a tree pointer, or an array of kMaxInline bytes.
+  class InlineRep {
+   public:
+    static constexpr unsigned char kMaxInline = cord_internal::kMaxInline;
+    static_assert(kMaxInline >= sizeof(absl::cord_internal::CordRep*), "");
+
+    constexpr InlineRep() : data_() {}
+    InlineRep(const InlineRep& src);
+    InlineRep(InlineRep&& src);
+    InlineRep& operator=(const InlineRep& src);
+    InlineRep& operator=(InlineRep&& src) noexcept;
+
+    explicit constexpr InlineRep(cord_internal::InlineData data);
+
+    void Swap(InlineRep* rhs);
+    bool empty() const;
+    size_t size() const;
+    const char* data() const;  // Returns nullptr if holding pointer
+    void set_data(const char* data, size_t n,
+                  bool nullify_tail);  // Discards pointer, if any
+    char* set_data(size_t n);  // Write data to the result
+    // Returns nullptr if holding bytes
+    absl::cord_internal::CordRep* tree() const;
+    absl::cord_internal::CordRep* as_tree() const;
+    // Discards old pointer, if any
+    void set_tree(absl::cord_internal::CordRep* rep);
+    // Replaces a tree with a new root. This is faster than set_tree, but it
+    // should only be used when it's clear that the old rep was a tree.
+    void replace_tree(absl::cord_internal::CordRep* rep);
+    // Returns non-null iff was holding a pointer
+    absl::cord_internal::CordRep* clear();
+    // Converts to pointer if necessary.
+    absl::cord_internal::CordRep* force_tree(size_t extra_hint);
+    void reduce_size(size_t n);  // REQUIRES: holding data
+    void remove_prefix(size_t n);  // REQUIRES: holding data
+    void AppendArray(const char* src_data, size_t src_size);
+    absl::string_view FindFlatStartPiece() const;
+    void AppendTree(absl::cord_internal::CordRep* tree);
+    void PrependTree(absl::cord_internal::CordRep* tree);
+    void GetAppendRegion(char** region, size_t* size, size_t max_length);
+    void GetAppendRegion(char** region, size_t* size);
+    bool IsSame(const InlineRep& other) const {
+      return memcmp(&data_, &other.data_, sizeof(data_)) == 0;
+    }
+    int BitwiseCompare(const InlineRep& other) const {
+      uint64_t x, y;
+      // Use memcpy to avoid aliasing issues.
+      memcpy(&x, &data_, sizeof(x));
+      memcpy(&y, &other.data_, sizeof(y));
+      if (x == y) {
+        memcpy(&x, reinterpret_cast<const char*>(&data_) + 8, sizeof(x));
+        memcpy(&y, reinterpret_cast<const char*>(&other.data_) + 8, sizeof(y));
+        if (x == y) return 0;
+      }
+      return absl::big_endian::FromHost64(x) < absl::big_endian::FromHost64(y)
+                 ? -1
+                 : 1;
+    }
+    void CopyTo(std::string* dst) const {
+      // memcpy is much faster when operating on a known size. On most supported
+      // platforms, the small string optimization is large enough that resizing
+      // to 15 bytes does not cause a memory allocation.
+      absl::strings_internal::STLStringResizeUninitialized(dst,
+                                                           sizeof(data_) - 1);
+      memcpy(&(*dst)[0], &data_, sizeof(data_) - 1);
+      // erase is faster than resize because the logic for memory allocation is
+      // not needed.
+      dst->erase(inline_size());
+    }
+
+    // Copies the inline contents into `dst`. Assumes the cord is not empty.
+    void CopyToArray(char* dst) const;
+
+    bool is_tree() const { return data_.is_tree(); }
+
+    // Returns true if the Cord is being profiled by cordz.
+    bool is_profiled() const { return data_.is_tree() && data_.is_profiled(); }
+
+    // Returns the profiled CordzInfo, or nullptr if not sampled.
+    absl::cord_internal::CordzInfo* cordz_info() const {
+      return data_.cordz_info();
+    }
+
+    // Sets the profiled CordzInfo. `cordz_info` must not be null.
+    void set_cordz_info(cord_internal::CordzInfo* cordz_info) {
+      assert(cordz_info != nullptr);
+      data_.set_cordz_info(cordz_info);
+    }
+
+    // Resets the current cordz_info to null / empty.
+    void clear_cordz_info() { data_.clear_cordz_info(); }
+
+   private:
+    friend class Cord;
+
+    void AssignSlow(const InlineRep& src);
+    // Unrefs the tree, stops profiling, and zeroes the contents
+    void ClearSlow();
+
+    void ResetToEmpty() { data_ = {}; }
+
+    void set_inline_size(size_t size) { data_.set_inline_size(size); }
+    size_t inline_size() const { return data_.inline_size(); }
+
+    cord_internal::InlineData data_;
+  };
+  InlineRep contents_;
+
+  // Helper for MemoryUsage().
+  static size_t MemoryUsageAux(const absl::cord_internal::CordRep* rep);
+
+  // Helper for GetFlat() and TryFlat().
+  static bool GetFlatAux(absl::cord_internal::CordRep* rep,
+                         absl::string_view* fragment);
+
+  // Helper for ForEachChunk().
+  static void ForEachChunkAux(
+      absl::cord_internal::CordRep* rep,
+      absl::FunctionRef<void(absl::string_view)> callback);
+
+  // The destructor for non-empty Cords.
+  void DestroyCordSlow();
+
+  // Out-of-line implementation of slower parts of logic.
+  void CopyToArraySlowPath(char* dst) const;
+  int CompareSlowPath(absl::string_view rhs, size_t compared_size,
+                      size_t size_to_compare) const;
+  int CompareSlowPath(const Cord& rhs, size_t compared_size,
+                      size_t size_to_compare) const;
+  bool EqualsImpl(absl::string_view rhs, size_t size_to_compare) const;
+  bool EqualsImpl(const Cord& rhs, size_t size_to_compare) const;
+  int CompareImpl(const Cord& rhs) const;
+
+  template <typename ResultType, typename RHS>
+  friend ResultType GenericCompare(const Cord& lhs, const RHS& rhs,
+                                   size_t size_to_compare);
+  static absl::string_view GetFirstChunk(const Cord& c);
+  static absl::string_view GetFirstChunk(absl::string_view sv);
+
+  // Returns a new reference to contents_.tree(), or steals an existing
+  // reference if called on an rvalue.
+  absl::cord_internal::CordRep* TakeRep() const&;
+  absl::cord_internal::CordRep* TakeRep() &&;
+
+  // Helper for Append().
+  template <typename C>
+  void AppendImpl(C&& src);
+
+  // Helper for AbslHashValue().
+  template <typename H>
+  H HashFragmented(H hash_state) const {
+    typename H::AbslInternalPiecewiseCombiner combiner;
+    ForEachChunk([&combiner, &hash_state](absl::string_view chunk) {
+      hash_state = combiner.add_buffer(std::move(hash_state), chunk.data(),
+                                       chunk.size());
+    });
+    return H::combine(combiner.finalize(std::move(hash_state)), size());
+  }
+};
+
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+
+// allow a Cord to be logged
+extern std::ostream& operator<<(std::ostream& out, const Cord& cord);
+
+// ------------------------------------------------------------------
+// Internal details follow.  Clients should ignore.
+
+namespace cord_internal {
+
+// Fast implementation of memmove for up to 15 bytes. This implementation is
+// safe for overlapping regions. If nullify_tail is true, the destination is
+// padded with '\0' up to 16 bytes.
+inline void SmallMemmove(char* dst, const char* src, size_t n,
+                         bool nullify_tail = false) {
+  if (n >= 8) {
+    assert(n <= 16);
+    uint64_t buf1;
+    uint64_t buf2;
+    memcpy(&buf1, src, 8);
+    memcpy(&buf2, src + n - 8, 8);
+    if (nullify_tail) {
+      memset(dst + 8, 0, 8);
+    }
+    memcpy(dst, &buf1, 8);
+    memcpy(dst + n - 8, &buf2, 8);
+  } else if (n >= 4) {
+    uint32_t buf1;
+    uint32_t buf2;
+    memcpy(&buf1, src, 4);
+    memcpy(&buf2, src + n - 4, 4);
+    if (nullify_tail) {
+      memset(dst + 4, 0, 4);
+      memset(dst + 8, 0, 8);
+    }
+    memcpy(dst, &buf1, 4);
+    memcpy(dst + n - 4, &buf2, 4);
+  } else {
+    if (n != 0) {
+      dst[0] = src[0];
+      dst[n / 2] = src[n / 2];
+      dst[n - 1] = src[n - 1];
+    }
+    if (nullify_tail) {
+      memset(dst + 8, 0, 8);
+      memset(dst + n, 0, 8);
+    }
+  }
+}
+
+// Does non-template-specific `CordRepExternal` initialization.
+// Expects `data` to be non-empty.
+void InitializeCordRepExternal(absl::string_view data, CordRepExternal* rep);
+
+// Creates a new `CordRep` that owns `data` and `releaser` and returns a pointer
+// to it, or `nullptr` if `data` was empty.
+template <typename Releaser>
+// NOLINTNEXTLINE - suppress clang-tidy raw pointer return.
+CordRep* NewExternalRep(absl::string_view data, Releaser&& releaser) {
+  using ReleaserType = absl::decay_t<Releaser>;
+  if (data.empty()) {
+    // Never create empty external nodes.
+    InvokeReleaser(Rank0{}, ReleaserType(std::forward<Releaser>(releaser)),
+                   data);
+    return nullptr;
+  }
+
+  CordRepExternal* rep = new CordRepExternalImpl<ReleaserType>(
+      std::forward<Releaser>(releaser), 0);
+  InitializeCordRepExternal(data, rep);
+  return rep;
+}
+
+// Overload for function reference types that dispatches using a function
+// pointer because there are no `alignof()` or `sizeof()` a function reference.
+// NOLINTNEXTLINE - suppress clang-tidy raw pointer return.
+inline CordRep* NewExternalRep(absl::string_view data,
+                               void (&releaser)(absl::string_view)) {
+  return NewExternalRep(data, &releaser);
+}
+
+}  // namespace cord_internal
+
+template <typename Releaser>
+Cord MakeCordFromExternal(absl::string_view data, Releaser&& releaser) {
+  Cord cord;
+  cord.contents_.set_tree(::absl::cord_internal::NewExternalRep(
+      data, std::forward<Releaser>(releaser)));
+  return cord;
+}
+
+constexpr Cord::InlineRep::InlineRep(cord_internal::InlineData data)
+    : data_(data) {}
+
+inline Cord::InlineRep::InlineRep(const Cord::InlineRep& src)
+    : data_(src.data_) {
+  if (is_tree()) {
+    data_.clear_cordz_info();
+    absl::cord_internal::CordRep::Ref(as_tree());
+  }
+}
+
+inline Cord::InlineRep::InlineRep(Cord::InlineRep&& src) {
+  data_ = src.data_;
+  src.ResetToEmpty();
+}
+
+inline Cord::InlineRep& Cord::InlineRep::operator=(const Cord::InlineRep& src) {
+  if (this == &src) {
+    return *this;
+  }
+  if (!is_tree() && !src.is_tree()) {
+    data_ = src.data_;
+    return *this;
+  }
+  AssignSlow(src);
+  return *this;
+}
+
+inline Cord::InlineRep& Cord::InlineRep::operator=(
+    Cord::InlineRep&& src) noexcept {
+  if (is_tree()) {
+    ClearSlow();
+  }
+  data_ = src.data_;
+  src.ResetToEmpty();
+  return *this;
+}
+
+inline void Cord::InlineRep::Swap(Cord::InlineRep* rhs) {
+  if (rhs == this) {
+    return;
+  }
+  std::swap(data_, rhs->data_);
+}
+
+inline const char* Cord::InlineRep::data() const {
+  return is_tree() ? nullptr : data_.as_chars();
+}
+
+inline absl::cord_internal::CordRep* Cord::InlineRep::as_tree() const {
+  assert(data_.is_tree());
+  return data_.as_tree();
+}
+
+inline absl::cord_internal::CordRep* Cord::InlineRep::tree() const {
+  if (is_tree()) {
+    return as_tree();
+  } else {
+    return nullptr;
+  }
+}
+
+inline bool Cord::InlineRep::empty() const { return data_.is_empty(); }
+
+inline size_t Cord::InlineRep::size() const {
+  return is_tree() ? as_tree()->length : inline_size();
+}
+
+inline void Cord::InlineRep::set_tree(absl::cord_internal::CordRep* rep) {
+  if (rep == nullptr) {
+    ResetToEmpty();
+  } else {
+    if (data_.is_tree()) {
+      // `data_` already holds a 'tree' value and an optional cordz_info value.
+      // Replace the tree value only, leaving the cordz_info value unchanged.
+      data_.set_tree(rep);
+    } else {
+      // `data_` contains inlined data: initialize data_ to tree value `rep`.
+      data_.make_tree(rep);
+    }
+  }
+}
+
+inline void Cord::InlineRep::replace_tree(absl::cord_internal::CordRep* rep) {
+  ABSL_ASSERT(is_tree());
+  if (ABSL_PREDICT_FALSE(rep == nullptr)) {
+    set_tree(rep);
+    return;
+  }
+  data_.set_tree(rep);
+}
+
+inline absl::cord_internal::CordRep* Cord::InlineRep::clear() {
+  absl::cord_internal::CordRep* result = tree();
+  ResetToEmpty();
+  return result;
+}
+
+inline void Cord::InlineRep::CopyToArray(char* dst) const {
+  assert(!is_tree());
+  size_t n = inline_size();
+  assert(n != 0);
+  cord_internal::SmallMemmove(dst, data_.as_chars(), n);
+}
+
+constexpr inline Cord::Cord() noexcept {}
+
+template <typename T>
+constexpr Cord::Cord(strings_internal::StringConstant<T>)
+    : contents_(strings_internal::StringConstant<T>::value.size() <=
+                        cord_internal::kMaxInline
+                    ? cord_internal::InlineData(
+                          strings_internal::StringConstant<T>::value)
+                    : cord_internal::InlineData(
+                          &cord_internal::ConstInitExternalStorage<
+                              strings_internal::StringConstant<T>>::value)) {}
+
+inline Cord& Cord::operator=(const Cord& x) {
+  contents_ = x.contents_;
+  return *this;
+}
+
+inline Cord::Cord(const Cord& src) : contents_(src.contents_) {}
+
+inline Cord::Cord(Cord&& src) noexcept : contents_(std::move(src.contents_)) {}
+
+inline void Cord::swap(Cord& other) noexcept {
+  contents_.Swap(&other.contents_);
+}
+
+inline Cord& Cord::operator=(Cord&& x) noexcept {
+  contents_ = std::move(x.contents_);
+  return *this;
+}
+
+extern template Cord::Cord(std::string&& src);
+extern template Cord& Cord::operator=(std::string&& src);
+
+inline size_t Cord::size() const {
+  // Length is 1st field in str.rep_
+  return contents_.size();
+}
+
+inline bool Cord::empty() const { return contents_.empty(); }
+
+inline size_t Cord::EstimatedMemoryUsage() const {
+  size_t result = sizeof(Cord);
+  if (const absl::cord_internal::CordRep* rep = contents_.tree()) {
+    result += MemoryUsageAux(rep);
+  }
+  return result;
+}
+
+inline absl::optional<absl::string_view> Cord::TryFlat() const {
+  absl::cord_internal::CordRep* rep = contents_.tree();
+  if (rep == nullptr) {
+    return absl::string_view(contents_.data(), contents_.size());
+  }
+  absl::string_view fragment;
+  if (GetFlatAux(rep, &fragment)) {
+    return fragment;
+  }
+  return absl::nullopt;
+}
+
+inline absl::string_view Cord::Flatten() {
+  absl::cord_internal::CordRep* rep = contents_.tree();
+  if (rep == nullptr) {
+    return absl::string_view(contents_.data(), contents_.size());
+  } else {
+    absl::string_view already_flat_contents;
+    if (GetFlatAux(rep, &already_flat_contents)) {
+      return already_flat_contents;
+    }
+  }
+  return FlattenSlowPath();
+}
+
+inline void Cord::Append(absl::string_view src) {
+  contents_.AppendArray(src.data(), src.size());
+}
+
+extern template void Cord::Append(std::string&& src);
+extern template void Cord::Prepend(std::string&& src);
+
+inline int Cord::Compare(const Cord& rhs) const {
+  if (!contents_.is_tree() && !rhs.contents_.is_tree()) {
+    return contents_.BitwiseCompare(rhs.contents_);
+  }
+
+  return CompareImpl(rhs);
+}
+
+// Does 'this' cord start/end with rhs
+inline bool Cord::StartsWith(const Cord& rhs) const {
+  if (contents_.IsSame(rhs.contents_)) return true;
+  size_t rhs_size = rhs.size();
+  if (size() < rhs_size) return false;
+  return EqualsImpl(rhs, rhs_size);
+}
+
+inline bool Cord::StartsWith(absl::string_view rhs) const {
+  size_t rhs_size = rhs.size();
+  if (size() < rhs_size) return false;
+  return EqualsImpl(rhs, rhs_size);
+}
+
+inline void Cord::ChunkIterator::InitTree(cord_internal::CordRep* tree) {
+  if (tree->tag == cord_internal::RING) {
+    current_chunk_ = ring_reader_.Reset(tree->ring());
+    return;
+  }
+
+  stack_of_right_children_.push_back(tree);
+  operator++();
+}
+
+inline Cord::ChunkIterator::ChunkIterator(cord_internal::CordRep* tree)
+    : bytes_remaining_(tree->length) {
+  InitTree(tree);
+}
+
+inline Cord::ChunkIterator::ChunkIterator(const Cord* cord)
+    : bytes_remaining_(cord->size()) {
+  if (cord->contents_.is_tree()) {
+    InitTree(cord->contents_.as_tree());
+  } else {
+    current_chunk_ =
+        absl::string_view(cord->contents_.data(), bytes_remaining_);
+  }
+}
+
+inline Cord::ChunkIterator& Cord::ChunkIterator::AdvanceRing() {
+  current_chunk_ = ring_reader_.Next();
+  return *this;
+}
+
+inline void Cord::ChunkIterator::AdvanceBytesRing(size_t n) {
+  assert(n >= current_chunk_.size());
+  bytes_remaining_ -= n;
+  if (bytes_remaining_) {
+    if (n == current_chunk_.size()) {
+      current_chunk_ = ring_reader_.Next();
+    } else {
+      size_t offset = ring_reader_.length() - bytes_remaining_;
+      current_chunk_ = ring_reader_.Seek(offset);
+    }
+  } else {
+    current_chunk_ = {};
+  }
+}
+
+inline Cord::ChunkIterator& Cord::ChunkIterator::operator++() {
+  ABSL_HARDENING_ASSERT(bytes_remaining_ > 0 &&
+                        "Attempted to iterate past `end()`");
+  assert(bytes_remaining_ >= current_chunk_.size());
+  bytes_remaining_ -= current_chunk_.size();
+  if (bytes_remaining_ > 0) {
+    return ring_reader_ ? AdvanceRing() : AdvanceStack();
+  } else {
+    current_chunk_ = {};
+  }
+  return *this;
+}
+
+inline Cord::ChunkIterator Cord::ChunkIterator::operator++(int) {
+  ChunkIterator tmp(*this);
+  operator++();
+  return tmp;
+}
+
+inline bool Cord::ChunkIterator::operator==(const ChunkIterator& other) const {
+  return bytes_remaining_ == other.bytes_remaining_;
+}
+
+inline bool Cord::ChunkIterator::operator!=(const ChunkIterator& other) const {
+  return !(*this == other);
+}
+
+inline Cord::ChunkIterator::reference Cord::ChunkIterator::operator*() const {
+  ABSL_HARDENING_ASSERT(bytes_remaining_ != 0);
+  return current_chunk_;
+}
+
+inline Cord::ChunkIterator::pointer Cord::ChunkIterator::operator->() const {
+  ABSL_HARDENING_ASSERT(bytes_remaining_ != 0);
+  return &current_chunk_;
+}
+
+inline void Cord::ChunkIterator::RemoveChunkPrefix(size_t n) {
+  assert(n < current_chunk_.size());
+  current_chunk_.remove_prefix(n);
+  bytes_remaining_ -= n;
+}
+
+inline void Cord::ChunkIterator::AdvanceBytes(size_t n) {
+  assert(bytes_remaining_ >= n);
+  if (ABSL_PREDICT_TRUE(n < current_chunk_.size())) {
+    RemoveChunkPrefix(n);
+  } else if (n != 0) {
+    ring_reader_ ? AdvanceBytesRing(n) : AdvanceBytesSlowPath(n);
+  }
+}
+
+inline Cord::ChunkIterator Cord::chunk_begin() const {
+  return ChunkIterator(this);
+}
+
+inline Cord::ChunkIterator Cord::chunk_end() const { return ChunkIterator(); }
+
+inline Cord::ChunkIterator Cord::ChunkRange::begin() const {
+  return cord_->chunk_begin();
+}
+
+inline Cord::ChunkIterator Cord::ChunkRange::end() const {
+  return cord_->chunk_end();
+}
+
+inline Cord::ChunkRange Cord::Chunks() const { return ChunkRange(this); }
+
+inline Cord::CharIterator& Cord::CharIterator::operator++() {
+  if (ABSL_PREDICT_TRUE(chunk_iterator_->size() > 1)) {
+    chunk_iterator_.RemoveChunkPrefix(1);
+  } else {
+    ++chunk_iterator_;
+  }
+  return *this;
+}
+
+inline Cord::CharIterator Cord::CharIterator::operator++(int) {
+  CharIterator tmp(*this);
+  operator++();
+  return tmp;
+}
+
+inline bool Cord::CharIterator::operator==(const CharIterator& other) const {
+  return chunk_iterator_ == other.chunk_iterator_;
+}
+
+inline bool Cord::CharIterator::operator!=(const CharIterator& other) const {
+  return !(*this == other);
+}
+
+inline Cord::CharIterator::reference Cord::CharIterator::operator*() const {
+  return *chunk_iterator_->data();
+}
+
+inline Cord::CharIterator::pointer Cord::CharIterator::operator->() const {
+  return chunk_iterator_->data();
+}
+
+inline Cord Cord::AdvanceAndRead(CharIterator* it, size_t n_bytes) {
+  assert(it != nullptr);
+  return it->chunk_iterator_.AdvanceAndReadBytes(n_bytes);
+}
+
+inline void Cord::Advance(CharIterator* it, size_t n_bytes) {
+  assert(it != nullptr);
+  it->chunk_iterator_.AdvanceBytes(n_bytes);
+}
+
+inline absl::string_view Cord::ChunkRemaining(const CharIterator& it) {
+  return *it.chunk_iterator_;
+}
+
+inline Cord::CharIterator Cord::char_begin() const {
+  return CharIterator(this);
+}
+
+inline Cord::CharIterator Cord::char_end() const { return CharIterator(); }
+
+inline Cord::CharIterator Cord::CharRange::begin() const {
+  return cord_->char_begin();
+}
+
+inline Cord::CharIterator Cord::CharRange::end() const {
+  return cord_->char_end();
+}
+
+inline Cord::CharRange Cord::Chars() const { return CharRange(this); }
+
+inline void Cord::ForEachChunk(
+    absl::FunctionRef<void(absl::string_view)> callback) const {
+  absl::cord_internal::CordRep* rep = contents_.tree();
+  if (rep == nullptr) {
+    callback(absl::string_view(contents_.data(), contents_.size()));
+  } else {
+    return ForEachChunkAux(rep, callback);
+  }
+}
+
+// Nonmember Cord-to-Cord relational operarators.
+inline bool operator==(const Cord& lhs, const Cord& rhs) {
+  if (lhs.contents_.IsSame(rhs.contents_)) return true;
+  size_t rhs_size = rhs.size();
+  if (lhs.size() != rhs_size) return false;
+  return lhs.EqualsImpl(rhs, rhs_size);
+}
+
+inline bool operator!=(const Cord& x, const Cord& y) { return !(x == y); }
+inline bool operator<(const Cord& x, const Cord& y) {
+  return x.Compare(y) < 0;
+}
+inline bool operator>(const Cord& x, const Cord& y) {
+  return x.Compare(y) > 0;
+}
+inline bool operator<=(const Cord& x, const Cord& y) {
+  return x.Compare(y) <= 0;
+}
+inline bool operator>=(const Cord& x, const Cord& y) {
+  return x.Compare(y) >= 0;
+}
+
+// Nonmember Cord-to-absl::string_view relational operators.
+//
+// Due to implicit conversions, these also enable comparisons of Cord with
+// with std::string, ::string, and const char*.
+inline bool operator==(const Cord& lhs, absl::string_view rhs) {
+  size_t lhs_size = lhs.size();
+  size_t rhs_size = rhs.size();
+  if (lhs_size != rhs_size) return false;
+  return lhs.EqualsImpl(rhs, rhs_size);
+}
+
+inline bool operator==(absl::string_view x, const Cord& y) { return y == x; }
+inline bool operator!=(const Cord& x, absl::string_view y) { return !(x == y); }
+inline bool operator!=(absl::string_view x, const Cord& y) { return !(x == y); }
+inline bool operator<(const Cord& x, absl::string_view y) {
+  return x.Compare(y) < 0;
+}
+inline bool operator<(absl::string_view x, const Cord& y) {
+  return y.Compare(x) > 0;
+}
+inline bool operator>(const Cord& x, absl::string_view y) { return y < x; }
+inline bool operator>(absl::string_view x, const Cord& y) { return y < x; }
+inline bool operator<=(const Cord& x, absl::string_view y) { return !(y < x); }
+inline bool operator<=(absl::string_view x, const Cord& y) { return !(y < x); }
+inline bool operator>=(const Cord& x, absl::string_view y) { return !(x < y); }
+inline bool operator>=(absl::string_view x, const Cord& y) { return !(x < y); }
+
+// Some internals exposed to test code.
+namespace strings_internal {
+class CordTestAccess {
+ public:
+  static size_t FlatOverhead();
+  static size_t MaxFlatLength();
+  static size_t SizeofCordRepConcat();
+  static size_t SizeofCordRepExternal();
+  static size_t SizeofCordRepSubstring();
+  static size_t FlatTagToLength(uint8_t tag);
+  static uint8_t LengthToTag(size_t s);
+};
+}  // namespace strings_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#endif  // ABSL_STRINGS_CORD_H_
diff --git a/src/absl/strings/escaping.cc b/src/absl/strings/escaping.cc
new file mode 100644 (file)
index 0000000..18b20b8
--- /dev/null
@@ -0,0 +1,949 @@
+// Copyright 2017 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "absl/strings/escaping.h"
+
+#include <algorithm>
+#include <cassert>
+#include <cstdint>
+#include <cstring>
+#include <iterator>
+#include <limits>
+#include <string>
+
+#include "absl/base/internal/endian.h"
+#include "absl/base/internal/raw_logging.h"
+#include "absl/base/internal/unaligned_access.h"
+#include "absl/strings/internal/char_map.h"
+#include "absl/strings/internal/escaping.h"
+#include "absl/strings/internal/resize_uninitialized.h"
+#include "absl/strings/internal/utf8.h"
+#include "absl/strings/str_cat.h"
+#include "absl/strings/str_join.h"
+#include "absl/strings/string_view.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace {
+
+// These are used for the leave_nulls_escaped argument to CUnescapeInternal().
+constexpr bool kUnescapeNulls = false;
+
+inline bool is_octal_digit(char c) { return ('0' <= c) && (c <= '7'); }
+
+inline int hex_digit_to_int(char c) {
+  static_assert('0' == 0x30 && 'A' == 0x41 && 'a' == 0x61,
+                "Character set must be ASCII.");
+  assert(absl::ascii_isxdigit(c));
+  int x = static_cast<unsigned char>(c);
+  if (x > '9') {
+    x += 9;
+  }
+  return x & 0xf;
+}
+
+inline bool IsSurrogate(char32_t c, absl::string_view src, std::string* error) {
+  if (c >= 0xD800 && c <= 0xDFFF) {
+    if (error) {
+      *error = absl::StrCat("invalid surrogate character (0xD800-DFFF): \\",
+                            src);
+    }
+    return true;
+  }
+  return false;
+}
+
+// ----------------------------------------------------------------------
+// CUnescapeInternal()
+//    Implements both CUnescape() and CUnescapeForNullTerminatedString().
+//
+//    Unescapes C escape sequences and is the reverse of CEscape().
+//
+//    If 'source' is valid, stores the unescaped string and its size in
+//    'dest' and 'dest_len' respectively, and returns true. Otherwise
+//    returns false and optionally stores the error description in
+//    'error'. Set 'error' to nullptr to disable error reporting.
+//
+//    'dest' should point to a buffer that is at least as big as 'source'.
+//    'source' and 'dest' may be the same.
+//
+//     NOTE: any changes to this function must also be reflected in the older
+//     UnescapeCEscapeSequences().
+// ----------------------------------------------------------------------
+bool CUnescapeInternal(absl::string_view source, bool leave_nulls_escaped,
+                       char* dest, ptrdiff_t* dest_len, std::string* error) {
+  char* d = dest;
+  const char* p = source.data();
+  const char* end = p + source.size();
+  const char* last_byte = end - 1;
+
+  // Small optimization for case where source = dest and there's no escaping
+  while (p == d && p < end && *p != '\\') p++, d++;
+
+  while (p < end) {
+    if (*p != '\\') {
+      *d++ = *p++;
+    } else {
+      if (++p > last_byte) {  // skip past the '\\'
+        if (error) *error = "String cannot end with \\";
+        return false;
+      }
+      switch (*p) {
+        case 'a':  *d++ = '\a';  break;
+        case 'b':  *d++ = '\b';  break;
+        case 'f':  *d++ = '\f';  break;
+        case 'n':  *d++ = '\n';  break;
+        case 'r':  *d++ = '\r';  break;
+        case 't':  *d++ = '\t';  break;
+        case 'v':  *d++ = '\v';  break;
+        case '\\': *d++ = '\\';  break;
+        case '?':  *d++ = '\?';  break;    // \?  Who knew?
+        case '\'': *d++ = '\'';  break;
+        case '"':  *d++ = '\"';  break;
+        case '0':
+        case '1':
+        case '2':
+        case '3':
+        case '4':
+        case '5':
+        case '6':
+        case '7': {
+          // octal digit: 1 to 3 digits
+          const char* octal_start = p;
+          unsigned int ch = *p - '0';
+          if (p < last_byte && is_octal_digit(p[1])) ch = ch * 8 + *++p - '0';
+          if (p < last_byte && is_octal_digit(p[1]))
+            ch = ch * 8 + *++p - '0';      // now points at last digit
+          if (ch > 0xff) {
+            if (error) {
+              *error = "Value of \\" +
+                       std::string(octal_start, p + 1 - octal_start) +
+                       " exceeds 0xff";
+            }
+            return false;
+          }
+          if ((ch == 0) && leave_nulls_escaped) {
+            // Copy the escape sequence for the null character
+            const ptrdiff_t octal_size = p + 1 - octal_start;
+            *d++ = '\\';
+            memmove(d, octal_start, octal_size);
+            d += octal_size;
+            break;
+          }
+          *d++ = ch;
+          break;
+        }
+        case 'x':
+        case 'X': {
+          if (p >= last_byte) {
+            if (error) *error = "String cannot end with \\x";
+            return false;
+          } else if (!absl::ascii_isxdigit(p[1])) {
+            if (error) *error = "\\x cannot be followed by a non-hex digit";
+            return false;
+          }
+          unsigned int ch = 0;
+          const char* hex_start = p;
+          while (p < last_byte && absl::ascii_isxdigit(p[1]))
+            // Arbitrarily many hex digits
+            ch = (ch << 4) + hex_digit_to_int(*++p);
+          if (ch > 0xFF) {
+            if (error) {
+              *error = "Value of \\" +
+                       std::string(hex_start, p + 1 - hex_start) +
+                       " exceeds 0xff";
+            }
+            return false;
+          }
+          if ((ch == 0) && leave_nulls_escaped) {
+            // Copy the escape sequence for the null character
+            const ptrdiff_t hex_size = p + 1 - hex_start;
+            *d++ = '\\';
+            memmove(d, hex_start, hex_size);
+            d += hex_size;
+            break;
+          }
+          *d++ = ch;
+          break;
+        }
+        case 'u': {
+          // \uhhhh => convert 4 hex digits to UTF-8
+          char32_t rune = 0;
+          const char* hex_start = p;
+          if (p + 4 >= end) {
+            if (error) {
+              *error = "\\u must be followed by 4 hex digits: \\" +
+                       std::string(hex_start, p + 1 - hex_start);
+            }
+            return false;
+          }
+          for (int i = 0; i < 4; ++i) {
+            // Look one char ahead.
+            if (absl::ascii_isxdigit(p[1])) {
+              rune = (rune << 4) + hex_digit_to_int(*++p);  // Advance p.
+            } else {
+              if (error) {
+                *error = "\\u must be followed by 4 hex digits: \\" +
+                         std::string(hex_start, p + 1 - hex_start);
+              }
+              return false;
+            }
+          }
+          if ((rune == 0) && leave_nulls_escaped) {
+            // Copy the escape sequence for the null character
+            *d++ = '\\';
+            memmove(d, hex_start, 5);  // u0000
+            d += 5;
+            break;
+          }
+          if (IsSurrogate(rune, absl::string_view(hex_start, 5), error)) {
+            return false;
+          }
+          d += strings_internal::EncodeUTF8Char(d, rune);
+          break;
+        }
+        case 'U': {
+          // \Uhhhhhhhh => convert 8 hex digits to UTF-8
+          char32_t rune = 0;
+          const char* hex_start = p;
+          if (p + 8 >= end) {
+            if (error) {
+              *error = "\\U must be followed by 8 hex digits: \\" +
+                       std::string(hex_start, p + 1 - hex_start);
+            }
+            return false;
+          }
+          for (int i = 0; i < 8; ++i) {
+            // Look one char ahead.
+            if (absl::ascii_isxdigit(p[1])) {
+              // Don't change rune until we're sure this
+              // is within the Unicode limit, but do advance p.
+              uint32_t newrune = (rune << 4) + hex_digit_to_int(*++p);
+              if (newrune > 0x10FFFF) {
+                if (error) {
+                  *error = "Value of \\" +
+                           std::string(hex_start, p + 1 - hex_start) +
+                           " exceeds Unicode limit (0x10FFFF)";
+                }
+                return false;
+              } else {
+                rune = newrune;
+              }
+            } else {
+              if (error) {
+                *error = "\\U must be followed by 8 hex digits: \\" +
+                         std::string(hex_start, p + 1 - hex_start);
+              }
+              return false;
+            }
+          }
+          if ((rune == 0) && leave_nulls_escaped) {
+            // Copy the escape sequence for the null character
+            *d++ = '\\';
+            memmove(d, hex_start, 9);  // U00000000
+            d += 9;
+            break;
+          }
+          if (IsSurrogate(rune, absl::string_view(hex_start, 9), error)) {
+            return false;
+          }
+          d += strings_internal::EncodeUTF8Char(d, rune);
+          break;
+        }
+        default: {
+          if (error) *error = std::string("Unknown escape sequence: \\") + *p;
+          return false;
+        }
+      }
+      p++;                                 // read past letter we escaped
+    }
+  }
+  *dest_len = d - dest;
+  return true;
+}
+
+// ----------------------------------------------------------------------
+// CUnescapeInternal()
+//
+//    Same as above but uses a std::string for output. 'source' and 'dest'
+//    may be the same.
+// ----------------------------------------------------------------------
+bool CUnescapeInternal(absl::string_view source, bool leave_nulls_escaped,
+                       std::string* dest, std::string* error) {
+  strings_internal::STLStringResizeUninitialized(dest, source.size());
+
+  ptrdiff_t dest_size;
+  if (!CUnescapeInternal(source,
+                         leave_nulls_escaped,
+                         &(*dest)[0],
+                         &dest_size,
+                         error)) {
+    return false;
+  }
+  dest->erase(dest_size);
+  return true;
+}
+
+// ----------------------------------------------------------------------
+// CEscape()
+// CHexEscape()
+// Utf8SafeCEscape()
+// Utf8SafeCHexEscape()
+//    Escapes 'src' using C-style escape sequences.  This is useful for
+//    preparing query flags.  The 'Hex' version uses hexadecimal rather than
+//    octal sequences.  The 'Utf8Safe' version does not touch UTF-8 bytes.
+//
+//    Escaped chars: \n, \r, \t, ", ', \, and !absl::ascii_isprint().
+// ----------------------------------------------------------------------
+std::string CEscapeInternal(absl::string_view src, bool use_hex,
+                            bool utf8_safe) {
+  std::string dest;
+  bool last_hex_escape = false;  // true if last output char was \xNN.
+
+  for (unsigned char c : src) {
+    bool is_hex_escape = false;
+    switch (c) {
+      case '\n': dest.append("\\" "n"); break;
+      case '\r': dest.append("\\" "r"); break;
+      case '\t': dest.append("\\" "t"); break;
+      case '\"': dest.append("\\" "\""); break;
+      case '\'': dest.append("\\" "'"); break;
+      case '\\': dest.append("\\" "\\"); break;
+      default:
+        // Note that if we emit \xNN and the src character after that is a hex
+        // digit then that digit must be escaped too to prevent it being
+        // interpreted as part of the character code by C.
+        if ((!utf8_safe || c < 0x80) &&
+            (!absl::ascii_isprint(c) ||
+             (last_hex_escape && absl::ascii_isxdigit(c)))) {
+          if (use_hex) {
+            dest.append("\\" "x");
+            dest.push_back(numbers_internal::kHexChar[c / 16]);
+            dest.push_back(numbers_internal::kHexChar[c % 16]);
+            is_hex_escape = true;
+          } else {
+            dest.append("\\");
+            dest.push_back(numbers_internal::kHexChar[c / 64]);
+            dest.push_back(numbers_internal::kHexChar[(c % 64) / 8]);
+            dest.push_back(numbers_internal::kHexChar[c % 8]);
+          }
+        } else {
+          dest.push_back(c);
+          break;
+        }
+    }
+    last_hex_escape = is_hex_escape;
+  }
+
+  return dest;
+}
+
+/* clang-format off */
+constexpr char c_escaped_len[256] = {
+    4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 4, 4, 2, 4, 4,  // \t, \n, \r
+    4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+    1, 1, 2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1,  // ", '
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  // '0'..'9'
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  // 'A'..'O'
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1,  // 'P'..'Z', '\'
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  // 'a'..'o'
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 4,  // 'p'..'z', DEL
+    4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+    4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+    4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+    4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+    4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+    4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+    4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+    4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+};
+/* clang-format on */
+
+// Calculates the length of the C-style escaped version of 'src'.
+// Assumes that non-printable characters are escaped using octal sequences, and
+// that UTF-8 bytes are not handled specially.
+inline size_t CEscapedLength(absl::string_view src) {
+  size_t escaped_len = 0;
+  for (unsigned char c : src) escaped_len += c_escaped_len[c];
+  return escaped_len;
+}
+
+void CEscapeAndAppendInternal(absl::string_view src, std::string* dest) {
+  size_t escaped_len = CEscapedLength(src);
+  if (escaped_len == src.size()) {
+    dest->append(src.data(), src.size());
+    return;
+  }
+
+  size_t cur_dest_len = dest->size();
+  strings_internal::STLStringResizeUninitialized(dest,
+                                                 cur_dest_len + escaped_len);
+  char* append_ptr = &(*dest)[cur_dest_len];
+
+  for (unsigned char c : src) {
+    int char_len = c_escaped_len[c];
+    if (char_len == 1) {
+      *append_ptr++ = c;
+    } else if (char_len == 2) {
+      switch (c) {
+        case '\n':
+          *append_ptr++ = '\\';
+          *append_ptr++ = 'n';
+          break;
+        case '\r':
+          *append_ptr++ = '\\';
+          *append_ptr++ = 'r';
+          break;
+        case '\t':
+          *append_ptr++ = '\\';
+          *append_ptr++ = 't';
+          break;
+        case '\"':
+          *append_ptr++ = '\\';
+          *append_ptr++ = '\"';
+          break;
+        case '\'':
+          *append_ptr++ = '\\';
+          *append_ptr++ = '\'';
+          break;
+        case '\\':
+          *append_ptr++ = '\\';
+          *append_ptr++ = '\\';
+          break;
+      }
+    } else {
+      *append_ptr++ = '\\';
+      *append_ptr++ = '0' + c / 64;
+      *append_ptr++ = '0' + (c % 64) / 8;
+      *append_ptr++ = '0' + c % 8;
+    }
+  }
+}
+
+bool Base64UnescapeInternal(const char* src_param, size_t szsrc, char* dest,
+                            size_t szdest, const signed char* unbase64,
+                            size_t* len) {
+  static const char kPad64Equals = '=';
+  static const char kPad64Dot = '.';
+
+  size_t destidx = 0;
+  int decode = 0;
+  int state = 0;
+  unsigned int ch = 0;
+  unsigned int temp = 0;
+
+  // If "char" is signed by default, using *src as an array index results in
+  // accessing negative array elements. Treat the input as a pointer to
+  // unsigned char to avoid this.
+  const unsigned char* src = reinterpret_cast<const unsigned char*>(src_param);
+
+  // The GET_INPUT macro gets the next input character, skipping
+  // over any whitespace, and stopping when we reach the end of the
+  // string or when we read any non-data character.  The arguments are
+  // an arbitrary identifier (used as a label for goto) and the number
+  // of data bytes that must remain in the input to avoid aborting the
+  // loop.
+#define GET_INPUT(label, remain)                                \
+  label:                                                        \
+  --szsrc;                                                      \
+  ch = *src++;                                                  \
+  decode = unbase64[ch];                                        \
+  if (decode < 0) {                                             \
+    if (absl::ascii_isspace(ch) && szsrc >= remain) goto label; \
+    state = 4 - remain;                                         \
+    break;                                                      \
+  }
+
+  // if dest is null, we're just checking to see if it's legal input
+  // rather than producing output.  (I suspect this could just be done
+  // with a regexp...).  We duplicate the loop so this test can be
+  // outside it instead of in every iteration.
+
+  if (dest) {
+    // This loop consumes 4 input bytes and produces 3 output bytes
+    // per iteration.  We can't know at the start that there is enough
+    // data left in the string for a full iteration, so the loop may
+    // break out in the middle; if so 'state' will be set to the
+    // number of input bytes read.
+
+    while (szsrc >= 4) {
+      // We'll start by optimistically assuming that the next four
+      // bytes of the string (src[0..3]) are four good data bytes
+      // (that is, no nulls, whitespace, padding chars, or illegal
+      // chars).  We need to test src[0..2] for nulls individually
+      // before constructing temp to preserve the property that we
+      // never read past a null in the string (no matter how long
+      // szsrc claims the string is).
+
+      if (!src[0] || !src[1] || !src[2] ||
+          ((temp = ((unsigned(unbase64[src[0]]) << 18) |
+                    (unsigned(unbase64[src[1]]) << 12) |
+                    (unsigned(unbase64[src[2]]) << 6) |
+                    (unsigned(unbase64[src[3]])))) &
+           0x80000000)) {
+        // Iff any of those four characters was bad (null, illegal,
+        // whitespace, padding), then temp's high bit will be set
+        // (because unbase64[] is -1 for all bad characters).
+        //
+        // We'll back up and resort to the slower decoder, which knows
+        // how to handle those cases.
+
+        GET_INPUT(first, 4);
+        temp = decode;
+        GET_INPUT(second, 3);
+        temp = (temp << 6) | decode;
+        GET_INPUT(third, 2);
+        temp = (temp << 6) | decode;
+        GET_INPUT(fourth, 1);
+        temp = (temp << 6) | decode;
+      } else {
+        // We really did have four good data bytes, so advance four
+        // characters in the string.
+
+        szsrc -= 4;
+        src += 4;
+      }
+
+      // temp has 24 bits of input, so write that out as three bytes.
+
+      if (destidx + 3 > szdest) return false;
+      dest[destidx + 2] = temp;
+      temp >>= 8;
+      dest[destidx + 1] = temp;
+      temp >>= 8;
+      dest[destidx] = temp;
+      destidx += 3;
+    }
+  } else {
+    while (szsrc >= 4) {
+      if (!src[0] || !src[1] || !src[2] ||
+          ((temp = ((unsigned(unbase64[src[0]]) << 18) |
+                    (unsigned(unbase64[src[1]]) << 12) |
+                    (unsigned(unbase64[src[2]]) << 6) |
+                    (unsigned(unbase64[src[3]])))) &
+           0x80000000)) {
+        GET_INPUT(first_no_dest, 4);
+        GET_INPUT(second_no_dest, 3);
+        GET_INPUT(third_no_dest, 2);
+        GET_INPUT(fourth_no_dest, 1);
+      } else {
+        szsrc -= 4;
+        src += 4;
+      }
+      destidx += 3;
+    }
+  }
+
+#undef GET_INPUT
+
+  // if the loop terminated because we read a bad character, return
+  // now.
+  if (decode < 0 && ch != kPad64Equals && ch != kPad64Dot &&
+      !absl::ascii_isspace(ch))
+    return false;
+
+  if (ch == kPad64Equals || ch == kPad64Dot) {
+    // if we stopped by hitting an '=' or '.', un-read that character -- we'll
+    // look at it again when we count to check for the proper number of
+    // equals signs at the end.
+    ++szsrc;
+    --src;
+  } else {
+    // This loop consumes 1 input byte per iteration.  It's used to
+    // clean up the 0-3 input bytes remaining when the first, faster
+    // loop finishes.  'temp' contains the data from 'state' input
+    // characters read by the first loop.
+    while (szsrc > 0) {
+      --szsrc;
+      ch = *src++;
+      decode = unbase64[ch];
+      if (decode < 0) {
+        if (absl::ascii_isspace(ch)) {
+          continue;
+        } else if (ch == kPad64Equals || ch == kPad64Dot) {
+          // back up one character; we'll read it again when we check
+          // for the correct number of pad characters at the end.
+          ++szsrc;
+          --src;
+          break;
+        } else {
+          return false;
+        }
+      }
+
+      // Each input character gives us six bits of output.
+      temp = (temp << 6) | decode;
+      ++state;
+      if (state == 4) {
+        // If we've accumulated 24 bits of output, write that out as
+        // three bytes.
+        if (dest) {
+          if (destidx + 3 > szdest) return false;
+          dest[destidx + 2] = temp;
+          temp >>= 8;
+          dest[destidx + 1] = temp;
+          temp >>= 8;
+          dest[destidx] = temp;
+        }
+        destidx += 3;
+        state = 0;
+        temp = 0;
+      }
+    }
+  }
+
+  // Process the leftover data contained in 'temp' at the end of the input.
+  int expected_equals = 0;
+  switch (state) {
+    case 0:
+      // Nothing left over; output is a multiple of 3 bytes.
+      break;
+
+    case 1:
+      // Bad input; we have 6 bits left over.
+      return false;
+
+    case 2:
+      // Produce one more output byte from the 12 input bits we have left.
+      if (dest) {
+        if (destidx + 1 > szdest) return false;
+        temp >>= 4;
+        dest[destidx] = temp;
+      }
+      ++destidx;
+      expected_equals = 2;
+      break;
+
+    case 3:
+      // Produce two more output bytes from the 18 input bits we have left.
+      if (dest) {
+        if (destidx + 2 > szdest) return false;
+        temp >>= 2;
+        dest[destidx + 1] = temp;
+        temp >>= 8;
+        dest[destidx] = temp;
+      }
+      destidx += 2;
+      expected_equals = 1;
+      break;
+
+    default:
+      // state should have no other values at this point.
+      ABSL_RAW_LOG(FATAL, "This can't happen; base64 decoder state = %d",
+                   state);
+  }
+
+  // The remainder of the string should be all whitespace, mixed with
+  // exactly 0 equals signs, or exactly 'expected_equals' equals
+  // signs.  (Always accepting 0 equals signs is an Abseil extension
+  // not covered in the RFC, as is accepting dot as the pad character.)
+
+  int equals = 0;
+  while (szsrc > 0) {
+    if (*src == kPad64Equals || *src == kPad64Dot)
+      ++equals;
+    else if (!absl::ascii_isspace(*src))
+      return false;
+    --szsrc;
+    ++src;
+  }
+
+  const bool ok = (equals == 0 || equals == expected_equals);
+  if (ok) *len = destidx;
+  return ok;
+}
+
+// The arrays below were generated by the following code
+// #include <sys/time.h>
+// #include <stdlib.h>
+// #include <string.h>
+// main()
+// {
+//   static const char Base64[] =
+//     "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+//   char* pos;
+//   int idx, i, j;
+//   printf("    ");
+//   for (i = 0; i < 255; i += 8) {
+//     for (j = i; j < i + 8; j++) {
+//       pos = strchr(Base64, j);
+//       if ((pos == nullptr) || (j == 0))
+//         idx = -1;
+//       else
+//         idx = pos - Base64;
+//       if (idx == -1)
+//         printf(" %2d,     ", idx);
+//       else
+//         printf(" %2d/*%c*/,", idx, j);
+//     }
+//     printf("\n    ");
+//   }
+// }
+//
+// where the value of "Base64[]" was replaced by one of the base-64 conversion
+// tables from the functions below.
+/* clang-format off */
+constexpr signed char kUnBase64[] = {
+    -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
+    -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
+    -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
+    -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
+    -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
+    -1,      -1,      -1,      62/*+*/, -1,      -1,      -1,      63/*/ */,
+    52/*0*/, 53/*1*/, 54/*2*/, 55/*3*/, 56/*4*/, 57/*5*/, 58/*6*/, 59/*7*/,
+    60/*8*/, 61/*9*/, -1,      -1,      -1,      -1,      -1,      -1,
+    -1,       0/*A*/,  1/*B*/,  2/*C*/,  3/*D*/,  4/*E*/,  5/*F*/,  6/*G*/,
+    07/*H*/,  8/*I*/,  9/*J*/, 10/*K*/, 11/*L*/, 12/*M*/, 13/*N*/, 14/*O*/,
+    15/*P*/, 16/*Q*/, 17/*R*/, 18/*S*/, 19/*T*/, 20/*U*/, 21/*V*/, 22/*W*/,
+    23/*X*/, 24/*Y*/, 25/*Z*/, -1,      -1,      -1,      -1,      -1,
+    -1,      26/*a*/, 27/*b*/, 28/*c*/, 29/*d*/, 30/*e*/, 31/*f*/, 32/*g*/,
+    33/*h*/, 34/*i*/, 35/*j*/, 36/*k*/, 37/*l*/, 38/*m*/, 39/*n*/, 40/*o*/,
+    41/*p*/, 42/*q*/, 43/*r*/, 44/*s*/, 45/*t*/, 46/*u*/, 47/*v*/, 48/*w*/,
+    49/*x*/, 50/*y*/, 51/*z*/, -1,      -1,      -1,      -1,      -1,
+    -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
+    -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
+    -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
+    -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
+    -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
+    -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
+    -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
+    -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
+    -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
+    -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
+    -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
+    -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
+    -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
+    -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
+    -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
+    -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1
+};
+
+constexpr signed char kUnWebSafeBase64[] = {
+    -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
+    -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
+    -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
+    -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
+    -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
+    -1,      -1,      -1,      -1,      -1,      62/*-*/, -1,      -1,
+    52/*0*/, 53/*1*/, 54/*2*/, 55/*3*/, 56/*4*/, 57/*5*/, 58/*6*/, 59/*7*/,
+    60/*8*/, 61/*9*/, -1,      -1,      -1,      -1,      -1,      -1,
+    -1,       0/*A*/,  1/*B*/,  2/*C*/,  3/*D*/,  4/*E*/,  5/*F*/,  6/*G*/,
+    07/*H*/,  8/*I*/,  9/*J*/, 10/*K*/, 11/*L*/, 12/*M*/, 13/*N*/, 14/*O*/,
+    15/*P*/, 16/*Q*/, 17/*R*/, 18/*S*/, 19/*T*/, 20/*U*/, 21/*V*/, 22/*W*/,
+    23/*X*/, 24/*Y*/, 25/*Z*/, -1,      -1,      -1,      -1,      63/*_*/,
+    -1,      26/*a*/, 27/*b*/, 28/*c*/, 29/*d*/, 30/*e*/, 31/*f*/, 32/*g*/,
+    33/*h*/, 34/*i*/, 35/*j*/, 36/*k*/, 37/*l*/, 38/*m*/, 39/*n*/, 40/*o*/,
+    41/*p*/, 42/*q*/, 43/*r*/, 44/*s*/, 45/*t*/, 46/*u*/, 47/*v*/, 48/*w*/,
+    49/*x*/, 50/*y*/, 51/*z*/, -1,      -1,      -1,      -1,      -1,
+    -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
+    -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
+    -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
+    -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
+    -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
+    -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
+    -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
+    -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
+    -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
+    -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
+    -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
+    -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
+    -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
+    -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
+    -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
+    -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1
+};
+/* clang-format on */
+
+constexpr char kWebSafeBase64Chars[] =
+    "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
+
+template <typename String>
+bool Base64UnescapeInternal(const char* src, size_t slen, String* dest,
+                            const signed char* unbase64) {
+  // Determine the size of the output string.  Base64 encodes every 3 bytes into
+  // 4 characters.  any leftover chars are added directly for good measure.
+  // This is documented in the base64 RFC: http://tools.ietf.org/html/rfc3548
+  const size_t dest_len = 3 * (slen / 4) + (slen % 4);
+
+  strings_internal::STLStringResizeUninitialized(dest, dest_len);
+
+  // We are getting the destination buffer by getting the beginning of the
+  // string and converting it into a char *.
+  size_t len;
+  const bool ok =
+      Base64UnescapeInternal(src, slen, &(*dest)[0], dest_len, unbase64, &len);
+  if (!ok) {
+    dest->clear();
+    return false;
+  }
+
+  // could be shorter if there was padding
+  assert(len <= dest_len);
+  dest->erase(len);
+
+  return true;
+}
+
+/* clang-format off */
+constexpr char kHexValueLenient[256] = {
+    0,  0,  0,  0,  0,  0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0,  0,  0,  0,  0,  0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0,  0,  0,  0,  0,  0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0,  1,  2,  3,  4,  5,  6, 7, 8, 9, 0, 0, 0, 0, 0, 0,  // '0'..'9'
+    0, 10, 11, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 'A'..'F'
+    0,  0,  0,  0,  0,  0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 10, 11, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 'a'..'f'
+    0,  0,  0,  0,  0,  0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0,  0,  0,  0,  0,  0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0,  0,  0,  0,  0,  0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0,  0,  0,  0,  0,  0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0,  0,  0,  0,  0,  0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0,  0,  0,  0,  0,  0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0,  0,  0,  0,  0,  0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0,  0,  0,  0,  0,  0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0,  0,  0,  0,  0,  0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+};
+
+/* clang-format on */
+
+// This is a templated function so that T can be either a char*
+// or a string.  This works because we use the [] operator to access
+// individual characters at a time.
+template <typename T>
+void HexStringToBytesInternal(const char* from, T to, ptrdiff_t num) {
+  for (int i = 0; i < num; i++) {
+    to[i] = (kHexValueLenient[from[i * 2] & 0xFF] << 4) +
+            (kHexValueLenient[from[i * 2 + 1] & 0xFF]);
+  }
+}
+
+// This is a templated function so that T can be either a char* or a
+// std::string.
+template <typename T>
+void BytesToHexStringInternal(const unsigned char* src, T dest, ptrdiff_t num) {
+  auto dest_ptr = &dest[0];
+  for (auto src_ptr = src; src_ptr != (src + num); ++src_ptr, dest_ptr += 2) {
+    const char* hex_p = &numbers_internal::kHexTable[*src_ptr * 2];
+    std::copy(hex_p, hex_p + 2, dest_ptr);
+  }
+}
+
+}  // namespace
+
+// ----------------------------------------------------------------------
+// CUnescape()
+//
+// See CUnescapeInternal() for implementation details.
+// ----------------------------------------------------------------------
+bool CUnescape(absl::string_view source, std::string* dest,
+               std::string* error) {
+  return CUnescapeInternal(source, kUnescapeNulls, dest, error);
+}
+
+std::string CEscape(absl::string_view src) {
+  std::string dest;
+  CEscapeAndAppendInternal(src, &dest);
+  return dest;
+}
+
+std::string CHexEscape(absl::string_view src) {
+  return CEscapeInternal(src, true, false);
+}
+
+std::string Utf8SafeCEscape(absl::string_view src) {
+  return CEscapeInternal(src, false, true);
+}
+
+std::string Utf8SafeCHexEscape(absl::string_view src) {
+  return CEscapeInternal(src, true, true);
+}
+
+// ----------------------------------------------------------------------
+// Base64Unescape() - base64 decoder
+// Base64Escape() - base64 encoder
+// WebSafeBase64Unescape() - Google's variation of base64 decoder
+// WebSafeBase64Escape() - Google's variation of base64 encoder
+//
+// Check out
+// http://tools.ietf.org/html/rfc2045 for formal description, but what we
+// care about is that...
+//   Take the encoded stuff in groups of 4 characters and turn each
+//   character into a code 0 to 63 thus:
+//           A-Z map to 0 to 25
+//           a-z map to 26 to 51
+//           0-9 map to 52 to 61
+//           +(- for WebSafe) maps to 62
+//           /(_ for WebSafe) maps to 63
+//   There will be four numbers, all less than 64 which can be represented
+//   by a 6 digit binary number (aaaaaa, bbbbbb, cccccc, dddddd respectively).
+//   Arrange the 6 digit binary numbers into three bytes as such:
+//   aaaaaabb bbbbcccc ccdddddd
+//   Equals signs (one or two) are used at the end of the encoded block to
+//   indicate that the text was not an integer multiple of three bytes long.
+// ----------------------------------------------------------------------
+
+bool Base64Unescape(absl::string_view src, std::string* dest) {
+  return Base64UnescapeInternal(src.data(), src.size(), dest, kUnBase64);
+}
+
+bool WebSafeBase64Unescape(absl::string_view src, std::string* dest) {
+  return Base64UnescapeInternal(src.data(), src.size(), dest, kUnWebSafeBase64);
+}
+
+void Base64Escape(absl::string_view src, std::string* dest) {
+  strings_internal::Base64EscapeInternal(
+      reinterpret_cast<const unsigned char*>(src.data()), src.size(), dest,
+      true, strings_internal::kBase64Chars);
+}
+
+void WebSafeBase64Escape(absl::string_view src, std::string* dest) {
+  strings_internal::Base64EscapeInternal(
+      reinterpret_cast<const unsigned char*>(src.data()), src.size(), dest,
+      false, kWebSafeBase64Chars);
+}
+
+std::string Base64Escape(absl::string_view src) {
+  std::string dest;
+  strings_internal::Base64EscapeInternal(
+      reinterpret_cast<const unsigned char*>(src.data()), src.size(), &dest,
+      true, strings_internal::kBase64Chars);
+  return dest;
+}
+
+std::string WebSafeBase64Escape(absl::string_view src) {
+  std::string dest;
+  strings_internal::Base64EscapeInternal(
+      reinterpret_cast<const unsigned char*>(src.data()), src.size(), &dest,
+      false, kWebSafeBase64Chars);
+  return dest;
+}
+
+std::string HexStringToBytes(absl::string_view from) {
+  std::string result;
+  const auto num = from.size() / 2;
+  strings_internal::STLStringResizeUninitialized(&result, num);
+  absl::HexStringToBytesInternal<std::string&>(from.data(), result, num);
+  return result;
+}
+
+std::string BytesToHexString(absl::string_view from) {
+  std::string result;
+  strings_internal::STLStringResizeUninitialized(&result, 2 * from.size());
+  absl::BytesToHexStringInternal<std::string&>(
+      reinterpret_cast<const unsigned char*>(from.data()), result, from.size());
+  return result;
+}
+
+ABSL_NAMESPACE_END
+}  // namespace absl
diff --git a/src/absl/strings/escaping.h b/src/absl/strings/escaping.h
new file mode 100644 (file)
index 0000000..f5ca26c
--- /dev/null
@@ -0,0 +1,164 @@
+//
+// Copyright 2017 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// -----------------------------------------------------------------------------
+// File: escaping.h
+// -----------------------------------------------------------------------------
+//
+// This header file contains string utilities involved in escaping and
+// unescaping strings in various ways.
+
+#ifndef ABSL_STRINGS_ESCAPING_H_
+#define ABSL_STRINGS_ESCAPING_H_
+
+#include <cstddef>
+#include <string>
+#include <vector>
+
+#include "absl/base/macros.h"
+#include "absl/strings/ascii.h"
+#include "absl/strings/str_join.h"
+#include "absl/strings/string_view.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+
+// CUnescape()
+//
+// Unescapes a `source` string and copies it into `dest`, rewriting C-style
+// escape sequences (https://en.cppreference.com/w/cpp/language/escape) into
+// their proper code point equivalents, returning `true` if successful.
+//
+// The following unescape sequences can be handled:
+//
+//   * ASCII escape sequences ('\n','\r','\\', etc.) to their ASCII equivalents
+//   * Octal escape sequences ('\nnn') to byte nnn. The unescaped value must
+//     resolve to a single byte or an error will occur. E.g. values greater than
+//     0xff will produce an error.
+//   * Hexadecimal escape sequences ('\xnn') to byte nn. While an arbitrary
+//     number of following digits are allowed, the unescaped value must resolve
+//     to a single byte or an error will occur. E.g. '\x0045' is equivalent to
+//     '\x45', but '\x1234' will produce an error.
+//   * Unicode escape sequences ('\unnnn' for exactly four hex digits or
+//     '\Unnnnnnnn' for exactly eight hex digits, which will be encoded in
+//     UTF-8. (E.g., `\u2019` unescapes to the three bytes 0xE2, 0x80, and
+//     0x99).
+//
+// If any errors are encountered, this function returns `false`, leaving the
+// `dest` output parameter in an unspecified state, and stores the first
+// encountered error in `error`. To disable error reporting, set `error` to
+// `nullptr` or use the overload with no error reporting below.
+//
+// Example:
+//
+//   std::string s = "foo\\rbar\\nbaz\\t";
+//   std::string unescaped_s;
+//   if (!absl::CUnescape(s, &unescaped_s) {
+//     ...
+//   }
+//   EXPECT_EQ(unescaped_s, "foo\rbar\nbaz\t");
+bool CUnescape(absl::string_view source, std::string* dest, std::string* error);
+
+// Overload of `CUnescape()` with no error reporting.
+inline bool CUnescape(absl::string_view source, std::string* dest) {
+  return CUnescape(source, dest, nullptr);
+}
+
+// CEscape()
+//
+// Escapes a 'src' string using C-style escapes sequences
+// (https://en.cppreference.com/w/cpp/language/escape), escaping other
+// non-printable/non-whitespace bytes as octal sequences (e.g. "\377").
+//
+// Example:
+//
+//   std::string s = "foo\rbar\tbaz\010\011\012\013\014\x0d\n";
+//   std::string escaped_s = absl::CEscape(s);
+//   EXPECT_EQ(escaped_s, "foo\\rbar\\tbaz\\010\\t\\n\\013\\014\\r\\n");
+std::string CEscape(absl::string_view src);
+
+// CHexEscape()
+//
+// Escapes a 'src' string using C-style escape sequences, escaping
+// other non-printable/non-whitespace bytes as hexadecimal sequences (e.g.
+// "\xFF").
+//
+// Example:
+//
+//   std::string s = "foo\rbar\tbaz\010\011\012\013\014\x0d\n";
+//   std::string escaped_s = absl::CHexEscape(s);
+//   EXPECT_EQ(escaped_s, "foo\\rbar\\tbaz\\x08\\t\\n\\x0b\\x0c\\r\\n");
+std::string CHexEscape(absl::string_view src);
+
+// Utf8SafeCEscape()
+//
+// Escapes a 'src' string using C-style escape sequences, escaping bytes as
+// octal sequences, and passing through UTF-8 characters without conversion.
+// I.e., when encountering any bytes with their high bit set, this function
+// will not escape those values, whether or not they are valid UTF-8.
+std::string Utf8SafeCEscape(absl::string_view src);
+
+// Utf8SafeCHexEscape()
+//
+// Escapes a 'src' string using C-style escape sequences, escaping bytes as
+// hexadecimal sequences, and passing through UTF-8 characters without
+// conversion.
+std::string Utf8SafeCHexEscape(absl::string_view src);
+
+// Base64Unescape()
+//
+// Converts a `src` string encoded in Base64 to its binary equivalent, writing
+// it to a `dest` buffer, returning `true` on success. If `src` contains invalid
+// characters, `dest` is cleared and returns `false`.
+bool Base64Unescape(absl::string_view src, std::string* dest);
+
+// WebSafeBase64Unescape()
+//
+// Converts a `src` string encoded in Base64 to its binary equivalent, writing
+// it to a `dest` buffer, but using '-' instead of '+', and '_' instead of '/'.
+// If `src` contains invalid characters, `dest` is cleared and returns `false`.
+bool WebSafeBase64Unescape(absl::string_view src, std::string* dest);
+
+// Base64Escape()
+//
+// Encodes a `src` string into a base64-encoded string, with padding characters.
+// This function conforms with RFC 4648 section 4 (base64).
+void Base64Escape(absl::string_view src, std::string* dest);
+std::string Base64Escape(absl::string_view src);
+
+// WebSafeBase64Escape()
+//
+// Encodes a `src` string into a base64-like string, using '-' instead of '+'
+// and '_' instead of '/', and without padding. This function conforms with RFC
+// 4648 section 5 (base64url).
+void WebSafeBase64Escape(absl::string_view src, std::string* dest);
+std::string WebSafeBase64Escape(absl::string_view src);
+
+// HexStringToBytes()
+//
+// Converts an ASCII hex string into bytes, returning binary data of length
+// `from.size()/2`.
+std::string HexStringToBytes(absl::string_view from);
+
+// BytesToHexString()
+//
+// Converts binary data into an ASCII text string, returning a string of size
+// `2*from.size()`.
+std::string BytesToHexString(absl::string_view from);
+
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#endif  // ABSL_STRINGS_ESCAPING_H_
diff --git a/src/absl/strings/internal/char_map.h b/src/absl/strings/internal/char_map.h
new file mode 100644 (file)
index 0000000..61484de
--- /dev/null
@@ -0,0 +1,156 @@
+// Copyright 2017 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// Character Map Class
+//
+// A fast, bit-vector map for 8-bit unsigned characters.
+// This class is useful for non-character purposes as well.
+
+#ifndef ABSL_STRINGS_INTERNAL_CHAR_MAP_H_
+#define ABSL_STRINGS_INTERNAL_CHAR_MAP_H_
+
+#include <cstddef>
+#include <cstdint>
+#include <cstring>
+
+#include "absl/base/macros.h"
+#include "absl/base/port.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace strings_internal {
+
+class Charmap {
+ public:
+  constexpr Charmap() : m_() {}
+
+  // Initializes with a given char*.  Note that NUL is not treated as
+  // a terminator, but rather a char to be flicked.
+  Charmap(const char* str, int len) : m_() {
+    while (len--) SetChar(*str++);
+  }
+
+  // Initializes with a given char*.  NUL is treated as a terminator
+  // and will not be in the charmap.
+  explicit Charmap(const char* str) : m_() {
+    while (*str) SetChar(*str++);
+  }
+
+  constexpr bool contains(unsigned char c) const {
+    return (m_[c / 64] >> (c % 64)) & 0x1;
+  }
+
+  // Returns true if and only if a character exists in both maps.
+  bool IntersectsWith(const Charmap& c) const {
+    for (size_t i = 0; i < ABSL_ARRAYSIZE(m_); ++i) {
+      if ((m_[i] & c.m_[i]) != 0) return true;
+    }
+    return false;
+  }
+
+  bool IsZero() const {
+    for (uint64_t c : m_) {
+      if (c != 0) return false;
+    }
+    return true;
+  }
+
+  // Containing only a single specified char.
+  static constexpr Charmap Char(char x) {
+    return Charmap(CharMaskForWord(x, 0), CharMaskForWord(x, 1),
+                   CharMaskForWord(x, 2), CharMaskForWord(x, 3));
+  }
+
+  // Containing all the chars in the C-string 's'.
+  // Note that this is expensively recursive because of the C++11 constexpr
+  // formulation. Use only in constexpr initializers.
+  static constexpr Charmap FromString(const char* s) {
+    return *s == 0 ? Charmap() : (Char(*s) | FromString(s + 1));
+  }
+
+  // Containing all the chars in the closed interval [lo,hi].
+  static constexpr Charmap Range(char lo, char hi) {
+    return Charmap(RangeForWord(lo, hi, 0), RangeForWord(lo, hi, 1),
+                   RangeForWord(lo, hi, 2), RangeForWord(lo, hi, 3));
+  }
+
+  friend constexpr Charmap operator&(const Charmap& a, const Charmap& b) {
+    return Charmap(a.m_[0] & b.m_[0], a.m_[1] & b.m_[1], a.m_[2] & b.m_[2],
+                   a.m_[3] & b.m_[3]);
+  }
+
+  friend constexpr Charmap operator|(const Charmap& a, const Charmap& b) {
+    return Charmap(a.m_[0] | b.m_[0], a.m_[1] | b.m_[1], a.m_[2] | b.m_[2],
+                   a.m_[3] | b.m_[3]);
+  }
+
+  friend constexpr Charmap operator~(const Charmap& a) {
+    return Charmap(~a.m_[0], ~a.m_[1], ~a.m_[2], ~a.m_[3]);
+  }
+
+ private:
+  constexpr Charmap(uint64_t b0, uint64_t b1, uint64_t b2, uint64_t b3)
+      : m_{b0, b1, b2, b3} {}
+
+  static constexpr uint64_t RangeForWord(unsigned char lo, unsigned char hi,
+                                         uint64_t word) {
+    return OpenRangeFromZeroForWord(hi + 1, word) &
+           ~OpenRangeFromZeroForWord(lo, word);
+  }
+
+  // All the chars in the specified word of the range [0, upper).
+  static constexpr uint64_t OpenRangeFromZeroForWord(uint64_t upper,
+                                                     uint64_t word) {
+    return (upper <= 64 * word)
+               ? 0
+               : (upper >= 64 * (word + 1))
+                     ? ~static_cast<uint64_t>(0)
+                     : (~static_cast<uint64_t>(0) >> (64 - upper % 64));
+  }
+
+  static constexpr uint64_t CharMaskForWord(unsigned char x, uint64_t word) {
+    return (x / 64 == word) ? (static_cast<uint64_t>(1) << (x % 64)) : 0;
+  }
+
+ private:
+  void SetChar(unsigned char c) {
+    m_[c / 64] |= static_cast<uint64_t>(1) << (c % 64);
+  }
+
+  uint64_t m_[4];
+};
+
+// Mirror the char-classifying predicates in <cctype>
+constexpr Charmap UpperCharmap() { return Charmap::Range('A', 'Z'); }
+constexpr Charmap LowerCharmap() { return Charmap::Range('a', 'z'); }
+constexpr Charmap DigitCharmap() { return Charmap::Range('0', '9'); }
+constexpr Charmap AlphaCharmap() { return LowerCharmap() | UpperCharmap(); }
+constexpr Charmap AlnumCharmap() { return DigitCharmap() | AlphaCharmap(); }
+constexpr Charmap XDigitCharmap() {
+  return DigitCharmap() | Charmap::Range('A', 'F') | Charmap::Range('a', 'f');
+}
+constexpr Charmap PrintCharmap() { return Charmap::Range(0x20, 0x7e); }
+constexpr Charmap SpaceCharmap() { return Charmap::FromString("\t\n\v\f\r "); }
+constexpr Charmap CntrlCharmap() {
+  return Charmap::Range(0, 0x7f) & ~PrintCharmap();
+}
+constexpr Charmap BlankCharmap() { return Charmap::FromString("\t "); }
+constexpr Charmap GraphCharmap() { return PrintCharmap() & ~SpaceCharmap(); }
+constexpr Charmap PunctCharmap() { return GraphCharmap() & ~AlnumCharmap(); }
+
+}  // namespace strings_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#endif  // ABSL_STRINGS_INTERNAL_CHAR_MAP_H_
diff --git a/src/absl/strings/internal/charconv_bigint.cc b/src/absl/strings/internal/charconv_bigint.cc
new file mode 100644 (file)
index 0000000..ebf8c07
--- /dev/null
@@ -0,0 +1,359 @@
+// Copyright 2018 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "absl/strings/internal/charconv_bigint.h"
+
+#include <algorithm>
+#include <cassert>
+#include <string>
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace strings_internal {
+
+namespace {
+
+// Table containing some large powers of 5, for fast computation.
+
+// Constant step size for entries in the kLargePowersOfFive table.  Each entry
+// is larger than the previous entry by a factor of 5**kLargePowerOfFiveStep
+// (or 5**27).
+//
+// In other words, the Nth entry in the table is 5**(27*N).
+//
+// 5**27 is the largest power of 5 that fits in 64 bits.
+constexpr int kLargePowerOfFiveStep = 27;
+
+// The largest legal index into the kLargePowersOfFive table.
+//
+// In other words, the largest precomputed power of 5 is 5**(27*20).
+constexpr int kLargestPowerOfFiveIndex = 20;
+
+// Table of powers of (5**27), up to (5**27)**20 == 5**540.
+//
+// Used to generate large powers of 5 while limiting the number of repeated
+// multiplications required.
+//
+// clang-format off
+const uint32_t kLargePowersOfFive[] = {
+// 5**27 (i=1), start=0, end=2
+  0xfa10079dU, 0x6765c793U,
+// 5**54 (i=2), start=2, end=6
+  0x97d9f649U, 0x6664242dU, 0x29939b14U, 0x29c30f10U,
+// 5**81 (i=3), start=6, end=12
+  0xc4f809c5U, 0x7bf3f22aU, 0x67bdae34U, 0xad340517U, 0x369d1b5fU, 0x10de1593U,
+// 5**108 (i=4), start=12, end=20
+  0x92b260d1U, 0x9efff7c7U, 0x81de0ec6U, 0xaeba5d56U, 0x410664a4U, 0x4f40737aU,
+  0x20d3846fU, 0x06d00f73U,
+// 5**135 (i=5), start=20, end=30
+  0xff1b172dU, 0x13a1d71cU, 0xefa07617U, 0x7f682d3dU, 0xff8c90c0U, 0x3f0131e7U,
+  0x3fdcb9feU, 0x917b0177U, 0x16c407a7U, 0x02c06b9dU,
+// 5**162 (i=6), start=30, end=42
+  0x960f7199U, 0x056667ecU, 0xe07aefd8U, 0x80f2b9ccU, 0x8273f5e3U, 0xeb9a214aU,
+  0x40b38005U, 0x0e477ad4U, 0x277d08e6U, 0xfa28b11eU, 0xd3f7d784U, 0x011c835bU,
+// 5**189 (i=7), start=42, end=56
+  0xf723d9d5U, 0x3282d3f3U, 0xe00857d1U, 0x69659d25U, 0x2cf117cfU, 0x24da6d07U,
+  0x954d1417U, 0x3e5d8cedU, 0x7a8bb766U, 0xfd785ae6U, 0x645436d2U, 0x40c78b34U,
+  0x94151217U, 0x0072e9f7U,
+// 5**216 (i=8), start=56, end=72
+  0x2b416aa1U, 0x7893c5a7U, 0xe37dc6d4U, 0x2bad2beaU, 0xf0fc846cU, 0x7575ae4bU,
+  0x62587b14U, 0x83b67a34U, 0x02110cdbU, 0xf7992f55U, 0x00deb022U, 0xa4a23becU,
+  0x8af5c5cdU, 0xb85b654fU, 0x818df38bU, 0x002e69d2U,
+// 5**243 (i=9), start=72, end=90
+  0x3518cbbdU, 0x20b0c15fU, 0x38756c2fU, 0xfb5dc3ddU, 0x22ad2d94U, 0xbf35a952U,
+  0xa699192aU, 0x9a613326U, 0xad2a9cedU, 0xd7f48968U, 0xe87dfb54U, 0xc8f05db6U,
+  0x5ef67531U, 0x31c1ab49U, 0xe202ac9fU, 0x9b2957b5U, 0xa143f6d3U, 0x0012bf07U,
+// 5**270 (i=10), start=90, end=110
+  0x8b971de9U, 0x21aba2e1U, 0x63944362U, 0x57172336U, 0xd9544225U, 0xfb534166U,
+  0x08c563eeU, 0x14640ee2U, 0x24e40d31U, 0x02b06537U, 0x03887f14U, 0x0285e533U,
+  0xb744ef26U, 0x8be3a6c4U, 0x266979b4U, 0x6761ece2U, 0xd9cb39e4U, 0xe67de319U,
+  0x0d39e796U, 0x00079250U,
+// 5**297 (i=11), start=110, end=132
+  0x260eb6e5U, 0xf414a796U, 0xee1a7491U, 0xdb9368ebU, 0xf50c105bU, 0x59157750U,
+  0x9ed2fb5cU, 0xf6e56d8bU, 0xeaee8d23U, 0x0f319f75U, 0x2aa134d6U, 0xac2908e9U,
+  0xd4413298U, 0x02f02a55U, 0x989d5a7aU, 0x70dde184U, 0xba8040a7U, 0x03200981U,
+  0xbe03b11cU, 0x3c1c2a18U, 0xd60427a1U, 0x00030ee0U,
+// 5**324 (i=12), start=132, end=156
+  0xce566d71U, 0xf1c4aa25U, 0x4e93ca53U, 0xa72283d0U, 0x551a73eaU, 0x3d0538e2U,
+  0x8da4303fU, 0x6a58de60U, 0x0e660221U, 0x49cf61a6U, 0x8d058fc1U, 0xb9d1a14cU,
+  0x4bab157dU, 0xc85c6932U, 0x518c8b9eU, 0x9b92b8d0U, 0x0d8a0e21U, 0xbd855df9U,
+  0xb3ea59a1U, 0x8da29289U, 0x4584d506U, 0x3752d80fU, 0xb72569c6U, 0x00013c33U,
+// 5**351 (i=13), start=156, end=182
+  0x190f354dU, 0x83695cfeU, 0xe5a4d0c7U, 0xb60fb7e8U, 0xee5bbcc4U, 0xb922054cU,
+  0xbb4f0d85U, 0x48394028U, 0x1d8957dbU, 0x0d7edb14U, 0x4ecc7587U, 0x505e9e02U,
+  0x4c87f36bU, 0x99e66bd6U, 0x44b9ed35U, 0x753037d4U, 0xe5fe5f27U, 0x2742c203U,
+  0x13b2ed2bU, 0xdc525d2cU, 0xe6fde59aU, 0x77ffb18fU, 0x13c5752cU, 0x08a84bccU,
+  0x859a4940U, 0x00007fb6U,
+// 5**378 (i=14), start=182, end=210
+  0x4f98cb39U, 0xa60edbbcU, 0x83b5872eU, 0xa501acffU, 0x9cc76f78U, 0xbadd4c73U,
+  0x43e989faU, 0xca7acf80U, 0x2e0c824fU, 0xb19f4ffcU, 0x092fd81cU, 0xe4eb645bU,
+  0xa1ff84c2U, 0x8a5a83baU, 0xa8a1fae9U, 0x1db43609U, 0xb0fed50bU, 0x0dd7d2bdU,
+  0x7d7accd8U, 0x91fa640fU, 0x37dcc6c5U, 0x1c417fd5U, 0xe4d462adU, 0xe8a43399U,
+  0x131bf9a5U, 0x8df54d29U, 0x36547dc1U, 0x00003395U,
+// 5**405 (i=15), start=210, end=240
+  0x5bd330f5U, 0x77d21967U, 0x1ac481b7U, 0x6be2f7ceU, 0x7f4792a9U, 0xe84c2c52U,
+  0x84592228U, 0x9dcaf829U, 0xdab44ce1U, 0x3d0c311bU, 0x532e297dU, 0x4704e8b4U,
+  0x9cdc32beU, 0x41e64d9dU, 0x7717bea1U, 0xa824c00dU, 0x08f50b27U, 0x0f198d77U,
+  0x49bbfdf0U, 0x025c6c69U, 0xd4e55cd3U, 0xf083602bU, 0xb9f0fecdU, 0xc0864aeaU,
+  0x9cb98681U, 0xaaf620e9U, 0xacb6df30U, 0x4faafe66U, 0x8af13c3bU, 0x000014d5U,
+// 5**432 (i=16), start=240, end=272
+  0x682bb941U, 0x89a9f297U, 0xcba75d7bU, 0x404217b1U, 0xb4e519e9U, 0xa1bc162bU,
+  0xf7f5910aU, 0x98715af5U, 0x2ff53e57U, 0xe3ef118cU, 0x490c4543U, 0xbc9b1734U,
+  0x2affbe4dU, 0x4cedcb4cU, 0xfb14e99eU, 0x35e34212U, 0xece39c24U, 0x07673ab3U,
+  0xe73115ddU, 0xd15d38e7U, 0x093eed3bU, 0xf8e7eac5U, 0x78a8cc80U, 0x25227aacU,
+  0x3f590551U, 0x413da1cbU, 0xdf643a55U, 0xab65ad44U, 0xd70b23d7U, 0xc672cd76U,
+  0x3364ea62U, 0x0000086aU,
+// 5**459 (i=17), start=272, end=306
+  0x22f163ddU, 0x23cf07acU, 0xbe2af6c2U, 0xf412f6f6U, 0xc3ff541eU, 0x6eeaf7deU,
+  0xa47047e0U, 0x408cda92U, 0x0f0eeb08U, 0x56deba9dU, 0xcfc6b090U, 0x8bbbdf04U,
+  0x3933cdb3U, 0x9e7bb67dU, 0x9f297035U, 0x38946244U, 0xee1d37bbU, 0xde898174U,
+  0x63f3559dU, 0x705b72fbU, 0x138d27d9U, 0xf8603a78U, 0x735eec44U, 0xe30987d5U,
+  0xc6d38070U, 0x9cfe548eU, 0x9ff01422U, 0x7c564aa8U, 0x91cc60baU, 0xcbc3565dU,
+  0x7550a50bU, 0x6909aeadU, 0x13234c45U, 0x00000366U,
+// 5**486 (i=18), start=306, end=342
+  0x17954989U, 0x3a7d7709U, 0x98042de5U, 0xa9011443U, 0x45e723c2U, 0x269ffd6fU,
+  0x58852a46U, 0xaaa1042aU, 0x2eee8153U, 0xb2b6c39eU, 0xaf845b65U, 0xf6c365d7U,
+  0xe4cffb2bU, 0xc840e90cU, 0xabea8abbU, 0x5c58f8d2U, 0x5c19fa3aU, 0x4670910aU,
+  0x4449f21cU, 0xefa645b3U, 0xcc427decU, 0x083c3d73U, 0x467cb413U, 0x6fe10ae4U,
+  0x3caffc72U, 0x9f8da55eU, 0x5e5c8ea7U, 0x490594bbU, 0xf0871b0bU, 0xdd89816cU,
+  0x8e931df8U, 0xe85ce1c9U, 0xcca090a5U, 0x575fa16bU, 0x6b9f106cU, 0x0000015fU,
+// 5**513 (i=19), start=342, end=380
+  0xee20d805U, 0x57bc3c07U, 0xcdea624eU, 0xd3f0f52dU, 0x9924b4f4U, 0xcf968640U,
+  0x61d41962U, 0xe87fb464U, 0xeaaf51c7U, 0x564c8b60U, 0xccda4028U, 0x529428bbU,
+  0x313a1fa8U, 0x96bd0f94U, 0x7a82ebaaU, 0xad99e7e9U, 0xf2668cd4U, 0xbe33a45eU,
+  0xfd0db669U, 0x87ee369fU, 0xd3ec20edU, 0x9c4d7db7U, 0xdedcf0d8U, 0x7cd2ca64U,
+  0xe25a6577U, 0x61003fd4U, 0xe56f54ccU, 0x10b7c748U, 0x40526e5eU, 0x7300ae87U,
+  0x5c439261U, 0x2c0ff469U, 0xbf723f12U, 0xb2379b61U, 0xbf59b4f5U, 0xc91b1c3fU,
+  0xf0046d27U, 0x0000008dU,
+// 5**540 (i=20), start=380, end=420
+  0x525c9e11U, 0xf4e0eb41U, 0xebb2895dU, 0x5da512f9U, 0x7d9b29d4U, 0x452f4edcU,
+  0x0b90bc37U, 0x341777cbU, 0x63d269afU, 0x1da77929U, 0x0a5c1826U, 0x77991898U,
+  0x5aeddf86U, 0xf853a877U, 0x538c31ccU, 0xe84896daU, 0xb7a0010bU, 0x17ef4de5U,
+  0xa52a2adeU, 0x029fd81cU, 0x987ce701U, 0x27fefd77U, 0xdb46c66fU, 0x5d301900U,
+  0x496998c0U, 0xbb6598b9U, 0x5eebb607U, 0xe547354aU, 0xdf4a2f7eU, 0xf06c4955U,
+  0x96242ffaU, 0x1775fb27U, 0xbecc58ceU, 0xebf2a53bU, 0x3eaad82aU, 0xf41137baU,
+  0x573e6fbaU, 0xfb4866b8U, 0x54002148U, 0x00000039U,
+};
+// clang-format on
+
+// Returns a pointer to the big integer data for (5**27)**i.  i must be
+// between 1 and 20, inclusive.
+const uint32_t* LargePowerOfFiveData(int i) {
+  return kLargePowersOfFive + i * (i - 1);
+}
+
+// Returns the size of the big integer data for (5**27)**i, in words.  i must be
+// between 1 and 20, inclusive.
+int LargePowerOfFiveSize(int i) { return 2 * i; }
+}  // namespace
+
+ABSL_DLL const uint32_t kFiveToNth[14] = {
+    1,     5,      25,      125,     625,      3125,      15625,
+    78125, 390625, 1953125, 9765625, 48828125, 244140625, 1220703125,
+};
+
+ABSL_DLL const uint32_t kTenToNth[10] = {
+    1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000,
+};
+
+template <int max_words>
+int BigUnsigned<max_words>::ReadFloatMantissa(const ParsedFloat& fp,
+                                              int significant_digits) {
+  SetToZero();
+  assert(fp.type == FloatType::kNumber);
+
+  if (fp.subrange_begin == nullptr) {
+    // We already exactly parsed the mantissa, so no more work is necessary.
+    words_[0] = fp.mantissa & 0xffffffffu;
+    words_[1] = fp.mantissa >> 32;
+    if (words_[1]) {
+      size_ = 2;
+    } else if (words_[0]) {
+      size_ = 1;
+    }
+    return fp.exponent;
+  }
+  int exponent_adjust =
+      ReadDigits(fp.subrange_begin, fp.subrange_end, significant_digits);
+  return fp.literal_exponent + exponent_adjust;
+}
+
+template <int max_words>
+int BigUnsigned<max_words>::ReadDigits(const char* begin, const char* end,
+                                       int significant_digits) {
+  assert(significant_digits <= Digits10() + 1);
+  SetToZero();
+
+  bool after_decimal_point = false;
+  // Discard any leading zeroes before the decimal point
+  while (begin < end && *begin == '0') {
+    ++begin;
+  }
+  int dropped_digits = 0;
+  // Discard any trailing zeroes.  These may or may not be after the decimal
+  // point.
+  while (begin < end && *std::prev(end) == '0') {
+    --end;
+    ++dropped_digits;
+  }
+  if (begin < end && *std::prev(end) == '.') {
+    // If the string ends in '.', either before or after dropping zeroes, then
+    // drop the decimal point and look for more digits to drop.
+    dropped_digits = 0;
+    --end;
+    while (begin < end && *std::prev(end) == '0') {
+      --end;
+      ++dropped_digits;
+    }
+  } else if (dropped_digits) {
+    // We dropped digits, and aren't sure if they're before or after the decimal
+    // point.  Figure that out now.
+    const char* dp = std::find(begin, end, '.');
+    if (dp != end) {
+      // The dropped trailing digits were after the decimal point, so don't
+      // count them.
+      dropped_digits = 0;
+    }
+  }
+  // Any non-fraction digits we dropped need to be accounted for in our exponent
+  // adjustment.
+  int exponent_adjust = dropped_digits;
+
+  uint32_t queued = 0;
+  int digits_queued = 0;
+  for (; begin != end && significant_digits > 0; ++begin) {
+    if (*begin == '.') {
+      after_decimal_point = true;
+      continue;
+    }
+    if (after_decimal_point) {
+      // For each fractional digit we emit in our parsed integer, adjust our
+      // decimal exponent to compensate.
+      --exponent_adjust;
+    }
+    int digit = (*begin - '0');
+    --significant_digits;
+    if (significant_digits == 0 && std::next(begin) != end &&
+        (digit == 0 || digit == 5)) {
+      // If this is the very last significant digit, but insignificant digits
+      // remain, we know that the last of those remaining significant digits is
+      // nonzero.  (If it wasn't, we would have stripped it before we got here.)
+      // So if this final digit is a 0 or 5, adjust it upward by 1.
+      //
+      // This adjustment is what allows incredibly large mantissas ending in
+      // 500000...000000000001 to correctly round up, rather than to nearest.
+      ++digit;
+    }
+    queued = 10 * queued + digit;
+    ++digits_queued;
+    if (digits_queued == kMaxSmallPowerOfTen) {
+      MultiplyBy(kTenToNth[kMaxSmallPowerOfTen]);
+      AddWithCarry(0, queued);
+      queued = digits_queued = 0;
+    }
+  }
+  // Encode any remaining digits.
+  if (digits_queued) {
+    MultiplyBy(kTenToNth[digits_queued]);
+    AddWithCarry(0, queued);
+  }
+
+  // If any insignificant digits remain, we will drop them.  But if we have not
+  // yet read the decimal point, then we have to adjust the exponent to account
+  // for the dropped digits.
+  if (begin < end && !after_decimal_point) {
+    // This call to std::find will result in a pointer either to the decimal
+    // point, or to the end of our buffer if there was none.
+    //
+    // Either way, [begin, decimal_point) will contain the set of dropped digits
+    // that require an exponent adjustment.
+    const char* decimal_point = std::find(begin, end, '.');
+    exponent_adjust += (decimal_point - begin);
+  }
+  return exponent_adjust;
+}
+
+template <int max_words>
+/* static */ BigUnsigned<max_words> BigUnsigned<max_words>::FiveToTheNth(
+    int n) {
+  BigUnsigned answer(1u);
+
+  // Seed from the table of large powers, if possible.
+  bool first_pass = true;
+  while (n >= kLargePowerOfFiveStep) {
+    int big_power =
+        std::min(n / kLargePowerOfFiveStep, kLargestPowerOfFiveIndex);
+    if (first_pass) {
+      // just copy, rather than multiplying by 1
+      std::copy(
+          LargePowerOfFiveData(big_power),
+          LargePowerOfFiveData(big_power) + LargePowerOfFiveSize(big_power),
+          answer.words_);
+      answer.size_ = LargePowerOfFiveSize(big_power);
+      first_pass = false;
+    } else {
+      answer.MultiplyBy(LargePowerOfFiveSize(big_power),
+                        LargePowerOfFiveData(big_power));
+    }
+    n -= kLargePowerOfFiveStep * big_power;
+  }
+  answer.MultiplyByFiveToTheNth(n);
+  return answer;
+}
+
+template <int max_words>
+void BigUnsigned<max_words>::MultiplyStep(int original_size,
+                                          const uint32_t* other_words,
+                                          int other_size, int step) {
+  int this_i = std::min(original_size - 1, step);
+  int other_i = step - this_i;
+
+  uint64_t this_word = 0;
+  uint64_t carry = 0;
+  for (; this_i >= 0 && other_i < other_size; --this_i, ++other_i) {
+    uint64_t product = words_[this_i];
+    product *= other_words[other_i];
+    this_word += product;
+    carry += (this_word >> 32);
+    this_word &= 0xffffffff;
+  }
+  AddWithCarry(step + 1, carry);
+  words_[step] = this_word & 0xffffffff;
+  if (this_word > 0 && size_ <= step) {
+    size_ = step + 1;
+  }
+}
+
+template <int max_words>
+std::string BigUnsigned<max_words>::ToString() const {
+  BigUnsigned<max_words> copy = *this;
+  std::string result;
+  // Build result in reverse order
+  while (copy.size() > 0) {
+    int next_digit = copy.DivMod<10>();
+    result.push_back('0' + next_digit);
+  }
+  if (result.empty()) {
+    result.push_back('0');
+  }
+  std::reverse(result.begin(), result.end());
+  return result;
+}
+
+template class BigUnsigned<4>;
+template class BigUnsigned<84>;
+
+}  // namespace strings_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
diff --git a/src/absl/strings/internal/charconv_bigint.h b/src/absl/strings/internal/charconv_bigint.h
new file mode 100644 (file)
index 0000000..8f70297
--- /dev/null
@@ -0,0 +1,423 @@
+// Copyright 2018 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef ABSL_STRINGS_INTERNAL_CHARCONV_BIGINT_H_
+#define ABSL_STRINGS_INTERNAL_CHARCONV_BIGINT_H_
+
+#include <algorithm>
+#include <cstdint>
+#include <iostream>
+#include <string>
+
+#include "absl/base/config.h"
+#include "absl/strings/ascii.h"
+#include "absl/strings/internal/charconv_parse.h"
+#include "absl/strings/string_view.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace strings_internal {
+
+// The largest power that 5 that can be raised to, and still fit in a uint32_t.
+constexpr int kMaxSmallPowerOfFive = 13;
+// The largest power that 10 that can be raised to, and still fit in a uint32_t.
+constexpr int kMaxSmallPowerOfTen = 9;
+
+ABSL_DLL extern const uint32_t
+    kFiveToNth[kMaxSmallPowerOfFive + 1];
+ABSL_DLL extern const uint32_t kTenToNth[kMaxSmallPowerOfTen + 1];
+
+// Large, fixed-width unsigned integer.
+//
+// Exact rounding for decimal-to-binary floating point conversion requires very
+// large integer math, but a design goal of absl::from_chars is to avoid
+// allocating memory.  The integer precision needed for decimal-to-binary
+// conversions is large but bounded, so a huge fixed-width integer class
+// suffices.
+//
+// This is an intentionally limited big integer class.  Only needed operations
+// are implemented.  All storage lives in an array data member, and all
+// arithmetic is done in-place, to avoid requiring separate storage for operand
+// and result.
+//
+// This is an internal class.  Some methods live in the .cc file, and are
+// instantiated only for the values of max_words we need.
+template <int max_words>
+class BigUnsigned {
+ public:
+  static_assert(max_words == 4 || max_words == 84,
+                "unsupported max_words value");
+
+  BigUnsigned() : size_(0), words_{} {}
+  explicit constexpr BigUnsigned(uint64_t v)
+      : size_((v >> 32) ? 2 : v ? 1 : 0),
+        words_{static_cast<uint32_t>(v & 0xffffffffu),
+               static_cast<uint32_t>(v >> 32)} {}
+
+  // Constructs a BigUnsigned from the given string_view containing a decimal
+  // value.  If the input string is not a decimal integer, constructs a 0
+  // instead.
+  explicit BigUnsigned(absl::string_view sv) : size_(0), words_{} {
+    // Check for valid input, returning a 0 otherwise.  This is reasonable
+    // behavior only because this constructor is for unit tests.
+    if (std::find_if_not(sv.begin(), sv.end(), ascii_isdigit) != sv.end() ||
+        sv.empty()) {
+      return;
+    }
+    int exponent_adjust =
+        ReadDigits(sv.data(), sv.data() + sv.size(), Digits10() + 1);
+    if (exponent_adjust > 0) {
+      MultiplyByTenToTheNth(exponent_adjust);
+    }
+  }
+
+  // Loads the mantissa value of a previously-parsed float.
+  //
+  // Returns the associated decimal exponent.  The value of the parsed float is
+  // exactly *this * 10**exponent.
+  int ReadFloatMantissa(const ParsedFloat& fp, int significant_digits);
+
+  // Returns the number of decimal digits of precision this type provides.  All
+  // numbers with this many decimal digits or fewer are representable by this
+  // type.
+  //
+  // Analagous to std::numeric_limits<BigUnsigned>::digits10.
+  static constexpr int Digits10() {
+    // 9975007/1035508 is very slightly less than log10(2**32).
+    return static_cast<uint64_t>(max_words) * 9975007 / 1035508;
+  }
+
+  // Shifts left by the given number of bits.
+  void ShiftLeft(int count) {
+    if (count > 0) {
+      const int word_shift = count / 32;
+      if (word_shift >= max_words) {
+        SetToZero();
+        return;
+      }
+      size_ = (std::min)(size_ + word_shift, max_words);
+      count %= 32;
+      if (count == 0) {
+        std::copy_backward(words_, words_ + size_ - word_shift, words_ + size_);
+      } else {
+        for (int i = (std::min)(size_, max_words - 1); i > word_shift; --i) {
+          words_[i] = (words_[i - word_shift] << count) |
+                      (words_[i - word_shift - 1] >> (32 - count));
+        }
+        words_[word_shift] = words_[0] << count;
+        // Grow size_ if necessary.
+        if (size_ < max_words && words_[size_]) {
+          ++size_;
+        }
+      }
+      std::fill(words_, words_ + word_shift, 0u);
+    }
+  }
+
+
+  // Multiplies by v in-place.
+  void MultiplyBy(uint32_t v) {
+    if (size_ == 0 || v == 1) {
+      return;
+    }
+    if (v == 0) {
+      SetToZero();
+      return;
+    }
+    const uint64_t factor = v;
+    uint64_t window = 0;
+    for (int i = 0; i < size_; ++i) {
+      window += factor * words_[i];
+      words_[i] = window & 0xffffffff;
+      window >>= 32;
+    }
+    // If carry bits remain and there's space for them, grow size_.
+    if (window && size_ < max_words) {
+      words_[size_] = window & 0xffffffff;
+      ++size_;
+    }
+  }
+
+  void MultiplyBy(uint64_t v) {
+    uint32_t words[2];
+    words[0] = static_cast<uint32_t>(v);
+    words[1] = static_cast<uint32_t>(v >> 32);
+    if (words[1] == 0) {
+      MultiplyBy(words[0]);
+    } else {
+      MultiplyBy(2, words);
+    }
+  }
+
+  // Multiplies in place by 5 to the power of n.  n must be non-negative.
+  void MultiplyByFiveToTheNth(int n) {
+    while (n >= kMaxSmallPowerOfFive) {
+      MultiplyBy(kFiveToNth[kMaxSmallPowerOfFive]);
+      n -= kMaxSmallPowerOfFive;
+    }
+    if (n > 0) {
+      MultiplyBy(kFiveToNth[n]);
+    }
+  }
+
+  // Multiplies in place by 10 to the power of n.  n must be non-negative.
+  void MultiplyByTenToTheNth(int n) {
+    if (n > kMaxSmallPowerOfTen) {
+      // For large n, raise to a power of 5, then shift left by the same amount.
+      // (10**n == 5**n * 2**n.)  This requires fewer multiplications overall.
+      MultiplyByFiveToTheNth(n);
+      ShiftLeft(n);
+    } else if (n > 0) {
+      // We can do this more quickly for very small N by using a single
+      // multiplication.
+      MultiplyBy(kTenToNth[n]);
+    }
+  }
+
+  // Returns the value of 5**n, for non-negative n.  This implementation uses
+  // a lookup table, and is faster then seeding a BigUnsigned with 1 and calling
+  // MultiplyByFiveToTheNth().
+  static BigUnsigned FiveToTheNth(int n);
+
+  // Multiplies by another BigUnsigned, in-place.
+  template <int M>
+  void MultiplyBy(const BigUnsigned<M>& other) {
+    MultiplyBy(other.size(), other.words());
+  }
+
+  void SetToZero() {
+    std::fill(words_, words_ + size_, 0u);
+    size_ = 0;
+  }
+
+  // Returns the value of the nth word of this BigUnsigned.  This is
+  // range-checked, and returns 0 on out-of-bounds accesses.
+  uint32_t GetWord(int index) const {
+    if (index < 0 || index >= size_) {
+      return 0;
+    }
+    return words_[index];
+  }
+
+  // Returns this integer as a decimal string.  This is not used in the decimal-
+  // to-binary conversion; it is intended to aid in testing.
+  std::string ToString() const;
+
+  int size() const { return size_; }
+  const uint32_t* words() const { return words_; }
+
+ private:
+  // Reads the number between [begin, end), possibly containing a decimal point,
+  // into this BigUnsigned.
+  //
+  // Callers are required to ensure [begin, end) contains a valid number, with
+  // one or more decimal digits and at most one decimal point.  This routine
+  // will behave unpredictably if these preconditions are not met.
+  //
+  // Only the first `significant_digits` digits are read.  Digits beyond this
+  // limit are "sticky": If the final significant digit is 0 or 5, and if any
+  // dropped digit is nonzero, then that final significant digit is adjusted up
+  // to 1 or 6.  This adjustment allows for precise rounding.
+  //
+  // Returns `exponent_adjustment`, a power-of-ten exponent adjustment to
+  // account for the decimal point and for dropped significant digits.  After
+  // this function returns,
+  //   actual_value_of_parsed_string ~= *this * 10**exponent_adjustment.
+  int ReadDigits(const char* begin, const char* end, int significant_digits);
+
+  // Performs a step of big integer multiplication.  This computes the full
+  // (64-bit-wide) values that should be added at the given index (step), and
+  // adds to that location in-place.
+  //
+  // Because our math all occurs in place, we must multiply starting from the
+  // highest word working downward.  (This is a bit more expensive due to the
+  // extra carries involved.)
+  //
+  // This must be called in steps, for each word to be calculated, starting from
+  // the high end and working down to 0.  The first value of `step` should be
+  //   `std::min(original_size + other.size_ - 2, max_words - 1)`.
+  // The reason for this expression is that multiplying the i'th word from one
+  // multiplicand and the j'th word of another multiplicand creates a
+  // two-word-wide value to be stored at the (i+j)'th element.  The highest
+  // word indices we will access are `original_size - 1` from this object, and
+  // `other.size_ - 1` from our operand.  Therefore,
+  // `original_size + other.size_ - 2` is the first step we should calculate,
+  // but limited on an upper bound by max_words.
+
+  // Working from high-to-low ensures that we do not overwrite the portions of
+  // the initial value of *this which are still needed for later steps.
+  //
+  // Once called with step == 0, *this contains the result of the
+  // multiplication.
+  //
+  // `original_size` is the size_ of *this before the first call to
+  // MultiplyStep().  `other_words` and `other_size` are the contents of our
+  // operand.  `step` is the step to perform, as described above.
+  void MultiplyStep(int original_size, const uint32_t* other_words,
+                    int other_size, int step);
+
+  void MultiplyBy(int other_size, const uint32_t* other_words) {
+    const int original_size = size_;
+    const int first_step =
+        (std::min)(original_size + other_size - 2, max_words - 1);
+    for (int step = first_step; step >= 0; --step) {
+      MultiplyStep(original_size, other_words, other_size, step);
+    }
+  }
+
+  // Adds a 32-bit value to the index'th word, with carry.
+  void AddWithCarry(int index, uint32_t value) {
+    if (value) {
+      while (index < max_words && value > 0) {
+        words_[index] += value;
+        // carry if we overflowed in this word:
+        if (value > words_[index]) {
+          value = 1;
+          ++index;
+        } else {
+          value = 0;
+        }
+      }
+      size_ = (std::min)(max_words, (std::max)(index + 1, size_));
+    }
+  }
+
+  void AddWithCarry(int index, uint64_t value) {
+    if (value && index < max_words) {
+      uint32_t high = value >> 32;
+      uint32_t low = value & 0xffffffff;
+      words_[index] += low;
+      if (words_[index] < low) {
+        ++high;
+        if (high == 0) {
+          // Carry from the low word caused our high word to overflow.
+          // Short circuit here to do the right thing.
+          AddWithCarry(index + 2, static_cast<uint32_t>(1));
+          return;
+        }
+      }
+      if (high > 0) {
+        AddWithCarry(index + 1, high);
+      } else {
+        // Normally 32-bit AddWithCarry() sets size_, but since we don't call
+        // it when `high` is 0, do it ourselves here.
+        size_ = (std::min)(max_words, (std::max)(index + 1, size_));
+      }
+    }
+  }
+
+  // Divide this in place by a constant divisor.  Returns the remainder of the
+  // division.
+  template <uint32_t divisor>
+  uint32_t DivMod() {
+    uint64_t accumulator = 0;
+    for (int i = size_ - 1; i >= 0; --i) {
+      accumulator <<= 32;
+      accumulator += words_[i];
+      // accumulator / divisor will never overflow an int32_t in this loop
+      words_[i] = static_cast<uint32_t>(accumulator / divisor);
+      accumulator = accumulator % divisor;
+    }
+    while (size_ > 0 && words_[size_ - 1] == 0) {
+      --size_;
+    }
+    return static_cast<uint32_t>(accumulator);
+  }
+
+  // The number of elements in words_ that may carry significant values.
+  // All elements beyond this point are 0.
+  //
+  // When size_ is 0, this BigUnsigned stores the value 0.
+  // When size_ is nonzero, is *not* guaranteed that words_[size_ - 1] is
+  // nonzero.  This can occur due to overflow truncation.
+  // In particular, x.size_ != y.size_ does *not* imply x != y.
+  int size_;
+  uint32_t words_[max_words];
+};
+
+// Compares two big integer instances.
+//
+// Returns -1 if lhs < rhs, 0 if lhs == rhs, and 1 if lhs > rhs.
+template <int N, int M>
+int Compare(const BigUnsigned<N>& lhs, const BigUnsigned<M>& rhs) {
+  int limit = (std::max)(lhs.size(), rhs.size());
+  for (int i = limit - 1; i >= 0; --i) {
+    const uint32_t lhs_word = lhs.GetWord(i);
+    const uint32_t rhs_word = rhs.GetWord(i);
+    if (lhs_word < rhs_word) {
+      return -1;
+    } else if (lhs_word > rhs_word) {
+      return 1;
+    }
+  }
+  return 0;
+}
+
+template <int N, int M>
+bool operator==(const BigUnsigned<N>& lhs, const BigUnsigned<M>& rhs) {
+  int limit = (std::max)(lhs.size(), rhs.size());
+  for (int i = 0; i < limit; ++i) {
+    if (lhs.GetWord(i) != rhs.GetWord(i)) {
+      return false;
+    }
+  }
+  return true;
+}
+
+template <int N, int M>
+bool operator!=(const BigUnsigned<N>& lhs, const BigUnsigned<M>& rhs) {
+  return !(lhs == rhs);
+}
+
+template <int N, int M>
+bool operator<(const BigUnsigned<N>& lhs, const BigUnsigned<M>& rhs) {
+  return Compare(lhs, rhs) == -1;
+}
+
+template <int N, int M>
+bool operator>(const BigUnsigned<N>& lhs, const BigUnsigned<M>& rhs) {
+  return rhs < lhs;
+}
+template <int N, int M>
+bool operator<=(const BigUnsigned<N>& lhs, const BigUnsigned<M>& rhs) {
+  return !(rhs < lhs);
+}
+template <int N, int M>
+bool operator>=(const BigUnsigned<N>& lhs, const BigUnsigned<M>& rhs) {
+  return !(lhs < rhs);
+}
+
+// Output operator for BigUnsigned, for testing purposes only.
+template <int N>
+std::ostream& operator<<(std::ostream& os, const BigUnsigned<N>& num) {
+  return os << num.ToString();
+}
+
+// Explicit instantiation declarations for the sizes of BigUnsigned that we
+// are using.
+//
+// For now, the choices of 4 and 84 are arbitrary; 4 is a small value that is
+// still bigger than an int128, and 84 is a large value we will want to use
+// in the from_chars implementation.
+//
+// Comments justifying the use of 84 belong in the from_chars implementation,
+// and will be added in a follow-up CL.
+extern template class BigUnsigned<4>;
+extern template class BigUnsigned<84>;
+
+}  // namespace strings_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#endif  // ABSL_STRINGS_INTERNAL_CHARCONV_BIGINT_H_
diff --git a/src/absl/strings/internal/charconv_parse.cc b/src/absl/strings/internal/charconv_parse.cc
new file mode 100644 (file)
index 0000000..8b11868
--- /dev/null
@@ -0,0 +1,504 @@
+// Copyright 2018 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "absl/strings/internal/charconv_parse.h"
+#include "absl/strings/charconv.h"
+
+#include <cassert>
+#include <cstdint>
+#include <limits>
+
+#include "absl/strings/internal/memutil.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace {
+
+// ParseFloat<10> will read the first 19 significant digits of the mantissa.
+// This number was chosen for multiple reasons.
+//
+// (a) First, for whatever integer type we choose to represent the mantissa, we
+// want to choose the largest possible number of decimal digits for that integer
+// type.  We are using uint64_t, which can express any 19-digit unsigned
+// integer.
+//
+// (b) Second, we need to parse enough digits that the binary value of any
+// mantissa we capture has more bits of resolution than the mantissa
+// representation in the target float.  Our algorithm requires at least 3 bits
+// of headway, but 19 decimal digits give a little more than that.
+//
+// The following static assertions verify the above comments:
+constexpr int kDecimalMantissaDigitsMax = 19;
+
+static_assert(std::numeric_limits<uint64_t>::digits10 ==
+                  kDecimalMantissaDigitsMax,
+              "(a) above");
+
+// IEEE doubles, which we assume in Abseil, have 53 binary bits of mantissa.
+static_assert(std::numeric_limits<double>::is_iec559, "IEEE double assumed");
+static_assert(std::numeric_limits<double>::radix == 2, "IEEE double fact");
+static_assert(std::numeric_limits<double>::digits == 53, "IEEE double fact");
+
+// The lowest valued 19-digit decimal mantissa we can read still contains
+// sufficient information to reconstruct a binary mantissa.
+static_assert(1000000000000000000u > (uint64_t(1) << (53 + 3)), "(b) above");
+
+// ParseFloat<16> will read the first 15 significant digits of the mantissa.
+//
+// Because a base-16-to-base-2 conversion can be done exactly, we do not need
+// to maximize the number of scanned hex digits to improve our conversion.  What
+// is required is to scan two more bits than the mantissa can represent, so that
+// we always round correctly.
+//
+// (One extra bit does not suffice to perform correct rounding, since a number
+// exactly halfway between two representable floats has unique rounding rules,
+// so we need to differentiate between a "halfway between" number and a "closer
+// to the larger value" number.)
+constexpr int kHexadecimalMantissaDigitsMax = 15;
+
+// The minimum number of significant bits that will be read from
+// kHexadecimalMantissaDigitsMax hex digits.  We must subtract by three, since
+// the most significant digit can be a "1", which only contributes a single
+// significant bit.
+constexpr int kGuaranteedHexadecimalMantissaBitPrecision =
+    4 * kHexadecimalMantissaDigitsMax - 3;
+
+static_assert(kGuaranteedHexadecimalMantissaBitPrecision >
+                  std::numeric_limits<double>::digits + 2,
+              "kHexadecimalMantissaDigitsMax too small");
+
+// We also impose a limit on the number of significant digits we will read from
+// an exponent, to avoid having to deal with integer overflow.  We use 9 for
+// this purpose.
+//
+// If we read a 9 digit exponent, the end result of the conversion will
+// necessarily be infinity or zero, depending on the sign of the exponent.
+// Therefore we can just drop extra digits on the floor without any extra
+// logic.
+constexpr int kDecimalExponentDigitsMax = 9;
+static_assert(std::numeric_limits<int>::digits10 >= kDecimalExponentDigitsMax,
+              "int type too small");
+
+// To avoid incredibly large inputs causing integer overflow for our exponent,
+// we impose an arbitrary but very large limit on the number of significant
+// digits we will accept.  The implementation refuses to match a string with
+// more consecutive significant mantissa digits than this.
+constexpr int kDecimalDigitLimit = 50000000;
+
+// Corresponding limit for hexadecimal digit inputs.  This is one fourth the
+// amount of kDecimalDigitLimit, since each dropped hexadecimal digit requires
+// a binary exponent adjustment of 4.
+constexpr int kHexadecimalDigitLimit = kDecimalDigitLimit / 4;
+
+// The largest exponent we can read is 999999999 (per
+// kDecimalExponentDigitsMax), and the largest exponent adjustment we can get
+// from dropped mantissa digits is 2 * kDecimalDigitLimit, and the sum of these
+// comfortably fits in an integer.
+//
+// We count kDecimalDigitLimit twice because there are independent limits for
+// numbers before and after the decimal point.  (In the case where there are no
+// significant digits before the decimal point, there are independent limits for
+// post-decimal-point leading zeroes and for significant digits.)
+static_assert(999999999 + 2 * kDecimalDigitLimit <
+                  std::numeric_limits<int>::max(),
+              "int type too small");
+static_assert(999999999 + 2 * (4 * kHexadecimalDigitLimit) <
+                  std::numeric_limits<int>::max(),
+              "int type too small");
+
+// Returns true if the provided bitfield allows parsing an exponent value
+// (e.g., "1.5e100").
+bool AllowExponent(chars_format flags) {
+  bool fixed = (flags & chars_format::fixed) == chars_format::fixed;
+  bool scientific =
+      (flags & chars_format::scientific) == chars_format::scientific;
+  return scientific || !fixed;
+}
+
+// Returns true if the provided bitfield requires an exponent value be present.
+bool RequireExponent(chars_format flags) {
+  bool fixed = (flags & chars_format::fixed) == chars_format::fixed;
+  bool scientific =
+      (flags & chars_format::scientific) == chars_format::scientific;
+  return scientific && !fixed;
+}
+
+const int8_t kAsciiToInt[256] = {
+    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0,  1,  2,  3,  4,  5,  6,  7,  8,
+    9,  -1, -1, -1, -1, -1, -1, -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1,
+    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+    -1, -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+    -1, -1, -1, -1, -1, -1, -1, -1, -1};
+
+// Returns true if `ch` is a digit in the given base
+template <int base>
+bool IsDigit(char ch);
+
+// Converts a valid `ch` to its digit value in the given base.
+template <int base>
+unsigned ToDigit(char ch);
+
+// Returns true if `ch` is the exponent delimiter for the given base.
+template <int base>
+bool IsExponentCharacter(char ch);
+
+// Returns the maximum number of significant digits we will read for a float
+// in the given base.
+template <int base>
+constexpr int MantissaDigitsMax();
+
+// Returns the largest consecutive run of digits we will accept when parsing a
+// number in the given base.
+template <int base>
+constexpr int DigitLimit();
+
+// Returns the amount the exponent must be adjusted by for each dropped digit.
+// (For decimal this is 1, since the digits are in base 10 and the exponent base
+// is also 10, but for hexadecimal this is 4, since the digits are base 16 but
+// the exponent base is 2.)
+template <int base>
+constexpr int DigitMagnitude();
+
+template <>
+bool IsDigit<10>(char ch) {
+  return ch >= '0' && ch <= '9';
+}
+template <>
+bool IsDigit<16>(char ch) {
+  return kAsciiToInt[static_cast<unsigned char>(ch)] >= 0;
+}
+
+template <>
+unsigned ToDigit<10>(char ch) {
+  return ch - '0';
+}
+template <>
+unsigned ToDigit<16>(char ch) {
+  return kAsciiToInt[static_cast<unsigned char>(ch)];
+}
+
+template <>
+bool IsExponentCharacter<10>(char ch) {
+  return ch == 'e' || ch == 'E';
+}
+
+template <>
+bool IsExponentCharacter<16>(char ch) {
+  return ch == 'p' || ch == 'P';
+}
+
+template <>
+constexpr int MantissaDigitsMax<10>() {
+  return kDecimalMantissaDigitsMax;
+}
+template <>
+constexpr int MantissaDigitsMax<16>() {
+  return kHexadecimalMantissaDigitsMax;
+}
+
+template <>
+constexpr int DigitLimit<10>() {
+  return kDecimalDigitLimit;
+}
+template <>
+constexpr int DigitLimit<16>() {
+  return kHexadecimalDigitLimit;
+}
+
+template <>
+constexpr int DigitMagnitude<10>() {
+  return 1;
+}
+template <>
+constexpr int DigitMagnitude<16>() {
+  return 4;
+}
+
+// Reads decimal digits from [begin, end) into *out.  Returns the number of
+// digits consumed.
+//
+// After max_digits has been read, keeps consuming characters, but no longer
+// adjusts *out.  If a nonzero digit is dropped this way, *dropped_nonzero_digit
+// is set; otherwise, it is left unmodified.
+//
+// If no digits are matched, returns 0 and leaves *out unchanged.
+//
+// ConsumeDigits does not protect against overflow on *out; max_digits must
+// be chosen with respect to type T to avoid the possibility of overflow.
+template <int base, typename T>
+int ConsumeDigits(const char* begin, const char* end, int max_digits, T* out,
+                  bool* dropped_nonzero_digit) {
+  if (base == 10) {
+    assert(max_digits <= std::numeric_limits<T>::digits10);
+  } else if (base == 16) {
+    assert(max_digits * 4 <= std::numeric_limits<T>::digits);
+  }
+  const char* const original_begin = begin;
+
+  // Skip leading zeros, but only if *out is zero.
+  // They don't cause an overflow so we don't have to count them for
+  // `max_digits`.
+  while (!*out && end != begin && *begin == '0') ++begin;
+
+  T accumulator = *out;
+  const char* significant_digits_end =
+      (end - begin > max_digits) ? begin + max_digits : end;
+  while (begin < significant_digits_end && IsDigit<base>(*begin)) {
+    // Do not guard against *out overflow; max_digits was chosen to avoid this.
+    // Do assert against it, to detect problems in debug builds.
+    auto digit = static_cast<T>(ToDigit<base>(*begin));
+    assert(accumulator * base >= accumulator);
+    accumulator *= base;
+    assert(accumulator + digit >= accumulator);
+    accumulator += digit;
+    ++begin;
+  }
+  bool dropped_nonzero = false;
+  while (begin < end && IsDigit<base>(*begin)) {
+    dropped_nonzero = dropped_nonzero || (*begin != '0');
+    ++begin;
+  }
+  if (dropped_nonzero && dropped_nonzero_digit != nullptr) {
+    *dropped_nonzero_digit = true;
+  }
+  *out = accumulator;
+  return static_cast<int>(begin - original_begin);
+}
+
+// Returns true if `v` is one of the chars allowed inside parentheses following
+// a NaN.
+bool IsNanChar(char v) {
+  return (v == '_') || (v >= '0' && v <= '9') || (v >= 'a' && v <= 'z') ||
+         (v >= 'A' && v <= 'Z');
+}
+
+// Checks the range [begin, end) for a strtod()-formatted infinity or NaN.  If
+// one is found, sets `out` appropriately and returns true.
+bool ParseInfinityOrNan(const char* begin, const char* end,
+                        strings_internal::ParsedFloat* out) {
+  if (end - begin < 3) {
+    return false;
+  }
+  switch (*begin) {
+    case 'i':
+    case 'I': {
+      // An infinity string consists of the characters "inf" or "infinity",
+      // case insensitive.
+      if (strings_internal::memcasecmp(begin + 1, "nf", 2) != 0) {
+        return false;
+      }
+      out->type = strings_internal::FloatType::kInfinity;
+      if (end - begin >= 8 &&
+          strings_internal::memcasecmp(begin + 3, "inity", 5) == 0) {
+        out->end = begin + 8;
+      } else {
+        out->end = begin + 3;
+      }
+      return true;
+    }
+    case 'n':
+    case 'N': {
+      // A NaN consists of the characters "nan", case insensitive, optionally
+      // followed by a parenthesized sequence of zero or more alphanumeric
+      // characters and/or underscores.
+      if (strings_internal::memcasecmp(begin + 1, "an", 2) != 0) {
+        return false;
+      }
+      out->type = strings_internal::FloatType::kNan;
+      out->end = begin + 3;
+      // NaN is allowed to be followed by a parenthesized string, consisting of
+      // only the characters [a-zA-Z0-9_].  Match that if it's present.
+      begin += 3;
+      if (begin < end && *begin == '(') {
+        const char* nan_begin = begin + 1;
+        while (nan_begin < end && IsNanChar(*nan_begin)) {
+          ++nan_begin;
+        }
+        if (nan_begin < end && *nan_begin == ')') {
+          // We found an extra NaN specifier range
+          out->subrange_begin = begin + 1;
+          out->subrange_end = nan_begin;
+          out->end = nan_begin + 1;
+        }
+      }
+      return true;
+    }
+    default:
+      return false;
+  }
+}
+}  // namespace
+
+namespace strings_internal {
+
+template <int base>
+strings_internal::ParsedFloat ParseFloat(const char* begin, const char* end,
+                                         chars_format format_flags) {
+  strings_internal::ParsedFloat result;
+
+  // Exit early if we're given an empty range.
+  if (begin == end) return result;
+
+  // Handle the infinity and NaN cases.
+  if (ParseInfinityOrNan(begin, end, &result)) {
+    return result;
+  }
+
+  const char* const mantissa_begin = begin;
+  while (begin < end && *begin == '0') {
+    ++begin;  // skip leading zeros
+  }
+  uint64_t mantissa = 0;
+
+  int exponent_adjustment = 0;
+  bool mantissa_is_inexact = false;
+  int pre_decimal_digits = ConsumeDigits<base>(
+      begin, end, MantissaDigitsMax<base>(), &mantissa, &mantissa_is_inexact);
+  begin += pre_decimal_digits;
+  int digits_left;
+  if (pre_decimal_digits >= DigitLimit<base>()) {
+    // refuse to parse pathological inputs
+    return result;
+  } else if (pre_decimal_digits > MantissaDigitsMax<base>()) {
+    // We dropped some non-fraction digits on the floor.  Adjust our exponent
+    // to compensate.
+    exponent_adjustment =
+        static_cast<int>(pre_decimal_digits - MantissaDigitsMax<base>());
+    digits_left = 0;
+  } else {
+    digits_left =
+        static_cast<int>(MantissaDigitsMax<base>() - pre_decimal_digits);
+  }
+  if (begin < end && *begin == '.') {
+    ++begin;
+    if (mantissa == 0) {
+      // If we haven't seen any nonzero digits yet, keep skipping zeros.  We
+      // have to adjust the exponent to reflect the changed place value.
+      const char* begin_zeros = begin;
+      while (begin < end && *begin == '0') {
+        ++begin;
+      }
+      int zeros_skipped = static_cast<int>(begin - begin_zeros);
+      if (zeros_skipped >= DigitLimit<base>()) {
+        // refuse to parse pathological inputs
+        return result;
+      }
+      exponent_adjustment -= static_cast<int>(zeros_skipped);
+    }
+    int post_decimal_digits = ConsumeDigits<base>(
+        begin, end, digits_left, &mantissa, &mantissa_is_inexact);
+    begin += post_decimal_digits;
+
+    // Since `mantissa` is an integer, each significant digit we read after
+    // the decimal point requires an adjustment to the exponent. "1.23e0" will
+    // be stored as `mantissa` == 123 and `exponent` == -2 (that is,
+    // "123e-2").
+    if (post_decimal_digits >= DigitLimit<base>()) {
+      // refuse to parse pathological inputs
+      return result;
+    } else if (post_decimal_digits > digits_left) {
+      exponent_adjustment -= digits_left;
+    } else {
+      exponent_adjustment -= post_decimal_digits;
+    }
+  }
+  // If we've found no mantissa whatsoever, this isn't a number.
+  if (mantissa_begin == begin) {
+    return result;
+  }
+  // A bare "." doesn't count as a mantissa either.
+  if (begin - mantissa_begin == 1 && *mantissa_begin == '.') {
+    return result;
+  }
+
+  if (mantissa_is_inexact) {
+    // We dropped significant digits on the floor.  Handle this appropriately.
+    if (base == 10) {
+      // If we truncated significant decimal digits, store the full range of the
+      // mantissa for future big integer math for exact rounding.
+      result.subrange_begin = mantissa_begin;
+      result.subrange_end = begin;
+    } else if (base == 16) {
+      // If we truncated hex digits, reflect this fact by setting the low
+      // ("sticky") bit.  This allows for correct rounding in all cases.
+      mantissa |= 1;
+    }
+  }
+  result.mantissa = mantissa;
+
+  const char* const exponent_begin = begin;
+  result.literal_exponent = 0;
+  bool found_exponent = false;
+  if (AllowExponent(format_flags) && begin < end &&
+      IsExponentCharacter<base>(*begin)) {
+    bool negative_exponent = false;
+    ++begin;
+    if (begin < end && *begin == '-') {
+      negative_exponent = true;
+      ++begin;
+    } else if (begin < end && *begin == '+') {
+      ++begin;
+    }
+    const char* const exponent_digits_begin = begin;
+    // Exponent is always expressed in decimal, even for hexadecimal floats.
+    begin += ConsumeDigits<10>(begin, end, kDecimalExponentDigitsMax,
+                               &result.literal_exponent, nullptr);
+    if (begin == exponent_digits_begin) {
+      // there were no digits where we expected an exponent.  We failed to read
+      // an exponent and should not consume the 'e' after all.  Rewind 'begin'.
+      found_exponent = false;
+      begin = exponent_begin;
+    } else {
+      found_exponent = true;
+      if (negative_exponent) {
+        result.literal_exponent = -result.literal_exponent;
+      }
+    }
+  }
+
+  if (!found_exponent && RequireExponent(format_flags)) {
+    // Provided flags required an exponent, but none was found.  This results
+    // in a failure to scan.
+    return result;
+  }
+
+  // Success!
+  result.type = strings_internal::FloatType::kNumber;
+  if (result.mantissa > 0) {
+    result.exponent = result.literal_exponent +
+                      (DigitMagnitude<base>() * exponent_adjustment);
+  } else {
+    result.exponent = 0;
+  }
+  result.end = begin;
+  return result;
+}
+
+template ParsedFloat ParseFloat<10>(const char* begin, const char* end,
+                                    chars_format format_flags);
+template ParsedFloat ParseFloat<16>(const char* begin, const char* end,
+                                    chars_format format_flags);
+
+}  // namespace strings_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
diff --git a/src/absl/strings/internal/charconv_parse.h b/src/absl/strings/internal/charconv_parse.h
new file mode 100644 (file)
index 0000000..505998b
--- /dev/null
@@ -0,0 +1,99 @@
+// Copyright 2018 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef ABSL_STRINGS_INTERNAL_CHARCONV_PARSE_H_
+#define ABSL_STRINGS_INTERNAL_CHARCONV_PARSE_H_
+
+#include <cstdint>
+
+#include "absl/base/config.h"
+#include "absl/strings/charconv.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace strings_internal {
+
+// Enum indicating whether a parsed float is a number or special value.
+enum class FloatType { kNumber, kInfinity, kNan };
+
+// The decomposed parts of a parsed `float` or `double`.
+struct ParsedFloat {
+  // Representation of the parsed mantissa, with the decimal point adjusted to
+  // make it an integer.
+  //
+  // During decimal scanning, this contains 19 significant digits worth of
+  // mantissa value.  If digits beyond this point are found, they
+  // are truncated, and if any of these dropped digits are nonzero, then
+  // `mantissa` is inexact, and the full mantissa is stored in [subrange_begin,
+  // subrange_end).
+  //
+  // During hexadecimal scanning, this contains 15 significant hex digits worth
+  // of mantissa value.  Digits beyond this point are sticky -- they are
+  // truncated, but if any dropped digits are nonzero, the low bit of mantissa
+  // will be set.  (This allows for precise rounding, and avoids the need
+  // to store the full mantissa in [subrange_begin, subrange_end).)
+  uint64_t mantissa = 0;
+
+  // Floating point expontent.  This reflects any decimal point adjustments and
+  // any truncated digits from the mantissa.  The absolute value of the parsed
+  // number is represented by mantissa * (base ** exponent), where base==10 for
+  // decimal floats, and base==2 for hexadecimal floats.
+  int exponent = 0;
+
+  // The literal exponent value scanned from the input, or 0 if none was
+  // present.  This does not reflect any adjustments applied to mantissa.
+  int literal_exponent = 0;
+
+  // The type of number scanned.
+  FloatType type = FloatType::kNumber;
+
+  // When non-null, [subrange_begin, subrange_end) marks a range of characters
+  // that require further processing.  The meaning is dependent on float type.
+  // If type == kNumber and this is set, this is a "wide input": the input
+  // mantissa contained more than 19 digits.  The range contains the full
+  // mantissa.  It plus `literal_exponent` need to be examined to find the best
+  // floating point match.
+  // If type == kNan and this is set, the range marks the contents of a
+  // matched parenthesized character region after the NaN.
+  const char* subrange_begin = nullptr;
+  const char* subrange_end = nullptr;
+
+  // One-past-the-end of the successfully parsed region, or nullptr if no
+  // matching pattern was found.
+  const char* end = nullptr;
+};
+
+// Read the floating point number in the provided range, and populate
+// ParsedFloat accordingly.
+//
+// format_flags is a bitmask value specifying what patterns this API will match.
+// `scientific` and `fixed`  are honored per std::from_chars rules
+// ([utility.from.chars], C++17): if exactly one of these bits is set, then an
+// exponent is required, or dislallowed, respectively.
+//
+// Template parameter `base` must be either 10 or 16.  For base 16, a "0x" is
+// *not* consumed.  The `hex` bit from format_flags is ignored by ParseFloat.
+template <int base>
+ParsedFloat ParseFloat(const char* begin, const char* end,
+                       absl::chars_format format_flags);
+
+extern template ParsedFloat ParseFloat<10>(const char* begin, const char* end,
+                                           absl::chars_format format_flags);
+extern template ParsedFloat ParseFloat<16>(const char* begin, const char* end,
+                                           absl::chars_format format_flags);
+
+}  // namespace strings_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
+#endif  // ABSL_STRINGS_INTERNAL_CHARCONV_PARSE_H_
diff --git a/src/absl/strings/internal/cord_internal.cc b/src/absl/strings/internal/cord_internal.cc
new file mode 100644 (file)
index 0000000..905ffd0
--- /dev/null
@@ -0,0 +1,83 @@
+// Copyright 2020 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+#include "absl/strings/internal/cord_internal.h"
+
+#include <atomic>
+#include <cassert>
+#include <memory>
+
+#include "absl/container/inlined_vector.h"
+#include "absl/strings/internal/cord_rep_flat.h"
+#include "absl/strings/internal/cord_rep_ring.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace cord_internal {
+
+ABSL_CONST_INIT std::atomic<bool> cord_ring_buffer_enabled(
+    kCordEnableRingBufferDefault);
+ABSL_CONST_INIT std::atomic<bool> shallow_subcords_enabled(
+    kCordShallowSubcordsDefault);
+
+void CordRep::Destroy(CordRep* rep) {
+  assert(rep != nullptr);
+
+  absl::InlinedVector<CordRep*, Constants::kInlinedVectorSize> pending;
+  while (true) {
+    assert(!rep->refcount.IsImmortal());
+    if (rep->tag == CONCAT) {
+      CordRepConcat* rep_concat = rep->concat();
+      CordRep* right = rep_concat->right;
+      if (!right->refcount.Decrement()) {
+        pending.push_back(right);
+      }
+      CordRep* left = rep_concat->left;
+      delete rep_concat;
+      rep = nullptr;
+      if (!left->refcount.Decrement()) {
+        rep = left;
+        continue;
+      }
+    } else if (rep->tag == RING) {
+      CordRepRing::Destroy(rep->ring());
+      rep = nullptr;
+    } else if (rep->tag == EXTERNAL) {
+      CordRepExternal::Delete(rep);
+      rep = nullptr;
+    } else if (rep->tag == SUBSTRING) {
+      CordRepSubstring* rep_substring = rep->substring();
+      CordRep* child = rep_substring->child;
+      delete rep_substring;
+      rep = nullptr;
+      if (!child->refcount.Decrement()) {
+        rep = child;
+        continue;
+      }
+    } else {
+      CordRepFlat::Delete(rep);
+      rep = nullptr;
+    }
+
+    if (!pending.empty()) {
+      rep = pending.back();
+      pending.pop_back();
+    } else {
+      break;
+    }
+  }
+}
+
+}  // namespace cord_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
diff --git a/src/absl/strings/internal/cord_internal.h b/src/absl/strings/internal/cord_internal.h
new file mode 100644 (file)
index 0000000..a1ba67f
--- /dev/null
@@ -0,0 +1,543 @@
+// Copyright 2021 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef ABSL_STRINGS_INTERNAL_CORD_INTERNAL_H_
+#define ABSL_STRINGS_INTERNAL_CORD_INTERNAL_H_
+
+#include <atomic>
+#include <cassert>
+#include <cstddef>
+#include <cstdint>
+#include <type_traits>
+
+#include "absl/base/config.h"
+#include "absl/base/internal/endian.h"
+#include "absl/base/internal/invoke.h"
+#include "absl/base/optimization.h"
+#include "absl/container/internal/compressed_tuple.h"
+#include "absl/meta/type_traits.h"
+#include "absl/strings/string_view.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace cord_internal {
+
+class CordzInfo;
+
+// Default feature enable states for cord ring buffers
+enum CordFeatureDefaults {
+  kCordEnableRingBufferDefault = false,
+  kCordShallowSubcordsDefault = false
+};
+
+extern std::atomic<bool> cord_ring_buffer_enabled;
+extern std::atomic<bool> shallow_subcords_enabled;
+
+inline void enable_cord_ring_buffer(bool enable) {
+  cord_ring_buffer_enabled.store(enable, std::memory_order_relaxed);
+}
+
+inline void enable_shallow_subcords(bool enable) {
+  shallow_subcords_enabled.store(enable, std::memory_order_relaxed);
+}
+
+enum Constants {
+  // The inlined size to use with absl::InlinedVector.
+  //
+  // Note: The InlinedVectors in this file (and in cord.h) do not need to use
+  // the same value for their inlined size. The fact that they do is historical.
+  // It may be desirable for each to use a different inlined size optimized for
+  // that InlinedVector's usage.
+  //
+  // TODO(jgm): Benchmark to see if there's a more optimal value than 47 for
+  // the inlined vector size (47 exists for backward compatibility).
+  kInlinedVectorSize = 47,
+
+  // Prefer copying blocks of at most this size, otherwise reference count.
+  kMaxBytesToCopy = 511
+};
+
+// Wraps std::atomic for reference counting.
+class Refcount {
+ public:
+  constexpr Refcount() : count_{kRefIncrement} {}
+  struct Immortal {};
+  explicit constexpr Refcount(Immortal) : count_(kImmortalTag) {}
+
+  // Increments the reference count. Imposes no memory ordering.
+  inline void Increment() {
+    count_.fetch_add(kRefIncrement, std::memory_order_relaxed);
+  }
+
+  // Asserts that the current refcount is greater than 0. If the refcount is
+  // greater than 1, decrements the reference count.
+  //
+  // Returns false if there are no references outstanding; true otherwise.
+  // Inserts barriers to ensure that state written before this method returns
+  // false will be visible to a thread that just observed this method returning
+  // false.
+  inline bool Decrement() {
+    int32_t refcount = count_.load(std::memory_order_acquire);
+    assert(refcount > 0 || refcount & kImmortalTag);
+    return refcount != kRefIncrement &&
+           count_.fetch_sub(kRefIncrement, std::memory_order_acq_rel) !=
+               kRefIncrement;
+  }
+
+  // Same as Decrement but expect that refcount is greater than 1.
+  inline bool DecrementExpectHighRefcount() {
+    int32_t refcount =
+        count_.fetch_sub(kRefIncrement, std::memory_order_acq_rel);
+    assert(refcount > 0 || refcount & kImmortalTag);
+    return refcount != kRefIncrement;
+  }
+
+  // Returns the current reference count using acquire semantics.
+  inline int32_t Get() const {
+    return count_.load(std::memory_order_acquire) >> kImmortalShift;
+  }
+
+  // Returns whether the atomic integer is 1.
+  // If the reference count is used in the conventional way, a
+  // reference count of 1 implies that the current thread owns the
+  // reference and no other thread shares it.
+  // This call performs the test for a reference count of one, and
+  // performs the memory barrier needed for the owning thread
+  // to act on the object, knowing that it has exclusive access to the
+  // object.
+  inline bool IsOne() {
+    return count_.load(std::memory_order_acquire) == kRefIncrement;
+  }
+
+  bool IsImmortal() const {
+    return (count_.load(std::memory_order_relaxed) & kImmortalTag) != 0;
+  }
+
+ private:
+  // We reserve the bottom bit to tag a reference count as immortal.
+  // By making it `1` we ensure that we never reach `0` when adding/subtracting
+  // `2`, thus it never looks as if it should be destroyed.
+  // These are used for the StringConstant constructor where we do not increase
+  // the refcount at construction time (due to constinit requirements) but we
+  // will still decrease it at destruction time to avoid branching on Unref.
+  enum {
+    kImmortalShift = 1,
+    kRefIncrement = 1 << kImmortalShift,
+    kImmortalTag = kRefIncrement - 1
+  };
+
+  std::atomic<int32_t> count_;
+};
+
+// The overhead of a vtable is too much for Cord, so we roll our own subclasses
+// using only a single byte to differentiate classes from each other - the "tag"
+// byte.  Define the subclasses first so we can provide downcasting helper
+// functions in the base class.
+
+struct CordRepConcat;
+struct CordRepExternal;
+struct CordRepFlat;
+struct CordRepSubstring;
+class CordRepRing;
+
+// Various representations that we allow
+enum CordRepKind {
+  CONCAT = 0,
+  EXTERNAL = 1,
+  SUBSTRING = 2,
+  RING = 3,
+
+  // We have different tags for different sized flat arrays,
+  // starting with FLAT, and limited to MAX_FLAT_TAG. The 224 value is based on
+  // the current 'size to tag' encoding of 8 / 32 bytes. If a new tag is needed
+  // in the future, then 'FLAT' and 'MAX_FLAT_TAG' should be adjusted as well
+  // as the Tag <---> Size logic so that FLAT stil represents the minimum flat
+  // allocation size. (32 bytes as of now).
+  FLAT = 4,
+  MAX_FLAT_TAG = 224
+};
+
+struct CordRep {
+  CordRep() = default;
+  constexpr CordRep(Refcount::Immortal immortal, size_t l)
+      : length(l), refcount(immortal), tag(EXTERNAL), storage{} {}
+
+  // The following three fields have to be less than 32 bytes since
+  // that is the smallest supported flat node size.
+  size_t length;
+  Refcount refcount;
+  // If tag < FLAT, it represents CordRepKind and indicates the type of node.
+  // Otherwise, the node type is CordRepFlat and the tag is the encoded size.
+  uint8_t tag;
+  char storage[1];  // Starting point for flat array: MUST BE LAST FIELD
+
+  inline CordRepRing* ring();
+  inline const CordRepRing* ring() const;
+  inline CordRepConcat* concat();
+  inline const CordRepConcat* concat() const;
+  inline CordRepSubstring* substring();
+  inline const CordRepSubstring* substring() const;
+  inline CordRepExternal* external();
+  inline const CordRepExternal* external() const;
+  inline CordRepFlat* flat();
+  inline const CordRepFlat* flat() const;
+
+  // --------------------------------------------------------------------
+  // Memory management
+
+  // Destroys the provided `rep`.
+  static void Destroy(CordRep* rep);
+
+  // Increments the reference count of `rep`.
+  // Requires `rep` to be a non-null pointer value.
+  static inline CordRep* Ref(CordRep* rep);
+
+  // Decrements the reference count of `rep`. Destroys rep if count reaches
+  // zero. Requires `rep` to be a non-null pointer value.
+  static inline void Unref(CordRep* rep);
+};
+
+struct CordRepConcat : public CordRep {
+  CordRep* left;
+  CordRep* right;
+
+  uint8_t depth() const { return static_cast<uint8_t>(storage[0]); }
+  void set_depth(uint8_t depth) { storage[0] = static_cast<char>(depth); }
+};
+
+struct CordRepSubstring : public CordRep {
+  size_t start;  // Starting offset of substring in child
+  CordRep* child;
+};
+
+// Type for function pointer that will invoke the releaser function and also
+// delete the `CordRepExternalImpl` corresponding to the passed in
+// `CordRepExternal`.
+using ExternalReleaserInvoker = void (*)(CordRepExternal*);
+
+// External CordReps are allocated together with a type erased releaser. The
+// releaser is stored in the memory directly following the CordRepExternal.
+struct CordRepExternal : public CordRep {
+  CordRepExternal() = default;
+  explicit constexpr CordRepExternal(absl::string_view str)
+      : CordRep(Refcount::Immortal{}, str.size()),
+        base(str.data()),
+        releaser_invoker(nullptr) {}
+
+  const char* base;
+  // Pointer to function that knows how to call and destroy the releaser.
+  ExternalReleaserInvoker releaser_invoker;
+
+  // Deletes (releases) the external rep.
+  // Requires rep != nullptr and rep->tag == EXTERNAL
+  static void Delete(CordRep* rep);
+};
+
+struct Rank1 {};
+struct Rank0 : Rank1 {};
+
+template <typename Releaser, typename = ::absl::base_internal::invoke_result_t<
+                                 Releaser, absl::string_view>>
+void InvokeReleaser(Rank0, Releaser&& releaser, absl::string_view data) {
+  ::absl::base_internal::invoke(std::forward<Releaser>(releaser), data);
+}
+
+template <typename Releaser,
+          typename = ::absl::base_internal::invoke_result_t<Releaser>>
+void InvokeReleaser(Rank1, Releaser&& releaser, absl::string_view) {
+  ::absl::base_internal::invoke(std::forward<Releaser>(releaser));
+}
+
+// We use CompressedTuple so that we can benefit from EBCO.
+template <typename Releaser>
+struct CordRepExternalImpl
+    : public CordRepExternal,
+      public ::absl::container_internal::CompressedTuple<Releaser> {
+  // The extra int arg is so that we can avoid interfering with copy/move
+  // constructors while still benefitting from perfect forwarding.
+  template <typename T>
+  CordRepExternalImpl(T&& releaser, int)
+      : CordRepExternalImpl::CompressedTuple(std::forward<T>(releaser)) {
+    this->releaser_invoker = &Release;
+  }
+
+  ~CordRepExternalImpl() {
+    InvokeReleaser(Rank0{}, std::move(this->template get<0>()),
+                   absl::string_view(base, length));
+  }
+
+  static void Release(CordRepExternal* rep) {
+    delete static_cast<CordRepExternalImpl*>(rep);
+  }
+};
+
+inline void CordRepExternal::Delete(CordRep* rep) {
+  assert(rep != nullptr && rep->tag == EXTERNAL);
+  auto* rep_external = static_cast<CordRepExternal*>(rep);
+  assert(rep_external->releaser_invoker != nullptr);
+  rep_external->releaser_invoker(rep_external);
+}
+
+template <typename Str>
+struct ConstInitExternalStorage {
+  ABSL_CONST_INIT static CordRepExternal value;
+};
+
+template <typename Str>
+CordRepExternal ConstInitExternalStorage<Str>::value(Str::value);
+
+enum {
+  kMaxInline = 15,
+};
+
+constexpr char GetOrNull(absl::string_view data, size_t pos) {
+  return pos < data.size() ? data[pos] : '\0';
+}
+
+// We store cordz_info as 64 bit pointer value in big endian format. This
+// guarantees that the least significant byte of cordz_info matches the last
+// byte of the inline data representation in as_chars_, which holds the inlined
+// size or the 'is_tree' bit.
+using cordz_info_t = int64_t;
+
+// Assert that the `cordz_info` pointer value perfectly overlaps the last half
+// of `as_chars_` and can hold a pointer value.
+static_assert(sizeof(cordz_info_t) * 2 == kMaxInline + 1, "");
+static_assert(sizeof(cordz_info_t) >= sizeof(intptr_t), "");
+
+// BigEndianByte() creates a big endian representation of 'value', i.e.: a big
+// endian value where the last byte in the host's representation holds 'value`,
+// with all other bytes being 0.
+static constexpr cordz_info_t BigEndianByte(unsigned char value) {
+#if defined(ABSL_IS_BIG_ENDIAN)
+  return value;
+#else
+  return static_cast<cordz_info_t>(value) << ((sizeof(cordz_info_t) - 1) * 8);
+#endif
+}
+
+class InlineData {
+ public:
+  // kNullCordzInfo holds the big endian representation of intptr_t(1)
+  // This is the 'null' / initial value of 'cordz_info'. The null value
+  // is specifically big endian 1 as with 64-bit pointers, the last
+  // byte of cordz_info overlaps with the last byte holding the tag.
+  static constexpr cordz_info_t kNullCordzInfo = BigEndianByte(1);
+
+  // kFakeCordzInfo holds a 'fake', non-null cordz-info value we use to
+  // emulate the previous 'kProfiled' tag logic in 'set_profiled' until
+  // cord code is changed to store cordz_info values in InlineData.
+  static constexpr cordz_info_t kFakeCordzInfo = BigEndianByte(9);
+
+  constexpr InlineData() : as_chars_{0} {}
+  explicit constexpr InlineData(CordRep* rep) : as_tree_(rep) {}
+  explicit constexpr InlineData(absl::string_view chars)
+      : as_chars_{
+            GetOrNull(chars, 0),  GetOrNull(chars, 1),
+            GetOrNull(chars, 2),  GetOrNull(chars, 3),
+            GetOrNull(chars, 4),  GetOrNull(chars, 5),
+            GetOrNull(chars, 6),  GetOrNull(chars, 7),
+            GetOrNull(chars, 8),  GetOrNull(chars, 9),
+            GetOrNull(chars, 10), GetOrNull(chars, 11),
+            GetOrNull(chars, 12), GetOrNull(chars, 13),
+            GetOrNull(chars, 14), static_cast<char>((chars.size() << 1))} {}
+
+  // Returns true if the current instance is empty.
+  // The 'empty value' is an inlined data value of zero length.
+  bool is_empty() const { return tag() == 0; }
+
+  // Returns true if the current instance holds a tree value.
+  bool is_tree() const { return (tag() & 1) != 0; }
+
+  // Returns true if the current instance holds a cordz_info value.
+  // Requires the current instance to hold a tree value.
+  bool is_profiled() const {
+    assert(is_tree());
+    return as_tree_.cordz_info != kNullCordzInfo;
+  }
+
+  // Returns the cordz_info sampling instance for this instance, or nullptr
+  // if the current instance is not sampled and does not have CordzInfo data.
+  // Requires the current instance to hold a tree value.
+  CordzInfo* cordz_info() const {
+    assert(is_tree());
+    intptr_t info =
+        static_cast<intptr_t>(absl::big_endian::ToHost64(as_tree_.cordz_info));
+    assert(info & 1);
+    return reinterpret_cast<CordzInfo*>(info - 1);
+  }
+
+  // Sets the current cordz_info sampling instance for this instance, or nullptr
+  // if the current instance is not sampled and does not have CordzInfo data.
+  // Requires the current instance to hold a tree value.
+  void set_cordz_info(CordzInfo* cordz_info) {
+    assert(is_tree());
+    intptr_t info = reinterpret_cast<intptr_t>(cordz_info) | 1;
+    as_tree_.cordz_info = absl::big_endian::FromHost64(info);
+  }
+
+  // Resets the current cordz_info to null / empty.
+  void clear_cordz_info() {
+    assert(is_tree());
+    as_tree_.cordz_info = kNullCordzInfo;
+  }
+
+  // Returns a read only pointer to the character data inside this instance.
+  // Requires the current instance to hold inline data.
+  const char* as_chars() const {
+    assert(!is_tree());
+    return as_chars_;
+  }
+
+  // Returns a mutable pointer to the character data inside this instance.
+  // Should be used for 'write only' operations setting an inlined value.
+  // Applications can set the value of inlined data either before or after
+  // setting the inlined size, i.e., both of the below are valid:
+  //
+  //   // Set inlined data and inline size
+  //   memcpy(data_.as_chars(), data, size);
+  //   data_.set_inline_size(size);
+  //
+  //   // Set inlined size and inline data
+  //   data_.set_inline_size(size);
+  //   memcpy(data_.as_chars(), data, size);
+  //
+  // It's an error to read from the returned pointer without a preceding write
+  // if the current instance does not hold inline data, i.e.: is_tree() == true.
+  char* as_chars() { return as_chars_; }
+
+  // Returns the tree value of this value.
+  // Requires the current instance to hold a tree value.
+  CordRep* as_tree() const {
+    assert(is_tree());
+    return as_tree_.rep;
+  }
+
+  // Initialize this instance to holding the tree value `rep`,
+  // initializing the cordz_info to null, i.e.: 'not profiled'.
+  void make_tree(CordRep* rep) {
+    as_tree_.rep = rep;
+    as_tree_.cordz_info = kNullCordzInfo;
+  }
+
+  // Set the tree value of this instance to 'rep`.
+  // Requires the current instance to already hold a tree value.
+  // Does not affect the value of cordz_info.
+  void set_tree(CordRep* rep) {
+    assert(is_tree());
+    as_tree_.rep = rep;
+  }
+
+  // Returns the size of the inlined character data inside this instance.
+  // Requires the current instance to hold inline data.
+  size_t inline_size() const {
+    assert(!is_tree());
+    return tag() >> 1;
+  }
+
+  // Sets the size of the inlined character data inside this instance.
+  // Requires `size` to be <= kMaxInline.
+  // See the documentation on 'as_chars()' for more information and examples.
+  void set_inline_size(size_t size) {
+    ABSL_ASSERT(size <= kMaxInline);
+    tag() = static_cast<char>(size << 1);
+  }
+
+  // Sets or unsets the 'is_profiled' state of this instance.
+  // Requires the current instance to hold a tree value.
+  void set_profiled(bool profiled) {
+    assert(is_tree());
+    as_tree_.cordz_info = profiled ? kFakeCordzInfo : kNullCordzInfo;
+  }
+
+ private:
+  // See cordz_info_t for forced alignment and size of `cordz_info` details.
+  struct AsTree {
+    explicit constexpr AsTree(absl::cord_internal::CordRep* tree)
+        : rep(tree), cordz_info(kNullCordzInfo) {}
+    // This union uses up extra space so that whether rep is 32 or 64 bits,
+    // cordz_info will still start at the eighth byte, and the last
+    // byte of cordz_info will still be the last byte of InlineData.
+    union {
+      absl::cord_internal::CordRep* rep;
+      cordz_info_t unused_aligner;
+    };
+    cordz_info_t cordz_info;
+  };
+
+  char& tag() { return reinterpret_cast<char*>(this)[kMaxInline]; }
+  char tag() const { return reinterpret_cast<const char*>(this)[kMaxInline]; }
+
+  // If the data has length <= kMaxInline, we store it in `as_chars_`, and
+  // store the size in the last char of `as_chars_` shifted left + 1.
+  // Else we store it in a tree and store a pointer to that tree in
+  // `as_tree_.rep` and store a tag in `tagged_size`.
+  union  {
+    char as_chars_[kMaxInline + 1];
+    AsTree as_tree_;
+  };
+};
+
+static_assert(sizeof(InlineData) == kMaxInline + 1, "");
+
+inline CordRepConcat* CordRep::concat() {
+  assert(tag == CONCAT);
+  return static_cast<CordRepConcat*>(this);
+}
+
+inline const CordRepConcat* CordRep::concat() const {
+  assert(tag == CONCAT);
+  return static_cast<const CordRepConcat*>(this);
+}
+
+inline CordRepSubstring* CordRep::substring() {
+  assert(tag == SUBSTRING);
+  return static_cast<CordRepSubstring*>(this);
+}
+
+inline const CordRepSubstring* CordRep::substring() const {
+  assert(tag == SUBSTRING);
+  return static_cast<const CordRepSubstring*>(this);
+}
+
+inline CordRepExternal* CordRep::external() {
+  assert(tag == EXTERNAL);
+  return static_cast<CordRepExternal*>(this);
+}
+
+inline const CordRepExternal* CordRep::external() const {
+  assert(tag == EXTERNAL);
+  return static_cast<const CordRepExternal*>(this);
+}
+
+inline CordRep* CordRep::Ref(CordRep* rep) {
+  assert(rep != nullptr);
+  rep->refcount.Increment();
+  return rep;
+}
+
+inline void CordRep::Unref(CordRep* rep) {
+  assert(rep != nullptr);
+  // Expect refcount to be 0. Avoiding the cost of an atomic decrement should
+  // typically outweigh the cost of an extra branch checking for ref == 1.
+  if (ABSL_PREDICT_FALSE(!rep->refcount.DecrementExpectHighRefcount())) {
+    Destroy(rep);
+  }
+}
+
+}  // namespace cord_internal
+
+ABSL_NAMESPACE_END
+}  // namespace absl
+#endif  // ABSL_STRINGS_INTERNAL_CORD_INTERNAL_H_
diff --git a/src/absl/strings/internal/cord_rep_flat.h b/src/absl/strings/internal/cord_rep_flat.h
new file mode 100644 (file)
index 0000000..a98aa9d
--- /dev/null
@@ -0,0 +1,146 @@
+// Copyright 2020 The Abseil Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef ABSL_STRINGS_INTERNAL_CORD_REP_FLAT_H_
+#define ABSL_STRINGS_INTERNAL_CORD_REP_FLAT_H_
+
+#include <cassert>
+#include <cstddef>
+#include <cstdint>
+#include <memory>
+
+#include "absl/strings/internal/cord_internal.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace cord_internal {
+
+// Note: all constants below are never ODR used and internal to cord, we define
+// these as static constexpr to avoid 'in struct' definition and usage clutter.
+
+// Largest and smallest flat node lengths we are willing to allocate
+// Flat allocation size is stored in tag, which currently can encode sizes up
+// to 4K, encoded as multiple of either 8 or 32 bytes.
+// If we allow for larger sizes, we need to change this to 8/64, 16/128, etc.
+// kMinFlatSize is bounded by tag needing to be at least FLAT * 8 bytes, and
+// ideally a 'nice' size aligning with allocation and cacheline sizes like 32.
+// kMaxFlatSize is bounded by the size resulting in a computed tag no greater
+// than MAX_FLAT_TAG. MAX_FLAT_TAG provides for additional 'high' tag values.
+static constexpr size_t kFlatOverhead = offsetof(CordRep, storage);
+static constexpr size_t kMinFlatSize = 32;
+static constexpr size_t kMaxFlatSize = 4096;
+static constexpr size_t kMaxFlatLength = kMaxFlatSize - kFlatOverhead;
+static constexpr size_t kMinFlatLength = kMinFlatSize - kFlatOverhead;
+
+constexpr uint8_t AllocatedSizeToTagUnchecked(size_t size) {
+  return static_cast<uint8_t>((size <= 1024) ? size / 8
+                                             : 128 + size / 32 - 1024 / 32);
+}
+
+static_assert(kMinFlatSize / 8 >= FLAT, "");
+static_assert(AllocatedSizeToTagUnchecked(kMaxFlatSize) <= MAX_FLAT_TAG, "");
+
+// Helper functions for rounded div, and rounding to exact sizes.
+constexpr size_t DivUp(size_t n, size_t m) { return (n + m - 1) / m; }
+constexpr size_t RoundUp(size_t n, size_t m) { return DivUp(n, m) * m; }
+
+// Returns the size to the nearest equal or larger value that can be
+// expressed exactly as a tag value.
+inline size_t RoundUpForTag(size_t size) {
+  return RoundUp(size, (size <= 1024) ? 8 : 32);
+}
+
+// Converts the allocated size to a tag, rounding down if the size
+// does not exactly match a 'tag expressible' size value. The result is
+// undefined if the size exceeds the maximum size that can be encoded in
+// a tag, i.e., if size is larger than TagToAllocatedSize(<max tag>).
+inline uint8_t AllocatedSizeToTag(size_t size) {
+  const uint8_t tag = AllocatedSizeToTagUnchecked(size);
+  assert(tag <= MAX_FLAT_TAG);
+  return tag;
+}
+
+// Converts the provided tag to the corresponding allocated size
+constexpr size_t TagToAllocatedSize(uint8_t tag) {
+  return (tag <= 128) ? (tag * 8) : (1024 + (tag - 128) * 32);
+}
+
+// Converts the provided tag to the corresponding available data length
+constexpr size_t TagToLength(uint8_t tag) {
+  return TagToAllocatedSize(tag) - kFlatOverhead;
+}
+
+// Enforce that kMaxFlatSize maps to a well-known exact tag value.
+static_assert(TagToAllocatedSize(224) == kMaxFlatSize, "Bad tag logic");
+
+struct CordRepFlat : public CordRep {
+  // Creates a new flat node.
+  static CordRepFlat* New(size_t len) {
+    if (len <= kMinFlatLength) {
+      len = kMinFlatLength;
+    } else if (len > kMaxFlatLength) {
+      len = kMaxFlatLength;
+    }
+
+    // Round size up so it matches a size we can exactly express in a tag.
+    const size_t size = RoundUpForTag(len + kFlatOverhead);
+    void* const raw_rep = ::operator new(size);
+    CordRepFlat* rep = new (raw_rep) CordRepFlat();
+    rep->tag = AllocatedSizeToTag(size);
+    return rep;
+  }
+
+  // Deletes a CordRepFlat instance created previously through a call to New().
+  // Flat CordReps are allocated and constructed with raw ::operator new and
+  // placement new, and must be destructed and deallocated accordingly.
+  static void Delete(CordRep*rep) {
+    assert(rep->tag >= FLAT && rep->tag <= MAX_FLAT_TAG);
+
+#if defined(__cpp_sized_deallocation)
+    size_t size = TagToAllocatedSize(rep->tag);
+    rep->~CordRep();
+    ::operator delete(rep, size);
+#else
+    rep->~CordRep();
+    ::operator delete(rep);
+#endif
+  }
+
+  // Returns a pointer to the data inside this flat rep.
+  char* Data() { return storage; }
+  const char* Data() const { return storage; }
+
+  // Returns the maximum capacity (payload size) of this instance.
+  size_t Capacity() const { return TagToLength(tag); }
+
+  // Returns the allocated size (payload + overhead) of this instance.
+  size_t AllocatedSize() const { return TagToAllocatedSize(tag); }
+};
+
+// Now that CordRepFlat is defined, we can define CordRep's helper casts:
+inline CordRepFlat* CordRep::flat() {
+  assert(tag >= FLAT && tag <= MAX_FLAT_TAG);
+  return reinterpret_cast<CordRepFlat*>(this);
+}
+
+inline const CordRepFlat* CordRep::flat() const {
+  assert(tag >= FLAT && tag <= MAX_FLAT_TAG);
+  return reinterpret_cast<const CordRepFlat*>(this);
+}
+
+}  // namespace cord_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#endif  // ABSL_STRINGS_INTERNAL_CORD_REP_FLAT_H_
diff --git a/src/absl/strings/internal/cord_rep_ring.cc b/src/absl/strings/internal/cord_rep_ring.cc
new file mode 100644 (file)
index 0000000..99a7dcf
--- /dev/null
@@ -0,0 +1,897 @@
+// Copyright 2020 The Abseil Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+#include "absl/strings/internal/cord_rep_ring.h"
+
+#include <cassert>
+#include <cstddef>
+#include <cstdint>
+#include <iostream>
+#include <limits>
+#include <memory>
+#include <string>
+
+#include "absl/base/internal/raw_logging.h"
+#include "absl/base/internal/throw_delegate.h"
+#include "absl/base/macros.h"
+#include "absl/container/inlined_vector.h"
+#include "absl/strings/internal/cord_internal.h"
+#include "absl/strings/internal/cord_rep_flat.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace cord_internal {
+
+// See https://bugs.llvm.org/show_bug.cgi?id=48477
+// #ifdef __clang__
+// #pragma clang diagnostic push
+// #pragma clang diagnostic ignored "-Wshadow"
+// #if __has_warning("-Wshadow-field")
+// #pragma clang diagnostic ignored "-Wshadow-field"
+// #endif
+// #endif
+
+namespace {
+
+using index_type = CordRepRing::index_type;
+
+enum class Direction { kForward, kReversed };
+
+inline bool IsFlatOrExternal(CordRep* rep) {
+  return rep->tag >= FLAT || rep->tag == EXTERNAL;
+}
+
+// Verifies that n + extra <= kMaxCapacity: throws std::length_error otherwise.
+inline void CheckCapacity(size_t n, size_t extra) {
+  if (ABSL_PREDICT_FALSE(extra > CordRepRing::kMaxCapacity - n)) {
+    base_internal::ThrowStdLengthError("Maximum capacity exceeded");
+  }
+}
+
+// Removes a reference from `rep` only.
+// Asserts that the refcount after decrement is not zero.
+inline bool UnrefNeverOne(CordRep* rep) {
+  bool result = rep->refcount.Decrement();
+  assert(result);
+  return result;
+}
+
+// Creates a flat from the provided string data, allocating up to `extra`
+// capacity in the returned flat depending on kMaxFlatLength limitations.
+// Requires `len` to be less or equal to `kMaxFlatLength`
+CordRepFlat* CreateFlat(const char* s, size_t n, size_t extra = 0) {  // NOLINT
+  assert(n <= kMaxFlatLength);
+  auto* rep = CordRepFlat::New(n + extra);
+  rep->length = n;
+  memcpy(rep->Data(), s, n);
+  return rep;
+}
+
+// Unrefs the provided `substring`, and returns `substring->child`
+// Adds or assumes a reference on `substring->child`
+CordRep* ClipSubstring(CordRepSubstring* substring) {
+  CordRep* child = substring->child;
+  if (substring->refcount.IsOne()) {
+    delete substring;
+  } else {
+    CordRep::Ref(child);
+    if (ABSL_PREDICT_FALSE(!substring->refcount.Decrement())) {
+      UnrefNeverOne(child);
+      delete substring;
+    }
+  }
+  return child;
+}
+
+// Unrefs the provided `concat`, and returns `{concat->left, concat->right}`
+// Adds or assumes a reference on `concat->left` and `concat->right`.
+std::pair<CordRep*, CordRep*> ClipConcat(CordRepConcat* concat) {
+  auto result = std::make_pair(concat->left, concat->right);
+  if (concat->refcount.IsOne()) {
+    delete concat;
+  } else {
+    CordRep::Ref(result.first);
+    CordRep::Ref(result.second);
+    if (ABSL_PREDICT_FALSE(!concat->refcount.Decrement())) {
+      UnrefNeverOne(result.first);
+      UnrefNeverOne(result.second);
+      delete concat;
+    }
+  }
+  return result;
+}
+
+// Unrefs the entries in `[head, tail)`.
+// Requires all entries to be a FLAT or EXTERNAL node.
+void UnrefEntries(const CordRepRing* rep, index_type head, index_type tail) {
+  rep->ForEach(head, tail, [rep](index_type ix) {
+    CordRep* child = rep->entry_child(ix);
+    if (!child->refcount.Decrement()) {
+      if (child->tag >= FLAT) {
+        CordRepFlat::Delete(child->flat());
+      } else {
+        CordRepExternal::Delete(child->external());
+      }
+    }
+  });
+}
+
+template <typename F>
+void Consume(Direction direction, CordRep* rep, F&& fn) {
+  size_t offset = 0;
+  size_t length = rep->length;
+  struct Entry {
+    CordRep* rep;
+    size_t offset;
+    size_t length;
+  };
+  absl::InlinedVector<Entry, 40> stack;
+
+  for (;;) {
+    if (rep->tag >= FLAT || rep->tag == EXTERNAL || rep->tag == RING) {
+      fn(rep, offset, length);
+      if (stack.empty()) return;
+
+      rep = stack.back().rep;
+      offset = stack.back().offset;
+      length = stack.back().length;
+      stack.pop_back();
+    } else if (rep->tag == SUBSTRING) {
+      offset += rep->substring()->start;
+      rep = ClipSubstring(rep->substring());
+    } else if (rep->tag == CONCAT) {
+      auto res = ClipConcat(rep->concat());
+      CordRep* left = res.first;
+      CordRep* right = res.second;
+
+      if (left->length <= offset) {
+        // Don't need left node
+        offset -= left->length;
+        CordRep::Unref(left);
+        rep = right;
+        continue;
+      }
+
+      size_t length_left = left->length - offset;
+      if (length_left >= length) {
+        // Don't need right node
+        CordRep::Unref(right);
+        rep = left;
+        continue;
+      }
+
+      // Need both nodes
+      size_t length_right = length - length_left;
+      if (direction == Direction::kReversed) {
+        stack.push_back({left, offset, length_left});
+        rep = right;
+        offset = 0;
+        length = length_right;
+      } else {
+        stack.push_back({right, 0, length_right});
+        rep = left;
+        length = length_left;
+      }
+    } else {
+      assert("Valid tag" == nullptr);
+      return;
+    }
+  }
+}
+
+template <typename F>
+void Consume(CordRep* rep, F&& fn) {
+  return Consume(Direction::kForward, rep, std::forward<F>(fn));
+}
+
+template <typename F>
+void RConsume(CordRep* rep, F&& fn) {
+  return Consume(Direction::kReversed, rep, std::forward<F>(fn));
+}
+
+}  // namespace
+
+std::ostream& operator<<(std::ostream& s, const CordRepRing& rep) {
+  // Note: 'pos' values are defined as size_t (for overflow reasons), but that
+  // prints really awkward for small prepended values such as -5. ssize_t is not
+  // portable (POSIX), so we use ptrdiff_t instead to cast to signed values.
+  s << "  CordRepRing(" << &rep << ", length = " << rep.length
+    << ", head = " << rep.head_ << ", tail = " << rep.tail_
+    << ", cap = " << rep.capacity_ << ", rc = " << rep.refcount.Get()
+    << ", begin_pos_ = " << static_cast<ptrdiff_t>(rep.begin_pos_) << ") {\n";
+  CordRepRing::index_type head = rep.head();
+  do {
+    CordRep* child = rep.entry_child(head);
+    s << " entry[" << head << "] length = " << rep.entry_length(head)
+      << ", child " << child << ", clen = " << child->length
+      << ", tag = " << static_cast<int>(child->tag)
+      << ", rc = " << child->refcount.Get()
+      << ", offset = " << rep.entry_data_offset(head)
+      << ", end_pos = " << static_cast<ptrdiff_t>(rep.entry_end_pos(head))
+      << "\n";
+    head = rep.advance(head);
+  } while (head != rep.tail());
+  return s << "}\n";
+}
+
+void CordRepRing::AddDataOffset(index_type index, size_t n) {
+  entry_data_offset()[index] += static_cast<offset_type>(n);
+}
+
+void CordRepRing::SubLength(index_type index, size_t n) {
+  entry_end_pos()[index] -= n;
+}
+
+class CordRepRing::Filler {
+ public:
+  Filler(CordRepRing* rep, index_type pos) : rep_(rep), head_(pos), pos_(pos) {}
+
+  index_type head() const { return head_; }
+  index_type pos() const { return pos_; }
+
+  void Add(CordRep* child, size_t offset, pos_type end_pos) {
+    rep_->entry_end_pos()[pos_] = end_pos;
+    rep_->entry_child()[pos_] = child;
+    rep_->entry_data_offset()[pos_] = static_cast<offset_type>(offset);
+    pos_ = rep_->advance(pos_);
+  }
+
+ private:
+  CordRepRing* rep_;
+  index_type head_;
+  index_type pos_;
+};
+
+constexpr size_t CordRepRing::kMaxCapacity; // NOLINT: needed for c++11
+
+bool CordRepRing::IsValid(std::ostream& output) const {
+  if (capacity_ == 0) {
+    output << "capacity == 0";
+    return false;
+  }
+
+  if (head_ >= capacity_ || tail_ >= capacity_) {
+    output << "head " << head_ << " and/or tail " << tail_ << "exceed capacity "
+           << capacity_;
+    return false;
+  }
+
+  const index_type back = retreat(tail_);
+  size_t pos_length = Distance(begin_pos_, entry_end_pos(back));
+  if (pos_length != length) {
+    output << "length " << length << " does not match positional length "
+           << pos_length << " from begin_pos " << begin_pos_ << " and entry["
+           << back << "].end_pos " << entry_end_pos(back);
+    return false;
+  }
+
+  index_type head = head_;
+  pos_type begin_pos = begin_pos_;
+  do {
+    pos_type end_pos = entry_end_pos(head);
+    size_t entry_length = Distance(begin_pos, end_pos);
+    if (entry_length == 0) {
+      output << "entry[" << head << "] has an invalid length " << entry_length
+             << " from begin_pos " << begin_pos << " and end_pos " << end_pos;
+      return false;
+    }
+
+    CordRep* child = entry_child(head);
+    if (child == nullptr) {
+      output << "entry[" << head << "].child == nullptr";
+      return false;
+    }
+    if (child->tag < FLAT && child->tag != EXTERNAL) {
+      output << "entry[" << head << "].child has an invalid tag "
+             << static_cast<int>(child->tag);
+      return false;
+    }
+
+    size_t offset = entry_data_offset(head);
+    if (offset >= child->length || entry_length > child->length - offset) {
+      output << "entry[" << head << "] has offset " << offset
+             << " and entry length " << entry_length
+             << " which are outside of the childs length of " << child->length;
+      return false;
+    }
+
+    begin_pos = end_pos;
+    head = advance(head);
+  } while (head != tail_);
+
+  return true;
+}
+
+#ifdef EXTRA_CORD_RING_VALIDATION
+CordRepRing* CordRepRing::Validate(CordRepRing* rep, const char* file,
+                                   int line) {
+  if (!rep->IsValid(std::cerr)) {
+    std::cerr << "\nERROR: CordRepRing corrupted";
+    if (line) std::cerr << " at line " << line;
+    if (file) std::cerr << " in file " << file;
+    std::cerr << "\nContent = " << *rep;
+    abort();
+  }
+  return rep;
+}
+#endif  // EXTRA_CORD_RING_VALIDATION
+
+CordRepRing* CordRepRing::New(size_t capacity, size_t extra) {
+  CheckCapacity(capacity, extra);
+
+  size_t size = AllocSize(capacity += extra);
+  void* mem = ::operator new(size);
+  auto* rep = new (mem) CordRepRing(static_cast<index_type>(capacity));
+  rep->tag = RING;
+  rep->capacity_ = static_cast<index_type>(capacity);
+  rep->begin_pos_ = 0;
+  return rep;
+}
+
+void CordRepRing::SetCapacityForTesting(size_t capacity) {
+  // Adjust for the changed layout
+  assert(capacity <= capacity_);
+  assert(head() == 0 || head() < tail());
+  memmove(Layout::Partial(capacity).Pointer<1>(data_) + head(),
+          Layout::Partial(capacity_).Pointer<1>(data_) + head(),
+          entries() * sizeof(Layout::ElementType<1>));
+  memmove(Layout::Partial(capacity, capacity).Pointer<2>(data_) + head(),
+          Layout::Partial(capacity_, capacity_).Pointer<2>(data_) + head(),
+          entries() * sizeof(Layout::ElementType<2>));
+  capacity_ = static_cast<index_type>(capacity);
+}
+
+void CordRepRing::Delete(CordRepRing* rep) {
+  assert(rep != nullptr && rep->tag == RING);
+#if defined(__cpp_sized_deallocation)
+  size_t size = AllocSize(rep->capacity_);
+  rep->~CordRepRing();
+  ::operator delete(rep, size);
+#else
+  rep->~CordRepRing();
+  ::operator delete(rep);
+#endif
+}
+
+void CordRepRing::Destroy(CordRepRing* rep) {
+  UnrefEntries(rep, rep->head(), rep->tail());
+  Delete(rep);
+}
+
+template <bool ref>
+void CordRepRing::Fill(const CordRepRing* src, index_type head,
+                       index_type tail) {
+  this->length = src->length;
+  head_ = 0;
+  tail_ = advance(0, src->entries(head, tail));
+  begin_pos_ = src->begin_pos_;
+
+  // TODO(mvels): there may be opportunities here for large buffers.
+  auto* dst_pos = entry_end_pos();
+  auto* dst_child = entry_child();
+  auto* dst_offset = entry_data_offset();
+  src->ForEach(head, tail, [&](index_type index) {
+    *dst_pos++ = src->entry_end_pos(index);
+    CordRep* child = src->entry_child(index);
+    *dst_child++ = ref ? CordRep::Ref(child) : child;
+    *dst_offset++ = src->entry_data_offset(index);
+  });
+}
+
+CordRepRing* CordRepRing::Copy(CordRepRing* rep, index_type head,
+                               index_type tail, size_t extra) {
+  CordRepRing* newrep = CordRepRing::New(rep->entries(head, tail), extra);
+  newrep->Fill<true>(rep, head, tail);
+  CordRep::Unref(rep);
+  return newrep;
+}
+
+CordRepRing* CordRepRing::Mutable(CordRepRing* rep, size_t extra) {
+  // Get current number of entries, and check for max capacity.
+  size_t entries = rep->entries();
+
+  size_t min_extra = (std::max)(extra, rep->capacity() * 2 - entries);
+  if (!rep->refcount.IsOne()) {
+    return Copy(rep, rep->head(), rep->tail(), min_extra);
+  } else if (entries + extra > rep->capacity()) {
+    CordRepRing* newrep = CordRepRing::New(entries, min_extra);
+    newrep->Fill<false>(rep, rep->head(), rep->tail());
+    CordRepRing::Delete(rep);
+    return newrep;
+  } else {
+    return rep;
+  }
+}
+
+Span<char> CordRepRing::GetAppendBuffer(size_t size) {
+  assert(refcount.IsOne());
+  index_type back = retreat(tail_);
+  CordRep* child = entry_child(back);
+  if (child->tag >= FLAT && child->refcount.IsOne()) {
+    size_t capacity = child->flat()->Capacity();
+    pos_type end_pos = entry_end_pos(back);
+    size_t data_offset = entry_data_offset(back);
+    size_t entry_length = Distance(entry_begin_pos(back), end_pos);
+    size_t used = data_offset + entry_length;
+    if (size_t n = (std::min)(capacity - used, size)) {
+      child->length = data_offset + entry_length + n;
+      entry_end_pos()[back] = end_pos + n;
+      this->length += n;
+      return {child->flat()->Data() + used, n};
+    }
+  }
+  return {nullptr, 0};
+}
+
+Span<char> CordRepRing::GetPrependBuffer(size_t size) {
+  assert(refcount.IsOne());
+  CordRep* child = entry_child(head_);
+  size_t data_offset = entry_data_offset(head_);
+  if (data_offset && child->refcount.IsOne() && child->tag >= FLAT) {
+    size_t n = (std::min)(data_offset, size);
+    this->length += n;
+    begin_pos_ -= n;
+    data_offset -= n;
+    entry_data_offset()[head_] = static_cast<offset_type>(data_offset);
+    return {child->flat()->Data() + data_offset, n};
+  }
+  return {nullptr, 0};
+}
+
+CordRepRing* CordRepRing::CreateFromLeaf(CordRep* child, size_t offset,
+                                         size_t length, size_t extra) {
+  CordRepRing* rep = CordRepRing::New(1, extra);
+  rep->head_ = 0;
+  rep->tail_ = rep->advance(0);
+  rep->length = length;
+  rep->entry_end_pos()[0] = length;
+  rep->entry_child()[0] = child;
+  rep->entry_data_offset()[0] = static_cast<offset_type>(offset);
+  return Validate(rep);
+}
+
+CordRepRing* CordRepRing::CreateSlow(CordRep* child, size_t extra) {
+  CordRepRing* rep = nullptr;
+  Consume(child, [&](CordRep* child, size_t offset, size_t length) {
+    if (IsFlatOrExternal(child)) {
+      rep = rep ? AppendLeaf(rep, child, offset, length)
+                : CreateFromLeaf(child, offset, length, extra);
+    } else if (rep) {
+      rep = AddRing<AddMode::kAppend>(rep, child->ring(), offset, length);
+    } else if (offset == 0 && child->length == length) {
+      rep = Mutable(child->ring(), extra);
+    } else {
+      rep = SubRing(child->ring(), offset, length, extra);
+    }
+  });
+  return Validate(rep, nullptr, __LINE__);
+}
+
+CordRepRing* CordRepRing::Create(CordRep* child, size_t extra) {
+  size_t length = child->length;
+  if (IsFlatOrExternal(child)) {
+    return CreateFromLeaf(child, 0, length, extra);
+  }
+  if (child->tag == RING) {
+    return Mutable(child->ring(), extra);
+  }
+  return CreateSlow(child, extra);
+}
+
+template <CordRepRing::AddMode mode>
+CordRepRing* CordRepRing::AddRing(CordRepRing* rep, CordRepRing* ring,
+                                  size_t offset, size_t length) {
+  assert(offset < ring->length);
+  constexpr bool append = mode == AddMode::kAppend;
+  Position head = ring->Find(offset);
+  Position tail = ring->FindTail(head.index, offset + length);
+  const index_type entries = ring->entries(head.index, tail.index);
+
+  rep = Mutable(rep, entries);
+
+  // The delta for making ring[head].end_pos into 'len - offset'
+  const pos_type delta_length =
+      (append ? rep->begin_pos_ + rep->length : rep->begin_pos_ - length) -
+      ring->entry_begin_pos(head.index) - head.offset;
+
+  // Start filling at `tail`, or `entries` before `head`
+  Filler filler(rep, append ? rep->tail_ : rep->retreat(rep->head_, entries));
+
+  if (ring->refcount.IsOne()) {
+    // Copy entries from source stealing the ref and adjusting the end position.
+    // Commit the filler as this is no-op.
+    ring->ForEach(head.index, tail.index, [&](index_type ix) {
+      filler.Add(ring->entry_child(ix), ring->entry_data_offset(ix),
+                 ring->entry_end_pos(ix) + delta_length);
+    });
+
+    // Unref entries we did not copy over, and delete source.
+    if (head.index != ring->head_) UnrefEntries(ring, ring->head_, head.index);
+    if (tail.index != ring->tail_) UnrefEntries(ring, tail.index, ring->tail_);
+    CordRepRing::Delete(ring);
+  } else {
+    ring->ForEach(head.index, tail.index, [&](index_type ix) {
+      CordRep* child = ring->entry_child(ix);
+      filler.Add(child, ring->entry_data_offset(ix),
+                 ring->entry_end_pos(ix) + delta_length);
+      CordRep::Ref(child);
+    });
+    CordRepRing::Unref(ring);
+  }
+
+  if (head.offset) {
+    // Increase offset of first 'source' entry appended or prepended.
+    // This is always the entry in `filler.head()`
+    rep->AddDataOffset(filler.head(), head.offset);
+  }
+
+  if (tail.offset) {
+    // Reduce length of last 'source' entry appended or prepended.
+    // This is always the entry tailed by `filler.pos()`
+    rep->SubLength(rep->retreat(filler.pos()), tail.offset);
+  }
+
+  // Commit changes
+  rep->length += length;
+  if (append) {
+    rep->tail_ = filler.pos();
+  } else {
+    rep->head_ = filler.head();
+    rep->begin_pos_ -= length;
+  }
+
+  return Validate(rep);
+}
+
+CordRepRing* CordRepRing::AppendSlow(CordRepRing* rep, CordRep* child) {
+  Consume(child, [&rep](CordRep* child, size_t offset, size_t length) {
+    if (child->tag == RING) {
+      rep = AddRing<AddMode::kAppend>(rep, child->ring(), offset, length);
+    } else {
+      rep = AppendLeaf(rep, child, offset, length);
+    }
+  });
+  return rep;
+}
+
+CordRepRing* CordRepRing::AppendLeaf(CordRepRing* rep, CordRep* child,
+                                     size_t offset, size_t length) {
+  rep = Mutable(rep, 1);
+  index_type back = rep->tail_;
+  const pos_type begin_pos = rep->begin_pos_ + rep->length;
+  rep->tail_ = rep->advance(rep->tail_);
+  rep->length += length;
+  rep->entry_end_pos()[back] = begin_pos + length;
+  rep->entry_child()[back] = child;
+  rep->entry_data_offset()[back] = static_cast<offset_type>(offset);
+  return Validate(rep, nullptr, __LINE__);
+}
+
+CordRepRing* CordRepRing::Append(CordRepRing* rep, CordRep* child) {
+  size_t length = child->length;
+  if (IsFlatOrExternal(child)) {
+    return AppendLeaf(rep, child, 0, length);
+  }
+  if (child->tag == RING) {
+    return AddRing<AddMode::kAppend>(rep, child->ring(), 0, length);
+  }
+  return AppendSlow(rep, child);
+}
+
+CordRepRing* CordRepRing::PrependSlow(CordRepRing* rep, CordRep* child) {
+  RConsume(child, [&](CordRep* child, size_t offset, size_t length) {
+    if (IsFlatOrExternal(child)) {
+      rep = PrependLeaf(rep, child, offset, length);
+    } else {
+      rep = AddRing<AddMode::kPrepend>(rep, child->ring(), offset, length);
+    }
+  });
+  return Validate(rep);
+}
+
+CordRepRing* CordRepRing::PrependLeaf(CordRepRing* rep, CordRep* child,
+                                      size_t offset, size_t length) {
+  rep = Mutable(rep, 1);
+  index_type head = rep->retreat(rep->head_);
+  pos_type end_pos = rep->begin_pos_;
+  rep->head_ = head;
+  rep->length += length;
+  rep->begin_pos_ -= length;
+  rep->entry_end_pos()[head] = end_pos;
+  rep->entry_child()[head] = child;
+  rep->entry_data_offset()[head] = static_cast<offset_type>(offset);
+  return Validate(rep);
+}
+
+CordRepRing* CordRepRing::Prepend(CordRepRing* rep, CordRep* child) {
+  size_t length = child->length;
+  if (IsFlatOrExternal(child)) {
+    return PrependLeaf(rep, child, 0, length);
+  }
+  if (child->tag == RING) {
+    return AddRing<AddMode::kPrepend>(rep, child->ring(), 0, length);
+  }
+  return PrependSlow(rep, child);
+}
+
+CordRepRing* CordRepRing::Append(CordRepRing* rep, absl::string_view data,
+                                 size_t extra) {
+  if (rep->refcount.IsOne()) {
+    Span<char> avail = rep->GetAppendBuffer(data.length());
+    if (!avail.empty()) {
+      memcpy(avail.data(), data.data(), avail.length());
+      data.remove_prefix(avail.length());
+    }
+  }
+  if (data.empty()) return Validate(rep);
+
+  const size_t flats = (data.length() - 1) / kMaxFlatLength + 1;
+  rep = Mutable(rep, flats);
+
+  Filler filler(rep, rep->tail_);
+  pos_type pos = rep->begin_pos_ + rep->length;
+
+  while (data.length() >= kMaxFlatLength) {
+    auto* flat = CreateFlat(data.data(), kMaxFlatLength);
+    filler.Add(flat, 0, pos += kMaxFlatLength);
+    data.remove_prefix(kMaxFlatLength);
+  }
+
+  if (data.length()) {
+    auto* flat = CreateFlat(data.data(), data.length(), extra);
+    filler.Add(flat, 0, pos += data.length());
+  }
+
+  rep->length = pos - rep->begin_pos_;
+  rep->tail_ = filler.pos();
+
+  return Validate(rep);
+}
+
+CordRepRing* CordRepRing::Prepend(CordRepRing* rep, absl::string_view data,
+                                  size_t extra) {
+  if (rep->refcount.IsOne()) {
+    Span<char> avail = rep->GetPrependBuffer(data.length());
+    if (!avail.empty()) {
+      const char* tail = data.data() + data.length() - avail.length();
+      memcpy(avail.data(), tail, avail.length());
+      data.remove_suffix(avail.length());
+    }
+  }
+  if (data.empty()) return rep;
+
+  const size_t flats = (data.length() - 1) / kMaxFlatLength + 1;
+  rep = Mutable(rep, flats);
+  pos_type pos = rep->begin_pos_;
+  Filler filler(rep, rep->retreat(rep->head_, static_cast<index_type>(flats)));
+
+  size_t first_size = data.size() - (flats - 1) * kMaxFlatLength;
+  CordRepFlat* flat = CordRepFlat::New(first_size + extra);
+  flat->length = first_size + extra;
+  memcpy(flat->Data() + extra, data.data(), first_size);
+  data.remove_prefix(first_size);
+  filler.Add(flat, extra, pos);
+  pos -= first_size;
+
+  while (!data.empty()) {
+    assert(data.size() >= kMaxFlatLength);
+    flat = CreateFlat(data.data(), kMaxFlatLength);
+    filler.Add(flat, 0, pos);
+    pos -= kMaxFlatLength;
+    data.remove_prefix(kMaxFlatLength);
+  }
+
+  rep->head_ = filler.head();
+  rep->length += rep->begin_pos_ - pos;
+  rep->begin_pos_ = pos;
+
+  return Validate(rep);
+}
+
+// 32 entries is 32 * sizeof(pos_type) = 4 cache lines on x86
+static constexpr index_type kBinarySearchThreshold = 32;
+static constexpr index_type kBinarySearchEndCount = 8;
+
+template <bool wrap>
+CordRepRing::index_type CordRepRing::FindBinary(index_type head,
+                                                index_type tail,
+                                                size_t offset) const {
+  index_type count = tail + (wrap ? capacity_ : 0) - head;
+  do {
+    count = (count - 1) / 2;
+    assert(count < entries(head, tail_));
+    index_type mid = wrap ? advance(head, count) : head + count;
+    index_type after_mid = wrap ? advance(mid) : mid + 1;
+    bool larger = (offset >= entry_end_offset(mid));
+    head = larger ? after_mid : head;
+    tail = larger ? tail : mid;
+    assert(head != tail);
+  } while (ABSL_PREDICT_TRUE(count > kBinarySearchEndCount));
+  return head;
+}
+
+CordRepRing::Position CordRepRing::FindSlow(index_type head,
+                                            size_t offset) const {
+  index_type tail = tail_;
+
+  // Binary search until we are good for linear search
+  // Optimize for branchless / non wrapping ops
+  if (tail > head) {
+    index_type count = tail - head;
+    if (count > kBinarySearchThreshold) {
+      head = FindBinary<false>(head, tail, offset);
+    }
+  } else {
+    index_type count = capacity_ + tail - head;
+    if (count > kBinarySearchThreshold) {
+      head = FindBinary<true>(head, tail, offset);
+    }
+  }
+
+  pos_type pos = entry_begin_pos(head);
+  pos_type end_pos = entry_end_pos(head);
+  while (offset >= Distance(begin_pos_, end_pos)) {
+    head = advance(head);
+    pos = end_pos;
+    end_pos = entry_end_pos(head);
+  }
+
+  return {head, offset - Distance(begin_pos_, pos)};
+}
+
+CordRepRing::Position CordRepRing::FindTailSlow(index_type head,
+                                                size_t offset) const {
+  index_type tail = tail_;
+  const size_t tail_offset = offset - 1;
+
+  // Binary search until we are good for linear search
+  // Optimize for branchless / non wrapping ops
+  if (tail > head) {
+    index_type count = tail - head;
+    if (count > kBinarySearchThreshold) {
+      head = FindBinary<false>(head, tail, tail_offset);
+    }
+  } else {
+    index_type count = capacity_ + tail - head;
+    if (count > kBinarySearchThreshold) {
+      head = FindBinary<true>(head, tail, tail_offset);
+    }
+  }
+
+  size_t end_offset = entry_end_offset(head);
+  while (tail_offset >= end_offset) {
+    head = advance(head);
+    end_offset = entry_end_offset(head);
+  }
+
+  return {advance(head), end_offset - offset};
+}
+
+char CordRepRing::GetCharacter(size_t offset) const {
+  assert(offset < length);
+
+  Position pos = Find(offset);
+  size_t data_offset = entry_data_offset(pos.index) + pos.offset;
+  return GetRepData(entry_child(pos.index))[data_offset];
+}
+
+CordRepRing* CordRepRing::SubRing(CordRepRing* rep, size_t offset,
+                                  size_t length, size_t extra) {
+  assert(offset <= rep->length);
+  assert(offset <= rep->length - length);
+
+  if (length == 0) {
+    CordRep::Unref(rep);
+    return nullptr;
+  }
+
+  // Find position of first byte
+  Position head = rep->Find(offset);
+  Position tail = rep->FindTail(head.index, offset + length);
+  const size_t new_entries = rep->entries(head.index, tail.index);
+
+  if (rep->refcount.IsOne() && extra <= (rep->capacity() - new_entries)) {
+    // We adopt a privately owned rep and no extra entries needed.
+    if (head.index != rep->head_) UnrefEntries(rep, rep->head_, head.index);
+    if (tail.index != rep->tail_) UnrefEntries(rep, tail.index, rep->tail_);
+    rep->head_ = head.index;
+    rep->tail_ = tail.index;
+  } else {
+    // Copy subset to new rep
+    rep = Copy(rep, head.index, tail.index, extra);
+    head.index = rep->head_;
+    tail.index = rep->tail_;
+  }
+
+  // Adjust begin_pos and length
+  rep->length = length;
+  rep->begin_pos_ += offset;
+
+  // Adjust head and tail blocks
+  if (head.offset) {
+    rep->AddDataOffset(head.index, head.offset);
+  }
+  if (tail.offset) {
+    rep->SubLength(rep->retreat(tail.index), tail.offset);
+  }
+
+  return Validate(rep);
+}
+
+CordRepRing* CordRepRing::RemovePrefix(CordRepRing* rep, size_t len,
+                                       size_t extra) {
+  assert(len <= rep->length);
+  if (len == rep->length) {
+    CordRep::Unref(rep);
+    return nullptr;
+  }
+
+  Position head = rep->Find(len);
+  if (rep->refcount.IsOne()) {
+    if (head.index != rep->head_) UnrefEntries(rep, rep->head_, head.index);
+    rep->head_ = head.index;
+  } else {
+    rep = Copy(rep, head.index, rep->tail_, extra);
+    head.index = rep->head_;
+  }
+
+  // Adjust begin_pos and length
+  rep->length -= len;
+  rep->begin_pos_ += len;
+
+  // Adjust head block
+  if (head.offset) {
+    rep->AddDataOffset(head.index, head.offset);
+  }
+
+  return Validate(rep);
+}
+
+CordRepRing* CordRepRing::RemoveSuffix(CordRepRing* rep, size_t len,
+                                       size_t extra) {
+  assert(len <= rep->length);
+
+  if (len == rep->length) {
+    CordRep::Unref(rep);
+    return nullptr;
+  }
+
+  Position tail = rep->FindTail(rep->length - len);
+  if (rep->refcount.IsOne()) {
+    // We adopt a privately owned rep, scrub.
+    if (tail.index != rep->tail_) UnrefEntries(rep, tail.index, rep->tail_);
+    rep->tail_ = tail.index;
+  } else {
+    // Copy subset to new rep
+    rep = Copy(rep, rep->head_, tail.index, extra);
+    tail.index = rep->tail_;
+  }
+
+  // Adjust length
+  rep->length -= len;
+
+  // Adjust tail block
+  if (tail.offset) {
+    rep->SubLength(rep->retreat(tail.index), tail.offset);
+  }
+
+  return Validate(rep);
+}
+
+// #ifdef __clang__
+// #pragma clang diagnostic pop
+// #endif
+
+}  // namespace cord_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
diff --git a/src/absl/strings/internal/cord_rep_ring.h b/src/absl/strings/internal/cord_rep_ring.h
new file mode 100644 (file)
index 0000000..d09f715
--- /dev/null
@@ -0,0 +1,589 @@
+// Copyright 2020 The Abseil Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef ABSL_STRINGS_INTERNAL_CORD_REP_RING_H_
+#define ABSL_STRINGS_INTERNAL_CORD_REP_RING_H_
+
+#include <cassert>
+#include <cstddef>
+#include <cstdint>
+#include <iosfwd>
+#include <limits>
+#include <memory>
+
+#include "absl/container/internal/layout.h"
+#include "absl/strings/internal/cord_internal.h"
+#include "absl/strings/internal/cord_rep_flat.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace cord_internal {
+
+// See https://bugs.llvm.org/show_bug.cgi?id=48477
+// #ifdef __clang__
+// #pragma clang diagnostic push
+// #pragma clang diagnostic ignored "-Wshadow"
+// #if __has_warning("-Wshadow-field")
+// #pragma clang diagnostic ignored "-Wshadow-field"
+// #endif
+// #endif
+
+// All operations modifying a ring buffer are implemented as static methods
+// requiring a CordRepRing instance with a reference adopted by the method.
+//
+// The methods return the modified ring buffer, which may be equal to the input
+// if the input was not shared, and having large enough capacity to accommodate
+// any newly added node(s). Otherwise, a copy of the input rep with the new
+// node(s) added is returned.
+//
+// Any modification on non shared ring buffers with enough capacity will then
+// require minimum atomic operations. Caller should where possible provide
+// reasonable `extra` hints for both anticipated extra `flat` byte space, as
+// well as anticipated extra nodes required for complex operations.
+//
+// Example of code creating a ring buffer, adding some data to it,
+// and discarding the buffer when done:
+//
+//   void FunWithRings() {
+//     // Create ring with 3 flats
+//     CordRep* flat = CreateFlat("Hello");
+//     CordRepRing* ring = CordRepRing::Create(flat, 2);
+//     ring = CordRepRing::Append(ring, CreateFlat(" "));
+//     ring = CordRepRing::Append(ring, CreateFlat("world"));
+//     DoSomethingWithRing(ring);
+//     CordRep::Unref(ring);
+//   }
+//
+// Example of code Copying an existing ring buffer and modifying it:
+//
+//   void MoreFunWithRings(CordRepRing* src) {
+//     CordRepRing* ring = CordRep::Ref(src)->ring();
+//     ring = CordRepRing::Append(ring, CreateFlat("Hello"));
+//     ring = CordRepRing::Append(ring, CreateFlat(" "));
+//     ring = CordRepRing::Append(ring, CreateFlat("world"));
+//     DoSomethingWithRing(ring);
+//     CordRep::Unref(ring);
+//   }
+//
+class CordRepRing : public CordRep {
+ public:
+  // `pos_type` represents a 'logical position'. A CordRepRing instance has a
+  // `begin_pos` (default 0), and each node inside the buffer will have an
+  // `end_pos` which is the `end_pos` of the previous node (or `begin_pos`) plus
+  // this node's length. The purpose is to allow for a binary search on this
+  // position, while allowing O(1) prepend and append operations.
+  using pos_type = size_t;
+
+  // `index_type` is the type for the `head`, `tail` and `capacity` indexes.
+  // Ring buffers are limited to having no more than four billion entries.
+  using index_type = uint32_t;
+
+  // `offset_type` is the type for the data offset inside a child rep's data.
+  using offset_type = uint32_t;
+
+  // Position holds the node index and relative offset into the node for
+  // some physical offset in the contained data as returned by the Find()
+  // and FindTail() methods.
+  struct Position {
+    index_type index;
+    size_t offset;
+  };
+
+  // The maximum # of child nodes that can be hosted inside a CordRepRing.
+  static constexpr size_t kMaxCapacity = (std::numeric_limits<uint32_t>::max)();
+
+  // CordRepring can not be default constructed, moved, copied or assigned.
+  CordRepRing() = delete;
+  CordRepRing(const CordRepRing&) = delete;
+  CordRepRing& operator=(const CordRepRing&) = delete;
+
+  // Returns true if this instance is valid, false if some or all of the
+  // invariants are broken. Intended for debug purposes only.
+  // `output` receives an explanation of the broken invariants.
+  bool IsValid(std::ostream& output) const;
+
+  // Returns the size in bytes for a CordRepRing with `capacity' entries.
+  static constexpr size_t AllocSize(size_t capacity);
+
+  // Returns the distance in bytes from `pos` to `end_pos`.
+  static constexpr size_t Distance(pos_type pos, pos_type end_pos);
+
+  // Creates a new ring buffer from the provided `rep`. Adopts a reference
+  // on `rep`. The returned ring buffer has a capacity of at least `extra + 1`
+  static CordRepRing* Create(CordRep* child, size_t extra = 0);
+
+  // `head`, `tail` and `capacity` indexes defining the ring buffer boundaries.
+  index_type head() const { return head_; }
+  index_type tail() const { return tail_; }
+  index_type capacity() const { return capacity_; }
+
+  // Returns the number of entries in this instance.
+  index_type entries() const { return entries(head_, tail_); }
+
+  // Returns the logical begin position of this instance.
+  pos_type begin_pos() const { return begin_pos_; }
+
+  // Returns the number of entries for a given head-tail range.
+  // Requires `head` and `tail` values to be less than `capacity()`.
+  index_type entries(index_type head, index_type tail) const {
+    assert(head < capacity_ && tail < capacity_);
+    return tail - head + ((tail > head) ? 0 : capacity_);
+  }
+
+  // Returns the logical end position of entry `index`.
+  pos_type const& entry_end_pos(index_type index) const {
+    assert(IsValidIndex(index));
+    return Layout::Partial().Pointer<0>(data_)[index];
+  }
+
+  // Returns the child pointer of entry `index`.
+  CordRep* const& entry_child(index_type index) const {
+    assert(IsValidIndex(index));
+    return Layout::Partial(capacity()).Pointer<1>(data_)[index];
+  }
+
+  // Returns the data offset of entry `index`
+  offset_type const& entry_data_offset(index_type index) const {
+    assert(IsValidIndex(index));
+    return Layout::Partial(capacity(), capacity()).Pointer<2>(data_)[index];
+  }
+
+  // Appends the provided child node to the `rep` instance.
+  // Adopts a reference from `rep` and `child` which may not be null.
+  // If the provided child is a FLAT or EXTERNAL node, or a SUBSTRING node
+  // containing a FLAT or EXTERNAL node, then flat or external the node is added
+  // 'as is', with an offset added for the SUBSTRING case.
+  // If the provided child is a RING or CONCAT tree, or a SUBSTRING of a RING or
+  // CONCAT tree, then all child nodes not excluded by any start offset or
+  // length values are added recursively.
+  static CordRepRing* Append(CordRepRing* rep, CordRep* child);
+
+  // Appends the provided string data to the `rep` instance.
+  // This function will attempt to utilize any remaining capacity in the last
+  // node of the input if that node is not shared (directly or indirectly), and
+  // of type FLAT. Remaining data will be added as one or more FLAT nodes.
+  // Any last node added to the ring buffer will be allocated with up to
+  // `extra` bytes of capacity for (anticipated) subsequent append actions.
+  static CordRepRing* Append(CordRepRing* rep, string_view data,
+                             size_t extra = 0);
+
+  // Prepends the provided child node to the `rep` instance.
+  // Adopts a reference from `rep` and `child` which may not be null.
+  // If the provided child is a FLAT or EXTERNAL node, or a SUBSTRING node
+  // containing a FLAT or EXTERNAL node, then flat or external the node is
+  // prepended 'as is', with an optional offset added for the SUBSTRING case.
+  // If the provided child is a RING or CONCAT tree, or a SUBSTRING of a RING
+  // or CONCAT tree, then all child nodes not excluded by any start offset or
+  // length values are added recursively.
+  static CordRepRing* Prepend(CordRepRing* rep, CordRep* child);
+
+  // Prepends the provided string data to the `rep` instance.
+  // This function will attempt to utilize any remaining capacity in the first
+  // node of the input if that node is not shared (directly or indirectly), and
+  // of type FLAT. Remaining data will be added as one or more FLAT nodes.
+  // Any first node prepnded to the ring buffer will be allocated with up to
+  // `extra` bytes of capacity for (anticipated) subsequent prepend actions.
+  static CordRepRing* Prepend(CordRepRing* rep, string_view data,
+                              size_t extra = 0);
+
+  // Returns a span referencing potentially unused capacity in the last node.
+  // The returned span may be empty if no such capacity is available, or if the
+  // current instance is shared. Else, a span of size `n <= size` is returned.
+  // If non empty, the ring buffer is adjusted to the new length, with the newly
+  // added capacity left uninitialized. Callers should assign a value to the
+  // entire span before any other operations on this instance.
+  Span<char> GetAppendBuffer(size_t size);
+
+  // Returns a span referencing potentially unused capacity in the first node.
+  // This function is identical to GetAppendBuffer except that it returns a span
+  // referencing up to `size` capacity directly before the existing data.
+  Span<char> GetPrependBuffer(size_t size);
+
+  // Returns a cord ring buffer containing `length` bytes of data starting at
+  // `offset`. If the input is not shared, this function will remove all head
+  // and tail child nodes outside of the requested range, and adjust the new
+  // head and tail nodes as required. If the input is shared, this function
+  // returns a new instance sharing some or all of the nodes from the input.
+  static CordRepRing* SubRing(CordRepRing* r, size_t offset, size_t length,
+                              size_t extra = 0);
+
+  // Returns a cord ring buffer with the first `length` bytes removed.
+  // If the input is not shared, this function will remove all head child nodes
+  // fully inside the first `length` bytes, and adjust the new head as required.
+  // If the input is shared, this function returns a new instance sharing some
+  // or all of the nodes from the input.
+  static CordRepRing* RemoveSuffix(CordRepRing* r, size_t length,
+                                   size_t extra = 0);
+
+  // Returns a cord ring buffer with the last `length` bytes removed.
+  // If the input is not shared, this function will remove all head child nodes
+  // fully inside the first `length` bytes, and adjust the new head as required.
+  // If the input is shared, this function returns a new instance sharing some
+  // or all of the nodes from the input.
+  static CordRepRing* RemovePrefix(CordRepRing* r, size_t len,
+                                   size_t extra = 0);
+
+  // Returns the character at `offset`. Requires that `offset < length`.
+  char GetCharacter(size_t offset) const;
+
+  // Testing only: set capacity to requested capacity.
+  void SetCapacityForTesting(size_t capacity);
+
+  // Returns the CordRep data pointer for the provided CordRep.
+  // Requires that the provided `rep` is either a FLAT or EXTERNAL CordRep.
+  static const char* GetLeafData(const CordRep* rep);
+
+  // Returns the CordRep data pointer for the provided CordRep.
+  // Requires that `rep` is either a FLAT, EXTERNAL, or SUBSTRING CordRep.
+  static const char* GetRepData(const CordRep* rep);
+
+  // Advances the provided position, wrapping around capacity as needed.
+  // Requires `index` < capacity()
+  inline index_type advance(index_type index) const;
+
+  // Advances the provided position by 'n`, wrapping around capacity as needed.
+  // Requires `index` < capacity() and `n` <= capacity.
+  inline index_type advance(index_type index, index_type n) const;
+
+  // Retreats the provided position, wrapping around 0 as needed.
+  // Requires `index` < capacity()
+  inline index_type retreat(index_type index) const;
+
+  // Retreats the provided position by 'n', wrapping around 0 as needed.
+  // Requires `index` < capacity()
+  inline index_type retreat(index_type index, index_type n) const;
+
+  // Returns the logical begin position of entry `index`
+  pos_type const& entry_begin_pos(index_type index) const {
+    return (index == head_) ? begin_pos_ : entry_end_pos(retreat(index));
+  }
+
+  // Returns the physical start offset of entry `index`
+  size_t entry_start_offset(index_type index) const {
+    return Distance(begin_pos_, entry_begin_pos(index));
+  }
+
+  // Returns the physical end offset of entry `index`
+  size_t entry_end_offset(index_type index) const {
+    return Distance(begin_pos_, entry_end_pos(index));
+  }
+
+  // Returns the data length for entry `index`
+  size_t entry_length(index_type index) const {
+    return Distance(entry_begin_pos(index), entry_end_pos(index));
+  }
+
+  // Returns the data for entry `index`
+  absl::string_view entry_data(index_type index) const;
+
+  // Returns the position for `offset` as {index, prefix}. `index` holds the
+  // index of the entry at the specified offset and `prefix` holds the relative
+  // offset inside that entry.
+  // Requires `offset` < length.
+  //
+  // For example we can implement GetCharacter(offset) as:
+  //   char GetCharacter(size_t offset) {
+  //     Position pos = this->Find(offset);
+  //     return this->entry_data(pos.pos)[pos.offset];
+  //   }
+  inline Position Find(size_t offset) const;
+
+  // Find starting at `head`
+  inline Position Find(index_type head, size_t offset) const;
+
+  // Returns the tail position for `offset` as {tail index, suffix}.
+  // `tail index` holds holds the index of the entry holding the offset directly
+  // before 'offset` advanced by one. 'suffix` holds the relative offset from
+  // that relative offset in the entry to the end of the entry.
+  // For example, FindTail(length) will return {tail(), 0}, FindTail(length - 5)
+  // will return {retreat(tail), 5)} provided the preceding entry contains at
+  // least 5 bytes of data.
+  // Requires offset >= 1 && offset <= length.
+  //
+  // This function is very useful in functions that need to clip the end of some
+  // ring buffer such as 'RemovePrefix'.
+  // For example, we could implement RemovePrefix for non shared instances as:
+  //   void RemoveSuffix(size_t n) {
+  //     Position pos = FindTail(length - n);
+  //     UnrefEntries(pos.pos, this->tail_);
+  //     this->tail_ = pos.pos;
+  //     entry(retreat(pos.pos)).end_pos -= pos.offset;
+  //   }
+  inline Position FindTail(size_t offset) const;
+
+  // Find tail starting at `head`
+  inline Position FindTail(index_type head, size_t offset) const;
+
+  // Invokes f(index_type index) for each entry inside the range [head, tail>
+  template <typename F>
+  void ForEach(index_type head, index_type tail, F&& f) const {
+    index_type n1 = (tail > head) ? tail : capacity_;
+    for (index_type i = head; i < n1; ++i) f(i);
+    if (tail <= head) {
+      for (index_type i = 0; i < tail; ++i) f(i);
+    }
+  }
+
+  // Invokes f(index_type index) for each entry inside this instance.
+  template <typename F>
+  void ForEach(F&& f) const {
+    ForEach(head_, tail_, std::forward<F>(f));
+  }
+
+  // Dump this instance's data tp stream `s` in human readable format, excluding
+  // the actual data content itself. Intended for debug purposes only.
+  friend std::ostream& operator<<(std::ostream& s, const CordRepRing& rep);
+
+ private:
+  enum class AddMode { kAppend, kPrepend };
+
+  using Layout = container_internal::Layout<pos_type, CordRep*, offset_type>;
+
+  class Filler;
+  class Transaction;
+  class CreateTransaction;
+
+  static constexpr size_t kLayoutAlignment = Layout::Partial().Alignment();
+
+  // Creates a new CordRepRing.
+  explicit CordRepRing(index_type capacity) : capacity_(capacity) {}
+
+  // Returns true if `index` is a valid index into this instance.
+  bool IsValidIndex(index_type index) const;
+
+  // Debug use only: validates the provided CordRepRing invariants.
+  // Verification of all CordRepRing methods can be enabled by defining
+  // EXTRA_CORD_RING_VALIDATION, i.e.: `--copts=-DEXTRA_CORD_RING_VALIDATION`
+  // Verification is VERY expensive, so only do it for debugging purposes.
+  static CordRepRing* Validate(CordRepRing* rep, const char* file = nullptr,
+                               int line = 0);
+
+  // Allocates a CordRepRing large enough to hold `capacity + extra' entries.
+  // The returned capacity may be larger if the allocated memory allows for it.
+  // The maximum capacity of a CordRepRing is capped at kMaxCapacity.
+  // Throws `std::length_error` if `capacity + extra' exceeds kMaxCapacity.
+  static CordRepRing* New(size_t capacity, size_t extra);
+
+  // Deallocates (but does not destroy) the provided ring buffer.
+  static void Delete(CordRepRing* rep);
+
+  // Destroys the provided ring buffer, decrementing the reference count of all
+  // contained child CordReps. The provided 1\`rep` should have a ref count of
+  // one (pre decrement destroy call observing `refcount.IsOne()`) or zero (post
+  // decrement destroy call observing `!refcount.Decrement()`).
+  static void Destroy(CordRepRing* rep);
+
+  // Returns a mutable reference to the logical end position array.
+  pos_type* entry_end_pos() {
+    return Layout::Partial().Pointer<0>(data_);
+  }
+
+  // Returns a mutable reference to the child pointer array.
+  CordRep** entry_child() {
+    return Layout::Partial(capacity()).Pointer<1>(data_);
+  }
+
+  // Returns a mutable reference to the data offset array.
+  offset_type* entry_data_offset() {
+    return Layout::Partial(capacity(), capacity()).Pointer<2>(data_);
+  }
+
+  // Find implementations for the non fast path 0 / length cases.
+  Position FindSlow(index_type head, size_t offset) const;
+  Position FindTailSlow(index_type head, size_t offset) const;
+
+  // Finds the index of the first node that is inside a reasonable distance
+  // of the node at `offset` from which we can continue with a linear search.
+  template <bool wrap>
+  index_type FindBinary(index_type head, index_type tail, size_t offset) const;
+
+  // Fills the current (initialized) instance from the provided source, copying
+  // entries [head, tail). Adds a reference to copied entries if `ref` is true.
+  template <bool ref>
+  void Fill(const CordRepRing* src, index_type head, index_type tail);
+
+  // Create a copy of 'rep', copying all entries [head, tail), allocating room
+  // for `extra` entries. Adds a reference on all copied entries.
+  static CordRepRing* Copy(CordRepRing* rep, index_type head, index_type tail,
+                           size_t extra = 0);
+
+  // Returns a Mutable CordRepRing reference from `rep` with room for at least
+  // `extra` additional nodes. Adopts a reference count from `rep`.
+  // This function will return `rep` if, and only if:
+  // - rep.entries + extra <= rep.capacity
+  // - rep.refcount == 1
+  // Otherwise, this function will create a new copy of `rep` with additional
+  // capacity to satisfy `extra` extra nodes, and unref the old `rep` instance.
+  //
+  // If a new CordRepRing can not be allocated, or the new capacity would exceed
+  // the maxmimum capacity, then the input is consumed only, and an exception is
+  // thrown.
+  static CordRepRing* Mutable(CordRepRing* rep, size_t extra);
+
+  // Slow path for Append(CordRepRing* rep, CordRep* child). This function is
+  // exercised if the provided `child` in Append() is not a leaf node, i.e., a
+  // ring buffer or old (concat) cord tree.
+  static CordRepRing* AppendSlow(CordRepRing* rep, CordRep* child);
+
+  // Appends the provided leaf node. Requires `child` to be FLAT or EXTERNAL.
+  static CordRepRing* AppendLeaf(CordRepRing* rep, CordRep* child,
+                                 size_t offset, size_t length);
+
+  // Prepends the provided leaf node. Requires `child` to be FLAT or EXTERNAL.
+  static CordRepRing* PrependLeaf(CordRepRing* rep, CordRep* child,
+                                  size_t offset, size_t length);
+
+  // Slow path for Prepend(CordRepRing* rep, CordRep* child). This function is
+  // exercised if the provided `child` in Prepend() is not a leaf node, i.e., a
+  // ring buffer or old (concat) cord tree.
+  static CordRepRing* PrependSlow(CordRepRing* rep, CordRep* child);
+
+  // Slow path for Create(CordRep* child, size_t extra). This function is
+  // exercised if the provided `child` in Prepend() is not a leaf node, i.e., a
+  // ring buffer or old (concat) cord tree.
+  static CordRepRing* CreateSlow(CordRep* child, size_t extra);
+
+  // Creates a new ring buffer from the provided `child` leaf node. Requires
+  // `child` to be FLAT or EXTERNAL. on `rep`.
+  // The returned ring buffer has a capacity of at least `1 + extra`
+  static CordRepRing* CreateFromLeaf(CordRep* child, size_t offset,
+                                     size_t length, size_t extra);
+
+  // Appends or prepends (depending on AddMode) the ring buffer in `ring' to
+  // `rep` starting at `offset` with length `length`.
+  template <AddMode mode>
+  static CordRepRing* AddRing(CordRepRing* rep, CordRepRing* ring,
+                              size_t offset, size_t length);
+
+  // Increases the data offset for entry `index` by `n`.
+  void AddDataOffset(index_type index, size_t n);
+
+  // Descreases the length for entry `index` by `n`.
+  void SubLength(index_type index, size_t n);
+
+  index_type head_;
+  index_type tail_;
+  index_type capacity_;
+  pos_type begin_pos_;
+
+  alignas(kLayoutAlignment) char data_[kLayoutAlignment];
+
+  friend struct CordRep;
+};
+
+constexpr size_t CordRepRing::AllocSize(size_t capacity) {
+  return sizeof(CordRepRing) - sizeof(data_) +
+         Layout(capacity, capacity, capacity).AllocSize();
+}
+
+inline constexpr size_t CordRepRing::Distance(pos_type pos, pos_type end_pos) {
+  return (end_pos - pos);
+}
+
+inline const char* CordRepRing::GetLeafData(const CordRep* rep) {
+  return rep->tag != EXTERNAL ? rep->flat()->Data() : rep->external()->base;
+}
+
+inline const char* CordRepRing::GetRepData(const CordRep* rep) {
+  if (rep->tag >= FLAT) return rep->flat()->Data();
+  if (rep->tag == EXTERNAL) return rep->external()->base;
+  return GetLeafData(rep->substring()->child) + rep->substring()->start;
+}
+
+inline CordRepRing::index_type CordRepRing::advance(index_type index) const {
+  assert(index < capacity_);
+  return ++index == capacity_ ? 0 : index;
+}
+
+inline CordRepRing::index_type CordRepRing::advance(index_type index,
+                                                    index_type n) const {
+  assert(index < capacity_ && n <= capacity_);
+  return (index += n) >= capacity_ ? index - capacity_ : index;
+}
+
+inline CordRepRing::index_type CordRepRing::retreat(index_type index) const {
+  assert(index < capacity_);
+  return (index > 0 ? index : capacity_) - 1;
+}
+
+inline CordRepRing::index_type CordRepRing::retreat(index_type index,
+                                                    index_type n) const {
+  assert(index < capacity_ && n <= capacity_);
+  return index >= n ? index - n : capacity_ - n + index;
+}
+
+inline absl::string_view CordRepRing::entry_data(index_type index) const {
+  size_t data_offset = entry_data_offset(index);
+  return {GetRepData(entry_child(index)) + data_offset, entry_length(index)};
+}
+
+inline bool CordRepRing::IsValidIndex(index_type index) const {
+  if (index >= capacity_) return false;
+  return (tail_ > head_) ? (index >= head_ && index < tail_)
+                         : (index >= head_ || index < tail_);
+}
+
+#ifndef EXTRA_CORD_RING_VALIDATION
+inline CordRepRing* CordRepRing::Validate(CordRepRing* rep,
+                                          const char* /*file*/, int /*line*/) {
+  return rep;
+}
+#endif
+
+inline CordRepRing::Position CordRepRing::Find(size_t offset) const {
+  assert(offset < length);
+  return (offset == 0) ? Position{head_, 0} : FindSlow(head_, offset);
+}
+
+inline CordRepRing::Position CordRepRing::Find(index_type head,
+                                               size_t offset) const {
+  assert(offset < length);
+  assert(IsValidIndex(head) && offset >= entry_start_offset(head));
+  return (offset == 0) ? Position{head_, 0} : FindSlow(head, offset);
+}
+
+inline CordRepRing::Position CordRepRing::FindTail(size_t offset) const {
+  assert(offset > 0 && offset <= length);
+  return (offset == length) ? Position{tail_, 0} : FindTailSlow(head_, offset);
+}
+
+inline CordRepRing::Position CordRepRing::FindTail(index_type head,
+                                                   size_t offset) const {
+  assert(offset > 0 && offset <= length);
+  assert(IsValidIndex(head) && offset >= entry_start_offset(head) + 1);
+  return (offset == length) ? Position{tail_, 0} : FindTailSlow(head, offset);
+}
+
+// Now that CordRepRing is defined, we can define CordRep's helper casts:
+inline CordRepRing* CordRep::ring() {
+  assert(tag == RING);
+  return static_cast<CordRepRing*>(this);
+}
+
+inline const CordRepRing* CordRep::ring() const {
+  assert(tag == RING);
+  return static_cast<const CordRepRing*>(this);
+}
+
+std::ostream& operator<<(std::ostream& s, const CordRepRing& rep);
+
+// #ifdef __clang__
+// #pragma clang diagnostic pop
+// #endif
+
+}  // namespace cord_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#endif  // ABSL_STRINGS_INTERNAL_CORD_REP_RING_H_
diff --git a/src/absl/strings/internal/cord_rep_ring_reader.h b/src/absl/strings/internal/cord_rep_ring_reader.h
new file mode 100644 (file)
index 0000000..396c0e2
--- /dev/null
@@ -0,0 +1,114 @@
+// Copyright 2021 The Abseil Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef ABSL_STRINGS_INTERNAL_CORD_REP_RING_READER_H_
+#define ABSL_STRINGS_INTERNAL_CORD_REP_RING_READER_H_
+
+#include <cassert>
+#include <cstddef>
+#include <cstdint>
+
+#include "absl/strings/internal/cord_internal.h"
+#include "absl/strings/internal/cord_rep_ring.h"
+#include "absl/strings/string_view.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace cord_internal {
+
+// CordRepRingReader provides basic navigation over CordRepRing data.
+class CordRepRingReader {
+ public:
+  // Returns true if this instance is not empty.
+  explicit operator bool() const { return ring_ != nullptr; }
+
+  // Returns the ring buffer reference for this instance, or nullptr if empty.
+  CordRepRing* ring() const { return ring_; }
+
+  // Returns the current node index inside the ring buffer for this instance.
+  // The returned value is undefined if this instance is empty.
+  CordRepRing::index_type index() const { return index_; }
+
+  // Returns the length of the referenced ring buffer.
+  // Requires the current instance to be non empty.
+  size_t length() const {
+    assert(ring_);
+    return ring_->length;
+  }
+
+  // Returns the end offset of the last navigated-to chunk, which represents the
+  // total bytes 'consumed' relative to the start of the ring. The returned
+  // value is never zero. For example, initializing a reader with a ring buffer
+  // with a first chunk of 19 bytes will return consumed() = 19.
+  // Requires the current instance to be non empty.
+  size_t consumed() const {
+    assert(ring_);
+    return ring_->entry_end_offset(index_);
+  }
+
+  // Returns the number of bytes remaining beyond the last navigated-to chunk.
+  // Requires the current instance to be non empty.
+  size_t remaining() const {
+    assert(ring_);
+    return length() - consumed();
+  }
+
+  // Resets this instance to an empty value
+  void Reset() { ring_ = nullptr; }
+
+  // Resets this instance to the start of `ring`. `ring` must not be null.
+  // Returns a reference into the first chunk of the provided ring.
+  absl::string_view Reset(CordRepRing* ring) {
+    assert(ring);
+    ring_ = ring;
+    index_ = ring_->head();
+    return ring_->entry_data(index_);
+  }
+
+  // Navigates to the next chunk inside the reference ring buffer.
+  // Returns a reference into the navigated-to chunk.
+  // Requires remaining() to be non zero.
+  absl::string_view Next() {
+    assert(remaining());
+    index_ = ring_->advance(index_);
+    return ring_->entry_data(index_);
+  }
+
+  // Navigates to the chunk at offset `offset`.
+  // Returns a reference into the navigated-to chunk, adjusted for the relative
+  // position of `offset` into that chunk. For example, calling Seek(13) on a
+  // ring buffer containing 2 chunks of 10 and 20 bytes respectively will return
+  // a string view into the second chunk starting at offset 3 with a size of 17.
+  // Requires `offset` to be less than `length()`
+  absl::string_view Seek(size_t offset) {
+    assert(offset < length());
+    size_t current = ring_->entry_end_offset(index_);
+    CordRepRing::index_type hint = (offset >= current) ? index_ : ring_->head();
+    const CordRepRing::Position head = ring_->Find(hint, offset);
+    index_ = head.index;
+    auto data = ring_->entry_data(head.index);
+    data.remove_prefix(head.offset);
+    return data;
+  }
+
+ private:
+  CordRepRing* ring_ = nullptr;
+  CordRepRing::index_type index_;
+};
+
+}  // namespace cord_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#endif  // ABSL_STRINGS_INTERNAL_CORD_REP_RING_READER_H_
diff --git a/src/absl/strings/internal/escaping.cc b/src/absl/strings/internal/escaping.cc
new file mode 100644 (file)
index 0000000..c527128
--- /dev/null
@@ -0,0 +1,180 @@
+// Copyright 2020 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "absl/strings/internal/escaping.h"
+
+#include "absl/base/internal/endian.h"
+#include "absl/base/internal/raw_logging.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace strings_internal {
+
+const char kBase64Chars[] =
+    "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+size_t CalculateBase64EscapedLenInternal(size_t input_len, bool do_padding) {
+  // Base64 encodes three bytes of input at a time. If the input is not
+  // divisible by three, we pad as appropriate.
+  //
+  // (from https://tools.ietf.org/html/rfc3548)
+  // Special processing is performed if fewer than 24 bits are available
+  // at the end of the data being encoded.  A full encoding quantum is
+  // always completed at the end of a quantity.  When fewer than 24 input
+  // bits are available in an input group, zero bits are added (on the
+  // right) to form an integral number of 6-bit groups.  Padding at the
+  // end of the data is performed using the '=' character.  Since all base
+  // 64 input is an integral number of octets, only the following cases
+  // can arise:
+
+  // Base64 encodes each three bytes of input into four bytes of output.
+  size_t len = (input_len / 3) * 4;
+
+  if (input_len % 3 == 0) {
+    // (from https://tools.ietf.org/html/rfc3548)
+    // (1) the final quantum of encoding input is an integral multiple of 24
+    // bits; here, the final unit of encoded output will be an integral
+    // multiple of 4 characters with no "=" padding,
+  } else if (input_len % 3 == 1) {
+    // (from https://tools.ietf.org/html/rfc3548)
+    // (2) the final quantum of encoding input is exactly 8 bits; here, the
+    // final unit of encoded output will be two characters followed by two
+    // "=" padding characters, or
+    len += 2;
+    if (do_padding) {
+      len += 2;
+    }
+  } else {  // (input_len % 3 == 2)
+    // (from https://tools.ietf.org/html/rfc3548)
+    // (3) the final quantum of encoding input is exactly 16 bits; here, the
+    // final unit of encoded output will be three characters followed by one
+    // "=" padding character.
+    len += 3;
+    if (do_padding) {
+      len += 1;
+    }
+  }
+
+  assert(len >= input_len);  // make sure we didn't overflow
+  return len;
+}
+
+size_t Base64EscapeInternal(const unsigned char* src, size_t szsrc, char* dest,
+                            size_t szdest, const char* base64,
+                            bool do_padding) {
+  static const char kPad64 = '=';
+
+  if (szsrc * 4 > szdest * 3) return 0;
+
+  char* cur_dest = dest;
+  const unsigned char* cur_src = src;
+
+  char* const limit_dest = dest + szdest;
+  const unsigned char* const limit_src = src + szsrc;
+
+  // Three bytes of data encodes to four characters of cyphertext.
+  // So we can pump through three-byte chunks atomically.
+  if (szsrc >= 3) {                    // "limit_src - 3" is UB if szsrc < 3.
+    while (cur_src < limit_src - 3) {  // While we have >= 32 bits.
+      uint32_t in = absl::big_endian::Load32(cur_src) >> 8;
+
+      cur_dest[0] = base64[in >> 18];
+      in &= 0x3FFFF;
+      cur_dest[1] = base64[in >> 12];
+      in &= 0xFFF;
+      cur_dest[2] = base64[in >> 6];
+      in &= 0x3F;
+      cur_dest[3] = base64[in];
+
+      cur_dest += 4;
+      cur_src += 3;
+    }
+  }
+  // To save time, we didn't update szdest or szsrc in the loop.  So do it now.
+  szdest = limit_dest - cur_dest;
+  szsrc = limit_src - cur_src;
+
+  /* now deal with the tail (<=3 bytes) */
+  switch (szsrc) {
+    case 0:
+      // Nothing left; nothing more to do.
+      break;
+    case 1: {
+      // One byte left: this encodes to two characters, and (optionally)
+      // two pad characters to round out the four-character cypherblock.
+      if (szdest < 2) return 0;
+      uint32_t in = cur_src[0];
+      cur_dest[0] = base64[in >> 2];
+      in &= 0x3;
+      cur_dest[1] = base64[in << 4];
+      cur_dest += 2;
+      szdest -= 2;
+      if (do_padding) {
+        if (szdest < 2) return 0;
+        cur_dest[0] = kPad64;
+        cur_dest[1] = kPad64;
+        cur_dest += 2;
+        szdest -= 2;
+      }
+      break;
+    }
+    case 2: {
+      // Two bytes left: this encodes to three characters, and (optionally)
+      // one pad character to round out the four-character cypherblock.
+      if (szdest < 3) return 0;
+      uint32_t in = absl::big_endian::Load16(cur_src);
+      cur_dest[0] = base64[in >> 10];
+      in &= 0x3FF;
+      cur_dest[1] = base64[in >> 4];
+      in &= 0x00F;
+      cur_dest[2] = base64[in << 2];
+      cur_dest += 3;
+      szdest -= 3;
+      if (do_padding) {
+        if (szdest < 1) return 0;
+        cur_dest[0] = kPad64;
+        cur_dest += 1;
+        szdest -= 1;
+      }
+      break;
+    }
+    case 3: {
+      // Three bytes left: same as in the big loop above.  We can't do this in
+      // the loop because the loop above always reads 4 bytes, and the fourth
+      // byte is past the end of the input.
+      if (szdest < 4) return 0;
+      uint32_t in = (cur_src[0] << 16) + absl::big_endian::Load16(cur_src + 1);
+      cur_dest[0] = base64[in >> 18];
+      in &= 0x3FFFF;
+      cur_dest[1] = base64[in >> 12];
+      in &= 0xFFF;
+      cur_dest[2] = base64[in >> 6];
+      in &= 0x3F;
+      cur_dest[3] = base64[in];
+      cur_dest += 4;
+      szdest -= 4;
+      break;
+    }
+    default:
+      // Should not be reached: blocks of 4 bytes are handled
+      // in the while loop before this switch statement.
+      ABSL_RAW_LOG(FATAL, "Logic problem? szsrc = %zu", szsrc);
+      break;
+  }
+  return (cur_dest - dest);
+}
+
+}  // namespace strings_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
diff --git a/src/absl/strings/internal/escaping.h b/src/absl/strings/internal/escaping.h
new file mode 100644 (file)
index 0000000..6a9ce60
--- /dev/null
@@ -0,0 +1,58 @@
+// Copyright 2020 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef ABSL_STRINGS_INTERNAL_ESCAPING_H_
+#define ABSL_STRINGS_INTERNAL_ESCAPING_H_
+
+#include <cassert>
+
+#include "absl/strings/internal/resize_uninitialized.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace strings_internal {
+
+ABSL_CONST_INIT extern const char kBase64Chars[];
+
+// Calculates how long a string will be when it is base64 encoded given its
+// length and whether or not the result should be padded.
+size_t CalculateBase64EscapedLenInternal(size_t input_len, bool do_padding);
+
+// Base64-encodes `src` using the alphabet provided in `base64` and writes the
+// result to `dest`. If `do_padding` is true, `dest` is padded with '=' chars
+// until its length is a multiple of 3. Returns the length of `dest`.
+size_t Base64EscapeInternal(const unsigned char* src, size_t szsrc, char* dest,
+                            size_t szdest, const char* base64, bool do_padding);
+
+// Base64-encodes `src` using the alphabet provided in `base64` and writes the
+// result to `dest`. If `do_padding` is true, `dest` is padded with '=' chars
+// until its length is a multiple of 3.
+template <typename String>
+void Base64EscapeInternal(const unsigned char* src, size_t szsrc, String* dest,
+                          bool do_padding, const char* base64_chars) {
+  const size_t calc_escaped_size =
+      CalculateBase64EscapedLenInternal(szsrc, do_padding);
+  STLStringResizeUninitialized(dest, calc_escaped_size);
+
+  const size_t escaped_len = Base64EscapeInternal(
+      src, szsrc, &(*dest)[0], dest->size(), base64_chars, do_padding);
+  assert(calc_escaped_size == escaped_len);
+  dest->erase(escaped_len);
+}
+
+}  // namespace strings_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#endif  // ABSL_STRINGS_INTERNAL_ESCAPING_H_
diff --git a/src/absl/strings/internal/memutil.cc b/src/absl/strings/internal/memutil.cc
new file mode 100644 (file)
index 0000000..2519c68
--- /dev/null
@@ -0,0 +1,112 @@
+// Copyright 2017 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "absl/strings/internal/memutil.h"
+
+#include <cstdlib>
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace strings_internal {
+
+int memcasecmp(const char* s1, const char* s2, size_t len) {
+  const unsigned char* us1 = reinterpret_cast<const unsigned char*>(s1);
+  const unsigned char* us2 = reinterpret_cast<const unsigned char*>(s2);
+
+  for (size_t i = 0; i < len; i++) {
+    const int diff =
+        int{static_cast<unsigned char>(absl::ascii_tolower(us1[i]))} -
+        int{static_cast<unsigned char>(absl::ascii_tolower(us2[i]))};
+    if (diff != 0) return diff;
+  }
+  return 0;
+}
+
+char* memdup(const char* s, size_t slen) {
+  void* copy;
+  if ((copy = malloc(slen)) == nullptr) return nullptr;
+  memcpy(copy, s, slen);
+  return reinterpret_cast<char*>(copy);
+}
+
+char* memrchr(const char* s, int c, size_t slen) {
+  for (const char* e = s + slen - 1; e >= s; e--) {
+    if (*e == c) return const_cast<char*>(e);
+  }
+  return nullptr;
+}
+
+size_t memspn(const char* s, size_t slen, const char* accept) {
+  const char* p = s;
+  const char* spanp;
+  char c, sc;
+
+cont:
+  c = *p++;
+  if (slen-- == 0) return p - 1 - s;
+  for (spanp = accept; (sc = *spanp++) != '\0';)
+    if (sc == c) goto cont;
+  return p - 1 - s;
+}
+
+size_t memcspn(const char* s, size_t slen, const char* reject) {
+  const char* p = s;
+  const char* spanp;
+  char c, sc;
+
+  while (slen-- != 0) {
+    c = *p++;
+    for (spanp = reject; (sc = *spanp++) != '\0';)
+      if (sc == c) return p - 1 - s;
+  }
+  return p - s;
+}
+
+char* mempbrk(const char* s, size_t slen, const char* accept) {
+  const char* scanp;
+  int sc;
+
+  for (; slen; ++s, --slen) {
+    for (scanp = accept; (sc = *scanp++) != '\0';)
+      if (sc == *s) return const_cast<char*>(s);
+  }
+  return nullptr;
+}
+
+// This is significantly faster for case-sensitive matches with very
+// few possible matches.  See unit test for benchmarks.
+const char* memmatch(const char* phaystack, size_t haylen, const char* pneedle,
+                     size_t neelen) {
+  if (0 == neelen) {
+    return phaystack;  // even if haylen is 0
+  }
+  if (haylen < neelen) return nullptr;
+
+  const char* match;
+  const char* hayend = phaystack + haylen - neelen + 1;
+  // A static cast is used here to work around the fact that memchr returns
+  // a void* on Posix-compliant systems and const void* on Windows.
+  while ((match = static_cast<const char*>(
+              memchr(phaystack, pneedle[0], hayend - phaystack)))) {
+    if (memcmp(match, pneedle, neelen) == 0)
+      return match;
+    else
+      phaystack = match + 1;
+  }
+  return nullptr;
+}
+
+}  // namespace strings_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
diff --git a/src/absl/strings/internal/memutil.h b/src/absl/strings/internal/memutil.h
new file mode 100644 (file)
index 0000000..9ad0535
--- /dev/null
@@ -0,0 +1,148 @@
+//
+// Copyright 2017 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// These routines provide mem versions of standard C string routines,
+// such as strpbrk.  They function exactly the same as the str versions,
+// so if you wonder what they are, replace the word "mem" by
+// "str" and check out the man page.  I could return void*, as the
+// strutil.h mem*() routines tend to do, but I return char* instead
+// since this is by far the most common way these functions are called.
+//
+// The difference between the mem and str versions is the mem version
+// takes a pointer and a length, rather than a '\0'-terminated string.
+// The memcase* routines defined here assume the locale is "C"
+// (they use absl::ascii_tolower instead of tolower).
+//
+// These routines are based on the BSD library.
+//
+// Here's a list of routines from string.h, and their mem analogues.
+// Functions in lowercase are defined in string.h; those in UPPERCASE
+// are defined here:
+//
+// strlen                  --
+// strcat strncat          MEMCAT
+// strcpy strncpy          memcpy
+// --                      memccpy   (very cool function, btw)
+// --                      memmove
+// --                      memset
+// strcmp strncmp          memcmp
+// strcasecmp strncasecmp  MEMCASECMP
+// strchr                  memchr
+// strcoll                 --
+// strxfrm                 --
+// strdup strndup          MEMDUP
+// strrchr                 MEMRCHR
+// strspn                  MEMSPN
+// strcspn                 MEMCSPN
+// strpbrk                 MEMPBRK
+// strstr                  MEMSTR MEMMEM
+// (g)strcasestr           MEMCASESTR MEMCASEMEM
+// strtok                  --
+// strprefix               MEMPREFIX      (strprefix is from strutil.h)
+// strcaseprefix           MEMCASEPREFIX  (strcaseprefix is from strutil.h)
+// strsuffix               MEMSUFFIX      (strsuffix is from strutil.h)
+// strcasesuffix           MEMCASESUFFIX  (strcasesuffix is from strutil.h)
+// --                      MEMIS
+// --                      MEMCASEIS
+// strcount                MEMCOUNT       (strcount is from strutil.h)
+
+#ifndef ABSL_STRINGS_INTERNAL_MEMUTIL_H_
+#define ABSL_STRINGS_INTERNAL_MEMUTIL_H_
+
+#include <cstddef>
+#include <cstring>
+
+#include "absl/base/port.h"  // disable some warnings on Windows
+#include "absl/strings/ascii.h"  // for absl::ascii_tolower
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace strings_internal {
+
+inline char* memcat(char* dest, size_t destlen, const char* src,
+                    size_t srclen) {
+  return reinterpret_cast<char*>(memcpy(dest + destlen, src, srclen));
+}
+
+int memcasecmp(const char* s1, const char* s2, size_t len);
+char* memdup(const char* s, size_t slen);
+char* memrchr(const char* s, int c, size_t slen);
+size_t memspn(const char* s, size_t slen, const char* accept);
+size_t memcspn(const char* s, size_t slen, const char* reject);
+char* mempbrk(const char* s, size_t slen, const char* accept);
+
+// This is for internal use only.  Don't call this directly
+template <bool case_sensitive>
+const char* int_memmatch(const char* haystack, size_t haylen,
+                         const char* needle, size_t neelen) {
+  if (0 == neelen) {
+    return haystack;  // even if haylen is 0
+  }
+  const char* hayend = haystack + haylen;
+  const char* needlestart = needle;
+  const char* needleend = needlestart + neelen;
+
+  for (; haystack < hayend; ++haystack) {
+    char hay = case_sensitive
+                   ? *haystack
+                   : absl::ascii_tolower(static_cast<unsigned char>(*haystack));
+    char nee = case_sensitive
+                   ? *needle
+                   : absl::ascii_tolower(static_cast<unsigned char>(*needle));
+    if (hay == nee) {
+      if (++needle == needleend) {
+        return haystack + 1 - neelen;
+      }
+    } else if (needle != needlestart) {
+      // must back up haystack in case a prefix matched (find "aab" in "aaab")
+      haystack -= needle - needlestart;  // for loop will advance one more
+      needle = needlestart;
+    }
+  }
+  return nullptr;
+}
+
+// These are the guys you can call directly
+inline const char* memstr(const char* phaystack, size_t haylen,
+                          const char* pneedle) {
+  return int_memmatch<true>(phaystack, haylen, pneedle, strlen(pneedle));
+}
+
+inline const char* memcasestr(const char* phaystack, size_t haylen,
+                              const char* pneedle) {
+  return int_memmatch<false>(phaystack, haylen, pneedle, strlen(pneedle));
+}
+
+inline const char* memmem(const char* phaystack, size_t haylen,
+                          const char* pneedle, size_t needlelen) {
+  return int_memmatch<true>(phaystack, haylen, pneedle, needlelen);
+}
+
+inline const char* memcasemem(const char* phaystack, size_t haylen,
+                              const char* pneedle, size_t needlelen) {
+  return int_memmatch<false>(phaystack, haylen, pneedle, needlelen);
+}
+
+// This is significantly faster for case-sensitive matches with very
+// few possible matches.  See unit test for benchmarks.
+const char* memmatch(const char* phaystack, size_t haylen, const char* pneedle,
+                     size_t neelen);
+
+}  // namespace strings_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#endif  // ABSL_STRINGS_INTERNAL_MEMUTIL_H_
diff --git a/src/absl/strings/internal/ostringstream.cc b/src/absl/strings/internal/ostringstream.cc
new file mode 100644 (file)
index 0000000..05324c7
--- /dev/null
@@ -0,0 +1,36 @@
+// Copyright 2017 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "absl/strings/internal/ostringstream.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace strings_internal {
+
+OStringStream::Buf::int_type OStringStream::overflow(int c) {
+  assert(s_);
+  if (!Buf::traits_type::eq_int_type(c, Buf::traits_type::eof()))
+    s_->push_back(static_cast<char>(c));
+  return 1;
+}
+
+std::streamsize OStringStream::xsputn(const char* s, std::streamsize n) {
+  assert(s_);
+  s_->append(s, n);
+  return n;
+}
+
+}  // namespace strings_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
diff --git a/src/absl/strings/internal/ostringstream.h b/src/absl/strings/internal/ostringstream.h
new file mode 100644 (file)
index 0000000..d25d604
--- /dev/null
@@ -0,0 +1,89 @@
+// Copyright 2017 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef ABSL_STRINGS_INTERNAL_OSTRINGSTREAM_H_
+#define ABSL_STRINGS_INTERNAL_OSTRINGSTREAM_H_
+
+#include <cassert>
+#include <ostream>
+#include <streambuf>
+#include <string>
+
+#include "absl/base/port.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace strings_internal {
+
+// The same as std::ostringstream but appends to a user-specified std::string,
+// and is faster. It is ~70% faster to create, ~50% faster to write to, and
+// completely free to extract the result std::string.
+//
+//   std::string s;
+//   OStringStream strm(&s);
+//   strm << 42 << ' ' << 3.14;  // appends to `s`
+//
+// The stream object doesn't have to be named. Starting from C++11 operator<<
+// works with rvalues of std::ostream.
+//
+//   std::string s;
+//   OStringStream(&s) << 42 << ' ' << 3.14;  // appends to `s`
+//
+// OStringStream is faster to create than std::ostringstream but it's still
+// relatively slow. Avoid creating multiple streams where a single stream will
+// do.
+//
+// Creates unnecessary instances of OStringStream: slow.
+//
+//   std::string s;
+//   OStringStream(&s) << 42;
+//   OStringStream(&s) << ' ';
+//   OStringStream(&s) << 3.14;
+//
+// Creates a single instance of OStringStream and reuses it: fast.
+//
+//   std::string s;
+//   OStringStream strm(&s);
+//   strm << 42;
+//   strm << ' ';
+//   strm << 3.14;
+//
+// Note: flush() has no effect. No reason to call it.
+class OStringStream : private std::basic_streambuf<char>, public std::ostream {
+ public:
+  // The argument can be null, in which case you'll need to call str(p) with a
+  // non-null argument before you can write to the stream.
+  //
+  // The destructor of OStringStream doesn't use the std::string. It's OK to
+  // destroy the std::string before the stream.
+  explicit OStringStream(std::string* s) : std::ostream(this), s_(s) {}
+
+  std::string* str() { return s_; }
+  const std::string* str() const { return s_; }
+  void str(std::string* s) { s_ = s; }
+
+ private:
+  using Buf = std::basic_streambuf<char>;
+
+  Buf::int_type overflow(int c) override;
+  std::streamsize xsputn(const char* s, std::streamsize n) override;
+
+  std::string* s_;
+};
+
+}  // namespace strings_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#endif  // ABSL_STRINGS_INTERNAL_OSTRINGSTREAM_H_
diff --git a/src/absl/strings/internal/pow10_helper.cc b/src/absl/strings/internal/pow10_helper.cc
new file mode 100644 (file)
index 0000000..42e96c3
--- /dev/null
@@ -0,0 +1,122 @@
+// Copyright 2018 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "absl/strings/internal/pow10_helper.h"
+
+#include <cmath>
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace strings_internal {
+
+namespace {
+
+// The exact value of 1e23 falls precisely halfway between two representable
+// doubles. Furthermore, the rounding rules we prefer (break ties by rounding
+// to the nearest even) dictate in this case that the number should be rounded
+// down, but this is not completely specified for floating-point literals in
+// C++. (It just says to use the default rounding mode of the standard
+// library.) We ensure the result we want by using a number that has an
+// unambiguous correctly rounded answer.
+constexpr double k1e23 = 9999999999999999e7;
+
+constexpr double kPowersOfTen[] = {
+    0.0,    1e-323, 1e-322, 1e-321, 1e-320, 1e-319, 1e-318, 1e-317, 1e-316,
+    1e-315, 1e-314, 1e-313, 1e-312, 1e-311, 1e-310, 1e-309, 1e-308, 1e-307,
+    1e-306, 1e-305, 1e-304, 1e-303, 1e-302, 1e-301, 1e-300, 1e-299, 1e-298,
+    1e-297, 1e-296, 1e-295, 1e-294, 1e-293, 1e-292, 1e-291, 1e-290, 1e-289,
+    1e-288, 1e-287, 1e-286, 1e-285, 1e-284, 1e-283, 1e-282, 1e-281, 1e-280,
+    1e-279, 1e-278, 1e-277, 1e-276, 1e-275, 1e-274, 1e-273, 1e-272, 1e-271,
+    1e-270, 1e-269, 1e-268, 1e-267, 1e-266, 1e-265, 1e-264, 1e-263, 1e-262,
+    1e-261, 1e-260, 1e-259, 1e-258, 1e-257, 1e-256, 1e-255, 1e-254, 1e-253,
+    1e-252, 1e-251, 1e-250, 1e-249, 1e-248, 1e-247, 1e-246, 1e-245, 1e-244,
+    1e-243, 1e-242, 1e-241, 1e-240, 1e-239, 1e-238, 1e-237, 1e-236, 1e-235,
+    1e-234, 1e-233, 1e-232, 1e-231, 1e-230, 1e-229, 1e-228, 1e-227, 1e-226,
+    1e-225, 1e-224, 1e-223, 1e-222, 1e-221, 1e-220, 1e-219, 1e-218, 1e-217,
+    1e-216, 1e-215, 1e-214, 1e-213, 1e-212, 1e-211, 1e-210, 1e-209, 1e-208,
+    1e-207, 1e-206, 1e-205, 1e-204, 1e-203, 1e-202, 1e-201, 1e-200, 1e-199,
+    1e-198, 1e-197, 1e-196, 1e-195, 1e-194, 1e-193, 1e-192, 1e-191, 1e-190,
+    1e-189, 1e-188, 1e-187, 1e-186, 1e-185, 1e-184, 1e-183, 1e-182, 1e-181,
+    1e-180, 1e-179, 1e-178, 1e-177, 1e-176, 1e-175, 1e-174, 1e-173, 1e-172,
+    1e-171, 1e-170, 1e-169, 1e-168, 1e-167, 1e-166, 1e-165, 1e-164, 1e-163,
+    1e-162, 1e-161, 1e-160, 1e-159, 1e-158, 1e-157, 1e-156, 1e-155, 1e-154,
+    1e-153, 1e-152, 1e-151, 1e-150, 1e-149, 1e-148, 1e-147, 1e-146, 1e-145,
+    1e-144, 1e-143, 1e-142, 1e-141, 1e-140, 1e-139, 1e-138, 1e-137, 1e-136,
+    1e-135, 1e-134, 1e-133, 1e-132, 1e-131, 1e-130, 1e-129, 1e-128, 1e-127,
+    1e-126, 1e-125, 1e-124, 1e-123, 1e-122, 1e-121, 1e-120, 1e-119, 1e-118,
+    1e-117, 1e-116, 1e-115, 1e-114, 1e-113, 1e-112, 1e-111, 1e-110, 1e-109,
+    1e-108, 1e-107, 1e-106, 1e-105, 1e-104, 1e-103, 1e-102, 1e-101, 1e-100,
+    1e-99,  1e-98,  1e-97,  1e-96,  1e-95,  1e-94,  1e-93,  1e-92,  1e-91,
+    1e-90,  1e-89,  1e-88,  1e-87,  1e-86,  1e-85,  1e-84,  1e-83,  1e-82,
+    1e-81,  1e-80,  1e-79,  1e-78,  1e-77,  1e-76,  1e-75,  1e-74,  1e-73,
+    1e-72,  1e-71,  1e-70,  1e-69,  1e-68,  1e-67,  1e-66,  1e-65,  1e-64,
+    1e-63,  1e-62,  1e-61,  1e-60,  1e-59,  1e-58,  1e-57,  1e-56,  1e-55,
+    1e-54,  1e-53,  1e-52,  1e-51,  1e-50,  1e-49,  1e-48,  1e-47,  1e-46,
+    1e-45,  1e-44,  1e-43,  1e-42,  1e-41,  1e-40,  1e-39,  1e-38,  1e-37,
+    1e-36,  1e-35,  1e-34,  1e-33,  1e-32,  1e-31,  1e-30,  1e-29,  1e-28,
+    1e-27,  1e-26,  1e-25,  1e-24,  1e-23,  1e-22,  1e-21,  1e-20,  1e-19,
+    1e-18,  1e-17,  1e-16,  1e-15,  1e-14,  1e-13,  1e-12,  1e-11,  1e-10,
+    1e-9,   1e-8,   1e-7,   1e-6,   1e-5,   1e-4,   1e-3,   1e-2,   1e-1,
+    1e+0,   1e+1,   1e+2,   1e+3,   1e+4,   1e+5,   1e+6,   1e+7,   1e+8,
+    1e+9,   1e+10,  1e+11,  1e+12,  1e+13,  1e+14,  1e+15,  1e+16,  1e+17,
+    1e+18,  1e+19,  1e+20,  1e+21,  1e+22,  k1e23,  1e+24,  1e+25,  1e+26,
+    1e+27,  1e+28,  1e+29,  1e+30,  1e+31,  1e+32,  1e+33,  1e+34,  1e+35,
+    1e+36,  1e+37,  1e+38,  1e+39,  1e+40,  1e+41,  1e+42,  1e+43,  1e+44,
+    1e+45,  1e+46,  1e+47,  1e+48,  1e+49,  1e+50,  1e+51,  1e+52,  1e+53,
+    1e+54,  1e+55,  1e+56,  1e+57,  1e+58,  1e+59,  1e+60,  1e+61,  1e+62,
+    1e+63,  1e+64,  1e+65,  1e+66,  1e+67,  1e+68,  1e+69,  1e+70,  1e+71,
+    1e+72,  1e+73,  1e+74,  1e+75,  1e+76,  1e+77,  1e+78,  1e+79,  1e+80,
+    1e+81,  1e+82,  1e+83,  1e+84,  1e+85,  1e+86,  1e+87,  1e+88,  1e+89,
+    1e+90,  1e+91,  1e+92,  1e+93,  1e+94,  1e+95,  1e+96,  1e+97,  1e+98,
+    1e+99,  1e+100, 1e+101, 1e+102, 1e+103, 1e+104, 1e+105, 1e+106, 1e+107,
+    1e+108, 1e+109, 1e+110, 1e+111, 1e+112, 1e+113, 1e+114, 1e+115, 1e+116,
+    1e+117, 1e+118, 1e+119, 1e+120, 1e+121, 1e+122, 1e+123, 1e+124, 1e+125,
+    1e+126, 1e+127, 1e+128, 1e+129, 1e+130, 1e+131, 1e+132, 1e+133, 1e+134,
+    1e+135, 1e+136, 1e+137, 1e+138, 1e+139, 1e+140, 1e+141, 1e+142, 1e+143,
+    1e+144, 1e+145, 1e+146, 1e+147, 1e+148, 1e+149, 1e+150, 1e+151, 1e+152,
+    1e+153, 1e+154, 1e+155, 1e+156, 1e+157, 1e+158, 1e+159, 1e+160, 1e+161,
+    1e+162, 1e+163, 1e+164, 1e+165, 1e+166, 1e+167, 1e+168, 1e+169, 1e+170,
+    1e+171, 1e+172, 1e+173, 1e+174, 1e+175, 1e+176, 1e+177, 1e+178, 1e+179,
+    1e+180, 1e+181, 1e+182, 1e+183, 1e+184, 1e+185, 1e+186, 1e+187, 1e+188,
+    1e+189, 1e+190, 1e+191, 1e+192, 1e+193, 1e+194, 1e+195, 1e+196, 1e+197,
+    1e+198, 1e+199, 1e+200, 1e+201, 1e+202, 1e+203, 1e+204, 1e+205, 1e+206,
+    1e+207, 1e+208, 1e+209, 1e+210, 1e+211, 1e+212, 1e+213, 1e+214, 1e+215,
+    1e+216, 1e+217, 1e+218, 1e+219, 1e+220, 1e+221, 1e+222, 1e+223, 1e+224,
+    1e+225, 1e+226, 1e+227, 1e+228, 1e+229, 1e+230, 1e+231, 1e+232, 1e+233,
+    1e+234, 1e+235, 1e+236, 1e+237, 1e+238, 1e+239, 1e+240, 1e+241, 1e+242,
+    1e+243, 1e+244, 1e+245, 1e+246, 1e+247, 1e+248, 1e+249, 1e+250, 1e+251,
+    1e+252, 1e+253, 1e+254, 1e+255, 1e+256, 1e+257, 1e+258, 1e+259, 1e+260,
+    1e+261, 1e+262, 1e+263, 1e+264, 1e+265, 1e+266, 1e+267, 1e+268, 1e+269,
+    1e+270, 1e+271, 1e+272, 1e+273, 1e+274, 1e+275, 1e+276, 1e+277, 1e+278,
+    1e+279, 1e+280, 1e+281, 1e+282, 1e+283, 1e+284, 1e+285, 1e+286, 1e+287,
+    1e+288, 1e+289, 1e+290, 1e+291, 1e+292, 1e+293, 1e+294, 1e+295, 1e+296,
+    1e+297, 1e+298, 1e+299, 1e+300, 1e+301, 1e+302, 1e+303, 1e+304, 1e+305,
+    1e+306, 1e+307, 1e+308,
+};
+
+}  // namespace
+
+double Pow10(int exp) {
+  if (exp < -324) {
+    return 0.0;
+  } else if (exp > 308) {
+    return INFINITY;
+  } else {
+    return kPowersOfTen[exp + 324];
+  }
+}
+
+}  // namespace strings_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
diff --git a/src/absl/strings/internal/pow10_helper.h b/src/absl/strings/internal/pow10_helper.h
new file mode 100644 (file)
index 0000000..c37c2c3
--- /dev/null
@@ -0,0 +1,40 @@
+//
+// Copyright 2018 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// This test helper library contains a table of powers of 10, to guarantee
+// precise values are computed across the full range of doubles. We can't rely
+// on the pow() function, because not all standard libraries ship a version
+// that is precise.
+#ifndef ABSL_STRINGS_INTERNAL_POW10_HELPER_H_
+#define ABSL_STRINGS_INTERNAL_POW10_HELPER_H_
+
+#include <vector>
+
+#include "absl/base/config.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace strings_internal {
+
+// Computes the precise value of 10^exp. (I.e. the nearest representable
+// double to the exact value, rounding to nearest-even in the (single) case of
+// being exactly halfway between.)
+double Pow10(int exp);
+
+}  // namespace strings_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#endif  // ABSL_STRINGS_INTERNAL_POW10_HELPER_H_
diff --git a/src/absl/strings/internal/resize_uninitialized.h b/src/absl/strings/internal/resize_uninitialized.h
new file mode 100644 (file)
index 0000000..e42628e
--- /dev/null
@@ -0,0 +1,73 @@
+//
+// Copyright 2017 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#ifndef ABSL_STRINGS_INTERNAL_RESIZE_UNINITIALIZED_H_
+#define ABSL_STRINGS_INTERNAL_RESIZE_UNINITIALIZED_H_
+
+#include <string>
+#include <type_traits>
+#include <utility>
+
+#include "absl/base/port.h"
+#include "absl/meta/type_traits.h"  //  for void_t
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace strings_internal {
+
+// Is a subclass of true_type or false_type, depending on whether or not
+// T has a __resize_default_init member.
+template <typename string_type, typename = void>
+struct ResizeUninitializedTraits {
+  using HasMember = std::false_type;
+  static void Resize(string_type* s, size_t new_size) { s->resize(new_size); }
+};
+
+// __resize_default_init is provided by libc++ >= 8.0
+template <typename string_type>
+struct ResizeUninitializedTraits<
+    string_type, absl::void_t<decltype(std::declval<string_type&>()
+                                           .__resize_default_init(237))> > {
+  using HasMember = std::true_type;
+  static void Resize(string_type* s, size_t new_size) {
+    s->__resize_default_init(new_size);
+  }
+};
+
+// Returns true if the std::string implementation supports a resize where
+// the new characters added to the std::string are left untouched.
+//
+// (A better name might be "STLStringSupportsUninitializedResize", alluding to
+// the previous function.)
+template <typename string_type>
+inline constexpr bool STLStringSupportsNontrashingResize(string_type*) {
+  return ResizeUninitializedTraits<string_type>::HasMember::value;
+}
+
+// Like str->resize(new_size), except any new characters added to "*str" as a
+// result of resizing may be left uninitialized, rather than being filled with
+// '0' bytes. Typically used when code is then going to overwrite the backing
+// store of the std::string with known data.
+template <typename string_type, typename = void>
+inline void STLStringResizeUninitialized(string_type* s, size_t new_size) {
+  ResizeUninitializedTraits<string_type>::Resize(s, new_size);
+}
+
+}  // namespace strings_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#endif  // ABSL_STRINGS_INTERNAL_RESIZE_UNINITIALIZED_H_
diff --git a/src/absl/strings/internal/stl_type_traits.h b/src/absl/strings/internal/stl_type_traits.h
new file mode 100644 (file)
index 0000000..6035ca4
--- /dev/null
@@ -0,0 +1,248 @@
+// Copyright 2017 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// Thie file provides the IsStrictlyBaseOfAndConvertibleToSTLContainer type
+// trait metafunction to assist in working with the _GLIBCXX_DEBUG debug
+// wrappers of STL containers.
+//
+// DO NOT INCLUDE THIS FILE DIRECTLY. Use this file by including
+// absl/strings/str_split.h.
+//
+// IWYU pragma: private, include "absl/strings/str_split.h"
+
+#ifndef ABSL_STRINGS_INTERNAL_STL_TYPE_TRAITS_H_
+#define ABSL_STRINGS_INTERNAL_STL_TYPE_TRAITS_H_
+
+#include <array>
+#include <bitset>
+#include <deque>
+#include <forward_list>
+#include <list>
+#include <map>
+#include <set>
+#include <type_traits>
+#include <unordered_map>
+#include <unordered_set>
+#include <vector>
+
+#include "absl/meta/type_traits.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace strings_internal {
+
+template <typename C, template <typename...> class T>
+struct IsSpecializationImpl : std::false_type {};
+template <template <typename...> class T, typename... Args>
+struct IsSpecializationImpl<T<Args...>, T> : std::true_type {};
+template <typename C, template <typename...> class T>
+using IsSpecialization = IsSpecializationImpl<absl::decay_t<C>, T>;
+
+template <typename C>
+struct IsArrayImpl : std::false_type {};
+template <template <typename, size_t> class A, typename T, size_t N>
+struct IsArrayImpl<A<T, N>> : std::is_same<A<T, N>, std::array<T, N>> {};
+template <typename C>
+using IsArray = IsArrayImpl<absl::decay_t<C>>;
+
+template <typename C>
+struct IsBitsetImpl : std::false_type {};
+template <template <size_t> class B, size_t N>
+struct IsBitsetImpl<B<N>> : std::is_same<B<N>, std::bitset<N>> {};
+template <typename C>
+using IsBitset = IsBitsetImpl<absl::decay_t<C>>;
+
+template <typename C>
+struct IsSTLContainer
+    : absl::disjunction<
+          IsArray<C>, IsBitset<C>, IsSpecialization<C, std::deque>,
+          IsSpecialization<C, std::forward_list>,
+          IsSpecialization<C, std::list>, IsSpecialization<C, std::map>,
+          IsSpecialization<C, std::multimap>, IsSpecialization<C, std::set>,
+          IsSpecialization<C, std::multiset>,
+          IsSpecialization<C, std::unordered_map>,
+          IsSpecialization<C, std::unordered_multimap>,
+          IsSpecialization<C, std::unordered_set>,
+          IsSpecialization<C, std::unordered_multiset>,
+          IsSpecialization<C, std::vector>> {};
+
+template <typename C, template <typename...> class T, typename = void>
+struct IsBaseOfSpecializationImpl : std::false_type {};
+// IsBaseOfSpecializationImpl needs multiple partial specializations to SFINAE
+// on the existence of container dependent types and plug them into the STL
+// template.
+template <typename C, template <typename, typename> class T>
+struct IsBaseOfSpecializationImpl<
+    C, T, absl::void_t<typename C::value_type, typename C::allocator_type>>
+    : std::is_base_of<C,
+                      T<typename C::value_type, typename C::allocator_type>> {};
+template <typename C, template <typename, typename, typename> class T>
+struct IsBaseOfSpecializationImpl<
+    C, T,
+    absl::void_t<typename C::key_type, typename C::key_compare,
+                 typename C::allocator_type>>
+    : std::is_base_of<C, T<typename C::key_type, typename C::key_compare,
+                           typename C::allocator_type>> {};
+template <typename C, template <typename, typename, typename, typename> class T>
+struct IsBaseOfSpecializationImpl<
+    C, T,
+    absl::void_t<typename C::key_type, typename C::mapped_type,
+                 typename C::key_compare, typename C::allocator_type>>
+    : std::is_base_of<C,
+                      T<typename C::key_type, typename C::mapped_type,
+                        typename C::key_compare, typename C::allocator_type>> {
+};
+template <typename C, template <typename, typename, typename, typename> class T>
+struct IsBaseOfSpecializationImpl<
+    C, T,
+    absl::void_t<typename C::key_type, typename C::hasher,
+                 typename C::key_equal, typename C::allocator_type>>
+    : std::is_base_of<C, T<typename C::key_type, typename C::hasher,
+                           typename C::key_equal, typename C::allocator_type>> {
+};
+template <typename C,
+          template <typename, typename, typename, typename, typename> class T>
+struct IsBaseOfSpecializationImpl<
+    C, T,
+    absl::void_t<typename C::key_type, typename C::mapped_type,
+                 typename C::hasher, typename C::key_equal,
+                 typename C::allocator_type>>
+    : std::is_base_of<C, T<typename C::key_type, typename C::mapped_type,
+                           typename C::hasher, typename C::key_equal,
+                           typename C::allocator_type>> {};
+template <typename C, template <typename...> class T>
+using IsBaseOfSpecialization = IsBaseOfSpecializationImpl<absl::decay_t<C>, T>;
+
+template <typename C>
+struct IsBaseOfArrayImpl : std::false_type {};
+template <template <typename, size_t> class A, typename T, size_t N>
+struct IsBaseOfArrayImpl<A<T, N>> : std::is_base_of<A<T, N>, std::array<T, N>> {
+};
+template <typename C>
+using IsBaseOfArray = IsBaseOfArrayImpl<absl::decay_t<C>>;
+
+template <typename C>
+struct IsBaseOfBitsetImpl : std::false_type {};
+template <template <size_t> class B, size_t N>
+struct IsBaseOfBitsetImpl<B<N>> : std::is_base_of<B<N>, std::bitset<N>> {};
+template <typename C>
+using IsBaseOfBitset = IsBaseOfBitsetImpl<absl::decay_t<C>>;
+
+template <typename C>
+struct IsBaseOfSTLContainer
+    : absl::disjunction<IsBaseOfArray<C>, IsBaseOfBitset<C>,
+                        IsBaseOfSpecialization<C, std::deque>,
+                        IsBaseOfSpecialization<C, std::forward_list>,
+                        IsBaseOfSpecialization<C, std::list>,
+                        IsBaseOfSpecialization<C, std::map>,
+                        IsBaseOfSpecialization<C, std::multimap>,
+                        IsBaseOfSpecialization<C, std::set>,
+                        IsBaseOfSpecialization<C, std::multiset>,
+                        IsBaseOfSpecialization<C, std::unordered_map>,
+                        IsBaseOfSpecialization<C, std::unordered_multimap>,
+                        IsBaseOfSpecialization<C, std::unordered_set>,
+                        IsBaseOfSpecialization<C, std::unordered_multiset>,
+                        IsBaseOfSpecialization<C, std::vector>> {};
+
+template <typename C, template <typename...> class T, typename = void>
+struct IsConvertibleToSpecializationImpl : std::false_type {};
+// IsConvertibleToSpecializationImpl needs multiple partial specializations to
+// SFINAE on the existence of container dependent types and plug them into the
+// STL template.
+template <typename C, template <typename, typename> class T>
+struct IsConvertibleToSpecializationImpl<
+    C, T, absl::void_t<typename C::value_type, typename C::allocator_type>>
+    : std::is_convertible<
+          C, T<typename C::value_type, typename C::allocator_type>> {};
+template <typename C, template <typename, typename, typename> class T>
+struct IsConvertibleToSpecializationImpl<
+    C, T,
+    absl::void_t<typename C::key_type, typename C::key_compare,
+                 typename C::allocator_type>>
+    : std::is_convertible<C, T<typename C::key_type, typename C::key_compare,
+                               typename C::allocator_type>> {};
+template <typename C, template <typename, typename, typename, typename> class T>
+struct IsConvertibleToSpecializationImpl<
+    C, T,
+    absl::void_t<typename C::key_type, typename C::mapped_type,
+                 typename C::key_compare, typename C::allocator_type>>
+    : std::is_convertible<
+          C, T<typename C::key_type, typename C::mapped_type,
+               typename C::key_compare, typename C::allocator_type>> {};
+template <typename C, template <typename, typename, typename, typename> class T>
+struct IsConvertibleToSpecializationImpl<
+    C, T,
+    absl::void_t<typename C::key_type, typename C::hasher,
+                 typename C::key_equal, typename C::allocator_type>>
+    : std::is_convertible<
+          C, T<typename C::key_type, typename C::hasher, typename C::key_equal,
+               typename C::allocator_type>> {};
+template <typename C,
+          template <typename, typename, typename, typename, typename> class T>
+struct IsConvertibleToSpecializationImpl<
+    C, T,
+    absl::void_t<typename C::key_type, typename C::mapped_type,
+                 typename C::hasher, typename C::key_equal,
+                 typename C::allocator_type>>
+    : std::is_convertible<C, T<typename C::key_type, typename C::mapped_type,
+                               typename C::hasher, typename C::key_equal,
+                               typename C::allocator_type>> {};
+template <typename C, template <typename...> class T>
+using IsConvertibleToSpecialization =
+    IsConvertibleToSpecializationImpl<absl::decay_t<C>, T>;
+
+template <typename C>
+struct IsConvertibleToArrayImpl : std::false_type {};
+template <template <typename, size_t> class A, typename T, size_t N>
+struct IsConvertibleToArrayImpl<A<T, N>>
+    : std::is_convertible<A<T, N>, std::array<T, N>> {};
+template <typename C>
+using IsConvertibleToArray = IsConvertibleToArrayImpl<absl::decay_t<C>>;
+
+template <typename C>
+struct IsConvertibleToBitsetImpl : std::false_type {};
+template <template <size_t> class B, size_t N>
+struct IsConvertibleToBitsetImpl<B<N>>
+    : std::is_convertible<B<N>, std::bitset<N>> {};
+template <typename C>
+using IsConvertibleToBitset = IsConvertibleToBitsetImpl<absl::decay_t<C>>;
+
+template <typename C>
+struct IsConvertibleToSTLContainer
+    : absl::disjunction<
+          IsConvertibleToArray<C>, IsConvertibleToBitset<C>,
+          IsConvertibleToSpecialization<C, std::deque>,
+          IsConvertibleToSpecialization<C, std::forward_list>,
+          IsConvertibleToSpecialization<C, std::list>,
+          IsConvertibleToSpecialization<C, std::map>,
+          IsConvertibleToSpecialization<C, std::multimap>,
+          IsConvertibleToSpecialization<C, std::set>,
+          IsConvertibleToSpecialization<C, std::multiset>,
+          IsConvertibleToSpecialization<C, std::unordered_map>,
+          IsConvertibleToSpecialization<C, std::unordered_multimap>,
+          IsConvertibleToSpecialization<C, std::unordered_set>,
+          IsConvertibleToSpecialization<C, std::unordered_multiset>,
+          IsConvertibleToSpecialization<C, std::vector>> {};
+
+template <typename C>
+struct IsStrictlyBaseOfAndConvertibleToSTLContainer
+    : absl::conjunction<absl::negation<IsSTLContainer<C>>,
+                        IsBaseOfSTLContainer<C>,
+                        IsConvertibleToSTLContainer<C>> {};
+
+}  // namespace strings_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
+#endif  // ABSL_STRINGS_INTERNAL_STL_TYPE_TRAITS_H_
diff --git a/src/absl/strings/internal/str_format/arg.cc b/src/absl/strings/internal/str_format/arg.cc
new file mode 100644 (file)
index 0000000..e28a29b
--- /dev/null
@@ -0,0 +1,488 @@
+// Copyright 2020 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+//
+// POSIX spec:
+//   http://pubs.opengroup.org/onlinepubs/009695399/functions/fprintf.html
+//
+#include "absl/strings/internal/str_format/arg.h"
+
+#include <cassert>
+#include <cerrno>
+#include <cstdlib>
+#include <string>
+#include <type_traits>
+
+#include "absl/base/port.h"
+#include "absl/strings/internal/str_format/float_conversion.h"
+#include "absl/strings/numbers.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace str_format_internal {
+namespace {
+
+// Reduce *capacity by s.size(), clipped to a 0 minimum.
+void ReducePadding(string_view s, size_t *capacity) {
+  *capacity = Excess(s.size(), *capacity);
+}
+
+// Reduce *capacity by n, clipped to a 0 minimum.
+void ReducePadding(size_t n, size_t *capacity) {
+  *capacity = Excess(n, *capacity);
+}
+
+template <typename T>
+struct MakeUnsigned : std::make_unsigned<T> {};
+template <>
+struct MakeUnsigned<absl::int128> {
+  using type = absl::uint128;
+};
+template <>
+struct MakeUnsigned<absl::uint128> {
+  using type = absl::uint128;
+};
+
+template <typename T>
+struct IsSigned : std::is_signed<T> {};
+template <>
+struct IsSigned<absl::int128> : std::true_type {};
+template <>
+struct IsSigned<absl::uint128> : std::false_type {};
+
+// Integral digit printer.
+// Call one of the PrintAs* routines after construction once.
+// Use with_neg_and_zero/without_neg_or_zero/is_negative to access the results.
+class IntDigits {
+ public:
+  // Print the unsigned integer as octal.
+  // Supports unsigned integral types and uint128.
+  template <typename T>
+  void PrintAsOct(T v) {
+    static_assert(!IsSigned<T>::value, "");
+    char *p = storage_ + sizeof(storage_);
+    do {
+      *--p = static_cast<char>('0' + (static_cast<size_t>(v) & 7));
+      v >>= 3;
+    } while (v);
+    start_ = p;
+    size_ = storage_ + sizeof(storage_) - p;
+  }
+
+  // Print the signed or unsigned integer as decimal.
+  // Supports all integral types.
+  template <typename T>
+  void PrintAsDec(T v) {
+    static_assert(std::is_integral<T>::value, "");
+    start_ = storage_;
+    size_ = numbers_internal::FastIntToBuffer(v, storage_) - storage_;
+  }
+
+  void PrintAsDec(int128 v) {
+    auto u = static_cast<uint128>(v);
+    bool add_neg = false;
+    if (v < 0) {
+      add_neg = true;
+      u = uint128{} - u;
+    }
+    PrintAsDec(u, add_neg);
+  }
+
+  void PrintAsDec(uint128 v, bool add_neg = false) {
+    // This function can be sped up if needed. We can call FastIntToBuffer
+    // twice, or fix FastIntToBuffer to support uint128.
+    char *p = storage_ + sizeof(storage_);
+    do {
+      p -= 2;
+      numbers_internal::PutTwoDigits(static_cast<size_t>(v % 100), p);
+      v /= 100;
+    } while (v);
+    if (p[0] == '0') {
+      // We printed one too many hexits.
+      ++p;
+    }
+    if (add_neg) {
+      *--p = '-';
+    }
+    size_ = storage_ + sizeof(storage_) - p;
+    start_ = p;
+  }
+
+  // Print the unsigned integer as hex using lowercase.
+  // Supports unsigned integral types and uint128.
+  template <typename T>
+  void PrintAsHexLower(T v) {
+    static_assert(!IsSigned<T>::value, "");
+    char *p = storage_ + sizeof(storage_);
+
+    do {
+      p -= 2;
+      constexpr const char* table = numbers_internal::kHexTable;
+      std::memcpy(p, table + 2 * (static_cast<size_t>(v) & 0xFF), 2);
+      if (sizeof(T) == 1) break;
+      v >>= 8;
+    } while (v);
+    if (p[0] == '0') {
+      // We printed one too many digits.
+      ++p;
+    }
+    start_ = p;
+    size_ = storage_ + sizeof(storage_) - p;
+  }
+
+  // Print the unsigned integer as hex using uppercase.
+  // Supports unsigned integral types and uint128.
+  template <typename T>
+  void PrintAsHexUpper(T v) {
+    static_assert(!IsSigned<T>::value, "");
+    char *p = storage_ + sizeof(storage_);
+
+    // kHexTable is only lowercase, so do it manually for uppercase.
+    do {
+      *--p = "0123456789ABCDEF"[static_cast<size_t>(v) & 15];
+      v >>= 4;
+    } while (v);
+    start_ = p;
+    size_ = storage_ + sizeof(storage_) - p;
+  }
+
+  // The printed value including the '-' sign if available.
+  // For inputs of value `0`, this will return "0"
+  string_view with_neg_and_zero() const { return {start_, size_}; }
+
+  // The printed value not including the '-' sign.
+  // For inputs of value `0`, this will return "".
+  string_view without_neg_or_zero() const {
+    static_assert('-' < '0', "The check below verifies both.");
+    size_t advance = start_[0] <= '0' ? 1 : 0;
+    return {start_ + advance, size_ - advance};
+  }
+
+  bool is_negative() const { return start_[0] == '-'; }
+
+ private:
+  const char *start_;
+  size_t size_;
+  // Max size: 128 bit value as octal -> 43 digits, plus sign char
+  char storage_[128 / 3 + 1 + 1];
+};
+
+// Note: 'o' conversions do not have a base indicator, it's just that
+// the '#' flag is specified to modify the precision for 'o' conversions.
+string_view BaseIndicator(const IntDigits &as_digits,
+                          const FormatConversionSpecImpl conv) {
+  // always show 0x for %p.
+  bool alt = conv.has_alt_flag() ||
+             conv.conversion_char() == FormatConversionCharInternal::p;
+  bool hex = (conv.conversion_char() == FormatConversionCharInternal::x ||
+              conv.conversion_char() == FormatConversionCharInternal::X ||
+              conv.conversion_char() == FormatConversionCharInternal::p);
+  // From the POSIX description of '#' flag:
+  //   "For x or X conversion specifiers, a non-zero result shall have
+  //   0x (or 0X) prefixed to it."
+  if (alt && hex && !as_digits.without_neg_or_zero().empty()) {
+    return conv.conversion_char() == FormatConversionCharInternal::X ? "0X"
+                                                                     : "0x";
+  }
+  return {};
+}
+
+string_view SignColumn(bool neg, const FormatConversionSpecImpl conv) {
+  if (conv.conversion_char() == FormatConversionCharInternal::d ||
+      conv.conversion_char() == FormatConversionCharInternal::i) {
+    if (neg) return "-";
+    if (conv.has_show_pos_flag()) return "+";
+    if (conv.has_sign_col_flag()) return " ";
+  }
+  return {};
+}
+
+bool ConvertCharImpl(unsigned char v, const FormatConversionSpecImpl conv,
+                     FormatSinkImpl *sink) {
+  size_t fill = 0;
+  if (conv.width() >= 0) fill = conv.width();
+  ReducePadding(1, &fill);
+  if (!conv.has_left_flag()) sink->Append(fill, ' ');
+  sink->Append(1, v);
+  if (conv.has_left_flag()) sink->Append(fill, ' ');
+  return true;
+}
+
+bool ConvertIntImplInnerSlow(const IntDigits &as_digits,
+                             const FormatConversionSpecImpl conv,
+                             FormatSinkImpl *sink) {
+  // Print as a sequence of Substrings:
+  //   [left_spaces][sign][base_indicator][zeroes][formatted][right_spaces]
+  size_t fill = 0;
+  if (conv.width() >= 0) fill = conv.width();
+
+  string_view formatted = as_digits.without_neg_or_zero();
+  ReducePadding(formatted, &fill);
+
+  string_view sign = SignColumn(as_digits.is_negative(), conv);
+  ReducePadding(sign, &fill);
+
+  string_view base_indicator = BaseIndicator(as_digits, conv);
+  ReducePadding(base_indicator, &fill);
+
+  int precision = conv.precision();
+  bool precision_specified = precision >= 0;
+  if (!precision_specified)
+    precision = 1;
+
+  if (conv.has_alt_flag() &&
+      conv.conversion_char() == FormatConversionCharInternal::o) {
+    // From POSIX description of the '#' (alt) flag:
+    //   "For o conversion, it increases the precision (if necessary) to
+    //   force the first digit of the result to be zero."
+    if (formatted.empty() || *formatted.begin() != '0') {
+      int needed = static_cast<int>(formatted.size()) + 1;
+      precision = std::max(precision, needed);
+    }
+  }
+
+  size_t num_zeroes = Excess(formatted.size(), precision);
+  ReducePadding(num_zeroes, &fill);
+
+  size_t num_left_spaces = !conv.has_left_flag() ? fill : 0;
+  size_t num_right_spaces = conv.has_left_flag() ? fill : 0;
+
+  // From POSIX description of the '0' (zero) flag:
+  //   "For d, i, o, u, x, and X conversion specifiers, if a precision
+  //   is specified, the '0' flag is ignored."
+  if (!precision_specified && conv.has_zero_flag()) {
+    num_zeroes += num_left_spaces;
+    num_left_spaces = 0;
+  }
+
+  sink->Append(num_left_spaces, ' ');
+  sink->Append(sign);
+  sink->Append(base_indicator);
+  sink->Append(num_zeroes, '0');
+  sink->Append(formatted);
+  sink->Append(num_right_spaces, ' ');
+  return true;
+}
+
+template <typename T>
+bool ConvertIntArg(T v, const FormatConversionSpecImpl conv,
+                   FormatSinkImpl *sink) {
+  using U = typename MakeUnsigned<T>::type;
+  IntDigits as_digits;
+
+  // This odd casting is due to a bug in -Wswitch behavior in gcc49 which causes
+  // it to complain about a switch/case type mismatch, even though both are
+  // FormatConverionChar.  Likely this is because at this point
+  // FormatConversionChar is declared, but not defined.
+  switch (static_cast<uint8_t>(conv.conversion_char())) {
+    case static_cast<uint8_t>(FormatConversionCharInternal::c):
+      return ConvertCharImpl(static_cast<unsigned char>(v), conv, sink);
+
+    case static_cast<uint8_t>(FormatConversionCharInternal::o):
+      as_digits.PrintAsOct(static_cast<U>(v));
+      break;
+
+    case static_cast<uint8_t>(FormatConversionCharInternal::x):
+      as_digits.PrintAsHexLower(static_cast<U>(v));
+      break;
+    case static_cast<uint8_t>(FormatConversionCharInternal::X):
+      as_digits.PrintAsHexUpper(static_cast<U>(v));
+      break;
+
+    case static_cast<uint8_t>(FormatConversionCharInternal::u):
+      as_digits.PrintAsDec(static_cast<U>(v));
+      break;
+
+    case static_cast<uint8_t>(FormatConversionCharInternal::d):
+    case static_cast<uint8_t>(FormatConversionCharInternal::i):
+      as_digits.PrintAsDec(v);
+      break;
+
+    case static_cast<uint8_t>(FormatConversionCharInternal::a):
+    case static_cast<uint8_t>(FormatConversionCharInternal::e):
+    case static_cast<uint8_t>(FormatConversionCharInternal::f):
+    case static_cast<uint8_t>(FormatConversionCharInternal::g):
+    case static_cast<uint8_t>(FormatConversionCharInternal::A):
+    case static_cast<uint8_t>(FormatConversionCharInternal::E):
+    case static_cast<uint8_t>(FormatConversionCharInternal::F):
+    case static_cast<uint8_t>(FormatConversionCharInternal::G):
+      return ConvertFloatImpl(static_cast<double>(v), conv, sink);
+
+    default:
+       ABSL_INTERNAL_ASSUME(false);
+  }
+
+  if (conv.is_basic()) {
+    sink->Append(as_digits.with_neg_and_zero());
+    return true;
+  }
+  return ConvertIntImplInnerSlow(as_digits, conv, sink);
+}
+
+template <typename T>
+bool ConvertFloatArg(T v, const FormatConversionSpecImpl conv,
+                     FormatSinkImpl *sink) {
+  return FormatConversionCharIsFloat(conv.conversion_char()) &&
+         ConvertFloatImpl(v, conv, sink);
+}
+
+inline bool ConvertStringArg(string_view v, const FormatConversionSpecImpl conv,
+                             FormatSinkImpl *sink) {
+  if (conv.is_basic()) {
+    sink->Append(v);
+    return true;
+  }
+  return sink->PutPaddedString(v, conv.width(), conv.precision(),
+                               conv.has_left_flag());
+}
+
+}  // namespace
+
+// ==================== Strings ====================
+StringConvertResult FormatConvertImpl(const std::string &v,
+                                      const FormatConversionSpecImpl conv,
+                                      FormatSinkImpl *sink) {
+  return {ConvertStringArg(v, conv, sink)};
+}
+
+StringConvertResult FormatConvertImpl(string_view v,
+                                      const FormatConversionSpecImpl conv,
+                                      FormatSinkImpl *sink) {
+  return {ConvertStringArg(v, conv, sink)};
+}
+
+ArgConvertResult<FormatConversionCharSetUnion(
+    FormatConversionCharSetInternal::s, FormatConversionCharSetInternal::p)>
+FormatConvertImpl(const char *v, const FormatConversionSpecImpl conv,
+                  FormatSinkImpl *sink) {
+  if (conv.conversion_char() == FormatConversionCharInternal::p)
+    return {FormatConvertImpl(VoidPtr(v), conv, sink).value};
+  size_t len;
+  if (v == nullptr) {
+    len = 0;
+  } else if (conv.precision() < 0) {
+    len = std::strlen(v);
+  } else {
+    // If precision is set, we look for the NUL-terminator on the valid range.
+    len = std::find(v, v + conv.precision(), '\0') - v;
+  }
+  return {ConvertStringArg(string_view(v, len), conv, sink)};
+}
+
+// ==================== Raw pointers ====================
+ArgConvertResult<FormatConversionCharSetInternal::p> FormatConvertImpl(
+    VoidPtr v, const FormatConversionSpecImpl conv, FormatSinkImpl *sink) {
+  if (!v.value) {
+    sink->Append("(nil)");
+    return {true};
+  }
+  IntDigits as_digits;
+  as_digits.PrintAsHexLower(v.value);
+  return {ConvertIntImplInnerSlow(as_digits, conv, sink)};
+}
+
+// ==================== Floats ====================
+FloatingConvertResult FormatConvertImpl(float v,
+                                        const FormatConversionSpecImpl conv,
+                                        FormatSinkImpl *sink) {
+  return {ConvertFloatArg(v, conv, sink)};
+}
+FloatingConvertResult FormatConvertImpl(double v,
+                                        const FormatConversionSpecImpl conv,
+                                        FormatSinkImpl *sink) {
+  return {ConvertFloatArg(v, conv, sink)};
+}
+FloatingConvertResult FormatConvertImpl(long double v,
+                                        const FormatConversionSpecImpl conv,
+                                        FormatSinkImpl *sink) {
+  return {ConvertFloatArg(v, conv, sink)};
+}
+
+// ==================== Chars ====================
+IntegralConvertResult FormatConvertImpl(char v,
+                                        const FormatConversionSpecImpl conv,
+                                        FormatSinkImpl *sink) {
+  return {ConvertIntArg(v, conv, sink)};
+}
+IntegralConvertResult FormatConvertImpl(signed char v,
+                                        const FormatConversionSpecImpl conv,
+                                        FormatSinkImpl *sink) {
+  return {ConvertIntArg(v, conv, sink)};
+}
+IntegralConvertResult FormatConvertImpl(unsigned char v,
+                                        const FormatConversionSpecImpl conv,
+                                        FormatSinkImpl *sink) {
+  return {ConvertIntArg(v, conv, sink)};
+}
+
+// ==================== Ints ====================
+IntegralConvertResult FormatConvertImpl(short v,  // NOLINT
+                                        const FormatConversionSpecImpl conv,
+                                        FormatSinkImpl *sink) {
+  return {ConvertIntArg(v, conv, sink)};
+}
+IntegralConvertResult FormatConvertImpl(unsigned short v,  // NOLINT
+                                        const FormatConversionSpecImpl conv,
+                                        FormatSinkImpl *sink) {
+  return {ConvertIntArg(v, conv, sink)};
+}
+IntegralConvertResult FormatConvertImpl(int v,
+                                        const FormatConversionSpecImpl conv,
+                                        FormatSinkImpl *sink) {
+  return {ConvertIntArg(v, conv, sink)};
+}
+IntegralConvertResult FormatConvertImpl(unsigned v,
+                                        const FormatConversionSpecImpl conv,
+                                        FormatSinkImpl *sink) {
+  return {ConvertIntArg(v, conv, sink)};
+}
+IntegralConvertResult FormatConvertImpl(long v,  // NOLINT
+                                        const FormatConversionSpecImpl conv,
+                                        FormatSinkImpl *sink) {
+  return {ConvertIntArg(v, conv, sink)};
+}
+IntegralConvertResult FormatConvertImpl(unsigned long v,  // NOLINT
+                                        const FormatConversionSpecImpl conv,
+                                        FormatSinkImpl *sink) {
+  return {ConvertIntArg(v, conv, sink)};
+}
+IntegralConvertResult FormatConvertImpl(long long v,  // NOLINT
+                                        const FormatConversionSpecImpl conv,
+                                        FormatSinkImpl *sink) {
+  return {ConvertIntArg(v, conv, sink)};
+}
+IntegralConvertResult FormatConvertImpl(unsigned long long v,  // NOLINT
+                                        const FormatConversionSpecImpl conv,
+                                        FormatSinkImpl *sink) {
+  return {ConvertIntArg(v, conv, sink)};
+}
+IntegralConvertResult FormatConvertImpl(absl::int128 v,
+                                        const FormatConversionSpecImpl conv,
+                                        FormatSinkImpl *sink) {
+  return {ConvertIntArg(v, conv, sink)};
+}
+IntegralConvertResult FormatConvertImpl(absl::uint128 v,
+                                        const FormatConversionSpecImpl conv,
+                                        FormatSinkImpl *sink) {
+  return {ConvertIntArg(v, conv, sink)};
+}
+
+ABSL_INTERNAL_FORMAT_DISPATCH_OVERLOADS_EXPAND_();
+
+
+
+}  // namespace str_format_internal
+
+ABSL_NAMESPACE_END
+}  // namespace absl
diff --git a/src/absl/strings/internal/str_format/arg.h b/src/absl/strings/internal/str_format/arg.h
new file mode 100644 (file)
index 0000000..7040c86
--- /dev/null
@@ -0,0 +1,518 @@
+// Copyright 2020 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef ABSL_STRINGS_INTERNAL_STR_FORMAT_ARG_H_
+#define ABSL_STRINGS_INTERNAL_STR_FORMAT_ARG_H_
+
+#include <string.h>
+#include <wchar.h>
+
+#include <cstdio>
+#include <iomanip>
+#include <limits>
+#include <memory>
+#include <sstream>
+#include <string>
+#include <type_traits>
+
+#include "absl/base/port.h"
+#include "absl/meta/type_traits.h"
+#include "absl/numeric/int128.h"
+#include "absl/strings/internal/str_format/extension.h"
+#include "absl/strings/string_view.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+
+class Cord;
+class FormatCountCapture;
+class FormatSink;
+
+template <absl::FormatConversionCharSet C>
+struct FormatConvertResult;
+class FormatConversionSpec;
+
+namespace str_format_internal {
+
+template <typename T, typename = void>
+struct HasUserDefinedConvert : std::false_type {};
+
+template <typename T>
+struct HasUserDefinedConvert<T, void_t<decltype(AbslFormatConvert(
+                                    std::declval<const T&>(),
+                                    std::declval<const FormatConversionSpec&>(),
+                                    std::declval<FormatSink*>()))>>
+    : std::true_type {};
+
+void AbslFormatConvert();  // Stops the lexical name lookup
+template <typename T>
+auto FormatConvertImpl(const T& v, FormatConversionSpecImpl conv,
+                       FormatSinkImpl* sink)
+    -> decltype(AbslFormatConvert(v,
+                                  std::declval<const FormatConversionSpec&>(),
+                                  std::declval<FormatSink*>())) {
+  using FormatConversionSpecT =
+      absl::enable_if_t<sizeof(const T& (*)()) != 0, FormatConversionSpec>;
+  using FormatSinkT =
+      absl::enable_if_t<sizeof(const T& (*)()) != 0, FormatSink>;
+  auto fcs = conv.Wrap<FormatConversionSpecT>();
+  auto fs = sink->Wrap<FormatSinkT>();
+  return AbslFormatConvert(v, fcs, &fs);
+}
+
+template <typename T>
+class StreamedWrapper;
+
+// If 'v' can be converted (in the printf sense) according to 'conv',
+// then convert it, appending to `sink` and return `true`.
+// Otherwise fail and return `false`.
+
+// AbslFormatConvert(v, conv, sink) is intended to be found by ADL on 'v'
+// as an extension mechanism. These FormatConvertImpl functions are the default
+// implementations.
+// The ADL search is augmented via the 'Sink*' parameter, which also
+// serves as a disambiguator to reject possible unintended 'AbslFormatConvert'
+// functions in the namespaces associated with 'v'.
+
+// Raw pointers.
+struct VoidPtr {
+  VoidPtr() = default;
+  template <typename T,
+            decltype(reinterpret_cast<uintptr_t>(std::declval<T*>())) = 0>
+  VoidPtr(T* ptr)  // NOLINT
+      : value(ptr ? reinterpret_cast<uintptr_t>(ptr) : 0) {}
+  uintptr_t value;
+};
+
+template <FormatConversionCharSet C>
+struct ArgConvertResult {
+  bool value;
+};
+
+template <FormatConversionCharSet C>
+constexpr FormatConversionCharSet ExtractCharSet(FormatConvertResult<C>) {
+  return C;
+}
+
+template <FormatConversionCharSet C>
+constexpr FormatConversionCharSet ExtractCharSet(ArgConvertResult<C>) {
+  return C;
+}
+
+using StringConvertResult =
+    ArgConvertResult<FormatConversionCharSetInternal::s>;
+ArgConvertResult<FormatConversionCharSetInternal::p> FormatConvertImpl(
+    VoidPtr v, FormatConversionSpecImpl conv, FormatSinkImpl* sink);
+
+// Strings.
+StringConvertResult FormatConvertImpl(const std::string& v,
+                                      FormatConversionSpecImpl conv,
+                                      FormatSinkImpl* sink);
+StringConvertResult FormatConvertImpl(string_view v,
+                                      FormatConversionSpecImpl conv,
+                                      FormatSinkImpl* sink);
+ArgConvertResult<FormatConversionCharSetUnion(
+    FormatConversionCharSetInternal::s, FormatConversionCharSetInternal::p)>
+FormatConvertImpl(const char* v, const FormatConversionSpecImpl conv,
+                  FormatSinkImpl* sink);
+
+template <class AbslCord, typename std::enable_if<std::is_same<
+                              AbslCord, absl::Cord>::value>::type* = nullptr>
+StringConvertResult FormatConvertImpl(const AbslCord& value,
+                                      FormatConversionSpecImpl conv,
+                                      FormatSinkImpl* sink) {
+  bool is_left = conv.has_left_flag();
+  size_t space_remaining = 0;
+
+  int width = conv.width();
+  if (width >= 0) space_remaining = width;
+
+  size_t to_write = value.size();
+
+  int precision = conv.precision();
+  if (precision >= 0)
+    to_write = (std::min)(to_write, static_cast<size_t>(precision));
+
+  space_remaining = Excess(to_write, space_remaining);
+
+  if (space_remaining > 0 && !is_left) sink->Append(space_remaining, ' ');
+
+  for (string_view piece : value.Chunks()) {
+    if (piece.size() > to_write) {
+      piece.remove_suffix(piece.size() - to_write);
+      to_write = 0;
+    } else {
+      to_write -= piece.size();
+    }
+    sink->Append(piece);
+    if (to_write == 0) {
+      break;
+    }
+  }
+
+  if (space_remaining > 0 && is_left) sink->Append(space_remaining, ' ');
+  return {true};
+}
+
+using IntegralConvertResult = ArgConvertResult<FormatConversionCharSetUnion(
+    FormatConversionCharSetInternal::c,
+    FormatConversionCharSetInternal::kNumeric,
+    FormatConversionCharSetInternal::kStar)>;
+using FloatingConvertResult =
+    ArgConvertResult<FormatConversionCharSetInternal::kFloating>;
+
+// Floats.
+FloatingConvertResult FormatConvertImpl(float v, FormatConversionSpecImpl conv,
+                                        FormatSinkImpl* sink);
+FloatingConvertResult FormatConvertImpl(double v, FormatConversionSpecImpl conv,
+                                        FormatSinkImpl* sink);
+FloatingConvertResult FormatConvertImpl(long double v,
+                                        FormatConversionSpecImpl conv,
+                                        FormatSinkImpl* sink);
+
+// Chars.
+IntegralConvertResult FormatConvertImpl(char v, FormatConversionSpecImpl conv,
+                                        FormatSinkImpl* sink);
+IntegralConvertResult FormatConvertImpl(signed char v,
+                                        FormatConversionSpecImpl conv,
+                                        FormatSinkImpl* sink);
+IntegralConvertResult FormatConvertImpl(unsigned char v,
+                                        FormatConversionSpecImpl conv,
+                                        FormatSinkImpl* sink);
+
+// Ints.
+IntegralConvertResult FormatConvertImpl(short v,  // NOLINT
+                                        FormatConversionSpecImpl conv,
+                                        FormatSinkImpl* sink);
+IntegralConvertResult FormatConvertImpl(unsigned short v,  // NOLINT
+                                        FormatConversionSpecImpl conv,
+                                        FormatSinkImpl* sink);
+IntegralConvertResult FormatConvertImpl(int v, FormatConversionSpecImpl conv,
+                                        FormatSinkImpl* sink);
+IntegralConvertResult FormatConvertImpl(unsigned v,
+                                        FormatConversionSpecImpl conv,
+                                        FormatSinkImpl* sink);
+IntegralConvertResult FormatConvertImpl(long v,  // NOLINT
+                                        FormatConversionSpecImpl conv,
+                                        FormatSinkImpl* sink);
+IntegralConvertResult FormatConvertImpl(unsigned long v,  // NOLINT
+                                        FormatConversionSpecImpl conv,
+                                        FormatSinkImpl* sink);
+IntegralConvertResult FormatConvertImpl(long long v,  // NOLINT
+                                        FormatConversionSpecImpl conv,
+                                        FormatSinkImpl* sink);
+IntegralConvertResult FormatConvertImpl(unsigned long long v,  // NOLINT
+                                        FormatConversionSpecImpl conv,
+                                        FormatSinkImpl* sink);
+IntegralConvertResult FormatConvertImpl(int128 v, FormatConversionSpecImpl conv,
+                                        FormatSinkImpl* sink);
+IntegralConvertResult FormatConvertImpl(uint128 v,
+                                        FormatConversionSpecImpl conv,
+                                        FormatSinkImpl* sink);
+template <typename T, enable_if_t<std::is_same<T, bool>::value, int> = 0>
+IntegralConvertResult FormatConvertImpl(T v, FormatConversionSpecImpl conv,
+                                        FormatSinkImpl* sink) {
+  return FormatConvertImpl(static_cast<int>(v), conv, sink);
+}
+
+// We provide this function to help the checker, but it is never defined.
+// FormatArgImpl will use the underlying Convert functions instead.
+template <typename T>
+typename std::enable_if<std::is_enum<T>::value &&
+                            !HasUserDefinedConvert<T>::value,
+                        IntegralConvertResult>::type
+FormatConvertImpl(T v, FormatConversionSpecImpl conv, FormatSinkImpl* sink);
+
+template <typename T>
+StringConvertResult FormatConvertImpl(const StreamedWrapper<T>& v,
+                                      FormatConversionSpecImpl conv,
+                                      FormatSinkImpl* out) {
+  std::ostringstream oss;
+  oss << v.v_;
+  if (!oss) return {false};
+  return str_format_internal::FormatConvertImpl(oss.str(), conv, out);
+}
+
+// Use templates and dependent types to delay evaluation of the function
+// until after FormatCountCapture is fully defined.
+struct FormatCountCaptureHelper {
+  template <class T = int>
+  static ArgConvertResult<FormatConversionCharSetInternal::n> ConvertHelper(
+      const FormatCountCapture& v, FormatConversionSpecImpl conv,
+      FormatSinkImpl* sink) {
+    const absl::enable_if_t<sizeof(T) != 0, FormatCountCapture>& v2 = v;
+
+    if (conv.conversion_char() !=
+        str_format_internal::FormatConversionCharInternal::n) {
+      return {false};
+    }
+    *v2.p_ = static_cast<int>(sink->size());
+    return {true};
+  }
+};
+
+template <class T = int>
+ArgConvertResult<FormatConversionCharSetInternal::n> FormatConvertImpl(
+    const FormatCountCapture& v, FormatConversionSpecImpl conv,
+    FormatSinkImpl* sink) {
+  return FormatCountCaptureHelper::ConvertHelper(v, conv, sink);
+}
+
+// Helper friend struct to hide implementation details from the public API of
+// FormatArgImpl.
+struct FormatArgImplFriend {
+  template <typename Arg>
+  static bool ToInt(Arg arg, int* out) {
+    // A value initialized FormatConversionSpecImpl has a `none` conv, which
+    // tells the dispatcher to run the `int` conversion.
+    return arg.dispatcher_(arg.data_, {}, out);
+  }
+
+  template <typename Arg>
+  static bool Convert(Arg arg, FormatConversionSpecImpl conv,
+                      FormatSinkImpl* out) {
+    return arg.dispatcher_(arg.data_, conv, out);
+  }
+
+  template <typename Arg>
+  static typename Arg::Dispatcher GetVTablePtrForTest(Arg arg) {
+    return arg.dispatcher_;
+  }
+};
+
+template <typename Arg>
+constexpr FormatConversionCharSet ArgumentToConv() {
+  return absl::str_format_internal::ExtractCharSet(
+      decltype(str_format_internal::FormatConvertImpl(
+          std::declval<const Arg&>(),
+          std::declval<const FormatConversionSpecImpl&>(),
+          std::declval<FormatSinkImpl*>())){});
+}
+
+// A type-erased handle to a format argument.
+class FormatArgImpl {
+ private:
+  enum { kInlinedSpace = 8 };
+
+  using VoidPtr = str_format_internal::VoidPtr;
+
+  union Data {
+    const void* ptr;
+    const volatile void* volatile_ptr;
+    char buf[kInlinedSpace];
+  };
+
+  using Dispatcher = bool (*)(Data, FormatConversionSpecImpl, void* out);
+
+  template <typename T>
+  struct store_by_value
+      : std::integral_constant<bool, (sizeof(T) <= kInlinedSpace) &&
+                                         (std::is_integral<T>::value ||
+                                          std::is_floating_point<T>::value ||
+                                          std::is_pointer<T>::value ||
+                                          std::is_same<VoidPtr, T>::value)> {};
+
+  enum StoragePolicy { ByPointer, ByVolatilePointer, ByValue };
+  template <typename T>
+  struct storage_policy
+      : std::integral_constant<StoragePolicy,
+                               (std::is_volatile<T>::value
+                                    ? ByVolatilePointer
+                                    : (store_by_value<T>::value ? ByValue
+                                                                : ByPointer))> {
+  };
+
+  // To reduce the number of vtables we will decay values before hand.
+  // Anything with a user-defined Convert will get its own vtable.
+  // For everything else:
+  //   - Decay char* and char arrays into `const char*`
+  //   - Decay any other pointer to `const void*`
+  //   - Decay all enums to their underlying type.
+  //   - Decay function pointers to void*.
+  template <typename T, typename = void>
+  struct DecayType {
+    static constexpr bool kHasUserDefined =
+        str_format_internal::HasUserDefinedConvert<T>::value;
+    using type = typename std::conditional<
+        !kHasUserDefined && std::is_convertible<T, const char*>::value,
+        const char*,
+        typename std::conditional<!kHasUserDefined &&
+                                      std::is_convertible<T, VoidPtr>::value,
+                                  VoidPtr, const T&>::type>::type;
+  };
+  template <typename T>
+  struct DecayType<T,
+                   typename std::enable_if<
+                       !str_format_internal::HasUserDefinedConvert<T>::value &&
+                       std::is_enum<T>::value>::type> {
+    using type = typename std::underlying_type<T>::type;
+  };
+
+ public:
+  template <typename T>
+  explicit FormatArgImpl(const T& value) {
+    using D = typename DecayType<T>::type;
+    static_assert(
+        std::is_same<D, const T&>::value || storage_policy<D>::value == ByValue,
+        "Decayed types must be stored by value");
+    Init(static_cast<D>(value));
+  }
+
+ private:
+  friend struct str_format_internal::FormatArgImplFriend;
+  template <typename T, StoragePolicy = storage_policy<T>::value>
+  struct Manager;
+
+  template <typename T>
+  struct Manager<T, ByPointer> {
+    static Data SetValue(const T& value) {
+      Data data;
+      data.ptr = std::addressof(value);
+      return data;
+    }
+
+    static const T& Value(Data arg) { return *static_cast<const T*>(arg.ptr); }
+  };
+
+  template <typename T>
+  struct Manager<T, ByVolatilePointer> {
+    static Data SetValue(const T& value) {
+      Data data;
+      data.volatile_ptr = &value;
+      return data;
+    }
+
+    static const T& Value(Data arg) {
+      return *static_cast<const T*>(arg.volatile_ptr);
+    }
+  };
+
+  template <typename T>
+  struct Manager<T, ByValue> {
+    static Data SetValue(const T& value) {
+      Data data;
+      memcpy(data.buf, &value, sizeof(value));
+      return data;
+    }
+
+    static T Value(Data arg) {
+      T value;
+      memcpy(&value, arg.buf, sizeof(T));
+      return value;
+    }
+  };
+
+  template <typename T>
+  void Init(const T& value) {
+    data_ = Manager<T>::SetValue(value);
+    dispatcher_ = &Dispatch<T>;
+  }
+
+  template <typename T>
+  static int ToIntVal(const T& val) {
+    using CommonType = typename std::conditional<std::is_signed<T>::value,
+                                                 int64_t, uint64_t>::type;
+    if (static_cast<CommonType>(val) >
+        static_cast<CommonType>((std::numeric_limits<int>::max)())) {
+      return (std::numeric_limits<int>::max)();
+    } else if (std::is_signed<T>::value &&
+               static_cast<CommonType>(val) <
+                   static_cast<CommonType>((std::numeric_limits<int>::min)())) {
+      return (std::numeric_limits<int>::min)();
+    }
+    return static_cast<int>(val);
+  }
+
+  template <typename T>
+  static bool ToInt(Data arg, int* out, std::true_type /* is_integral */,
+                    std::false_type) {
+    *out = ToIntVal(Manager<T>::Value(arg));
+    return true;
+  }
+
+  template <typename T>
+  static bool ToInt(Data arg, int* out, std::false_type,
+                    std::true_type /* is_enum */) {
+    *out = ToIntVal(static_cast<typename std::underlying_type<T>::type>(
+        Manager<T>::Value(arg)));
+    return true;
+  }
+
+  template <typename T>
+  static bool ToInt(Data, int*, std::false_type, std::false_type) {
+    return false;
+  }
+
+  template <typename T>
+  static bool Dispatch(Data arg, FormatConversionSpecImpl spec, void* out) {
+    // A `none` conv indicates that we want the `int` conversion.
+    if (ABSL_PREDICT_FALSE(spec.conversion_char() ==
+                           FormatConversionCharInternal::kNone)) {
+      return ToInt<T>(arg, static_cast<int*>(out), std::is_integral<T>(),
+                      std::is_enum<T>());
+    }
+    if (ABSL_PREDICT_FALSE(!Contains(ArgumentToConv<T>(),
+                                     spec.conversion_char()))) {
+      return false;
+    }
+    return str_format_internal::FormatConvertImpl(
+               Manager<T>::Value(arg), spec,
+               static_cast<FormatSinkImpl*>(out))
+        .value;
+  }
+
+  Data data_;
+  Dispatcher dispatcher_;
+};
+
+#define ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(T, E)                     \
+  E template bool FormatArgImpl::Dispatch<T>(Data, FormatConversionSpecImpl, \
+                                             void*)
+
+#define ABSL_INTERNAL_FORMAT_DISPATCH_OVERLOADS_EXPAND_(...)                   \
+  ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(str_format_internal::VoidPtr,     \
+                                             __VA_ARGS__);                     \
+  ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(bool, __VA_ARGS__);               \
+  ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(char, __VA_ARGS__);               \
+  ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(signed char, __VA_ARGS__);        \
+  ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(unsigned char, __VA_ARGS__);      \
+  ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(short, __VA_ARGS__); /* NOLINT */ \
+  ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(unsigned short,      /* NOLINT */ \
+                                             __VA_ARGS__);                     \
+  ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(int, __VA_ARGS__);                \
+  ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(unsigned int, __VA_ARGS__);       \
+  ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(long, __VA_ARGS__); /* NOLINT */  \
+  ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(unsigned long,      /* NOLINT */  \
+                                             __VA_ARGS__);                     \
+  ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(long long, /* NOLINT */           \
+                                             __VA_ARGS__);                     \
+  ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(unsigned long long, /* NOLINT */  \
+                                             __VA_ARGS__);                     \
+  ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(int128, __VA_ARGS__);             \
+  ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(uint128, __VA_ARGS__);            \
+  ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(float, __VA_ARGS__);              \
+  ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(double, __VA_ARGS__);             \
+  ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(long double, __VA_ARGS__);        \
+  ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(const char*, __VA_ARGS__);        \
+  ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(std::string, __VA_ARGS__);        \
+  ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(string_view, __VA_ARGS__)
+
+ABSL_INTERNAL_FORMAT_DISPATCH_OVERLOADS_EXPAND_(extern);
+
+
+}  // namespace str_format_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#endif  // ABSL_STRINGS_INTERNAL_STR_FORMAT_ARG_H_
diff --git a/src/absl/strings/internal/str_format/bind.cc b/src/absl/strings/internal/str_format/bind.cc
new file mode 100644 (file)
index 0000000..4e68b90
--- /dev/null
@@ -0,0 +1,259 @@
+// Copyright 2020 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "absl/strings/internal/str_format/bind.h"
+
+#include <cerrno>
+#include <limits>
+#include <sstream>
+#include <string>
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace str_format_internal {
+
+namespace {
+
+inline bool BindFromPosition(int position, int* value,
+                             absl::Span<const FormatArgImpl> pack) {
+  assert(position > 0);
+  if (static_cast<size_t>(position) > pack.size()) {
+    return false;
+  }
+  // -1 because positions are 1-based
+  return FormatArgImplFriend::ToInt(pack[position - 1], value);
+}
+
+class ArgContext {
+ public:
+  explicit ArgContext(absl::Span<const FormatArgImpl> pack) : pack_(pack) {}
+
+  // Fill 'bound' with the results of applying the context's argument pack
+  // to the specified 'unbound'. We synthesize a BoundConversion by
+  // lining up a UnboundConversion with a user argument. We also
+  // resolve any '*' specifiers for width and precision, so after
+  // this call, 'bound' has all the information it needs to be formatted.
+  // Returns false on failure.
+  bool Bind(const UnboundConversion* unbound, BoundConversion* bound);
+
+ private:
+  absl::Span<const FormatArgImpl> pack_;
+};
+
+inline bool ArgContext::Bind(const UnboundConversion* unbound,
+                             BoundConversion* bound) {
+  const FormatArgImpl* arg = nullptr;
+  int arg_position = unbound->arg_position;
+  if (static_cast<size_t>(arg_position - 1) >= pack_.size()) return false;
+  arg = &pack_[arg_position - 1];  // 1-based
+
+  if (!unbound->flags.basic) {
+    int width = unbound->width.value();
+    bool force_left = false;
+    if (unbound->width.is_from_arg()) {
+      if (!BindFromPosition(unbound->width.get_from_arg(), &width, pack_))
+        return false;
+      if (width < 0) {
+        // "A negative field width is taken as a '-' flag followed by a
+        // positive field width."
+        force_left = true;
+        // Make sure we don't overflow the width when negating it.
+        width = -std::max(width, -std::numeric_limits<int>::max());
+      }
+    }
+
+    int precision = unbound->precision.value();
+    if (unbound->precision.is_from_arg()) {
+      if (!BindFromPosition(unbound->precision.get_from_arg(), &precision,
+                            pack_))
+        return false;
+    }
+
+    FormatConversionSpecImplFriend::SetWidth(width, bound);
+    FormatConversionSpecImplFriend::SetPrecision(precision, bound);
+
+    if (force_left) {
+      Flags flags = unbound->flags;
+      flags.left = true;
+      FormatConversionSpecImplFriend::SetFlags(flags, bound);
+    } else {
+      FormatConversionSpecImplFriend::SetFlags(unbound->flags, bound);
+    }
+  } else {
+    FormatConversionSpecImplFriend::SetFlags(unbound->flags, bound);
+    FormatConversionSpecImplFriend::SetWidth(-1, bound);
+    FormatConversionSpecImplFriend::SetPrecision(-1, bound);
+  }
+  FormatConversionSpecImplFriend::SetConversionChar(unbound->conv, bound);
+  bound->set_arg(arg);
+  return true;
+}
+
+template <typename Converter>
+class ConverterConsumer {
+ public:
+  ConverterConsumer(Converter converter, absl::Span<const FormatArgImpl> pack)
+      : converter_(converter), arg_context_(pack) {}
+
+  bool Append(string_view s) {
+    converter_.Append(s);
+    return true;
+  }
+  bool ConvertOne(const UnboundConversion& conv, string_view conv_string) {
+    BoundConversion bound;
+    if (!arg_context_.Bind(&conv, &bound)) return false;
+    return converter_.ConvertOne(bound, conv_string);
+  }
+
+ private:
+  Converter converter_;
+  ArgContext arg_context_;
+};
+
+template <typename Converter>
+bool ConvertAll(const UntypedFormatSpecImpl format,
+                absl::Span<const FormatArgImpl> args, Converter converter) {
+  if (format.has_parsed_conversion()) {
+    return format.parsed_conversion()->ProcessFormat(
+        ConverterConsumer<Converter>(converter, args));
+  } else {
+    return ParseFormatString(format.str(),
+                             ConverterConsumer<Converter>(converter, args));
+  }
+}
+
+class DefaultConverter {
+ public:
+  explicit DefaultConverter(FormatSinkImpl* sink) : sink_(sink) {}
+
+  void Append(string_view s) const { sink_->Append(s); }
+
+  bool ConvertOne(const BoundConversion& bound, string_view /*conv*/) const {
+    return FormatArgImplFriend::Convert(*bound.arg(), bound, sink_);
+  }
+
+ private:
+  FormatSinkImpl* sink_;
+};
+
+class SummarizingConverter {
+ public:
+  explicit SummarizingConverter(FormatSinkImpl* sink) : sink_(sink) {}
+
+  void Append(string_view s) const { sink_->Append(s); }
+
+  bool ConvertOne(const BoundConversion& bound, string_view /*conv*/) const {
+    UntypedFormatSpecImpl spec("%d");
+
+    std::ostringstream ss;
+    ss << "{" << Streamable(spec, {*bound.arg()}) << ":"
+       << FormatConversionSpecImplFriend::FlagsToString(bound);
+    if (bound.width() >= 0) ss << bound.width();
+    if (bound.precision() >= 0) ss << "." << bound.precision();
+    ss << bound.conversion_char() << "}";
+    Append(ss.str());
+    return true;
+  }
+
+ private:
+  FormatSinkImpl* sink_;
+};
+
+}  // namespace
+
+bool BindWithPack(const UnboundConversion* props,
+                  absl::Span<const FormatArgImpl> pack,
+                  BoundConversion* bound) {
+  return ArgContext(pack).Bind(props, bound);
+}
+
+std::string Summarize(const UntypedFormatSpecImpl format,
+                      absl::Span<const FormatArgImpl> args) {
+  typedef SummarizingConverter Converter;
+  std::string out;
+  {
+    // inner block to destroy sink before returning out. It ensures a last
+    // flush.
+    FormatSinkImpl sink(&out);
+    if (!ConvertAll(format, args, Converter(&sink))) {
+      return "";
+    }
+  }
+  return out;
+}
+
+bool FormatUntyped(FormatRawSinkImpl raw_sink,
+                   const UntypedFormatSpecImpl format,
+                   absl::Span<const FormatArgImpl> args) {
+  FormatSinkImpl sink(raw_sink);
+  using Converter = DefaultConverter;
+  return ConvertAll(format, args, Converter(&sink));
+}
+
+std::ostream& Streamable::Print(std::ostream& os) const {
+  if (!FormatUntyped(&os, format_, args_)) os.setstate(std::ios::failbit);
+  return os;
+}
+
+std::string& AppendPack(std::string* out, const UntypedFormatSpecImpl format,
+                        absl::Span<const FormatArgImpl> args) {
+  size_t orig = out->size();
+  if (ABSL_PREDICT_FALSE(!FormatUntyped(out, format, args))) {
+    out->erase(orig);
+  }
+  return *out;
+}
+
+std::string FormatPack(const UntypedFormatSpecImpl format,
+                       absl::Span<const FormatArgImpl> args) {
+  std::string out;
+  if (ABSL_PREDICT_FALSE(!FormatUntyped(&out, format, args))) {
+    out.clear();
+  }
+  return out;
+}
+
+int FprintF(std::FILE* output, const UntypedFormatSpecImpl format,
+            absl::Span<const FormatArgImpl> args) {
+  FILERawSink sink(output);
+  if (!FormatUntyped(&sink, format, args)) {
+    errno = EINVAL;
+    return -1;
+  }
+  if (sink.error()) {
+    errno = sink.error();
+    return -1;
+  }
+  if (sink.count() > static_cast<size_t>(std::numeric_limits<int>::max())) {
+    errno = EFBIG;
+    return -1;
+  }
+  return static_cast<int>(sink.count());
+}
+
+int SnprintF(char* output, size_t size, const UntypedFormatSpecImpl format,
+             absl::Span<const FormatArgImpl> args) {
+  BufferRawSink sink(output, size ? size - 1 : 0);
+  if (!FormatUntyped(&sink, format, args)) {
+    errno = EINVAL;
+    return -1;
+  }
+  size_t total = sink.total_written();
+  if (size) output[std::min(total, size - 1)] = 0;
+  return static_cast<int>(total);
+}
+
+}  // namespace str_format_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
diff --git a/src/absl/strings/internal/str_format/bind.h b/src/absl/strings/internal/str_format/bind.h
new file mode 100644 (file)
index 0000000..267cc0e
--- /dev/null
@@ -0,0 +1,217 @@
+// Copyright 2020 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef ABSL_STRINGS_INTERNAL_STR_FORMAT_BIND_H_
+#define ABSL_STRINGS_INTERNAL_STR_FORMAT_BIND_H_
+
+#include <array>
+#include <cstdio>
+#include <sstream>
+#include <string>
+
+#include "absl/base/port.h"
+#include "absl/strings/internal/str_format/arg.h"
+#include "absl/strings/internal/str_format/checker.h"
+#include "absl/strings/internal/str_format/parser.h"
+#include "absl/types/span.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+
+class UntypedFormatSpec;
+
+namespace str_format_internal {
+
+class BoundConversion : public FormatConversionSpecImpl {
+ public:
+  const FormatArgImpl* arg() const { return arg_; }
+  void set_arg(const FormatArgImpl* a) { arg_ = a; }
+
+ private:
+  const FormatArgImpl* arg_;
+};
+
+// This is the type-erased class that the implementation uses.
+class UntypedFormatSpecImpl {
+ public:
+  UntypedFormatSpecImpl() = delete;
+
+  explicit UntypedFormatSpecImpl(string_view s)
+      : data_(s.data()), size_(s.size()) {}
+  explicit UntypedFormatSpecImpl(
+      const str_format_internal::ParsedFormatBase* pc)
+      : data_(pc), size_(~size_t{}) {}
+
+  bool has_parsed_conversion() const { return size_ == ~size_t{}; }
+
+  string_view str() const {
+    assert(!has_parsed_conversion());
+    return string_view(static_cast<const char*>(data_), size_);
+  }
+  const str_format_internal::ParsedFormatBase* parsed_conversion() const {
+    assert(has_parsed_conversion());
+    return static_cast<const str_format_internal::ParsedFormatBase*>(data_);
+  }
+
+  template <typename T>
+  static const UntypedFormatSpecImpl& Extract(const T& s) {
+    return s.spec_;
+  }
+
+ private:
+  const void* data_;
+  size_t size_;
+};
+
+template <typename T, FormatConversionCharSet...>
+struct MakeDependent {
+  using type = T;
+};
+
+// Implicitly convertible from `const char*`, `string_view`, and the
+// `ExtendedParsedFormat` type. This abstraction allows all format functions to
+// operate on any without providing too many overloads.
+template <FormatConversionCharSet... Args>
+class FormatSpecTemplate
+    : public MakeDependent<UntypedFormatSpec, Args...>::type {
+  using Base = typename MakeDependent<UntypedFormatSpec, Args...>::type;
+
+ public:
+#ifdef ABSL_INTERNAL_ENABLE_FORMAT_CHECKER
+
+  // Honeypot overload for when the string is not constexpr.
+  // We use the 'unavailable' attribute to give a better compiler error than
+  // just 'method is deleted'.
+  FormatSpecTemplate(...)  // NOLINT
+      __attribute__((unavailable("Format string is not constexpr.")));
+
+  // Honeypot overload for when the format is constexpr and invalid.
+  // We use the 'unavailable' attribute to give a better compiler error than
+  // just 'method is deleted'.
+  // To avoid checking the format twice, we just check that the format is
+  // constexpr. If is it valid, then the overload below will kick in.
+  // We add the template here to make this overload have lower priority.
+  template <typename = void>
+  FormatSpecTemplate(const char* s)  // NOLINT
+      __attribute__((
+          enable_if(str_format_internal::EnsureConstexpr(s), "constexpr trap"),
+          unavailable(
+              "Format specified does not match the arguments passed.")));
+
+  template <typename T = void>
+  FormatSpecTemplate(string_view s)  // NOLINT
+      __attribute__((enable_if(str_format_internal::EnsureConstexpr(s),
+                               "constexpr trap"))) {
+    static_assert(sizeof(T*) == 0,
+                  "Format specified does not match the arguments passed.");
+  }
+
+  // Good format overload.
+  FormatSpecTemplate(const char* s)  // NOLINT
+      __attribute__((enable_if(ValidFormatImpl<Args...>(s), "bad format trap")))
+      : Base(s) {}
+
+  FormatSpecTemplate(string_view s)  // NOLINT
+      __attribute__((enable_if(ValidFormatImpl<Args...>(s), "bad format trap")))
+      : Base(s) {}
+
+#else  // ABSL_INTERNAL_ENABLE_FORMAT_CHECKER
+
+  FormatSpecTemplate(const char* s) : Base(s) {}  // NOLINT
+  FormatSpecTemplate(string_view s) : Base(s) {}  // NOLINT
+
+#endif  // ABSL_INTERNAL_ENABLE_FORMAT_CHECKER
+
+  template <
+      FormatConversionCharSet... C,
+      typename = typename std::enable_if<sizeof...(C) == sizeof...(Args)>::type,
+      typename = typename std::enable_if<AllOf(Contains(Args,
+                                                        C)...)>::type>
+  FormatSpecTemplate(const ExtendedParsedFormat<C...>& pc)  // NOLINT
+      : Base(&pc) {}
+};
+
+class Streamable {
+ public:
+  Streamable(const UntypedFormatSpecImpl& format,
+             absl::Span<const FormatArgImpl> args)
+      : format_(format) {
+    if (args.size() <= ABSL_ARRAYSIZE(few_args_)) {
+      for (size_t i = 0; i < args.size(); ++i) {
+        few_args_[i] = args[i];
+      }
+      args_ = absl::MakeSpan(few_args_, args.size());
+    } else {
+      many_args_.assign(args.begin(), args.end());
+      args_ = many_args_;
+    }
+  }
+
+  std::ostream& Print(std::ostream& os) const;
+
+  friend std::ostream& operator<<(std::ostream& os, const Streamable& l) {
+    return l.Print(os);
+  }
+
+ private:
+  const UntypedFormatSpecImpl& format_;
+  absl::Span<const FormatArgImpl> args_;
+  // if args_.size() is 4 or less:
+  FormatArgImpl few_args_[4] = {FormatArgImpl(0), FormatArgImpl(0),
+                                FormatArgImpl(0), FormatArgImpl(0)};
+  // if args_.size() is more than 4:
+  std::vector<FormatArgImpl> many_args_;
+};
+
+// for testing
+std::string Summarize(UntypedFormatSpecImpl format,
+                      absl::Span<const FormatArgImpl> args);
+bool BindWithPack(const UnboundConversion* props,
+                  absl::Span<const FormatArgImpl> pack, BoundConversion* bound);
+
+bool FormatUntyped(FormatRawSinkImpl raw_sink,
+                   UntypedFormatSpecImpl format,
+                   absl::Span<const FormatArgImpl> args);
+
+std::string& AppendPack(std::string* out, UntypedFormatSpecImpl format,
+                        absl::Span<const FormatArgImpl> args);
+
+std::string FormatPack(const UntypedFormatSpecImpl format,
+                       absl::Span<const FormatArgImpl> args);
+
+int FprintF(std::FILE* output, UntypedFormatSpecImpl format,
+            absl::Span<const FormatArgImpl> args);
+int SnprintF(char* output, size_t size, UntypedFormatSpecImpl format,
+             absl::Span<const FormatArgImpl> args);
+
+// Returned by Streamed(v). Converts via '%s' to the std::string created
+// by std::ostream << v.
+template <typename T>
+class StreamedWrapper {
+ public:
+  explicit StreamedWrapper(const T& v) : v_(v) { }
+
+ private:
+  template <typename S>
+  friend ArgConvertResult<FormatConversionCharSetInternal::s> FormatConvertImpl(
+      const StreamedWrapper<S>& v, FormatConversionSpecImpl conv,
+      FormatSinkImpl* out);
+  const T& v_;
+};
+
+}  // namespace str_format_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#endif  // ABSL_STRINGS_INTERNAL_STR_FORMAT_BIND_H_
diff --git a/src/absl/strings/internal/str_format/checker.h b/src/absl/strings/internal/str_format/checker.h
new file mode 100644 (file)
index 0000000..2a2601e
--- /dev/null
@@ -0,0 +1,333 @@
+// Copyright 2020 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef ABSL_STRINGS_INTERNAL_STR_FORMAT_CHECKER_H_
+#define ABSL_STRINGS_INTERNAL_STR_FORMAT_CHECKER_H_
+
+#include "absl/base/attributes.h"
+#include "absl/strings/internal/str_format/arg.h"
+#include "absl/strings/internal/str_format/extension.h"
+
+// Compile time check support for entry points.
+
+#ifndef ABSL_INTERNAL_ENABLE_FORMAT_CHECKER
+#if ABSL_HAVE_ATTRIBUTE(enable_if) && !defined(__native_client__)
+#define ABSL_INTERNAL_ENABLE_FORMAT_CHECKER 1
+#endif  // ABSL_HAVE_ATTRIBUTE(enable_if) && !defined(__native_client__)
+#endif  // ABSL_INTERNAL_ENABLE_FORMAT_CHECKER
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace str_format_internal {
+
+constexpr bool AllOf() { return true; }
+
+template <typename... T>
+constexpr bool AllOf(bool b, T... t) {
+  return b && AllOf(t...);
+}
+
+#ifdef ABSL_INTERNAL_ENABLE_FORMAT_CHECKER
+
+constexpr bool ContainsChar(const char* chars, char c) {
+  return *chars == c || (*chars && ContainsChar(chars + 1, c));
+}
+
+// A constexpr compatible list of Convs.
+struct ConvList {
+  const FormatConversionCharSet* array;
+  int count;
+
+  // We do the bound check here to avoid having to do it on the callers.
+  // Returning an empty FormatConversionCharSet has the same effect as
+  // short circuiting because it will never match any conversion.
+  constexpr FormatConversionCharSet operator[](int i) const {
+    return i < count ? array[i] : FormatConversionCharSet{};
+  }
+
+  constexpr ConvList without_front() const {
+    return count != 0 ? ConvList{array + 1, count - 1} : *this;
+  }
+};
+
+template <size_t count>
+struct ConvListT {
+  // Make sure the array has size > 0.
+  FormatConversionCharSet list[count ? count : 1];
+};
+
+constexpr char GetChar(string_view str, size_t index) {
+  return index < str.size() ? str[index] : char{};
+}
+
+constexpr string_view ConsumeFront(string_view str, size_t len = 1) {
+  return len <= str.size() ? string_view(str.data() + len, str.size() - len)
+                           : string_view();
+}
+
+constexpr string_view ConsumeAnyOf(string_view format, const char* chars) {
+  return ContainsChar(chars, GetChar(format, 0))
+             ? ConsumeAnyOf(ConsumeFront(format), chars)
+             : format;
+}
+
+constexpr bool IsDigit(char c) { return c >= '0' && c <= '9'; }
+
+// Helper class for the ParseDigits function.
+// It encapsulates the two return values we need there.
+struct Integer {
+  string_view format;
+  int value;
+
+  // If the next character is a '$', consume it.
+  // Otherwise, make `this` an invalid positional argument.
+  constexpr Integer ConsumePositionalDollar() const {
+    return GetChar(format, 0) == '$' ? Integer{ConsumeFront(format), value}
+                                     : Integer{format, 0};
+  }
+};
+
+constexpr Integer ParseDigits(string_view format, int value = 0) {
+  return IsDigit(GetChar(format, 0))
+             ? ParseDigits(ConsumeFront(format),
+                           10 * value + GetChar(format, 0) - '0')
+             : Integer{format, value};
+}
+
+// Parse digits for a positional argument.
+// The parsing also consumes the '$'.
+constexpr Integer ParsePositional(string_view format) {
+  return ParseDigits(format).ConsumePositionalDollar();
+}
+
+// Parses a single conversion specifier.
+// See ConvParser::Run() for post conditions.
+class ConvParser {
+  constexpr ConvParser SetFormat(string_view format) const {
+    return ConvParser(format, args_, error_, arg_position_, is_positional_);
+  }
+
+  constexpr ConvParser SetArgs(ConvList args) const {
+    return ConvParser(format_, args, error_, arg_position_, is_positional_);
+  }
+
+  constexpr ConvParser SetError(bool error) const {
+    return ConvParser(format_, args_, error_ || error, arg_position_,
+                      is_positional_);
+  }
+
+  constexpr ConvParser SetArgPosition(int arg_position) const {
+    return ConvParser(format_, args_, error_, arg_position, is_positional_);
+  }
+
+  // Consumes the next arg and verifies that it matches `conv`.
+  // `error_` is set if there is no next arg or if it doesn't match `conv`.
+  constexpr ConvParser ConsumeNextArg(char conv) const {
+    return SetArgs(args_.without_front()).SetError(!Contains(args_[0], conv));
+  }
+
+  // Verify that positional argument `i.value` matches `conv`.
+  // `error_` is set if `i.value` is not a valid argument or if it doesn't
+  // match.
+  constexpr ConvParser VerifyPositional(Integer i, char conv) const {
+    return SetFormat(i.format).SetError(!Contains(args_[i.value - 1], conv));
+  }
+
+  // Parse the position of the arg and store it in `arg_position_`.
+  constexpr ConvParser ParseArgPosition(Integer arg) const {
+    return SetFormat(arg.format).SetArgPosition(arg.value);
+  }
+
+  // Consume the flags.
+  constexpr ConvParser ParseFlags() const {
+    return SetFormat(ConsumeAnyOf(format_, "-+ #0"));
+  }
+
+  // Consume the width.
+  // If it is '*', we verify that it matches `args_`. `error_` is set if it
+  // doesn't match.
+  constexpr ConvParser ParseWidth() const {
+    return IsDigit(GetChar(format_, 0))
+               ? SetFormat(ParseDigits(format_).format)
+               : GetChar(format_, 0) == '*'
+                     ? is_positional_
+                           ? VerifyPositional(
+                                 ParsePositional(ConsumeFront(format_)), '*')
+                           : SetFormat(ConsumeFront(format_))
+                                 .ConsumeNextArg('*')
+                     : *this;
+  }
+
+  // Consume the precision.
+  // If it is '*', we verify that it matches `args_`. `error_` is set if it
+  // doesn't match.
+  constexpr ConvParser ParsePrecision() const {
+    return GetChar(format_, 0) != '.'
+               ? *this
+               : GetChar(format_, 1) == '*'
+                     ? is_positional_
+                           ? VerifyPositional(
+                                 ParsePositional(ConsumeFront(format_, 2)), '*')
+                           : SetFormat(ConsumeFront(format_, 2))
+                                 .ConsumeNextArg('*')
+                     : SetFormat(ParseDigits(ConsumeFront(format_)).format);
+  }
+
+  // Consume the length characters.
+  constexpr ConvParser ParseLength() const {
+    return SetFormat(ConsumeAnyOf(format_, "lLhjztq"));
+  }
+
+  // Consume the conversion character and verify that it matches `args_`.
+  // `error_` is set if it doesn't match.
+  constexpr ConvParser ParseConversion() const {
+    return is_positional_
+               ? VerifyPositional({ConsumeFront(format_), arg_position_},
+                                  GetChar(format_, 0))
+               : ConsumeNextArg(GetChar(format_, 0))
+                     .SetFormat(ConsumeFront(format_));
+  }
+
+  constexpr ConvParser(string_view format, ConvList args, bool error,
+                       int arg_position, bool is_positional)
+      : format_(format),
+        args_(args),
+        error_(error),
+        arg_position_(arg_position),
+        is_positional_(is_positional) {}
+
+ public:
+  constexpr ConvParser(string_view format, ConvList args, bool is_positional)
+      : format_(format),
+        args_(args),
+        error_(false),
+        arg_position_(0),
+        is_positional_(is_positional) {}
+
+  // Consume the whole conversion specifier.
+  // `format()` will be set to the character after the conversion character.
+  // `error()` will be set if any of the arguments do not match.
+  constexpr ConvParser Run() const {
+    return (is_positional_ ? ParseArgPosition(ParsePositional(format_)) : *this)
+        .ParseFlags()
+        .ParseWidth()
+        .ParsePrecision()
+        .ParseLength()
+        .ParseConversion();
+  }
+
+  constexpr string_view format() const { return format_; }
+  constexpr ConvList args() const { return args_; }
+  constexpr bool error() const { return error_; }
+  constexpr bool is_positional() const { return is_positional_; }
+
+ private:
+  string_view format_;
+  // Current list of arguments. If we are not in positional mode we will consume
+  // from the front.
+  ConvList args_;
+  bool error_;
+  // Holds the argument position of the conversion character, if we are in
+  // positional mode. Otherwise, it is unspecified.
+  int arg_position_;
+  // Whether we are in positional mode.
+  // It changes the behavior of '*' and where to find the converted argument.
+  bool is_positional_;
+};
+
+// Parses a whole format expression.
+// See FormatParser::Run().
+class FormatParser {
+  static constexpr bool FoundPercent(string_view format) {
+    return format.empty() ||
+           (GetChar(format, 0) == '%' && GetChar(format, 1) != '%');
+  }
+
+  // We use an inner function to increase the recursion limit.
+  // The inner function consumes up to `limit` characters on every run.
+  // This increases the limit from 512 to ~512*limit.
+  static constexpr string_view ConsumeNonPercentInner(string_view format,
+                                                      int limit = 20) {
+    return FoundPercent(format) || !limit
+               ? format
+               : ConsumeNonPercentInner(
+                     ConsumeFront(format, GetChar(format, 0) == '%' &&
+                                                  GetChar(format, 1) == '%'
+                                              ? 2
+                                              : 1),
+                     limit - 1);
+  }
+
+  // Consume characters until the next conversion spec %.
+  // It skips %%.
+  static constexpr string_view ConsumeNonPercent(string_view format) {
+    return FoundPercent(format)
+               ? format
+               : ConsumeNonPercent(ConsumeNonPercentInner(format));
+  }
+
+  static constexpr bool IsPositional(string_view format) {
+    return IsDigit(GetChar(format, 0)) ? IsPositional(ConsumeFront(format))
+                                       : GetChar(format, 0) == '$';
+  }
+
+  constexpr bool RunImpl(bool is_positional) const {
+    // In non-positional mode we require all arguments to be consumed.
+    // In positional mode just reaching the end of the format without errors is
+    // enough.
+    return (format_.empty() && (is_positional || args_.count == 0)) ||
+           (!format_.empty() &&
+            ValidateArg(
+                ConvParser(ConsumeFront(format_), args_, is_positional).Run()));
+  }
+
+  constexpr bool ValidateArg(ConvParser conv) const {
+    return !conv.error() && FormatParser(conv.format(), conv.args())
+                                .RunImpl(conv.is_positional());
+  }
+
+ public:
+  constexpr FormatParser(string_view format, ConvList args)
+      : format_(ConsumeNonPercent(format)), args_(args) {}
+
+  // Runs the parser for `format` and `args`.
+  // It verifies that the format is valid and that all conversion specifiers
+  // match the arguments passed.
+  // In non-positional mode it also verfies that all arguments are consumed.
+  constexpr bool Run() const {
+    return RunImpl(!format_.empty() && IsPositional(ConsumeFront(format_)));
+  }
+
+ private:
+  string_view format_;
+  // Current list of arguments.
+  // If we are not in positional mode we will consume from the front and will
+  // have to be empty in the end.
+  ConvList args_;
+};
+
+template <FormatConversionCharSet... C>
+constexpr bool ValidFormatImpl(string_view format) {
+  return FormatParser(format,
+                      {ConvListT<sizeof...(C)>{{C...}}.list, sizeof...(C)})
+      .Run();
+}
+
+#endif  // ABSL_INTERNAL_ENABLE_FORMAT_CHECKER
+
+}  // namespace str_format_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#endif  // ABSL_STRINGS_INTERNAL_STR_FORMAT_CHECKER_H_
diff --git a/src/absl/strings/internal/str_format/extension.cc b/src/absl/strings/internal/str_format/extension.cc
new file mode 100644 (file)
index 0000000..bb0d96c
--- /dev/null
@@ -0,0 +1,75 @@
+//
+// Copyright 2017 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "absl/strings/internal/str_format/extension.h"
+
+#include <errno.h>
+#include <algorithm>
+#include <string>
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace str_format_internal {
+
+std::string Flags::ToString() const {
+  std::string s;
+  s.append(left     ? "-" : "");
+  s.append(show_pos ? "+" : "");
+  s.append(sign_col ? " " : "");
+  s.append(alt      ? "#" : "");
+  s.append(zero     ? "0" : "");
+  return s;
+}
+
+#define ABSL_INTERNAL_X_VAL(id) \
+  constexpr absl::FormatConversionChar FormatConversionCharInternal::id;
+ABSL_INTERNAL_CONVERSION_CHARS_EXPAND_(ABSL_INTERNAL_X_VAL, )
+#undef ABSL_INTERNAL_X_VAL
+// NOLINTNEXTLINE(readability-redundant-declaration)
+constexpr absl::FormatConversionChar FormatConversionCharInternal::kNone;
+
+#define ABSL_INTERNAL_CHAR_SET_CASE(c) \
+  constexpr FormatConversionCharSet FormatConversionCharSetInternal::c;
+ABSL_INTERNAL_CONVERSION_CHARS_EXPAND_(ABSL_INTERNAL_CHAR_SET_CASE, )
+#undef ABSL_INTERNAL_CHAR_SET_CASE
+
+// NOLINTNEXTLINE(readability-redundant-declaration)
+constexpr FormatConversionCharSet FormatConversionCharSetInternal::kStar;
+// NOLINTNEXTLINE(readability-redundant-declaration)
+constexpr FormatConversionCharSet FormatConversionCharSetInternal::kIntegral;
+// NOLINTNEXTLINE(readability-redundant-declaration)
+constexpr FormatConversionCharSet FormatConversionCharSetInternal::kFloating;
+// NOLINTNEXTLINE(readability-redundant-declaration)
+constexpr FormatConversionCharSet FormatConversionCharSetInternal::kNumeric;
+// NOLINTNEXTLINE(readability-redundant-declaration)
+constexpr FormatConversionCharSet FormatConversionCharSetInternal::kPointer;
+
+bool FormatSinkImpl::PutPaddedString(string_view value, int width,
+                                     int precision, bool left) {
+  size_t space_remaining = 0;
+  if (width >= 0) space_remaining = width;
+  size_t n = value.size();
+  if (precision >= 0) n = std::min(n, static_cast<size_t>(precision));
+  string_view shown(value.data(), n);
+  space_remaining = Excess(shown.size(), space_remaining);
+  if (!left) Append(space_remaining, ' ');
+  Append(shown);
+  if (left) Append(space_remaining, ' ');
+  return true;
+}
+
+}  // namespace str_format_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
diff --git a/src/absl/strings/internal/str_format/extension.h b/src/absl/strings/internal/str_format/extension.h
new file mode 100644 (file)
index 0000000..a9b9e13
--- /dev/null
@@ -0,0 +1,427 @@
+//
+// Copyright 2017 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+#ifndef ABSL_STRINGS_INTERNAL_STR_FORMAT_EXTENSION_H_
+#define ABSL_STRINGS_INTERNAL_STR_FORMAT_EXTENSION_H_
+
+#include <limits.h>
+
+#include <cstddef>
+#include <cstring>
+#include <ostream>
+
+#include "absl/base/config.h"
+#include "absl/base/port.h"
+#include "absl/meta/type_traits.h"
+#include "absl/strings/internal/str_format/output.h"
+#include "absl/strings/string_view.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+
+enum class FormatConversionChar : uint8_t;
+enum class FormatConversionCharSet : uint64_t;
+
+namespace str_format_internal {
+
+class FormatRawSinkImpl {
+ public:
+  // Implicitly convert from any type that provides the hook function as
+  // described above.
+  template <typename T, decltype(str_format_internal::InvokeFlush(
+                            std::declval<T*>(), string_view()))* = nullptr>
+  FormatRawSinkImpl(T* raw)  // NOLINT
+      : sink_(raw), write_(&FormatRawSinkImpl::Flush<T>) {}
+
+  void Write(string_view s) { write_(sink_, s); }
+
+  template <typename T>
+  static FormatRawSinkImpl Extract(T s) {
+    return s.sink_;
+  }
+
+ private:
+  template <typename T>
+  static void Flush(void* r, string_view s) {
+    str_format_internal::InvokeFlush(static_cast<T*>(r), s);
+  }
+
+  void* sink_;
+  void (*write_)(void*, string_view);
+};
+
+// An abstraction to which conversions write their string data.
+class FormatSinkImpl {
+ public:
+  explicit FormatSinkImpl(FormatRawSinkImpl raw) : raw_(raw) {}
+
+  ~FormatSinkImpl() { Flush(); }
+
+  void Flush() {
+    raw_.Write(string_view(buf_, pos_ - buf_));
+    pos_ = buf_;
+  }
+
+  void Append(size_t n, char c) {
+    if (n == 0) return;
+    size_ += n;
+    auto raw_append = [&](size_t count) {
+      memset(pos_, c, count);
+      pos_ += count;
+    };
+    while (n > Avail()) {
+      n -= Avail();
+      if (Avail() > 0) {
+        raw_append(Avail());
+      }
+      Flush();
+    }
+    raw_append(n);
+  }
+
+  void Append(string_view v) {
+    size_t n = v.size();
+    if (n == 0) return;
+    size_ += n;
+    if (n >= Avail()) {
+      Flush();
+      raw_.Write(v);
+      return;
+    }
+    memcpy(pos_, v.data(), n);
+    pos_ += n;
+  }
+
+  size_t size() const { return size_; }
+
+  // Put 'v' to 'sink' with specified width, precision, and left flag.
+  bool PutPaddedString(string_view v, int width, int precision, bool left);
+
+  template <typename T>
+  T Wrap() {
+    return T(this);
+  }
+
+  template <typename T>
+  static FormatSinkImpl* Extract(T* s) {
+    return s->sink_;
+  }
+
+ private:
+  size_t Avail() const { return buf_ + sizeof(buf_) - pos_; }
+
+  FormatRawSinkImpl raw_;
+  size_t size_ = 0;
+  char* pos_ = buf_;
+  char buf_[1024];
+};
+
+struct Flags {
+  bool basic : 1;     // fastest conversion: no flags, width, or precision
+  bool left : 1;      // "-"
+  bool show_pos : 1;  // "+"
+  bool sign_col : 1;  // " "
+  bool alt : 1;       // "#"
+  bool zero : 1;      // "0"
+  std::string ToString() const;
+  friend std::ostream& operator<<(std::ostream& os, const Flags& v) {
+    return os << v.ToString();
+  }
+};
+
+// clang-format off
+#define ABSL_INTERNAL_CONVERSION_CHARS_EXPAND_(X_VAL, X_SEP) \
+  /* text */ \
+  X_VAL(c) X_SEP X_VAL(s) X_SEP \
+  /* ints */ \
+  X_VAL(d) X_SEP X_VAL(i) X_SEP X_VAL(o) X_SEP \
+  X_VAL(u) X_SEP X_VAL(x) X_SEP X_VAL(X) X_SEP \
+  /* floats */ \
+  X_VAL(f) X_SEP X_VAL(F) X_SEP X_VAL(e) X_SEP X_VAL(E) X_SEP \
+  X_VAL(g) X_SEP X_VAL(G) X_SEP X_VAL(a) X_SEP X_VAL(A) X_SEP \
+  /* misc */ \
+  X_VAL(n) X_SEP X_VAL(p)
+// clang-format on
+
+// This type should not be referenced, it exists only to provide labels
+// internally that match the values declared in FormatConversionChar in
+// str_format.h. This is meant to allow internal libraries to use the same
+// declared interface type as the public interface
+// (absl::StrFormatConversionChar) while keeping the definition in a public
+// header.
+// Internal libraries should use the form
+// `FormatConversionCharInternal::c`, `FormatConversionCharInternal::kNone` for
+// comparisons.  Use in switch statements is not recommended due to a bug in how
+// gcc 4.9 -Wswitch handles declared but undefined enums.
+struct FormatConversionCharInternal {
+  FormatConversionCharInternal() = delete;
+
+ private:
+  // clang-format off
+  enum class Enum : uint8_t {
+    c, s,                    // text
+    d, i, o, u, x, X,        // int
+    f, F, e, E, g, G, a, A,  // float
+    n, p,                    // misc
+    kNone
+  };
+  // clang-format on
+ public:
+#define ABSL_INTERNAL_X_VAL(id)              \
+  static constexpr FormatConversionChar id = \
+      static_cast<FormatConversionChar>(Enum::id);
+  ABSL_INTERNAL_CONVERSION_CHARS_EXPAND_(ABSL_INTERNAL_X_VAL, )
+#undef ABSL_INTERNAL_X_VAL
+  static constexpr FormatConversionChar kNone =
+      static_cast<FormatConversionChar>(Enum::kNone);
+};
+// clang-format on
+
+inline FormatConversionChar FormatConversionCharFromChar(char c) {
+  switch (c) {
+#define ABSL_INTERNAL_X_VAL(id) \
+  case #id[0]:                  \
+    return FormatConversionCharInternal::id;
+    ABSL_INTERNAL_CONVERSION_CHARS_EXPAND_(ABSL_INTERNAL_X_VAL, )
+#undef ABSL_INTERNAL_X_VAL
+  }
+  return FormatConversionCharInternal::kNone;
+}
+
+inline bool FormatConversionCharIsUpper(FormatConversionChar c) {
+  if (c == FormatConversionCharInternal::X ||
+      c == FormatConversionCharInternal::F ||
+      c == FormatConversionCharInternal::E ||
+      c == FormatConversionCharInternal::G ||
+      c == FormatConversionCharInternal::A) {
+    return true;
+  } else {
+    return false;
+  }
+}
+
+inline bool FormatConversionCharIsFloat(FormatConversionChar c) {
+  if (c == FormatConversionCharInternal::a ||
+      c == FormatConversionCharInternal::e ||
+      c == FormatConversionCharInternal::f ||
+      c == FormatConversionCharInternal::g ||
+      c == FormatConversionCharInternal::A ||
+      c == FormatConversionCharInternal::E ||
+      c == FormatConversionCharInternal::F ||
+      c == FormatConversionCharInternal::G) {
+    return true;
+  } else {
+    return false;
+  }
+}
+
+inline char FormatConversionCharToChar(FormatConversionChar c) {
+  if (c == FormatConversionCharInternal::kNone) {
+    return '\0';
+
+#define ABSL_INTERNAL_X_VAL(e)                       \
+  } else if (c == FormatConversionCharInternal::e) { \
+    return #e[0];
+#define ABSL_INTERNAL_X_SEP
+  ABSL_INTERNAL_CONVERSION_CHARS_EXPAND_(ABSL_INTERNAL_X_VAL,
+                                         ABSL_INTERNAL_X_SEP)
+  } else {
+    return '\0';
+  }
+
+#undef ABSL_INTERNAL_X_VAL
+#undef ABSL_INTERNAL_X_SEP
+}
+
+// The associated char.
+inline std::ostream& operator<<(std::ostream& os, FormatConversionChar v) {
+  char c = FormatConversionCharToChar(v);
+  if (!c) c = '?';
+  return os << c;
+}
+
+struct FormatConversionSpecImplFriend;
+
+class FormatConversionSpecImpl {
+ public:
+  // Width and precison are not specified, no flags are set.
+  bool is_basic() const { return flags_.basic; }
+  bool has_left_flag() const { return flags_.left; }
+  bool has_show_pos_flag() const { return flags_.show_pos; }
+  bool has_sign_col_flag() const { return flags_.sign_col; }
+  bool has_alt_flag() const { return flags_.alt; }
+  bool has_zero_flag() const { return flags_.zero; }
+
+  FormatConversionChar conversion_char() const {
+    // Keep this field first in the struct . It generates better code when
+    // accessing it when ConversionSpec is passed by value in registers.
+    static_assert(offsetof(FormatConversionSpecImpl, conv_) == 0, "");
+    return conv_;
+  }
+
+  // Returns the specified width. If width is unspecfied, it returns a negative
+  // value.
+  int width() const { return width_; }
+  // Returns the specified precision. If precision is unspecfied, it returns a
+  // negative value.
+  int precision() const { return precision_; }
+
+  template <typename T>
+  T Wrap() {
+    return T(*this);
+  }
+
+ private:
+  friend struct str_format_internal::FormatConversionSpecImplFriend;
+  FormatConversionChar conv_ = FormatConversionCharInternal::kNone;
+  Flags flags_;
+  int width_;
+  int precision_;
+};
+
+struct FormatConversionSpecImplFriend final {
+  static void SetFlags(Flags f, FormatConversionSpecImpl* conv) {
+    conv->flags_ = f;
+  }
+  static void SetConversionChar(FormatConversionChar c,
+                                FormatConversionSpecImpl* conv) {
+    conv->conv_ = c;
+  }
+  static void SetWidth(int w, FormatConversionSpecImpl* conv) {
+    conv->width_ = w;
+  }
+  static void SetPrecision(int p, FormatConversionSpecImpl* conv) {
+    conv->precision_ = p;
+  }
+  static std::string FlagsToString(const FormatConversionSpecImpl& spec) {
+    return spec.flags_.ToString();
+  }
+};
+
+// Type safe OR operator.
+// We need this for two reasons:
+//  1. operator| on enums makes them decay to integers and the result is an
+//     integer. We need the result to stay as an enum.
+//  2. We use "enum class" which would not work even if we accepted the decay.
+constexpr FormatConversionCharSet FormatConversionCharSetUnion(
+    FormatConversionCharSet a) {
+  return a;
+}
+
+template <typename... CharSet>
+constexpr FormatConversionCharSet FormatConversionCharSetUnion(
+    FormatConversionCharSet a, CharSet... rest) {
+  return static_cast<FormatConversionCharSet>(
+      static_cast<uint64_t>(a) |
+      static_cast<uint64_t>(FormatConversionCharSetUnion(rest...)));
+}
+
+constexpr uint64_t FormatConversionCharToConvInt(FormatConversionChar c) {
+  return uint64_t{1} << (1 + static_cast<uint8_t>(c));
+}
+
+constexpr uint64_t FormatConversionCharToConvInt(char conv) {
+  return
+#define ABSL_INTERNAL_CHAR_SET_CASE(c)                                 \
+  conv == #c[0]                                                        \
+      ? FormatConversionCharToConvInt(FormatConversionCharInternal::c) \
+      :
+      ABSL_INTERNAL_CONVERSION_CHARS_EXPAND_(ABSL_INTERNAL_CHAR_SET_CASE, )
+#undef ABSL_INTERNAL_CHAR_SET_CASE
+                  conv == '*'
+          ? 1
+          : 0;
+}
+
+constexpr FormatConversionCharSet FormatConversionCharToConvValue(char conv) {
+  return static_cast<FormatConversionCharSet>(
+      FormatConversionCharToConvInt(conv));
+}
+
+struct FormatConversionCharSetInternal {
+#define ABSL_INTERNAL_CHAR_SET_CASE(c)         \
+  static constexpr FormatConversionCharSet c = \
+      FormatConversionCharToConvValue(#c[0]);
+  ABSL_INTERNAL_CONVERSION_CHARS_EXPAND_(ABSL_INTERNAL_CHAR_SET_CASE, )
+#undef ABSL_INTERNAL_CHAR_SET_CASE
+
+  // Used for width/precision '*' specification.
+  static constexpr FormatConversionCharSet kStar =
+      FormatConversionCharToConvValue('*');
+
+  static constexpr FormatConversionCharSet kIntegral =
+      FormatConversionCharSetUnion(d, i, u, o, x, X);
+  static constexpr FormatConversionCharSet kFloating =
+      FormatConversionCharSetUnion(a, e, f, g, A, E, F, G);
+  static constexpr FormatConversionCharSet kNumeric =
+      FormatConversionCharSetUnion(kIntegral, kFloating);
+  static constexpr FormatConversionCharSet kPointer = p;
+};
+
+// Type safe OR operator.
+// We need this for two reasons:
+//  1. operator| on enums makes them decay to integers and the result is an
+//     integer. We need the result to stay as an enum.
+//  2. We use "enum class" which would not work even if we accepted the decay.
+constexpr FormatConversionCharSet operator|(FormatConversionCharSet a,
+                                            FormatConversionCharSet b) {
+  return FormatConversionCharSetUnion(a, b);
+}
+
+// Overloaded conversion functions to support absl::ParsedFormat.
+// Get a conversion with a single character in it.
+constexpr FormatConversionCharSet ToFormatConversionCharSet(char c) {
+  return static_cast<FormatConversionCharSet>(
+      FormatConversionCharToConvValue(c));
+}
+
+// Get a conversion with a single character in it.
+constexpr FormatConversionCharSet ToFormatConversionCharSet(
+    FormatConversionCharSet c) {
+  return c;
+}
+
+template <typename T>
+void ToFormatConversionCharSet(T) = delete;
+
+// Checks whether `c` exists in `set`.
+constexpr bool Contains(FormatConversionCharSet set, char c) {
+  return (static_cast<uint64_t>(set) &
+          static_cast<uint64_t>(FormatConversionCharToConvValue(c))) != 0;
+}
+
+// Checks whether all the characters in `c` are contained in `set`
+constexpr bool Contains(FormatConversionCharSet set,
+                        FormatConversionCharSet c) {
+  return (static_cast<uint64_t>(set) & static_cast<uint64_t>(c)) ==
+         static_cast<uint64_t>(c);
+}
+
+// Checks whether all the characters in `c` are contained in `set`
+constexpr bool Contains(FormatConversionCharSet set, FormatConversionChar c) {
+  return (static_cast<uint64_t>(set) & FormatConversionCharToConvInt(c)) != 0;
+}
+
+// Return capacity - used, clipped to a minimum of 0.
+inline size_t Excess(size_t used, size_t capacity) {
+  return used < capacity ? capacity - used : 0;
+}
+
+}  // namespace str_format_internal
+
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#endif  // ABSL_STRINGS_INTERNAL_STR_FORMAT_EXTENSION_H_
diff --git a/src/absl/strings/internal/str_format/float_conversion.cc b/src/absl/strings/internal/str_format/float_conversion.cc
new file mode 100644 (file)
index 0000000..b1c4068
--- /dev/null
@@ -0,0 +1,1423 @@
+// Copyright 2020 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "absl/strings/internal/str_format/float_conversion.h"
+
+#include <string.h>
+
+#include <algorithm>
+#include <cassert>
+#include <cmath>
+#include <limits>
+#include <string>
+
+#include "absl/base/attributes.h"
+#include "absl/base/config.h"
+#include "absl/base/optimization.h"
+#include "absl/functional/function_ref.h"
+#include "absl/meta/type_traits.h"
+#include "absl/numeric/bits.h"
+#include "absl/numeric/int128.h"
+#include "absl/numeric/internal/representation.h"
+#include "absl/strings/numbers.h"
+#include "absl/types/optional.h"
+#include "absl/types/span.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace str_format_internal {
+
+namespace {
+
+using ::absl::numeric_internal::IsDoubleDouble;
+
+// The code below wants to avoid heap allocations.
+// To do so it needs to allocate memory on the stack.
+// `StackArray` will allocate memory on the stack in the form of a uint32_t
+// array and call the provided callback with said memory.
+// It will allocate memory in increments of 512 bytes. We could allocate the
+// largest needed unconditionally, but that is more than we need in most of
+// cases. This way we use less stack in the common cases.
+class StackArray {
+  using Func = absl::FunctionRef<void(absl::Span<uint32_t>)>;
+  static constexpr size_t kStep = 512 / sizeof(uint32_t);
+  // 5 steps is 2560 bytes, which is enough to hold a long double with the
+  // largest/smallest exponents.
+  // The operations below will static_assert their particular maximum.
+  static constexpr size_t kNumSteps = 5;
+
+  // We do not want this function to be inlined.
+  // Otherwise the caller will allocate the stack space unnecessarily for all
+  // the variants even though it only calls one.
+  template <size_t steps>
+  ABSL_ATTRIBUTE_NOINLINE static void RunWithCapacityImpl(Func f) {
+    uint32_t values[steps * kStep]{};
+    f(absl::MakeSpan(values));
+  }
+
+ public:
+  static constexpr size_t kMaxCapacity = kStep * kNumSteps;
+
+  static void RunWithCapacity(size_t capacity, Func f) {
+    assert(capacity <= kMaxCapacity);
+    const size_t step = (capacity + kStep - 1) / kStep;
+    assert(step <= kNumSteps);
+    switch (step) {
+      case 1:
+        return RunWithCapacityImpl<1>(f);
+      case 2:
+        return RunWithCapacityImpl<2>(f);
+      case 3:
+        return RunWithCapacityImpl<3>(f);
+      case 4:
+        return RunWithCapacityImpl<4>(f);
+      case 5:
+        return RunWithCapacityImpl<5>(f);
+    }
+
+    assert(false && "Invalid capacity");
+  }
+};
+
+// Calculates `10 * (*v) + carry` and stores the result in `*v` and returns
+// the carry.
+template <typename Int>
+inline Int MultiplyBy10WithCarry(Int *v, Int carry) {
+  using BiggerInt = absl::conditional_t<sizeof(Int) == 4, uint64_t, uint128>;
+  BiggerInt tmp = 10 * static_cast<BiggerInt>(*v) + carry;
+  *v = static_cast<Int>(tmp);
+  return static_cast<Int>(tmp >> (sizeof(Int) * 8));
+}
+
+// Calculates `(2^64 * carry + *v) / 10`.
+// Stores the quotient in `*v` and returns the remainder.
+// Requires: `0 <= carry <= 9`
+inline uint64_t DivideBy10WithCarry(uint64_t *v, uint64_t carry) {
+  constexpr uint64_t divisor = 10;
+  // 2^64 / divisor = chunk_quotient + chunk_remainder / divisor
+  constexpr uint64_t chunk_quotient = (uint64_t{1} << 63) / (divisor / 2);
+  constexpr uint64_t chunk_remainder = uint64_t{} - chunk_quotient * divisor;
+
+  const uint64_t mod = *v % divisor;
+  const uint64_t next_carry = chunk_remainder * carry + mod;
+  *v = *v / divisor + carry * chunk_quotient + next_carry / divisor;
+  return next_carry % divisor;
+}
+
+using MaxFloatType =
+    typename std::conditional<IsDoubleDouble(), double, long double>::type;
+
+// Generates the decimal representation for an integer of the form `v * 2^exp`,
+// where `v` and `exp` are both positive integers.
+// It generates the digits from the left (ie the most significant digit first)
+// to allow for direct printing into the sink.
+//
+// Requires `0 <= exp` and `exp <= numeric_limits<MaxFloatType>::max_exponent`.
+class BinaryToDecimal {
+  static constexpr int ChunksNeeded(int exp) {
+    // We will left shift a uint128 by `exp` bits, so we need `128+exp` total
+    // bits. Round up to 32.
+    // See constructor for details about adding `10%` to the value.
+    return (128 + exp + 31) / 32 * 11 / 10;
+  }
+
+ public:
+  // Run the conversion for `v * 2^exp` and call `f(binary_to_decimal)`.
+  // This function will allocate enough stack space to perform the conversion.
+  static void RunConversion(uint128 v, int exp,
+                            absl::FunctionRef<void(BinaryToDecimal)> f) {
+    assert(exp > 0);
+    assert(exp <= std::numeric_limits<MaxFloatType>::max_exponent);
+    static_assert(
+        static_cast<int>(StackArray::kMaxCapacity) >=
+            ChunksNeeded(std::numeric_limits<MaxFloatType>::max_exponent),
+        "");
+
+    StackArray::RunWithCapacity(
+        ChunksNeeded(exp),
+        [=](absl::Span<uint32_t> input) { f(BinaryToDecimal(input, v, exp)); });
+  }
+
+  int TotalDigits() const {
+    return static_cast<int>((decimal_end_ - decimal_start_) * kDigitsPerChunk +
+                            CurrentDigits().size());
+  }
+
+  // See the current block of digits.
+  absl::string_view CurrentDigits() const {
+    return absl::string_view(digits_ + kDigitsPerChunk - size_, size_);
+  }
+
+  // Advance the current view of digits.
+  // Returns `false` when no more digits are available.
+  bool AdvanceDigits() {
+    if (decimal_start_ >= decimal_end_) return false;
+
+    uint32_t w = data_[decimal_start_++];
+    for (size_ = 0; size_ < kDigitsPerChunk; w /= 10) {
+      digits_[kDigitsPerChunk - ++size_] = w % 10 + '0';
+    }
+    return true;
+  }
+
+ private:
+  BinaryToDecimal(absl::Span<uint32_t> data, uint128 v, int exp) : data_(data) {
+    // We need to print the digits directly into the sink object without
+    // buffering them all first. To do this we need two things:
+    // - to know the total number of digits to do padding when necessary
+    // - to generate the decimal digits from the left.
+    //
+    // In order to do this, we do a two pass conversion.
+    // On the first pass we convert the binary representation of the value into
+    // a decimal representation in which each uint32_t chunk holds up to 9
+    // decimal digits.  In the second pass we take each decimal-holding-uint32_t
+    // value and generate the ascii decimal digits into `digits_`.
+    //
+    // The binary and decimal representations actually share the same memory
+    // region. As we go converting the chunks from binary to decimal we free
+    // them up and reuse them for the decimal representation. One caveat is that
+    // the decimal representation is around 7% less efficient in space than the
+    // binary one. We allocate an extra 10% memory to account for this. See
+    // ChunksNeeded for this calculation.
+    int chunk_index = exp / 32;
+    decimal_start_ = decimal_end_ = ChunksNeeded(exp);
+    const int offset = exp % 32;
+    // Left shift v by exp bits.
+    data_[chunk_index] = static_cast<uint32_t>(v << offset);
+    for (v >>= (32 - offset); v; v >>= 32)
+      data_[++chunk_index] = static_cast<uint32_t>(v);
+
+    while (chunk_index >= 0) {
+      // While we have more than one chunk available, go in steps of 1e9.
+      // `data_[chunk_index]` holds the highest non-zero binary chunk, so keep
+      // the variable updated.
+      uint32_t carry = 0;
+      for (int i = chunk_index; i >= 0; --i) {
+        uint64_t tmp = uint64_t{data_[i]} + (uint64_t{carry} << 32);
+        data_[i] = static_cast<uint32_t>(tmp / uint64_t{1000000000});
+        carry = static_cast<uint32_t>(tmp % uint64_t{1000000000});
+      }
+
+      // If the highest chunk is now empty, remove it from view.
+      if (data_[chunk_index] == 0) --chunk_index;
+
+      --decimal_start_;
+      assert(decimal_start_ != chunk_index);
+      data_[decimal_start_] = carry;
+    }
+
+    // Fill the first set of digits. The first chunk might not be complete, so
+    // handle differently.
+    for (uint32_t first = data_[decimal_start_++]; first != 0; first /= 10) {
+      digits_[kDigitsPerChunk - ++size_] = first % 10 + '0';
+    }
+  }
+
+ private:
+  static constexpr int kDigitsPerChunk = 9;
+
+  int decimal_start_;
+  int decimal_end_;
+
+  char digits_[kDigitsPerChunk];
+  int size_ = 0;
+
+  absl::Span<uint32_t> data_;
+};
+
+// Converts a value of the form `x * 2^-exp` into a sequence of decimal digits.
+// Requires `-exp < 0` and
+// `-exp >= limits<MaxFloatType>::min_exponent - limits<MaxFloatType>::digits`.
+class FractionalDigitGenerator {
+ public:
+  // Run the conversion for `v * 2^exp` and call `f(generator)`.
+  // This function will allocate enough stack space to perform the conversion.
+  static void RunConversion(
+      uint128 v, int exp, absl::FunctionRef<void(FractionalDigitGenerator)> f) {
+    using Limits = std::numeric_limits<MaxFloatType>;
+    assert(-exp < 0);
+    assert(-exp >= Limits::min_exponent - 128);
+    static_assert(StackArray::kMaxCapacity >=
+                      (Limits::digits + 128 - Limits::min_exponent + 31) / 32,
+                  "");
+    StackArray::RunWithCapacity((Limits::digits + exp + 31) / 32,
+                                [=](absl::Span<uint32_t> input) {
+                                  f(FractionalDigitGenerator(input, v, exp));
+                                });
+  }
+
+  // Returns true if there are any more non-zero digits left.
+  bool HasMoreDigits() const { return next_digit_ != 0 || chunk_index_ >= 0; }
+
+  // Returns true if the remainder digits are greater than 5000...
+  bool IsGreaterThanHalf() const {
+    return next_digit_ > 5 || (next_digit_ == 5 && chunk_index_ >= 0);
+  }
+  // Returns true if the remainder digits are exactly 5000...
+  bool IsExactlyHalf() const { return next_digit_ == 5 && chunk_index_ < 0; }
+
+  struct Digits {
+    int digit_before_nine;
+    int num_nines;
+  };
+
+  // Get the next set of digits.
+  // They are composed by a non-9 digit followed by a runs of zero or more 9s.
+  Digits GetDigits() {
+    Digits digits{next_digit_, 0};
+
+    next_digit_ = GetOneDigit();
+    while (next_digit_ == 9) {
+      ++digits.num_nines;
+      next_digit_ = GetOneDigit();
+    }
+
+    return digits;
+  }
+
+ private:
+  // Return the next digit.
+  int GetOneDigit() {
+    if (chunk_index_ < 0) return 0;
+
+    uint32_t carry = 0;
+    for (int i = chunk_index_; i >= 0; --i) {
+      carry = MultiplyBy10WithCarry(&data_[i], carry);
+    }
+    // If the lowest chunk is now empty, remove it from view.
+    if (data_[chunk_index_] == 0) --chunk_index_;
+    return carry;
+  }
+
+  FractionalDigitGenerator(absl::Span<uint32_t> data, uint128 v, int exp)
+      : chunk_index_(exp / 32), data_(data) {
+    const int offset = exp % 32;
+    // Right shift `v` by `exp` bits.
+    data_[chunk_index_] = static_cast<uint32_t>(v << (32 - offset));
+    v >>= offset;
+    // Make sure we don't overflow the data. We already calculated that
+    // non-zero bits fit, so we might not have space for leading zero bits.
+    for (int pos = chunk_index_; v; v >>= 32)
+      data_[--pos] = static_cast<uint32_t>(v);
+
+    // Fill next_digit_, as GetDigits expects it to be populated always.
+    next_digit_ = GetOneDigit();
+  }
+
+  int next_digit_;
+  int chunk_index_;
+  absl::Span<uint32_t> data_;
+};
+
+// Count the number of leading zero bits.
+int LeadingZeros(uint64_t v) { return countl_zero(v); }
+int LeadingZeros(uint128 v) {
+  auto high = static_cast<uint64_t>(v >> 64);
+  auto low = static_cast<uint64_t>(v);
+  return high != 0 ? countl_zero(high) : 64 + countl_zero(low);
+}
+
+// Round up the text digits starting at `p`.
+// The buffer must have an extra digit that is known to not need rounding.
+// This is done below by having an extra '0' digit on the left.
+void RoundUp(char *p) {
+  while (*p == '9' || *p == '.') {
+    if (*p == '9') *p = '0';
+    --p;
+  }
+  ++*p;
+}
+
+// Check the previous digit and round up or down to follow the round-to-even
+// policy.
+void RoundToEven(char *p) {
+  if (*p == '.') --p;
+  if (*p % 2 == 1) RoundUp(p);
+}
+
+// Simple integral decimal digit printing for values that fit in 64-bits.
+// Returns the pointer to the last written digit.
+char *PrintIntegralDigitsFromRightFast(uint64_t v, char *p) {
+  do {
+    *--p = DivideBy10WithCarry(&v, 0) + '0';
+  } while (v != 0);
+  return p;
+}
+
+// Simple integral decimal digit printing for values that fit in 128-bits.
+// Returns the pointer to the last written digit.
+char *PrintIntegralDigitsFromRightFast(uint128 v, char *p) {
+  auto high = static_cast<uint64_t>(v >> 64);
+  auto low = static_cast<uint64_t>(v);
+
+  while (high != 0) {
+    uint64_t carry = DivideBy10WithCarry(&high, 0);
+    carry = DivideBy10WithCarry(&low, carry);
+    *--p = carry + '0';
+  }
+  return PrintIntegralDigitsFromRightFast(low, p);
+}
+
+// Simple fractional decimal digit printing for values that fir in 64-bits after
+// shifting.
+// Performs rounding if necessary to fit within `precision`.
+// Returns the pointer to one after the last character written.
+char *PrintFractionalDigitsFast(uint64_t v, char *start, int exp,
+                                int precision) {
+  char *p = start;
+  v <<= (64 - exp);
+  while (precision > 0) {
+    if (!v) return p;
+    *p++ = MultiplyBy10WithCarry(&v, uint64_t{0}) + '0';
+    --precision;
+  }
+
+  // We need to round.
+  if (v < 0x8000000000000000) {
+    // We round down, so nothing to do.
+  } else if (v > 0x8000000000000000) {
+    // We round up.
+    RoundUp(p - 1);
+  } else {
+    RoundToEven(p - 1);
+  }
+
+  assert(precision == 0);
+  // Precision can only be zero here.
+  return p;
+}
+
+// Simple fractional decimal digit printing for values that fir in 128-bits
+// after shifting.
+// Performs rounding if necessary to fit within `precision`.
+// Returns the pointer to one after the last character written.
+char *PrintFractionalDigitsFast(uint128 v, char *start, int exp,
+                                int precision) {
+  char *p = start;
+  v <<= (128 - exp);
+  auto high = static_cast<uint64_t>(v >> 64);
+  auto low = static_cast<uint64_t>(v);
+
+  // While we have digits to print and `low` is not empty, do the long
+  // multiplication.
+  while (precision > 0 && low != 0) {
+    uint64_t carry = MultiplyBy10WithCarry(&low, uint64_t{0});
+    carry = MultiplyBy10WithCarry(&high, carry);
+
+    *p++ = carry + '0';
+    --precision;
+  }
+
+  // Now `low` is empty, so use a faster approach for the rest of the digits.
+  // This block is pretty much the same as the main loop for the 64-bit case
+  // above.
+  while (precision > 0) {
+    if (!high) return p;
+    *p++ = MultiplyBy10WithCarry(&high, uint64_t{0}) + '0';
+    --precision;
+  }
+
+  // We need to round.
+  if (high < 0x8000000000000000) {
+    // We round down, so nothing to do.
+  } else if (high > 0x8000000000000000 || low != 0) {
+    // We round up.
+    RoundUp(p - 1);
+  } else {
+    RoundToEven(p - 1);
+  }
+
+  assert(precision == 0);
+  // Precision can only be zero here.
+  return p;
+}
+
+struct FormatState {
+  char sign_char;
+  int precision;
+  const FormatConversionSpecImpl &conv;
+  FormatSinkImpl *sink;
+
+  // In `alt` mode (flag #) we keep the `.` even if there are no fractional
+  // digits. In non-alt mode, we strip it.
+  bool ShouldPrintDot() const { return precision != 0 || conv.has_alt_flag(); }
+};
+
+struct Padding {
+  int left_spaces;
+  int zeros;
+  int right_spaces;
+};
+
+Padding ExtraWidthToPadding(size_t total_size, const FormatState &state) {
+  if (state.conv.width() < 0 ||
+      static_cast<size_t>(state.conv.width()) <= total_size) {
+    return {0, 0, 0};
+  }
+  int missing_chars = state.conv.width() - total_size;
+  if (state.conv.has_left_flag()) {
+    return {0, 0, missing_chars};
+  } else if (state.conv.has_zero_flag()) {
+    return {0, missing_chars, 0};
+  } else {
+    return {missing_chars, 0, 0};
+  }
+}
+
+void FinalPrint(const FormatState &state, absl::string_view data,
+                int padding_offset, int trailing_zeros,
+                absl::string_view data_postfix) {
+  if (state.conv.width() < 0) {
+    // No width specified. Fast-path.
+    if (state.sign_char != '\0') state.sink->Append(1, state.sign_char);
+    state.sink->Append(data);
+    state.sink->Append(trailing_zeros, '0');
+    state.sink->Append(data_postfix);
+    return;
+  }
+
+  auto padding = ExtraWidthToPadding((state.sign_char != '\0' ? 1 : 0) +
+                                         data.size() + data_postfix.size() +
+                                         static_cast<size_t>(trailing_zeros),
+                                     state);
+
+  state.sink->Append(padding.left_spaces, ' ');
+  if (state.sign_char != '\0') state.sink->Append(1, state.sign_char);
+  // Padding in general needs to be inserted somewhere in the middle of `data`.
+  state.sink->Append(data.substr(0, padding_offset));
+  state.sink->Append(padding.zeros, '0');
+  state.sink->Append(data.substr(padding_offset));
+  state.sink->Append(trailing_zeros, '0');
+  state.sink->Append(data_postfix);
+  state.sink->Append(padding.right_spaces, ' ');
+}
+
+// Fastpath %f formatter for when the shifted value fits in a simple integral
+// type.
+// Prints `v*2^exp` with the options from `state`.
+template <typename Int>
+void FormatFFast(Int v, int exp, const FormatState &state) {
+  constexpr int input_bits = sizeof(Int) * 8;
+
+  static constexpr size_t integral_size =
+      /* in case we need to round up an extra digit */ 1 +
+      /* decimal digits for uint128 */ 40 + 1;
+  char buffer[integral_size + /* . */ 1 + /* max digits uint128 */ 128];
+  buffer[integral_size] = '.';
+  char *const integral_digits_end = buffer + integral_size;
+  char *integral_digits_start;
+  char *const fractional_digits_start = buffer + integral_size + 1;
+  char *fractional_digits_end = fractional_digits_start;
+
+  if (exp >= 0) {
+    const int total_bits = input_bits - LeadingZeros(v) + exp;
+    integral_digits_start =
+        total_bits <= 64
+            ? PrintIntegralDigitsFromRightFast(static_cast<uint64_t>(v) << exp,
+                                               integral_digits_end)
+            : PrintIntegralDigitsFromRightFast(static_cast<uint128>(v) << exp,
+                                               integral_digits_end);
+  } else {
+    exp = -exp;
+
+    integral_digits_start = PrintIntegralDigitsFromRightFast(
+        exp < input_bits ? v >> exp : 0, integral_digits_end);
+    // PrintFractionalDigits may pull a carried 1 all the way up through the
+    // integral portion.
+    integral_digits_start[-1] = '0';
+
+    fractional_digits_end =
+        exp <= 64 ? PrintFractionalDigitsFast(v, fractional_digits_start, exp,
+                                              state.precision)
+                  : PrintFractionalDigitsFast(static_cast<uint128>(v),
+                                              fractional_digits_start, exp,
+                                              state.precision);
+    // There was a carry, so include the first digit too.
+    if (integral_digits_start[-1] != '0') --integral_digits_start;
+  }
+
+  size_t size = fractional_digits_end - integral_digits_start;
+
+  // In `alt` mode (flag #) we keep the `.` even if there are no fractional
+  // digits. In non-alt mode, we strip it.
+  if (!state.ShouldPrintDot()) --size;
+  FinalPrint(state, absl::string_view(integral_digits_start, size),
+             /*padding_offset=*/0,
+             static_cast<int>(state.precision - (fractional_digits_end -
+                                                 fractional_digits_start)),
+             /*data_postfix=*/"");
+}
+
+// Slow %f formatter for when the shifted value does not fit in a uint128, and
+// `exp > 0`.
+// Prints `v*2^exp` with the options from `state`.
+// This one is guaranteed to not have fractional digits, so we don't have to
+// worry about anything after the `.`.
+void FormatFPositiveExpSlow(uint128 v, int exp, const FormatState &state) {
+  BinaryToDecimal::RunConversion(v, exp, [&](BinaryToDecimal btd) {
+    const size_t total_digits =
+        btd.TotalDigits() +
+        (state.ShouldPrintDot() ? static_cast<size_t>(state.precision) + 1 : 0);
+
+    const auto padding = ExtraWidthToPadding(
+        total_digits + (state.sign_char != '\0' ? 1 : 0), state);
+
+    state.sink->Append(padding.left_spaces, ' ');
+    if (state.sign_char != '\0') state.sink->Append(1, state.sign_char);
+    state.sink->Append(padding.zeros, '0');
+
+    do {
+      state.sink->Append(btd.CurrentDigits());
+    } while (btd.AdvanceDigits());
+
+    if (state.ShouldPrintDot()) state.sink->Append(1, '.');
+    state.sink->Append(state.precision, '0');
+    state.sink->Append(padding.right_spaces, ' ');
+  });
+}
+
+// Slow %f formatter for when the shifted value does not fit in a uint128, and
+// `exp < 0`.
+// Prints `v*2^exp` with the options from `state`.
+// This one is guaranteed to be < 1.0, so we don't have to worry about integral
+// digits.
+void FormatFNegativeExpSlow(uint128 v, int exp, const FormatState &state) {
+  const size_t total_digits =
+      /* 0 */ 1 +
+      (state.ShouldPrintDot() ? static_cast<size_t>(state.precision) + 1 : 0);
+  auto padding =
+      ExtraWidthToPadding(total_digits + (state.sign_char ? 1 : 0), state);
+  padding.zeros += 1;
+  state.sink->Append(padding.left_spaces, ' ');
+  if (state.sign_char != '\0') state.sink->Append(1, state.sign_char);
+  state.sink->Append(padding.zeros, '0');
+
+  if (state.ShouldPrintDot()) state.sink->Append(1, '.');
+
+  // Print digits
+  int digits_to_go = state.precision;
+
+  FractionalDigitGenerator::RunConversion(
+      v, exp, [&](FractionalDigitGenerator digit_gen) {
+        // There are no digits to print here.
+        if (state.precision == 0) return;
+
+        // We go one digit at a time, while keeping track of runs of nines.
+        // The runs of nines are used to perform rounding when necessary.
+
+        while (digits_to_go > 0 && digit_gen.HasMoreDigits()) {
+          auto digits = digit_gen.GetDigits();
+
+          // Now we have a digit and a run of nines.
+          // See if we can print them all.
+          if (digits.num_nines + 1 < digits_to_go) {
+            // We don't have to round yet, so print them.
+            state.sink->Append(1, digits.digit_before_nine + '0');
+            state.sink->Append(digits.num_nines, '9');
+            digits_to_go -= digits.num_nines + 1;
+
+          } else {
+            // We can't print all the nines, see where we have to truncate.
+
+            bool round_up = false;
+            if (digits.num_nines + 1 > digits_to_go) {
+              // We round up at a nine. No need to print them.
+              round_up = true;
+            } else {
+              // We can fit all the nines, but truncate just after it.
+              if (digit_gen.IsGreaterThanHalf()) {
+                round_up = true;
+              } else if (digit_gen.IsExactlyHalf()) {
+                // Round to even
+                round_up =
+                    digits.num_nines != 0 || digits.digit_before_nine % 2 == 1;
+              }
+            }
+
+            if (round_up) {
+              state.sink->Append(1, digits.digit_before_nine + '1');
+              --digits_to_go;
+              // The rest will be zeros.
+            } else {
+              state.sink->Append(1, digits.digit_before_nine + '0');
+              state.sink->Append(digits_to_go - 1, '9');
+              digits_to_go = 0;
+            }
+            return;
+          }
+        }
+      });
+
+  state.sink->Append(digits_to_go, '0');
+  state.sink->Append(padding.right_spaces, ' ');
+}
+
+template <typename Int>
+void FormatF(Int mantissa, int exp, const FormatState &state) {
+  if (exp >= 0) {
+    const int total_bits = sizeof(Int) * 8 - LeadingZeros(mantissa) + exp;
+
+    // Fallback to the slow stack-based approach if we can't do it in a 64 or
+    // 128 bit state.
+    if (ABSL_PREDICT_FALSE(total_bits > 128)) {
+      return FormatFPositiveExpSlow(mantissa, exp, state);
+    }
+  } else {
+    // Fallback to the slow stack-based approach if we can't do it in a 64 or
+    // 128 bit state.
+    if (ABSL_PREDICT_FALSE(exp < -128)) {
+      return FormatFNegativeExpSlow(mantissa, -exp, state);
+    }
+  }
+  return FormatFFast(mantissa, exp, state);
+}
+
+// Grab the group of four bits (nibble) from `n`. E.g., nibble 1 corresponds to
+// bits 4-7.
+template <typename Int>
+uint8_t GetNibble(Int n, int nibble_index) {
+  constexpr Int mask_low_nibble = Int{0xf};
+  int shift = nibble_index * 4;
+  n &= mask_low_nibble << shift;
+  return static_cast<uint8_t>((n >> shift) & 0xf);
+}
+
+// Add one to the given nibble, applying carry to higher nibbles. Returns true
+// if overflow, false otherwise.
+template <typename Int>
+bool IncrementNibble(int nibble_index, Int *n) {
+  constexpr int kShift = sizeof(Int) * 8 - 1;
+  constexpr int kNumNibbles = sizeof(Int) * 8 / 4;
+  Int before = *n >> kShift;
+  // Here we essentially want to take the number 1 and move it into the requsted
+  // nibble, then add it to *n to effectively increment the nibble. However,
+  // ASan will complain if we try to shift the 1 beyond the limits of the Int,
+  // i.e., if the nibble_index is out of range. So therefore we check for this
+  // and if we are out of range we just add 0 which leaves *n unchanged, which
+  // seems like the reasonable thing to do in that case.
+  *n += ((nibble_index >= kNumNibbles) ? 0 : (Int{1} << (nibble_index * 4)));
+  Int after = *n >> kShift;
+  return (before && !after) || (nibble_index >= kNumNibbles);
+}
+
+// Return a mask with 1's in the given nibble and all lower nibbles.
+template <typename Int>
+Int MaskUpToNibbleInclusive(int nibble_index) {
+  constexpr int kNumNibbles = sizeof(Int) * 8 / 4;
+  static const Int ones = ~Int{0};
+  return ones >> std::max(0, 4 * (kNumNibbles - nibble_index - 1));
+}
+
+// Return a mask with 1's below the given nibble.
+template <typename Int>
+Int MaskUpToNibbleExclusive(int nibble_index) {
+  return nibble_index <= 0 ? 0 : MaskUpToNibbleInclusive<Int>(nibble_index - 1);
+}
+
+template <typename Int>
+Int MoveToNibble(uint8_t nibble, int nibble_index) {
+  return Int{nibble} << (4 * nibble_index);
+}
+
+// Given mantissa size, find optimal # of mantissa bits to put in initial digit.
+//
+// In the hex representation we keep a single hex digit to the left of the dot.
+// However, the question as to how many bits of the mantissa should be put into
+// that hex digit in theory is arbitrary, but in practice it is optimal to
+// choose based on the size of the mantissa. E.g., for a `double`, there are 53
+// mantissa bits, so that means that we should put 1 bit to the left of the dot,
+// thereby leaving 52 bits to the right, which is evenly divisible by four and
+// thus all fractional digits represent actual precision. For a `long double`,
+// on the other hand, there are 64 bits of mantissa, thus we can use all four
+// bits for the initial hex digit and still have a number left over (60) that is
+// a multiple of four. Once again, the goal is to have all fractional digits
+// represent real precision.
+template <typename Float>
+constexpr int HexFloatLeadingDigitSizeInBits() {
+  return std::numeric_limits<Float>::digits % 4 > 0
+             ? std::numeric_limits<Float>::digits % 4
+             : 4;
+}
+
+// This function captures the rounding behavior of glibc for hex float
+// representations. E.g. when rounding 0x1.ab800000 to a precision of .2
+// ("%.2a") glibc will round up because it rounds toward the even number (since
+// 0xb is an odd number, it will round up to 0xc). However, when rounding at a
+// point that is not followed by 800000..., it disregards the parity and rounds
+// up if > 8 and rounds down if < 8.
+template <typename Int>
+bool HexFloatNeedsRoundUp(Int mantissa, int final_nibble_displayed,
+                          uint8_t leading) {
+  // If the last nibble (hex digit) to be displayed is the lowest on in the
+  // mantissa then that means that we don't have any further nibbles to inform
+  // rounding, so don't round.
+  if (final_nibble_displayed <= 0) {
+    return false;
+  }
+  int rounding_nibble_idx = final_nibble_displayed - 1;
+  constexpr int kTotalNibbles = sizeof(Int) * 8 / 4;
+  assert(final_nibble_displayed <= kTotalNibbles);
+  Int mantissa_up_to_rounding_nibble_inclusive =
+      mantissa & MaskUpToNibbleInclusive<Int>(rounding_nibble_idx);
+  Int eight = MoveToNibble<Int>(8, rounding_nibble_idx);
+  if (mantissa_up_to_rounding_nibble_inclusive != eight) {
+    return mantissa_up_to_rounding_nibble_inclusive > eight;
+  }
+  // Nibble in question == 8.
+  uint8_t round_if_odd = (final_nibble_displayed == kTotalNibbles)
+                             ? leading
+                             : GetNibble(mantissa, final_nibble_displayed);
+  return round_if_odd % 2 == 1;
+}
+
+// Stores values associated with a Float type needed by the FormatA
+// implementation in order to avoid templatizing that function by the Float
+// type.
+struct HexFloatTypeParams {
+  template <typename Float>
+  explicit HexFloatTypeParams(Float)
+      : min_exponent(std::numeric_limits<Float>::min_exponent - 1),
+        leading_digit_size_bits(HexFloatLeadingDigitSizeInBits<Float>()) {
+    assert(leading_digit_size_bits >= 1 && leading_digit_size_bits <= 4);
+  }
+
+  int min_exponent;
+  int leading_digit_size_bits;
+};
+
+// Hex Float Rounding. First check if we need to round; if so, then we do that
+// by manipulating (incrementing) the mantissa, that way we can later print the
+// mantissa digits by iterating through them in the same way regardless of
+// whether a rounding happened.
+template <typename Int>
+void FormatARound(bool precision_specified, const FormatState &state,
+                  uint8_t *leading, Int *mantissa, int *exp) {
+  constexpr int kTotalNibbles = sizeof(Int) * 8 / 4;
+  // Index of the last nibble that we could display given precision.
+  int final_nibble_displayed =
+      precision_specified ? std::max(0, (kTotalNibbles - state.precision)) : 0;
+  if (HexFloatNeedsRoundUp(*mantissa, final_nibble_displayed, *leading)) {
+    // Need to round up.
+    bool overflow = IncrementNibble(final_nibble_displayed, mantissa);
+    *leading += (overflow ? 1 : 0);
+    if (ABSL_PREDICT_FALSE(*leading > 15)) {
+      // We have overflowed the leading digit. This would mean that we would
+      // need two hex digits to the left of the dot, which is not allowed. So
+      // adjust the mantissa and exponent so that the result is always 1.0eXXX.
+      *leading = 1;
+      *mantissa = 0;
+      *exp += 4;
+    }
+  }
+  // Now that we have handled a possible round-up we can go ahead and zero out
+  // all the nibbles of the mantissa that we won't need.
+  if (precision_specified) {
+    *mantissa &= ~MaskUpToNibbleExclusive<Int>(final_nibble_displayed);
+  }
+}
+
+template <typename Int>
+void FormatANormalize(const HexFloatTypeParams float_traits, uint8_t *leading,
+                      Int *mantissa, int *exp) {
+  constexpr int kIntBits = sizeof(Int) * 8;
+  static const Int kHighIntBit = Int{1} << (kIntBits - 1);
+  const int kLeadDigitBitsCount = float_traits.leading_digit_size_bits;
+  // Normalize mantissa so that highest bit set is in MSB position, unless we
+  // get interrupted by the exponent threshold.
+  while (*mantissa && !(*mantissa & kHighIntBit)) {
+    if (ABSL_PREDICT_FALSE(*exp - 1 < float_traits.min_exponent)) {
+      *mantissa >>= (float_traits.min_exponent - *exp);
+      *exp = float_traits.min_exponent;
+      return;
+    }
+    *mantissa <<= 1;
+    --*exp;
+  }
+  // Extract bits for leading digit then shift them away leaving the
+  // fractional part.
+  *leading =
+      static_cast<uint8_t>(*mantissa >> (kIntBits - kLeadDigitBitsCount));
+  *exp -= (*mantissa != 0) ? kLeadDigitBitsCount : *exp;
+  *mantissa <<= kLeadDigitBitsCount;
+}
+
+template <typename Int>
+void FormatA(const HexFloatTypeParams float_traits, Int mantissa, int exp,
+             bool uppercase, const FormatState &state) {
+  // Int properties.
+  constexpr int kIntBits = sizeof(Int) * 8;
+  constexpr int kTotalNibbles = sizeof(Int) * 8 / 4;
+  // Did the user specify a precision explicitly?
+  const bool precision_specified = state.conv.precision() >= 0;
+
+  // ========== Normalize/Denormalize ==========
+  exp += kIntBits;  // make all digits fractional digits.
+  // This holds the (up to four) bits of leading digit, i.e., the '1' in the
+  // number 0x1.e6fp+2. It's always > 0 unless number is zero or denormal.
+  uint8_t leading = 0;
+  FormatANormalize(float_traits, &leading, &mantissa, &exp);
+
+  // =============== Rounding ==================
+  // Check if we need to round; if so, then we do that by manipulating
+  // (incrementing) the mantissa before beginning to print characters.
+  FormatARound(precision_specified, state, &leading, &mantissa, &exp);
+
+  // ============= Format Result ===============
+  // This buffer holds the "0x1.ab1de3" portion of "0x1.ab1de3pe+2". Compute the
+  // size with long double which is the largest of the floats.
+  constexpr size_t kBufSizeForHexFloatRepr =
+      2                                                // 0x
+      + std::numeric_limits<MaxFloatType>::digits / 4  // number of hex digits
+      + 1                                              // round up
+      + 1;                                             // "." (dot)
+  char digits_buffer[kBufSizeForHexFloatRepr];
+  char *digits_iter = digits_buffer;
+  const char *const digits =
+      static_cast<const char *>("0123456789ABCDEF0123456789abcdef") +
+      (uppercase ? 0 : 16);
+
+  // =============== Hex Prefix ================
+  *digits_iter++ = '0';
+  *digits_iter++ = uppercase ? 'X' : 'x';
+
+  // ========== Non-Fractional Digit ===========
+  *digits_iter++ = digits[leading];
+
+  // ================== Dot ====================
+  // There are three reasons we might need a dot. Keep in mind that, at this
+  // point, the mantissa holds only the fractional part.
+  if ((precision_specified && state.precision > 0) ||
+      (!precision_specified && mantissa > 0) || state.conv.has_alt_flag()) {
+    *digits_iter++ = '.';
+  }
+
+  // ============ Fractional Digits ============
+  int digits_emitted = 0;
+  while (mantissa > 0) {
+    *digits_iter++ = digits[GetNibble(mantissa, kTotalNibbles - 1)];
+    mantissa <<= 4;
+    ++digits_emitted;
+  }
+  int trailing_zeros =
+      precision_specified ? state.precision - digits_emitted : 0;
+  assert(trailing_zeros >= 0);
+  auto digits_result = string_view(digits_buffer, digits_iter - digits_buffer);
+
+  // =============== Exponent ==================
+  constexpr size_t kBufSizeForExpDecRepr =
+      numbers_internal::kFastToBufferSize  // requred for FastIntToBuffer
+      + 1                                  // 'p' or 'P'
+      + 1;                                 // '+' or '-'
+  char exp_buffer[kBufSizeForExpDecRepr];
+  exp_buffer[0] = uppercase ? 'P' : 'p';
+  exp_buffer[1] = exp >= 0 ? '+' : '-';
+  numbers_internal::FastIntToBuffer(exp < 0 ? -exp : exp, exp_buffer + 2);
+
+  // ============ Assemble Result ==============
+  FinalPrint(state,           //
+             digits_result,   // 0xN.NNN...
+             2,               // offset in `data` to start padding if needed.
+             trailing_zeros,  // num remaining mantissa padding zeros
+             exp_buffer);     // exponent
+}
+
+char *CopyStringTo(absl::string_view v, char *out) {
+  std::memcpy(out, v.data(), v.size());
+  return out + v.size();
+}
+
+template <typename Float>
+bool FallbackToSnprintf(const Float v, const FormatConversionSpecImpl &conv,
+                        FormatSinkImpl *sink) {
+  int w = conv.width() >= 0 ? conv.width() : 0;
+  int p = conv.precision() >= 0 ? conv.precision() : -1;
+  char fmt[32];
+  {
+    char *fp = fmt;
+    *fp++ = '%';
+    fp = CopyStringTo(FormatConversionSpecImplFriend::FlagsToString(conv), fp);
+    fp = CopyStringTo("*.*", fp);
+    if (std::is_same<long double, Float>()) {
+      *fp++ = 'L';
+    }
+    *fp++ = FormatConversionCharToChar(conv.conversion_char());
+    *fp = 0;
+    assert(fp < fmt + sizeof(fmt));
+  }
+  std::string space(512, '\0');
+  absl::string_view result;
+  while (true) {
+    int n = snprintf(&space[0], space.size(), fmt, w, p, v);
+    if (n < 0) return false;
+    if (static_cast<size_t>(n) < space.size()) {
+      result = absl::string_view(space.data(), n);
+      break;
+    }
+    space.resize(n + 1);
+  }
+  sink->Append(result);
+  return true;
+}
+
+// 128-bits in decimal: ceil(128*log(2)/log(10))
+//   or std::numeric_limits<__uint128_t>::digits10
+constexpr int kMaxFixedPrecision = 39;
+
+constexpr int kBufferLength = /*sign*/ 1 +
+                              /*integer*/ kMaxFixedPrecision +
+                              /*point*/ 1 +
+                              /*fraction*/ kMaxFixedPrecision +
+                              /*exponent e+123*/ 5;
+
+struct Buffer {
+  void push_front(char c) {
+    assert(begin > data);
+    *--begin = c;
+  }
+  void push_back(char c) {
+    assert(end < data + sizeof(data));
+    *end++ = c;
+  }
+  void pop_back() {
+    assert(begin < end);
+    --end;
+  }
+
+  char &back() {
+    assert(begin < end);
+    return end[-1];
+  }
+
+  char last_digit() const { return end[-1] == '.' ? end[-2] : end[-1]; }
+
+  int size() const { return static_cast<int>(end - begin); }
+
+  char data[kBufferLength];
+  char *begin;
+  char *end;
+};
+
+enum class FormatStyle { Fixed, Precision };
+
+// If the value is Inf or Nan, print it and return true.
+// Otherwise, return false.
+template <typename Float>
+bool ConvertNonNumericFloats(char sign_char, Float v,
+                             const FormatConversionSpecImpl &conv,
+                             FormatSinkImpl *sink) {
+  char text[4], *ptr = text;
+  if (sign_char != '\0') *ptr++ = sign_char;
+  if (std::isnan(v)) {
+    ptr = std::copy_n(
+        FormatConversionCharIsUpper(conv.conversion_char()) ? "NAN" : "nan", 3,
+        ptr);
+  } else if (std::isinf(v)) {
+    ptr = std::copy_n(
+        FormatConversionCharIsUpper(conv.conversion_char()) ? "INF" : "inf", 3,
+        ptr);
+  } else {
+    return false;
+  }
+
+  return sink->PutPaddedString(string_view(text, ptr - text), conv.width(), -1,
+                               conv.has_left_flag());
+}
+
+// Round up the last digit of the value.
+// It will carry over and potentially overflow. 'exp' will be adjusted in that
+// case.
+template <FormatStyle mode>
+void RoundUp(Buffer *buffer, int *exp) {
+  char *p = &buffer->back();
+  while (p >= buffer->begin && (*p == '9' || *p == '.')) {
+    if (*p == '9') *p = '0';
+    --p;
+  }
+
+  if (p < buffer->begin) {
+    *p = '1';
+    buffer->begin = p;
+    if (mode == FormatStyle::Precision) {
+      std::swap(p[1], p[2]);  // move the .
+      ++*exp;
+      buffer->pop_back();
+    }
+  } else {
+    ++*p;
+  }
+}
+
+void PrintExponent(int exp, char e, Buffer *out) {
+  out->push_back(e);
+  if (exp < 0) {
+    out->push_back('-');
+    exp = -exp;
+  } else {
+    out->push_back('+');
+  }
+  // Exponent digits.
+  if (exp > 99) {
+    out->push_back(exp / 100 + '0');
+    out->push_back(exp / 10 % 10 + '0');
+    out->push_back(exp % 10 + '0');
+  } else {
+    out->push_back(exp / 10 + '0');
+    out->push_back(exp % 10 + '0');
+  }
+}
+
+template <typename Float, typename Int>
+constexpr bool CanFitMantissa() {
+  return
+#if defined(__clang__) && !defined(__SSE3__)
+      // Workaround for clang bug: https://bugs.llvm.org/show_bug.cgi?id=38289
+      // Casting from long double to uint64_t is miscompiled and drops bits.
+      (!std::is_same<Float, long double>::value ||
+       !std::is_same<Int, uint64_t>::value) &&
+#endif
+      std::numeric_limits<Float>::digits <= std::numeric_limits<Int>::digits;
+}
+
+template <typename Float>
+struct Decomposed {
+  using MantissaType =
+      absl::conditional_t<std::is_same<long double, Float>::value, uint128,
+                          uint64_t>;
+  static_assert(std::numeric_limits<Float>::digits <= sizeof(MantissaType) * 8,
+                "");
+  MantissaType mantissa;
+  int exponent;
+};
+
+// Decompose the double into an integer mantissa and an exponent.
+template <typename Float>
+Decomposed<Float> Decompose(Float v) {
+  int exp;
+  Float m = std::frexp(v, &exp);
+  m = std::ldexp(m, std::numeric_limits<Float>::digits);
+  exp -= std::numeric_limits<Float>::digits;
+
+  return {static_cast<typename Decomposed<Float>::MantissaType>(m), exp};
+}
+
+// Print 'digits' as decimal.
+// In Fixed mode, we add a '.' at the end.
+// In Precision mode, we add a '.' after the first digit.
+template <FormatStyle mode, typename Int>
+int PrintIntegralDigits(Int digits, Buffer *out) {
+  int printed = 0;
+  if (digits) {
+    for (; digits; digits /= 10) out->push_front(digits % 10 + '0');
+    printed = out->size();
+    if (mode == FormatStyle::Precision) {
+      out->push_front(*out->begin);
+      out->begin[1] = '.';
+    } else {
+      out->push_back('.');
+    }
+  } else if (mode == FormatStyle::Fixed) {
+    out->push_front('0');
+    out->push_back('.');
+    printed = 1;
+  }
+  return printed;
+}
+
+// Back out 'extra_digits' digits and round up if necessary.
+bool RemoveExtraPrecision(int extra_digits, bool has_leftover_value,
+                          Buffer *out, int *exp_out) {
+  if (extra_digits <= 0) return false;
+
+  // Back out the extra digits
+  out->end -= extra_digits;
+
+  bool needs_to_round_up = [&] {
+    // We look at the digit just past the end.
+    // There must be 'extra_digits' extra valid digits after end.
+    if (*out->end > '5') return true;
+    if (*out->end < '5') return false;
+    if (has_leftover_value || std::any_of(out->end + 1, out->end + extra_digits,
+                                          [](char c) { return c != '0'; }))
+      return true;
+
+    // Ends in ...50*, round to even.
+    return out->last_digit() % 2 == 1;
+  }();
+
+  if (needs_to_round_up) {
+    RoundUp<FormatStyle::Precision>(out, exp_out);
+  }
+  return true;
+}
+
+// Print the value into the buffer.
+// This will not include the exponent, which will be returned in 'exp_out' for
+// Precision mode.
+template <typename Int, typename Float, FormatStyle mode>
+bool FloatToBufferImpl(Int int_mantissa, int exp, int precision, Buffer *out,
+                       int *exp_out) {
+  assert((CanFitMantissa<Float, Int>()));
+
+  const int int_bits = std::numeric_limits<Int>::digits;
+
+  // In precision mode, we start printing one char to the right because it will
+  // also include the '.'
+  // In fixed mode we put the dot afterwards on the right.
+  out->begin = out->end =
+      out->data + 1 + kMaxFixedPrecision + (mode == FormatStyle::Precision);
+
+  if (exp >= 0) {
+    if (std::numeric_limits<Float>::digits + exp > int_bits) {
+      // The value will overflow the Int
+      return false;
+    }
+    int digits_printed = PrintIntegralDigits<mode>(int_mantissa << exp, out);
+    int digits_to_zero_pad = precision;
+    if (mode == FormatStyle::Precision) {
+      *exp_out = digits_printed - 1;
+      digits_to_zero_pad -= digits_printed - 1;
+      if (RemoveExtraPrecision(-digits_to_zero_pad, false, out, exp_out)) {
+        return true;
+      }
+    }
+    for (; digits_to_zero_pad-- > 0;) out->push_back('0');
+    return true;
+  }
+
+  exp = -exp;
+  // We need at least 4 empty bits for the next decimal digit.
+  // We will multiply by 10.
+  if (exp > int_bits - 4) return false;
+
+  const Int mask = (Int{1} << exp) - 1;
+
+  // Print the integral part first.
+  int digits_printed = PrintIntegralDigits<mode>(int_mantissa >> exp, out);
+  int_mantissa &= mask;
+
+  int fractional_count = precision;
+  if (mode == FormatStyle::Precision) {
+    if (digits_printed == 0) {
+      // Find the first non-zero digit, when in Precision mode.
+      *exp_out = 0;
+      if (int_mantissa) {
+        while (int_mantissa <= mask) {
+          int_mantissa *= 10;
+          --*exp_out;
+        }
+      }
+      out->push_front(static_cast<char>(int_mantissa >> exp) + '0');
+      out->push_back('.');
+      int_mantissa &= mask;
+    } else {
+      // We already have a digit, and a '.'
+      *exp_out = digits_printed - 1;
+      fractional_count -= *exp_out;
+      if (RemoveExtraPrecision(-fractional_count, int_mantissa != 0, out,
+                               exp_out)) {
+        // If we had enough digits, return right away.
+        // The code below will try to round again otherwise.
+        return true;
+      }
+    }
+  }
+
+  auto get_next_digit = [&] {
+    int_mantissa *= 10;
+    int digit = static_cast<int>(int_mantissa >> exp);
+    int_mantissa &= mask;
+    return digit;
+  };
+
+  // Print fractional_count more digits, if available.
+  for (; fractional_count > 0; --fractional_count) {
+    out->push_back(get_next_digit() + '0');
+  }
+
+  int next_digit = get_next_digit();
+  if (next_digit > 5 ||
+      (next_digit == 5 && (int_mantissa || out->last_digit() % 2 == 1))) {
+    RoundUp<mode>(out, exp_out);
+  }
+
+  return true;
+}
+
+template <FormatStyle mode, typename Float>
+bool FloatToBuffer(Decomposed<Float> decomposed, int precision, Buffer *out,
+                   int *exp) {
+  if (precision > kMaxFixedPrecision) return false;
+
+  // Try with uint64_t.
+  if (CanFitMantissa<Float, std::uint64_t>() &&
+      FloatToBufferImpl<std::uint64_t, Float, mode>(
+          static_cast<std::uint64_t>(decomposed.mantissa),
+          static_cast<std::uint64_t>(decomposed.exponent), precision, out, exp))
+    return true;
+
+#if defined(ABSL_HAVE_INTRINSIC_INT128)
+  // If that is not enough, try with __uint128_t.
+  return CanFitMantissa<Float, __uint128_t>() &&
+         FloatToBufferImpl<__uint128_t, Float, mode>(
+             static_cast<__uint128_t>(decomposed.mantissa),
+             static_cast<__uint128_t>(decomposed.exponent), precision, out,
+             exp);
+#endif
+  return false;
+}
+
+void WriteBufferToSink(char sign_char, absl::string_view str,
+                       const FormatConversionSpecImpl &conv,
+                       FormatSinkImpl *sink) {
+  int left_spaces = 0, zeros = 0, right_spaces = 0;
+  int missing_chars =
+      conv.width() >= 0 ? std::max(conv.width() - static_cast<int>(str.size()) -
+                                       static_cast<int>(sign_char != 0),
+                                   0)
+                        : 0;
+  if (conv.has_left_flag()) {
+    right_spaces = missing_chars;
+  } else if (conv.has_zero_flag()) {
+    zeros = missing_chars;
+  } else {
+    left_spaces = missing_chars;
+  }
+
+  sink->Append(left_spaces, ' ');
+  if (sign_char != '\0') sink->Append(1, sign_char);
+  sink->Append(zeros, '0');
+  sink->Append(str);
+  sink->Append(right_spaces, ' ');
+}
+
+template <typename Float>
+bool FloatToSink(const Float v, const FormatConversionSpecImpl &conv,
+                 FormatSinkImpl *sink) {
+  // Print the sign or the sign column.
+  Float abs_v = v;
+  char sign_char = 0;
+  if (std::signbit(abs_v)) {
+    sign_char = '-';
+    abs_v = -abs_v;
+  } else if (conv.has_show_pos_flag()) {
+    sign_char = '+';
+  } else if (conv.has_sign_col_flag()) {
+    sign_char = ' ';
+  }
+
+  // Print nan/inf.
+  if (ConvertNonNumericFloats(sign_char, abs_v, conv, sink)) {
+    return true;
+  }
+
+  int precision = conv.precision() < 0 ? 6 : conv.precision();
+
+  int exp = 0;
+
+  auto decomposed = Decompose(abs_v);
+
+  Buffer buffer;
+
+  FormatConversionChar c = conv.conversion_char();
+
+  if (c == FormatConversionCharInternal::f ||
+      c == FormatConversionCharInternal::F) {
+    FormatF(decomposed.mantissa, decomposed.exponent,
+            {sign_char, precision, conv, sink});
+    return true;
+  } else if (c == FormatConversionCharInternal::e ||
+             c == FormatConversionCharInternal::E) {
+    if (!FloatToBuffer<FormatStyle::Precision>(decomposed, precision, &buffer,
+                                               &exp)) {
+      return FallbackToSnprintf(v, conv, sink);
+    }
+    if (!conv.has_alt_flag() && buffer.back() == '.') buffer.pop_back();
+    PrintExponent(
+        exp, FormatConversionCharIsUpper(conv.conversion_char()) ? 'E' : 'e',
+        &buffer);
+  } else if (c == FormatConversionCharInternal::g ||
+             c == FormatConversionCharInternal::G) {
+    precision = std::max(0, precision - 1);
+    if (!FloatToBuffer<FormatStyle::Precision>(decomposed, precision, &buffer,
+                                               &exp)) {
+      return FallbackToSnprintf(v, conv, sink);
+    }
+    if (precision + 1 > exp && exp >= -4) {
+      if (exp < 0) {
+        // Have 1.23456, needs 0.00123456
+        // Move the first digit
+        buffer.begin[1] = *buffer.begin;
+        // Add some zeros
+        for (; exp < -1; ++exp) *buffer.begin-- = '0';
+        *buffer.begin-- = '.';
+        *buffer.begin = '0';
+      } else if (exp > 0) {
+        // Have 1.23456, needs 1234.56
+        // Move the '.' exp positions to the right.
+        std::rotate(buffer.begin + 1, buffer.begin + 2, buffer.begin + exp + 2);
+      }
+      exp = 0;
+    }
+    if (!conv.has_alt_flag()) {
+      while (buffer.back() == '0') buffer.pop_back();
+      if (buffer.back() == '.') buffer.pop_back();
+    }
+    if (exp) {
+      PrintExponent(
+          exp, FormatConversionCharIsUpper(conv.conversion_char()) ? 'E' : 'e',
+          &buffer);
+    }
+  } else if (c == FormatConversionCharInternal::a ||
+             c == FormatConversionCharInternal::A) {
+    bool uppercase = (c == FormatConversionCharInternal::A);
+    FormatA(HexFloatTypeParams(Float{}), decomposed.mantissa,
+            decomposed.exponent, uppercase, {sign_char, precision, conv, sink});
+    return true;
+  } else {
+    return false;
+  }
+
+  WriteBufferToSink(sign_char,
+                    absl::string_view(buffer.begin, buffer.end - buffer.begin),
+                    conv, sink);
+
+  return true;
+}
+
+}  // namespace
+
+bool ConvertFloatImpl(long double v, const FormatConversionSpecImpl &conv,
+                      FormatSinkImpl *sink) {
+  if (IsDoubleDouble()) {
+    // This is the `double-double` representation of `long double`. We do not
+    // handle it natively. Fallback to snprintf.
+    return FallbackToSnprintf(v, conv, sink);
+  }
+
+  return FloatToSink(v, conv, sink);
+}
+
+bool ConvertFloatImpl(float v, const FormatConversionSpecImpl &conv,
+                      FormatSinkImpl *sink) {
+  return FloatToSink(static_cast<double>(v), conv, sink);
+}
+
+bool ConvertFloatImpl(double v, const FormatConversionSpecImpl &conv,
+                      FormatSinkImpl *sink) {
+  return FloatToSink(v, conv, sink);
+}
+
+}  // namespace str_format_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
diff --git a/src/absl/strings/internal/str_format/float_conversion.h b/src/absl/strings/internal/str_format/float_conversion.h
new file mode 100644 (file)
index 0000000..71100e7
--- /dev/null
@@ -0,0 +1,37 @@
+// Copyright 2020 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef ABSL_STRINGS_INTERNAL_STR_FORMAT_FLOAT_CONVERSION_H_
+#define ABSL_STRINGS_INTERNAL_STR_FORMAT_FLOAT_CONVERSION_H_
+
+#include "absl/strings/internal/str_format/extension.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace str_format_internal {
+
+bool ConvertFloatImpl(float v, const FormatConversionSpecImpl &conv,
+                      FormatSinkImpl *sink);
+
+bool ConvertFloatImpl(double v, const FormatConversionSpecImpl &conv,
+                      FormatSinkImpl *sink);
+
+bool ConvertFloatImpl(long double v, const FormatConversionSpecImpl &conv,
+                      FormatSinkImpl *sink);
+
+}  // namespace str_format_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#endif  // ABSL_STRINGS_INTERNAL_STR_FORMAT_FLOAT_CONVERSION_H_
diff --git a/src/absl/strings/internal/str_format/output.cc b/src/absl/strings/internal/str_format/output.cc
new file mode 100644 (file)
index 0000000..c4b2470
--- /dev/null
@@ -0,0 +1,72 @@
+// Copyright 2017 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "absl/strings/internal/str_format/output.h"
+
+#include <errno.h>
+#include <cstring>
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace str_format_internal {
+
+namespace {
+struct ClearErrnoGuard {
+  ClearErrnoGuard() : old_value(errno) { errno = 0; }
+  ~ClearErrnoGuard() {
+    if (!errno) errno = old_value;
+  }
+  int old_value;
+};
+}  // namespace
+
+void BufferRawSink::Write(string_view v) {
+  size_t to_write = std::min(v.size(), size_);
+  std::memcpy(buffer_, v.data(), to_write);
+  buffer_ += to_write;
+  size_ -= to_write;
+  total_written_ += v.size();
+}
+
+void FILERawSink::Write(string_view v) {
+  while (!v.empty() && !error_) {
+    // Reset errno to zero in case the libc implementation doesn't set errno
+    // when a failure occurs.
+    ClearErrnoGuard guard;
+
+    if (size_t result = std::fwrite(v.data(), 1, v.size(), output_)) {
+      // Some progress was made.
+      count_ += result;
+      v.remove_prefix(result);
+    } else {
+      if (errno == EINTR) {
+        continue;
+      } else if (errno) {
+        error_ = errno;
+      } else if (std::ferror(output_)) {
+        // Non-POSIX compliant libc implementations may not set errno, so we
+        // have check the streams error indicator.
+        error_ = EBADF;
+      } else {
+        // We're likely on a non-POSIX system that encountered EINTR but had no
+        // way of reporting it.
+        continue;
+      }
+    }
+  }
+}
+
+}  // namespace str_format_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
diff --git a/src/absl/strings/internal/str_format/output.h b/src/absl/strings/internal/str_format/output.h
new file mode 100644 (file)
index 0000000..8030dae
--- /dev/null
@@ -0,0 +1,96 @@
+// Copyright 2017 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// Output extension hooks for the Format library.
+// `internal::InvokeFlush` calls the appropriate flush function for the
+// specified output argument.
+// `BufferRawSink` is a simple output sink for a char buffer. Used by SnprintF.
+// `FILERawSink` is a std::FILE* based sink. Used by PrintF and FprintF.
+
+#ifndef ABSL_STRINGS_INTERNAL_STR_FORMAT_OUTPUT_H_
+#define ABSL_STRINGS_INTERNAL_STR_FORMAT_OUTPUT_H_
+
+#include <cstdio>
+#include <ostream>
+#include <string>
+
+#include "absl/base/port.h"
+#include "absl/strings/string_view.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace str_format_internal {
+
+// RawSink implementation that writes into a char* buffer.
+// It will not overflow the buffer, but will keep the total count of chars
+// that would have been written.
+class BufferRawSink {
+ public:
+  BufferRawSink(char* buffer, size_t size) : buffer_(buffer), size_(size) {}
+
+  size_t total_written() const { return total_written_; }
+  void Write(string_view v);
+
+ private:
+  char* buffer_;
+  size_t size_;
+  size_t total_written_ = 0;
+};
+
+// RawSink implementation that writes into a FILE*.
+// It keeps track of the total number of bytes written and any error encountered
+// during the writes.
+class FILERawSink {
+ public:
+  explicit FILERawSink(std::FILE* output) : output_(output) {}
+
+  void Write(string_view v);
+
+  size_t count() const { return count_; }
+  int error() const { return error_; }
+
+ private:
+  std::FILE* output_;
+  int error_ = 0;
+  size_t count_ = 0;
+};
+
+// Provide RawSink integration with common types from the STL.
+inline void AbslFormatFlush(std::string* out, string_view s) {
+  out->append(s.data(), s.size());
+}
+inline void AbslFormatFlush(std::ostream* out, string_view s) {
+  out->write(s.data(), s.size());
+}
+
+inline void AbslFormatFlush(FILERawSink* sink, string_view v) {
+  sink->Write(v);
+}
+
+inline void AbslFormatFlush(BufferRawSink* sink, string_view v) {
+  sink->Write(v);
+}
+
+// This is a SFINAE to get a better compiler error message when the type
+// is not supported.
+template <typename T>
+auto InvokeFlush(T* out, string_view s) -> decltype(AbslFormatFlush(out, s)) {
+  AbslFormatFlush(out, s);
+}
+
+}  // namespace str_format_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#endif  // ABSL_STRINGS_INTERNAL_STR_FORMAT_OUTPUT_H_
diff --git a/src/absl/strings/internal/str_format/parser.cc b/src/absl/strings/internal/str_format/parser.cc
new file mode 100644 (file)
index 0000000..f308d02
--- /dev/null
@@ -0,0 +1,350 @@
+// Copyright 2020 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "absl/strings/internal/str_format/parser.h"
+
+#include <assert.h>
+#include <string.h>
+#include <wchar.h>
+#include <cctype>
+#include <cstdint>
+
+#include <algorithm>
+#include <initializer_list>
+#include <limits>
+#include <ostream>
+#include <string>
+#include <unordered_set>
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace str_format_internal {
+
+using CC = FormatConversionCharInternal;
+using LM = LengthMod;
+
+ABSL_CONST_INIT const ConvTag kTags[256] = {
+    {},    {},    {},    {},    {},    {},    {},    {},     // 00-07
+    {},    {},    {},    {},    {},    {},    {},    {},     // 08-0f
+    {},    {},    {},    {},    {},    {},    {},    {},     // 10-17
+    {},    {},    {},    {},    {},    {},    {},    {},     // 18-1f
+    {},    {},    {},    {},    {},    {},    {},    {},     // 20-27
+    {},    {},    {},    {},    {},    {},    {},    {},     // 28-2f
+    {},    {},    {},    {},    {},    {},    {},    {},     // 30-37
+    {},    {},    {},    {},    {},    {},    {},    {},     // 38-3f
+    {},    CC::A, {},    {},    {},    CC::E, CC::F, CC::G,  // @ABCDEFG
+    {},    {},    {},    {},    LM::L, {},    {},    {},     // HIJKLMNO
+    {},    {},    {},    {},    {},    {},    {},    {},     // PQRSTUVW
+    CC::X, {},    {},    {},    {},    {},    {},    {},     // XYZ[\]^_
+    {},    CC::a, {},    CC::c, CC::d, CC::e, CC::f, CC::g,  // `abcdefg
+    LM::h, CC::i, LM::j, {},    LM::l, {},    CC::n, CC::o,  // hijklmno
+    CC::p, LM::q, {},    CC::s, LM::t, CC::u, {},    {},     // pqrstuvw
+    CC::x, {},    LM::z, {},    {},    {},    {},    {},     // xyz{|}!
+    {},    {},    {},    {},    {},    {},    {},    {},     // 80-87
+    {},    {},    {},    {},    {},    {},    {},    {},     // 88-8f
+    {},    {},    {},    {},    {},    {},    {},    {},     // 90-97
+    {},    {},    {},    {},    {},    {},    {},    {},     // 98-9f
+    {},    {},    {},    {},    {},    {},    {},    {},     // a0-a7
+    {},    {},    {},    {},    {},    {},    {},    {},     // a8-af
+    {},    {},    {},    {},    {},    {},    {},    {},     // b0-b7
+    {},    {},    {},    {},    {},    {},    {},    {},     // b8-bf
+    {},    {},    {},    {},    {},    {},    {},    {},     // c0-c7
+    {},    {},    {},    {},    {},    {},    {},    {},     // c8-cf
+    {},    {},    {},    {},    {},    {},    {},    {},     // d0-d7
+    {},    {},    {},    {},    {},    {},    {},    {},     // d8-df
+    {},    {},    {},    {},    {},    {},    {},    {},     // e0-e7
+    {},    {},    {},    {},    {},    {},    {},    {},     // e8-ef
+    {},    {},    {},    {},    {},    {},    {},    {},     // f0-f7
+    {},    {},    {},    {},    {},    {},    {},    {},     // f8-ff
+};
+
+namespace {
+
+bool CheckFastPathSetting(const UnboundConversion& conv) {
+  bool should_be_basic = !conv.flags.left &&      //
+                         !conv.flags.show_pos &&  //
+                         !conv.flags.sign_col &&  //
+                         !conv.flags.alt &&       //
+                         !conv.flags.zero &&      //
+                         (conv.width.value() == -1) &&
+                         (conv.precision.value() == -1);
+  if (should_be_basic != conv.flags.basic) {
+    fprintf(stderr,
+            "basic=%d left=%d show_pos=%d sign_col=%d alt=%d zero=%d "
+            "width=%d precision=%d\n",
+            conv.flags.basic, conv.flags.left, conv.flags.show_pos,
+            conv.flags.sign_col, conv.flags.alt, conv.flags.zero,
+            conv.width.value(), conv.precision.value());
+  }
+  return should_be_basic == conv.flags.basic;
+}
+
+template <bool is_positional>
+const char *ConsumeConversion(const char *pos, const char *const end,
+                              UnboundConversion *conv, int *next_arg) {
+  const char* const original_pos = pos;
+  char c;
+  // Read the next char into `c` and update `pos`. Returns false if there are
+  // no more chars to read.
+#define ABSL_FORMAT_PARSER_INTERNAL_GET_CHAR()          \
+  do {                                                  \
+    if (ABSL_PREDICT_FALSE(pos == end)) return nullptr; \
+    c = *pos++;                                         \
+  } while (0)
+
+  const auto parse_digits = [&] {
+    int digits = c - '0';
+    // We do not want to overflow `digits` so we consume at most digits10
+    // digits. If there are more digits the parsing will fail later on when the
+    // digit doesn't match the expected characters.
+    int num_digits = std::numeric_limits<int>::digits10;
+    for (;;) {
+      if (ABSL_PREDICT_FALSE(pos == end)) break;
+      c = *pos++;
+      if (!std::isdigit(c)) break;
+      --num_digits;
+      if (ABSL_PREDICT_FALSE(!num_digits)) break;
+      digits = 10 * digits + c - '0';
+    }
+    return digits;
+  };
+
+  if (is_positional) {
+    ABSL_FORMAT_PARSER_INTERNAL_GET_CHAR();
+    if (ABSL_PREDICT_FALSE(c < '1' || c > '9')) return nullptr;
+    conv->arg_position = parse_digits();
+    assert(conv->arg_position > 0);
+    if (ABSL_PREDICT_FALSE(c != '$')) return nullptr;
+  }
+
+  ABSL_FORMAT_PARSER_INTERNAL_GET_CHAR();
+
+  // We should start with the basic flag on.
+  assert(conv->flags.basic);
+
+  // Any non alpha character makes this conversion not basic.
+  // This includes flags (-+ #0), width (1-9, *) or precision (.).
+  // All conversion characters and length modifiers are alpha characters.
+  if (c < 'A') {
+    conv->flags.basic = false;
+
+    for (; c <= '0';) {
+      // FIXME: We might be able to speed this up reusing the lookup table from
+      // above. It might require changing Flags to be a plain integer where we
+      // can |= a value.
+      switch (c) {
+        case '-':
+          conv->flags.left = true;
+          break;
+        case '+':
+          conv->flags.show_pos = true;
+          break;
+        case ' ':
+          conv->flags.sign_col = true;
+          break;
+        case '#':
+          conv->flags.alt = true;
+          break;
+        case '0':
+          conv->flags.zero = true;
+          break;
+        default:
+          goto flags_done;
+      }
+      ABSL_FORMAT_PARSER_INTERNAL_GET_CHAR();
+    }
+flags_done:
+
+    if (c <= '9') {
+      if (c >= '0') {
+        int maybe_width = parse_digits();
+        if (!is_positional && c == '$') {
+          if (ABSL_PREDICT_FALSE(*next_arg != 0)) return nullptr;
+          // Positional conversion.
+          *next_arg = -1;
+          conv->flags = Flags();
+          conv->flags.basic = true;
+          return ConsumeConversion<true>(original_pos, end, conv, next_arg);
+        }
+        conv->width.set_value(maybe_width);
+      } else if (c == '*') {
+        ABSL_FORMAT_PARSER_INTERNAL_GET_CHAR();
+        if (is_positional) {
+          if (ABSL_PREDICT_FALSE(c < '1' || c > '9')) return nullptr;
+          conv->width.set_from_arg(parse_digits());
+          if (ABSL_PREDICT_FALSE(c != '$')) return nullptr;
+          ABSL_FORMAT_PARSER_INTERNAL_GET_CHAR();
+        } else {
+          conv->width.set_from_arg(++*next_arg);
+        }
+      }
+    }
+
+    if (c == '.') {
+      ABSL_FORMAT_PARSER_INTERNAL_GET_CHAR();
+      if (std::isdigit(c)) {
+        conv->precision.set_value(parse_digits());
+      } else if (c == '*') {
+        ABSL_FORMAT_PARSER_INTERNAL_GET_CHAR();
+        if (is_positional) {
+          if (ABSL_PREDICT_FALSE(c < '1' || c > '9')) return nullptr;
+          conv->precision.set_from_arg(parse_digits());
+          if (c != '$') return nullptr;
+          ABSL_FORMAT_PARSER_INTERNAL_GET_CHAR();
+        } else {
+          conv->precision.set_from_arg(++*next_arg);
+        }
+      } else {
+        conv->precision.set_value(0);
+      }
+    }
+  }
+
+  auto tag = GetTagForChar(c);
+
+  if (ABSL_PREDICT_FALSE(!tag.is_conv())) {
+    if (ABSL_PREDICT_FALSE(!tag.is_length())) return nullptr;
+
+    // It is a length modifier.
+    using str_format_internal::LengthMod;
+    LengthMod length_mod = tag.as_length();
+    ABSL_FORMAT_PARSER_INTERNAL_GET_CHAR();
+    if (c == 'h' && length_mod == LengthMod::h) {
+      conv->length_mod = LengthMod::hh;
+      ABSL_FORMAT_PARSER_INTERNAL_GET_CHAR();
+    } else if (c == 'l' && length_mod == LengthMod::l) {
+      conv->length_mod = LengthMod::ll;
+      ABSL_FORMAT_PARSER_INTERNAL_GET_CHAR();
+    } else {
+      conv->length_mod = length_mod;
+    }
+    tag = GetTagForChar(c);
+    if (ABSL_PREDICT_FALSE(!tag.is_conv())) return nullptr;
+  }
+
+  assert(CheckFastPathSetting(*conv));
+  (void)(&CheckFastPathSetting);
+
+  conv->conv = tag.as_conv();
+  if (!is_positional) conv->arg_position = ++*next_arg;
+  return pos;
+}
+
+}  // namespace
+
+std::string LengthModToString(LengthMod v) {
+  switch (v) {
+    case LengthMod::h:
+      return "h";
+    case LengthMod::hh:
+      return "hh";
+    case LengthMod::l:
+      return "l";
+    case LengthMod::ll:
+      return "ll";
+    case LengthMod::L:
+      return "L";
+    case LengthMod::j:
+      return "j";
+    case LengthMod::z:
+      return "z";
+    case LengthMod::t:
+      return "t";
+    case LengthMod::q:
+      return "q";
+    case LengthMod::none:
+      return "";
+  }
+  return "";
+}
+
+const char *ConsumeUnboundConversion(const char *p, const char *end,
+                                     UnboundConversion *conv, int *next_arg) {
+  if (*next_arg < 0) return ConsumeConversion<true>(p, end, conv, next_arg);
+  return ConsumeConversion<false>(p, end, conv, next_arg);
+}
+
+struct ParsedFormatBase::ParsedFormatConsumer {
+  explicit ParsedFormatConsumer(ParsedFormatBase *parsedformat)
+      : parsed(parsedformat), data_pos(parsedformat->data_.get()) {}
+
+  bool Append(string_view s) {
+    if (s.empty()) return true;
+
+    size_t text_end = AppendText(s);
+
+    if (!parsed->items_.empty() && !parsed->items_.back().is_conversion) {
+      // Let's extend the existing text run.
+      parsed->items_.back().text_end = text_end;
+    } else {
+      // Let's make a new text run.
+      parsed->items_.push_back({false, text_end, {}});
+    }
+    return true;
+  }
+
+  bool ConvertOne(const UnboundConversion &conv, string_view s) {
+    size_t text_end = AppendText(s);
+    parsed->items_.push_back({true, text_end, conv});
+    return true;
+  }
+
+  size_t AppendText(string_view s) {
+    memcpy(data_pos, s.data(), s.size());
+    data_pos += s.size();
+    return static_cast<size_t>(data_pos - parsed->data_.get());
+  }
+
+  ParsedFormatBase *parsed;
+  char* data_pos;
+};
+
+ParsedFormatBase::ParsedFormatBase(
+    string_view format, bool allow_ignored,
+    std::initializer_list<FormatConversionCharSet> convs)
+    : data_(format.empty() ? nullptr : new char[format.size()]) {
+  has_error_ = !ParseFormatString(format, ParsedFormatConsumer(this)) ||
+               !MatchesConversions(allow_ignored, convs);
+}
+
+bool ParsedFormatBase::MatchesConversions(
+    bool allow_ignored,
+    std::initializer_list<FormatConversionCharSet> convs) const {
+  std::unordered_set<int> used;
+  auto add_if_valid_conv = [&](int pos, char c) {
+      if (static_cast<size_t>(pos) > convs.size() ||
+          !Contains(convs.begin()[pos - 1], c))
+        return false;
+      used.insert(pos);
+      return true;
+  };
+  for (const ConversionItem &item : items_) {
+    if (!item.is_conversion) continue;
+    auto &conv = item.conv;
+    if (conv.precision.is_from_arg() &&
+        !add_if_valid_conv(conv.precision.get_from_arg(), '*'))
+      return false;
+    if (conv.width.is_from_arg() &&
+        !add_if_valid_conv(conv.width.get_from_arg(), '*'))
+      return false;
+    if (!add_if_valid_conv(conv.arg_position,
+                           FormatConversionCharToChar(conv.conv)))
+      return false;
+  }
+  return used.size() == convs.size() || allow_ignored;
+}
+
+}  // namespace str_format_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
diff --git a/src/absl/strings/internal/str_format/parser.h b/src/absl/strings/internal/str_format/parser.h
new file mode 100644 (file)
index 0000000..6504dd3
--- /dev/null
@@ -0,0 +1,349 @@
+// Copyright 2020 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef ABSL_STRINGS_INTERNAL_STR_FORMAT_PARSER_H_
+#define ABSL_STRINGS_INTERNAL_STR_FORMAT_PARSER_H_
+
+#include <limits.h>
+#include <stddef.h>
+#include <stdlib.h>
+
+#include <cassert>
+#include <cstdint>
+#include <initializer_list>
+#include <iosfwd>
+#include <iterator>
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "absl/strings/internal/str_format/checker.h"
+#include "absl/strings/internal/str_format/extension.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace str_format_internal {
+
+enum class LengthMod : std::uint8_t { h, hh, l, ll, L, j, z, t, q, none };
+
+std::string LengthModToString(LengthMod v);
+
+// The analyzed properties of a single specified conversion.
+struct UnboundConversion {
+  UnboundConversion()
+      : flags() /* This is required to zero all the fields of flags. */ {
+    flags.basic = true;
+  }
+
+  class InputValue {
+   public:
+    void set_value(int value) {
+      assert(value >= 0);
+      value_ = value;
+    }
+    int value() const { return value_; }
+
+    // Marks the value as "from arg". aka the '*' format.
+    // Requires `value >= 1`.
+    // When set, is_from_arg() return true and get_from_arg() returns the
+    // original value.
+    // `value()`'s return value is unspecfied in this state.
+    void set_from_arg(int value) {
+      assert(value > 0);
+      value_ = -value - 1;
+    }
+    bool is_from_arg() const { return value_ < -1; }
+    int get_from_arg() const {
+      assert(is_from_arg());
+      return -value_ - 1;
+    }
+
+   private:
+    int value_ = -1;
+  };
+
+  // No need to initialize. It will always be set in the parser.
+  int arg_position;
+
+  InputValue width;
+  InputValue precision;
+
+  Flags flags;
+  LengthMod length_mod = LengthMod::none;
+  FormatConversionChar conv = FormatConversionCharInternal::kNone;
+};
+
+// Consume conversion spec prefix (not including '%') of [p, end) if valid.
+// Examples of valid specs would be e.g.: "s", "d", "-12.6f".
+// If valid, it returns the first character following the conversion spec,
+// and the spec part is broken down and returned in 'conv'.
+// If invalid, returns nullptr.
+const char* ConsumeUnboundConversion(const char* p, const char* end,
+                                     UnboundConversion* conv, int* next_arg);
+
+// Helper tag class for the table below.
+// It allows fast `char -> ConversionChar/LengthMod` checking and
+// conversions.
+class ConvTag {
+ public:
+  constexpr ConvTag(FormatConversionChar conversion_char)  // NOLINT
+      : tag_(static_cast<int8_t>(conversion_char)) {}
+  // We invert the length modifiers to make them negative so that we can easily
+  // test for them.
+  constexpr ConvTag(LengthMod length_mod)  // NOLINT
+      : tag_(~static_cast<std::int8_t>(length_mod)) {}
+  // Everything else is -128, which is negative to make is_conv() simpler.
+  constexpr ConvTag() : tag_(-128) {}
+
+  bool is_conv() const { return tag_ >= 0; }
+  bool is_length() const { return tag_ < 0 && tag_ != -128; }
+  FormatConversionChar as_conv() const {
+    assert(is_conv());
+    return static_cast<FormatConversionChar>(tag_);
+  }
+  LengthMod as_length() const {
+    assert(is_length());
+    return static_cast<LengthMod>(~tag_);
+  }
+
+ private:
+  std::int8_t tag_;
+};
+
+extern const ConvTag kTags[256];
+// Keep a single table for all the conversion chars and length modifiers.
+inline ConvTag GetTagForChar(char c) {
+  return kTags[static_cast<unsigned char>(c)];
+}
+
+// Parse the format string provided in 'src' and pass the identified items into
+// 'consumer'.
+// Text runs will be passed by calling
+//   Consumer::Append(string_view);
+// ConversionItems will be passed by calling
+//   Consumer::ConvertOne(UnboundConversion, string_view);
+// In the case of ConvertOne, the string_view that is passed is the
+// portion of the format string corresponding to the conversion, not including
+// the leading %. On success, it returns true. On failure, it stops and returns
+// false.
+template <typename Consumer>
+bool ParseFormatString(string_view src, Consumer consumer) {
+  int next_arg = 0;
+  const char* p = src.data();
+  const char* const end = p + src.size();
+  while (p != end) {
+    const char* percent = static_cast<const char*>(memchr(p, '%', end - p));
+    if (!percent) {
+      // We found the last substring.
+      return consumer.Append(string_view(p, end - p));
+    }
+    // We found a percent, so push the text run then process the percent.
+    if (ABSL_PREDICT_FALSE(!consumer.Append(string_view(p, percent - p)))) {
+      return false;
+    }
+    if (ABSL_PREDICT_FALSE(percent + 1 >= end)) return false;
+
+    auto tag = GetTagForChar(percent[1]);
+    if (tag.is_conv()) {
+      if (ABSL_PREDICT_FALSE(next_arg < 0)) {
+        // This indicates an error in the format string.
+        // The only way to get `next_arg < 0` here is to have a positional
+        // argument first which sets next_arg to -1 and then a non-positional
+        // argument.
+        return false;
+      }
+      p = percent + 2;
+
+      // Keep this case separate from the one below.
+      // ConvertOne is more efficient when the compiler can see that the `basic`
+      // flag is set.
+      UnboundConversion conv;
+      conv.conv = tag.as_conv();
+      conv.arg_position = ++next_arg;
+      if (ABSL_PREDICT_FALSE(
+              !consumer.ConvertOne(conv, string_view(percent + 1, 1)))) {
+        return false;
+      }
+    } else if (percent[1] != '%') {
+      UnboundConversion conv;
+      p = ConsumeUnboundConversion(percent + 1, end, &conv, &next_arg);
+      if (ABSL_PREDICT_FALSE(p == nullptr)) return false;
+      if (ABSL_PREDICT_FALSE(!consumer.ConvertOne(
+          conv, string_view(percent + 1, p - (percent + 1))))) {
+        return false;
+      }
+    } else {
+      if (ABSL_PREDICT_FALSE(!consumer.Append("%"))) return false;
+      p = percent + 2;
+      continue;
+    }
+  }
+  return true;
+}
+
+// Always returns true, or fails to compile in a constexpr context if s does not
+// point to a constexpr char array.
+constexpr bool EnsureConstexpr(string_view s) {
+  return s.empty() || s[0] == s[0];
+}
+
+class ParsedFormatBase {
+ public:
+  explicit ParsedFormatBase(
+      string_view format, bool allow_ignored,
+      std::initializer_list<FormatConversionCharSet> convs);
+
+  ParsedFormatBase(const ParsedFormatBase& other) { *this = other; }
+
+  ParsedFormatBase(ParsedFormatBase&& other) { *this = std::move(other); }
+
+  ParsedFormatBase& operator=(const ParsedFormatBase& other) {
+    if (this == &other) return *this;
+    has_error_ = other.has_error_;
+    items_ = other.items_;
+    size_t text_size = items_.empty() ? 0 : items_.back().text_end;
+    data_.reset(new char[text_size]);
+    memcpy(data_.get(), other.data_.get(), text_size);
+    return *this;
+  }
+
+  ParsedFormatBase& operator=(ParsedFormatBase&& other) {
+    if (this == &other) return *this;
+    has_error_ = other.has_error_;
+    data_ = std::move(other.data_);
+    items_ = std::move(other.items_);
+    // Reset the vector to make sure the invariants hold.
+    other.items_.clear();
+    return *this;
+  }
+
+  template <typename Consumer>
+  bool ProcessFormat(Consumer consumer) const {
+    const char* const base = data_.get();
+    string_view text(base, 0);
+    for (const auto& item : items_) {
+      const char* const end = text.data() + text.size();
+      text = string_view(end, (base + item.text_end) - end);
+      if (item.is_conversion) {
+        if (!consumer.ConvertOne(item.conv, text)) return false;
+      } else {
+        if (!consumer.Append(text)) return false;
+      }
+    }
+    return !has_error_;
+  }
+
+  bool has_error() const { return has_error_; }
+
+ private:
+  // Returns whether the conversions match and if !allow_ignored it verifies
+  // that all conversions are used by the format.
+  bool MatchesConversions(
+      bool allow_ignored,
+      std::initializer_list<FormatConversionCharSet> convs) const;
+
+  struct ParsedFormatConsumer;
+
+  struct ConversionItem {
+    bool is_conversion;
+    // Points to the past-the-end location of this element in the data_ array.
+    size_t text_end;
+    UnboundConversion conv;
+  };
+
+  bool has_error_;
+  std::unique_ptr<char[]> data_;
+  std::vector<ConversionItem> items_;
+};
+
+
+// A value type representing a preparsed format.  These can be created, copied
+// around, and reused to speed up formatting loops.
+// The user must specify through the template arguments the conversion
+// characters used in the format. This will be checked at compile time.
+//
+// This class uses Conv enum values to specify each argument.
+// This allows for more flexibility as you can specify multiple possible
+// conversion characters for each argument.
+// ParsedFormat<char...> is a simplified alias for when the user only
+// needs to specify a single conversion character for each argument.
+//
+// Example:
+//   // Extended format supports multiple characters per argument:
+//   using MyFormat = ExtendedParsedFormat<Conv::d | Conv::x>;
+//   MyFormat GetFormat(bool use_hex) {
+//     if (use_hex) return MyFormat("foo %x bar");
+//     return MyFormat("foo %d bar");
+//   }
+//   // 'format' can be used with any value that supports 'd' and 'x',
+//   // like `int`.
+//   auto format = GetFormat(use_hex);
+//   value = StringF(format, i);
+//
+// This class also supports runtime format checking with the ::New() and
+// ::NewAllowIgnored() factory functions.
+// This is the only API that allows the user to pass a runtime specified format
+// string. These factory functions will return NULL if the format does not match
+// the conversions requested by the user.
+template <FormatConversionCharSet... C>
+class ExtendedParsedFormat : public str_format_internal::ParsedFormatBase {
+ public:
+  explicit ExtendedParsedFormat(string_view format)
+#ifdef ABSL_INTERNAL_ENABLE_FORMAT_CHECKER
+      __attribute__((
+          enable_if(str_format_internal::EnsureConstexpr(format),
+                    "Format string is not constexpr."),
+          enable_if(str_format_internal::ValidFormatImpl<C...>(format),
+                    "Format specified does not match the template arguments.")))
+#endif  // ABSL_INTERNAL_ENABLE_FORMAT_CHECKER
+      : ExtendedParsedFormat(format, false) {
+  }
+
+  // ExtendedParsedFormat factory function.
+  // The user still has to specify the conversion characters, but they will not
+  // be checked at compile time. Instead, it will be checked at runtime.
+  // This delays the checking to runtime, but allows the user to pass
+  // dynamically sourced formats.
+  // It returns NULL if the format does not match the conversion characters.
+  // The user is responsible for checking the return value before using it.
+  //
+  // The 'New' variant will check that all the specified arguments are being
+  // consumed by the format and return NULL if any argument is being ignored.
+  // The 'NewAllowIgnored' variant will not verify this and will allow formats
+  // that ignore arguments.
+  static std::unique_ptr<ExtendedParsedFormat> New(string_view format) {
+    return New(format, false);
+  }
+  static std::unique_ptr<ExtendedParsedFormat> NewAllowIgnored(
+      string_view format) {
+    return New(format, true);
+  }
+
+ private:
+  static std::unique_ptr<ExtendedParsedFormat> New(string_view format,
+                                                   bool allow_ignored) {
+    std::unique_ptr<ExtendedParsedFormat> conv(
+        new ExtendedParsedFormat(format, allow_ignored));
+    if (conv->has_error()) return nullptr;
+    return conv;
+  }
+
+  ExtendedParsedFormat(string_view s, bool allow_ignored)
+      : ParsedFormatBase(s, allow_ignored, {C...}) {}
+};
+}  // namespace str_format_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#endif  // ABSL_STRINGS_INTERNAL_STR_FORMAT_PARSER_H_
diff --git a/src/absl/strings/internal/str_join_internal.h b/src/absl/strings/internal/str_join_internal.h
new file mode 100644 (file)
index 0000000..31dbf67
--- /dev/null
@@ -0,0 +1,314 @@
+//
+// Copyright 2017 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// This file declares INTERNAL parts of the Join API that are inlined/templated
+// or otherwise need to be available at compile time. The main abstractions
+// defined in this file are:
+//
+//   - A handful of default Formatters
+//   - JoinAlgorithm() overloads
+//   - JoinRange() overloads
+//   - JoinTuple()
+//
+// DO NOT INCLUDE THIS FILE DIRECTLY. Use this file by including
+// absl/strings/str_join.h
+//
+// IWYU pragma: private, include "absl/strings/str_join.h"
+
+#ifndef ABSL_STRINGS_INTERNAL_STR_JOIN_INTERNAL_H_
+#define ABSL_STRINGS_INTERNAL_STR_JOIN_INTERNAL_H_
+
+#include <cstring>
+#include <iterator>
+#include <memory>
+#include <string>
+#include <type_traits>
+#include <utility>
+
+#include "absl/strings/internal/ostringstream.h"
+#include "absl/strings/internal/resize_uninitialized.h"
+#include "absl/strings/str_cat.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace strings_internal {
+
+//
+// Formatter objects
+//
+// The following are implementation classes for standard Formatter objects. The
+// factory functions that users will call to create and use these formatters are
+// defined and documented in strings/join.h.
+//
+
+// The default formatter. Converts alpha-numeric types to strings.
+struct AlphaNumFormatterImpl {
+  // This template is needed in order to support passing in a dereferenced
+  // vector<bool>::iterator
+  template <typename T>
+  void operator()(std::string* out, const T& t) const {
+    StrAppend(out, AlphaNum(t));
+  }
+
+  void operator()(std::string* out, const AlphaNum& t) const {
+    StrAppend(out, t);
+  }
+};
+
+// A type that's used to overload the JoinAlgorithm() function (defined below)
+// for ranges that do not require additional formatting (e.g., a range of
+// strings).
+
+struct NoFormatter : public AlphaNumFormatterImpl {};
+
+// Formats types to strings using the << operator.
+class StreamFormatterImpl {
+ public:
+  // The method isn't const because it mutates state. Making it const will
+  // render StreamFormatterImpl thread-hostile.
+  template <typename T>
+  void operator()(std::string* out, const T& t) {
+    // The stream is created lazily to avoid paying the relatively high cost
+    // of its construction when joining an empty range.
+    if (strm_) {
+      strm_->clear();  // clear the bad, fail and eof bits in case they were set
+      strm_->str(out);
+    } else {
+      strm_.reset(new strings_internal::OStringStream(out));
+    }
+    *strm_ << t;
+  }
+
+ private:
+  std::unique_ptr<strings_internal::OStringStream> strm_;
+};
+
+// Formats a std::pair<>. The 'first' member is formatted using f1_ and the
+// 'second' member is formatted using f2_. sep_ is the separator.
+template <typename F1, typename F2>
+class PairFormatterImpl {
+ public:
+  PairFormatterImpl(F1 f1, absl::string_view sep, F2 f2)
+      : f1_(std::move(f1)), sep_(sep), f2_(std::move(f2)) {}
+
+  template <typename T>
+  void operator()(std::string* out, const T& p) {
+    f1_(out, p.first);
+    out->append(sep_);
+    f2_(out, p.second);
+  }
+
+  template <typename T>
+  void operator()(std::string* out, const T& p) const {
+    f1_(out, p.first);
+    out->append(sep_);
+    f2_(out, p.second);
+  }
+
+ private:
+  F1 f1_;
+  std::string sep_;
+  F2 f2_;
+};
+
+// Wraps another formatter and dereferences the argument to operator() then
+// passes the dereferenced argument to the wrapped formatter. This can be
+// useful, for example, to join a std::vector<int*>.
+template <typename Formatter>
+class DereferenceFormatterImpl {
+ public:
+  DereferenceFormatterImpl() : f_() {}
+  explicit DereferenceFormatterImpl(Formatter&& f)
+      : f_(std::forward<Formatter>(f)) {}
+
+  template <typename T>
+  void operator()(std::string* out, const T& t) {
+    f_(out, *t);
+  }
+
+  template <typename T>
+  void operator()(std::string* out, const T& t) const {
+    f_(out, *t);
+  }
+
+ private:
+  Formatter f_;
+};
+
+// DefaultFormatter<T> is a traits class that selects a default Formatter to use
+// for the given type T. The ::Type member names the Formatter to use. This is
+// used by the strings::Join() functions that do NOT take a Formatter argument,
+// in which case a default Formatter must be chosen.
+//
+// AlphaNumFormatterImpl is the default in the base template, followed by
+// specializations for other types.
+template <typename ValueType>
+struct DefaultFormatter {
+  typedef AlphaNumFormatterImpl Type;
+};
+template <>
+struct DefaultFormatter<const char*> {
+  typedef AlphaNumFormatterImpl Type;
+};
+template <>
+struct DefaultFormatter<char*> {
+  typedef AlphaNumFormatterImpl Type;
+};
+template <>
+struct DefaultFormatter<std::string> {
+  typedef NoFormatter Type;
+};
+template <>
+struct DefaultFormatter<absl::string_view> {
+  typedef NoFormatter Type;
+};
+template <typename ValueType>
+struct DefaultFormatter<ValueType*> {
+  typedef DereferenceFormatterImpl<typename DefaultFormatter<ValueType>::Type>
+      Type;
+};
+
+template <typename ValueType>
+struct DefaultFormatter<std::unique_ptr<ValueType>>
+    : public DefaultFormatter<ValueType*> {};
+
+//
+// JoinAlgorithm() functions
+//
+
+// The main joining algorithm. This simply joins the elements in the given
+// iterator range, each separated by the given separator, into an output string,
+// and formats each element using the provided Formatter object.
+template <typename Iterator, typename Formatter>
+std::string JoinAlgorithm(Iterator start, Iterator end, absl::string_view s,
+                          Formatter&& f) {
+  std::string result;
+  absl::string_view sep("");
+  for (Iterator it = start; it != end; ++it) {
+    result.append(sep.data(), sep.size());
+    f(&result, *it);
+    sep = s;
+  }
+  return result;
+}
+
+// A joining algorithm that's optimized for a forward iterator range of
+// string-like objects that do not need any additional formatting. This is to
+// optimize the common case of joining, say, a std::vector<string> or a
+// std::vector<absl::string_view>.
+//
+// This is an overload of the previous JoinAlgorithm() function. Here the
+// Formatter argument is of type NoFormatter. Since NoFormatter is an internal
+// type, this overload is only invoked when strings::Join() is called with a
+// range of string-like objects (e.g., std::string, absl::string_view), and an
+// explicit Formatter argument was NOT specified.
+//
+// The optimization is that the needed space will be reserved in the output
+// string to avoid the need to resize while appending. To do this, the iterator
+// range will be traversed twice: once to calculate the total needed size, and
+// then again to copy the elements and delimiters to the output string.
+template <typename Iterator,
+          typename = typename std::enable_if<std::is_convertible<
+              typename std::iterator_traits<Iterator>::iterator_category,
+              std::forward_iterator_tag>::value>::type>
+std::string JoinAlgorithm(Iterator start, Iterator end, absl::string_view s,
+                          NoFormatter) {
+  std::string result;
+  if (start != end) {
+    // Sums size
+    size_t result_size = start->size();
+    for (Iterator it = start; ++it != end;) {
+      result_size += s.size();
+      result_size += it->size();
+    }
+
+    if (result_size > 0) {
+      STLStringResizeUninitialized(&result, result_size);
+
+      // Joins strings
+      char* result_buf = &*result.begin();
+      memcpy(result_buf, start->data(), start->size());
+      result_buf += start->size();
+      for (Iterator it = start; ++it != end;) {
+        memcpy(result_buf, s.data(), s.size());
+        result_buf += s.size();
+        memcpy(result_buf, it->data(), it->size());
+        result_buf += it->size();
+      }
+    }
+  }
+
+  return result;
+}
+
+// JoinTupleLoop implements a loop over the elements of a std::tuple, which
+// are heterogeneous. The primary template matches the tuple interior case. It
+// continues the iteration after appending a separator (for nonzero indices)
+// and formatting an element of the tuple. The specialization for the I=N case
+// matches the end-of-tuple, and terminates the iteration.
+template <size_t I, size_t N>
+struct JoinTupleLoop {
+  template <typename Tup, typename Formatter>
+  void operator()(std::string* out, const Tup& tup, absl::string_view sep,
+                  Formatter&& fmt) {
+    if (I > 0) out->append(sep.data(), sep.size());
+    fmt(out, std::get<I>(tup));
+    JoinTupleLoop<I + 1, N>()(out, tup, sep, fmt);
+  }
+};
+template <size_t N>
+struct JoinTupleLoop<N, N> {
+  template <typename Tup, typename Formatter>
+  void operator()(std::string*, const Tup&, absl::string_view, Formatter&&) {}
+};
+
+template <typename... T, typename Formatter>
+std::string JoinAlgorithm(const std::tuple<T...>& tup, absl::string_view sep,
+                          Formatter&& fmt) {
+  std::string result;
+  JoinTupleLoop<0, sizeof...(T)>()(&result, tup, sep, fmt);
+  return result;
+}
+
+template <typename Iterator>
+std::string JoinRange(Iterator first, Iterator last,
+                      absl::string_view separator) {
+  // No formatter was explicitly given, so a default must be chosen.
+  typedef typename std::iterator_traits<Iterator>::value_type ValueType;
+  typedef typename DefaultFormatter<ValueType>::Type Formatter;
+  return JoinAlgorithm(first, last, separator, Formatter());
+}
+
+template <typename Range, typename Formatter>
+std::string JoinRange(const Range& range, absl::string_view separator,
+                      Formatter&& fmt) {
+  using std::begin;
+  using std::end;
+  return JoinAlgorithm(begin(range), end(range), separator, fmt);
+}
+
+template <typename Range>
+std::string JoinRange(const Range& range, absl::string_view separator) {
+  using std::begin;
+  using std::end;
+  return JoinRange(begin(range), end(range), separator);
+}
+
+}  // namespace strings_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#endif  // ABSL_STRINGS_INTERNAL_STR_JOIN_INTERNAL_H_
diff --git a/src/absl/strings/internal/str_split_internal.h b/src/absl/strings/internal/str_split_internal.h
new file mode 100644 (file)
index 0000000..a2f41c1
--- /dev/null
@@ -0,0 +1,430 @@
+// Copyright 2017 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// This file declares INTERNAL parts of the Split API that are inline/templated
+// or otherwise need to be available at compile time. The main abstractions
+// defined in here are
+//
+//   - ConvertibleToStringView
+//   - SplitIterator<>
+//   - Splitter<>
+//
+// DO NOT INCLUDE THIS FILE DIRECTLY. Use this file by including
+// absl/strings/str_split.h.
+//
+// IWYU pragma: private, include "absl/strings/str_split.h"
+
+#ifndef ABSL_STRINGS_INTERNAL_STR_SPLIT_INTERNAL_H_
+#define ABSL_STRINGS_INTERNAL_STR_SPLIT_INTERNAL_H_
+
+#include <array>
+#include <initializer_list>
+#include <iterator>
+#include <map>
+#include <type_traits>
+#include <utility>
+#include <vector>
+
+#include "absl/base/macros.h"
+#include "absl/base/port.h"
+#include "absl/meta/type_traits.h"
+#include "absl/strings/string_view.h"
+
+#ifdef _GLIBCXX_DEBUG
+#include "absl/strings/internal/stl_type_traits.h"
+#endif  // _GLIBCXX_DEBUG
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace strings_internal {
+
+// This class is implicitly constructible from everything that absl::string_view
+// is implicitly constructible from, except for rvalue strings.  This means it
+// can be used as a function parameter in places where passing a temporary
+// string might cause memory lifetime issues.
+class ConvertibleToStringView {
+ public:
+  ConvertibleToStringView(const char* s)  // NOLINT(runtime/explicit)
+      : value_(s) {}
+  ConvertibleToStringView(char* s) : value_(s) {}  // NOLINT(runtime/explicit)
+  ConvertibleToStringView(absl::string_view s)     // NOLINT(runtime/explicit)
+      : value_(s) {}
+  ConvertibleToStringView(const std::string& s)  // NOLINT(runtime/explicit)
+      : value_(s) {}
+
+  // Matches rvalue strings and moves their data to a member.
+  ConvertibleToStringView(std::string&& s) = delete;
+  ConvertibleToStringView(const std::string&& s) = delete;
+
+  absl::string_view value() const { return value_; }
+
+ private:
+  absl::string_view value_;
+};
+
+// An iterator that enumerates the parts of a string from a Splitter. The text
+// to be split, the Delimiter, and the Predicate are all taken from the given
+// Splitter object. Iterators may only be compared if they refer to the same
+// Splitter instance.
+//
+// This class is NOT part of the public splitting API.
+template <typename Splitter>
+class SplitIterator {
+ public:
+  using iterator_category = std::input_iterator_tag;
+  using value_type = absl::string_view;
+  using difference_type = ptrdiff_t;
+  using pointer = const value_type*;
+  using reference = const value_type&;
+
+  enum State { kInitState, kLastState, kEndState };
+  SplitIterator(State state, const Splitter* splitter)
+      : pos_(0),
+        state_(state),
+        splitter_(splitter),
+        delimiter_(splitter->delimiter()),
+        predicate_(splitter->predicate()) {
+    // Hack to maintain backward compatibility. This one block makes it so an
+    // empty absl::string_view whose .data() happens to be nullptr behaves
+    // *differently* from an otherwise empty absl::string_view whose .data() is
+    // not nullptr. This is an undesirable difference in general, but this
+    // behavior is maintained to avoid breaking existing code that happens to
+    // depend on this old behavior/bug. Perhaps it will be fixed one day. The
+    // difference in behavior is as follows:
+    //   Split(absl::string_view(""), '-');  // {""}
+    //   Split(absl::string_view(), '-');    // {}
+    if (splitter_->text().data() == nullptr) {
+      state_ = kEndState;
+      pos_ = splitter_->text().size();
+      return;
+    }
+
+    if (state_ == kEndState) {
+      pos_ = splitter_->text().size();
+    } else {
+      ++(*this);
+    }
+  }
+
+  bool at_end() const { return state_ == kEndState; }
+
+  reference operator*() const { return curr_; }
+  pointer operator->() const { return &curr_; }
+
+  SplitIterator& operator++() {
+    do {
+      if (state_ == kLastState) {
+        state_ = kEndState;
+        return *this;
+      }
+      const absl::string_view text = splitter_->text();
+      const absl::string_view d = delimiter_.Find(text, pos_);
+      if (d.data() == text.data() + text.size()) state_ = kLastState;
+      curr_ = text.substr(pos_, d.data() - (text.data() + pos_));
+      pos_ += curr_.size() + d.size();
+    } while (!predicate_(curr_));
+    return *this;
+  }
+
+  SplitIterator operator++(int) {
+    SplitIterator old(*this);
+    ++(*this);
+    return old;
+  }
+
+  friend bool operator==(const SplitIterator& a, const SplitIterator& b) {
+    return a.state_ == b.state_ && a.pos_ == b.pos_;
+  }
+
+  friend bool operator!=(const SplitIterator& a, const SplitIterator& b) {
+    return !(a == b);
+  }
+
+ private:
+  size_t pos_;
+  State state_;
+  absl::string_view curr_;
+  const Splitter* splitter_;
+  typename Splitter::DelimiterType delimiter_;
+  typename Splitter::PredicateType predicate_;
+};
+
+// HasMappedType<T>::value is true iff there exists a type T::mapped_type.
+template <typename T, typename = void>
+struct HasMappedType : std::false_type {};
+template <typename T>
+struct HasMappedType<T, absl::void_t<typename T::mapped_type>>
+    : std::true_type {};
+
+// HasValueType<T>::value is true iff there exists a type T::value_type.
+template <typename T, typename = void>
+struct HasValueType : std::false_type {};
+template <typename T>
+struct HasValueType<T, absl::void_t<typename T::value_type>> : std::true_type {
+};
+
+// HasConstIterator<T>::value is true iff there exists a type T::const_iterator.
+template <typename T, typename = void>
+struct HasConstIterator : std::false_type {};
+template <typename T>
+struct HasConstIterator<T, absl::void_t<typename T::const_iterator>>
+    : std::true_type {};
+
+// IsInitializerList<T>::value is true iff T is an std::initializer_list. More
+// details below in Splitter<> where this is used.
+std::false_type IsInitializerListDispatch(...);  // default: No
+template <typename T>
+std::true_type IsInitializerListDispatch(std::initializer_list<T>*);
+template <typename T>
+struct IsInitializerList
+    : decltype(IsInitializerListDispatch(static_cast<T*>(nullptr))) {};
+
+// A SplitterIsConvertibleTo<C>::type alias exists iff the specified condition
+// is true for type 'C'.
+//
+// Restricts conversion to container-like types (by testing for the presence of
+// a const_iterator member type) and also to disable conversion to an
+// std::initializer_list (which also has a const_iterator). Otherwise, code
+// compiled in C++11 will get an error due to ambiguous conversion paths (in
+// C++11 std::vector<T>::operator= is overloaded to take either a std::vector<T>
+// or an std::initializer_list<T>).
+
+template <typename C, bool has_value_type, bool has_mapped_type>
+struct SplitterIsConvertibleToImpl : std::false_type {};
+
+template <typename C>
+struct SplitterIsConvertibleToImpl<C, true, false>
+    : std::is_constructible<typename C::value_type, absl::string_view> {};
+
+template <typename C>
+struct SplitterIsConvertibleToImpl<C, true, true>
+    : absl::conjunction<
+          std::is_constructible<typename C::key_type, absl::string_view>,
+          std::is_constructible<typename C::mapped_type, absl::string_view>> {};
+
+template <typename C>
+struct SplitterIsConvertibleTo
+    : SplitterIsConvertibleToImpl<
+          C,
+#ifdef _GLIBCXX_DEBUG
+          !IsStrictlyBaseOfAndConvertibleToSTLContainer<C>::value &&
+#endif  // _GLIBCXX_DEBUG
+              !IsInitializerList<
+                  typename std::remove_reference<C>::type>::value &&
+              HasValueType<C>::value && HasConstIterator<C>::value,
+          HasMappedType<C>::value> {
+};
+
+// This class implements the range that is returned by absl::StrSplit(). This
+// class has templated conversion operators that allow it to be implicitly
+// converted to a variety of types that the caller may have specified on the
+// left-hand side of an assignment.
+//
+// The main interface for interacting with this class is through its implicit
+// conversion operators. However, this class may also be used like a container
+// in that it has .begin() and .end() member functions. It may also be used
+// within a range-for loop.
+//
+// Output containers can be collections of any type that is constructible from
+// an absl::string_view.
+//
+// An Predicate functor may be supplied. This predicate will be used to filter
+// the split strings: only strings for which the predicate returns true will be
+// kept. A Predicate object is any unary functor that takes an absl::string_view
+// and returns bool.
+//
+// The StringType parameter can be either string_view or string, depending on
+// whether the Splitter refers to a string stored elsewhere, or if the string
+// resides inside the Splitter itself.
+template <typename Delimiter, typename Predicate, typename StringType>
+class Splitter {
+ public:
+  using DelimiterType = Delimiter;
+  using PredicateType = Predicate;
+  using const_iterator = strings_internal::SplitIterator<Splitter>;
+  using value_type = typename std::iterator_traits<const_iterator>::value_type;
+
+  Splitter(StringType input_text, Delimiter d, Predicate p)
+      : text_(std::move(input_text)),
+        delimiter_(std::move(d)),
+        predicate_(std::move(p)) {}
+
+  absl::string_view text() const { return text_; }
+  const Delimiter& delimiter() const { return delimiter_; }
+  const Predicate& predicate() const { return predicate_; }
+
+  // Range functions that iterate the split substrings as absl::string_view
+  // objects. These methods enable a Splitter to be used in a range-based for
+  // loop.
+  const_iterator begin() const { return {const_iterator::kInitState, this}; }
+  const_iterator end() const { return {const_iterator::kEndState, this}; }
+
+  // An implicit conversion operator that is restricted to only those containers
+  // that the splitter is convertible to.
+  template <typename Container,
+            typename = typename std::enable_if<
+                SplitterIsConvertibleTo<Container>::value>::type>
+  operator Container() const {  // NOLINT(runtime/explicit)
+    return ConvertToContainer<Container, typename Container::value_type,
+                              HasMappedType<Container>::value>()(*this);
+  }
+
+  // Returns a pair with its .first and .second members set to the first two
+  // strings returned by the begin() iterator. Either/both of .first and .second
+  // will be constructed with empty strings if the iterator doesn't have a
+  // corresponding value.
+  template <typename First, typename Second>
+  operator std::pair<First, Second>() const {  // NOLINT(runtime/explicit)
+    absl::string_view first, second;
+    auto it = begin();
+    if (it != end()) {
+      first = *it;
+      if (++it != end()) {
+        second = *it;
+      }
+    }
+    return {First(first), Second(second)};
+  }
+
+ private:
+  // ConvertToContainer is a functor converting a Splitter to the requested
+  // Container of ValueType. It is specialized below to optimize splitting to
+  // certain combinations of Container and ValueType.
+  //
+  // This base template handles the generic case of storing the split results in
+  // the requested non-map-like container and converting the split substrings to
+  // the requested type.
+  template <typename Container, typename ValueType, bool is_map = false>
+  struct ConvertToContainer {
+    Container operator()(const Splitter& splitter) const {
+      Container c;
+      auto it = std::inserter(c, c.end());
+      for (const auto& sp : splitter) {
+        *it++ = ValueType(sp);
+      }
+      return c;
+    }
+  };
+
+  // Partial specialization for a std::vector<absl::string_view>.
+  //
+  // Optimized for the common case of splitting to a
+  // std::vector<absl::string_view>. In this case we first split the results to
+  // a small array of absl::string_view on the stack, to reduce reallocations.
+  template <typename A>
+  struct ConvertToContainer<std::vector<absl::string_view, A>,
+                            absl::string_view, false> {
+    std::vector<absl::string_view, A> operator()(
+        const Splitter& splitter) const {
+      struct raw_view {
+        const char* data;
+        size_t size;
+        operator absl::string_view() const {  // NOLINT(runtime/explicit)
+          return {data, size};
+        }
+      };
+      std::vector<absl::string_view, A> v;
+      std::array<raw_view, 16> ar;
+      for (auto it = splitter.begin(); !it.at_end();) {
+        size_t index = 0;
+        do {
+          ar[index].data = it->data();
+          ar[index].size = it->size();
+          ++it;
+        } while (++index != ar.size() && !it.at_end());
+        v.insert(v.end(), ar.begin(), ar.begin() + index);
+      }
+      return v;
+    }
+  };
+
+  // Partial specialization for a std::vector<std::string>.
+  //
+  // Optimized for the common case of splitting to a std::vector<std::string>.
+  // In this case we first split the results to a std::vector<absl::string_view>
+  // so the returned std::vector<std::string> can have space reserved to avoid
+  // std::string moves.
+  template <typename A>
+  struct ConvertToContainer<std::vector<std::string, A>, std::string, false> {
+    std::vector<std::string, A> operator()(const Splitter& splitter) const {
+      const std::vector<absl::string_view> v = splitter;
+      return std::vector<std::string, A>(v.begin(), v.end());
+    }
+  };
+
+  // Partial specialization for containers of pairs (e.g., maps).
+  //
+  // The algorithm is to insert a new pair into the map for each even-numbered
+  // item, with the even-numbered item as the key with a default-constructed
+  // value. Each odd-numbered item will then be assigned to the last pair's
+  // value.
+  template <typename Container, typename First, typename Second>
+  struct ConvertToContainer<Container, std::pair<const First, Second>, true> {
+    Container operator()(const Splitter& splitter) const {
+      Container m;
+      typename Container::iterator it;
+      bool insert = true;
+      for (const auto& sp : splitter) {
+        if (insert) {
+          it = Inserter<Container>::Insert(&m, First(sp), Second());
+        } else {
+          it->second = Second(sp);
+        }
+        insert = !insert;
+      }
+      return m;
+    }
+
+    // Inserts the key and value into the given map, returning an iterator to
+    // the inserted item. Specialized for std::map and std::multimap to use
+    // emplace() and adapt emplace()'s return value.
+    template <typename Map>
+    struct Inserter {
+      using M = Map;
+      template <typename... Args>
+      static typename M::iterator Insert(M* m, Args&&... args) {
+        return m->insert(std::make_pair(std::forward<Args>(args)...)).first;
+      }
+    };
+
+    template <typename... Ts>
+    struct Inserter<std::map<Ts...>> {
+      using M = std::map<Ts...>;
+      template <typename... Args>
+      static typename M::iterator Insert(M* m, Args&&... args) {
+        return m->emplace(std::make_pair(std::forward<Args>(args)...)).first;
+      }
+    };
+
+    template <typename... Ts>
+    struct Inserter<std::multimap<Ts...>> {
+      using M = std::multimap<Ts...>;
+      template <typename... Args>
+      static typename M::iterator Insert(M* m, Args&&... args) {
+        return m->emplace(std::make_pair(std::forward<Args>(args)...));
+      }
+    };
+  };
+
+  StringType text_;
+  Delimiter delimiter_;
+  Predicate predicate_;
+};
+
+}  // namespace strings_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#endif  // ABSL_STRINGS_INTERNAL_STR_SPLIT_INTERNAL_H_
diff --git a/src/absl/strings/internal/string_constant.h b/src/absl/strings/internal/string_constant.h
new file mode 100644 (file)
index 0000000..a11336b
--- /dev/null
@@ -0,0 +1,64 @@
+// Copyright 2020 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef ABSL_STRINGS_INTERNAL_STRING_CONSTANT_H_
+#define ABSL_STRINGS_INTERNAL_STRING_CONSTANT_H_
+
+#include "absl/meta/type_traits.h"
+#include "absl/strings/string_view.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace strings_internal {
+
+// StringConstant<T> represents a compile time string constant.
+// It can be accessed via its `absl::string_view value` static member.
+// It is guaranteed that the `string_view` returned has constant `.data()`,
+// constant `.size()` and constant `value[i]` for all `0 <= i < .size()`
+//
+// The `T` is an opaque type. It is guaranteed that different string constants
+// will have different values of `T`. This allows users to associate the string
+// constant with other static state at compile time.
+//
+// Instances should be made using the `MakeStringConstant()` factory function
+// below.
+template <typename T>
+struct StringConstant {
+  static constexpr absl::string_view value = T{}();
+  constexpr absl::string_view operator()() const { return value; }
+
+  // Check to be sure `view` points to constant data.
+  // Otherwise, it can't be constant evaluated.
+  static_assert(value.empty() || 2 * value[0] != 1,
+                "The input string_view must point to constant data.");
+};
+
+template <typename T>
+constexpr absl::string_view StringConstant<T>::value;  // NOLINT
+
+// Factory function for `StringConstant` instances.
+// It supports callables that have a constexpr default constructor and a
+// constexpr operator().
+// It must return an `absl::string_view` or `const char*` pointing to constant
+// data. This is validated at compile time.
+template <typename T>
+constexpr StringConstant<T> MakeStringConstant(T) {
+  return {};
+}
+
+}  // namespace strings_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#endif  // ABSL_STRINGS_INTERNAL_STRING_CONSTANT_H_
diff --git a/src/absl/strings/internal/utf8.cc b/src/absl/strings/internal/utf8.cc
new file mode 100644 (file)
index 0000000..8fd8edc
--- /dev/null
@@ -0,0 +1,53 @@
+// Copyright 2017 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// UTF8 utilities, implemented to reduce dependencies.
+
+#include "absl/strings/internal/utf8.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace strings_internal {
+
+size_t EncodeUTF8Char(char *buffer, char32_t utf8_char) {
+  if (utf8_char <= 0x7F) {
+    *buffer = static_cast<char>(utf8_char);
+    return 1;
+  } else if (utf8_char <= 0x7FF) {
+    buffer[1] = 0x80 | (utf8_char & 0x3F);
+    utf8_char >>= 6;
+    buffer[0] = 0xC0 | utf8_char;
+    return 2;
+  } else if (utf8_char <= 0xFFFF) {
+    buffer[2] = 0x80 | (utf8_char & 0x3F);
+    utf8_char >>= 6;
+    buffer[1] = 0x80 | (utf8_char & 0x3F);
+    utf8_char >>= 6;
+    buffer[0] = 0xE0 | utf8_char;
+    return 3;
+  } else {
+    buffer[3] = 0x80 | (utf8_char & 0x3F);
+    utf8_char >>= 6;
+    buffer[2] = 0x80 | (utf8_char & 0x3F);
+    utf8_char >>= 6;
+    buffer[1] = 0x80 | (utf8_char & 0x3F);
+    utf8_char >>= 6;
+    buffer[0] = 0xF0 | utf8_char;
+    return 4;
+  }
+}
+
+}  // namespace strings_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
diff --git a/src/absl/strings/internal/utf8.h b/src/absl/strings/internal/utf8.h
new file mode 100644 (file)
index 0000000..32fb109
--- /dev/null
@@ -0,0 +1,50 @@
+// Copyright 2017 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// UTF8 utilities, implemented to reduce dependencies.
+
+#ifndef ABSL_STRINGS_INTERNAL_UTF8_H_
+#define ABSL_STRINGS_INTERNAL_UTF8_H_
+
+#include <cstddef>
+#include <cstdint>
+
+#include "absl/base/config.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace strings_internal {
+
+// For Unicode code points 0 through 0x10FFFF, EncodeUTF8Char writes
+// out the UTF-8 encoding into buffer, and returns the number of chars
+// it wrote.
+//
+// As described in https://tools.ietf.org/html/rfc3629#section-3 , the encodings
+// are:
+//    00 -     7F : 0xxxxxxx
+//    80 -    7FF : 110xxxxx 10xxxxxx
+//   800 -   FFFF : 1110xxxx 10xxxxxx 10xxxxxx
+// 10000 - 10FFFF : 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
+//
+// Values greater than 0x10FFFF are not supported and may or may not write
+// characters into buffer, however never will more than kMaxEncodedUTF8Size
+// bytes be written, regardless of the value of utf8_char.
+enum { kMaxEncodedUTF8Size = 4 };
+size_t EncodeUTF8Char(char *buffer, char32_t utf8_char);
+
+}  // namespace strings_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#endif  // ABSL_STRINGS_INTERNAL_UTF8_H_
diff --git a/src/absl/strings/match.cc b/src/absl/strings/match.cc
new file mode 100644 (file)
index 0000000..2d67250
--- /dev/null
@@ -0,0 +1,43 @@
+// Copyright 2017 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "absl/strings/match.h"
+
+#include "absl/strings/internal/memutil.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+
+bool EqualsIgnoreCase(absl::string_view piece1,
+                      absl::string_view piece2) noexcept {
+  return (piece1.size() == piece2.size() &&
+          0 == absl::strings_internal::memcasecmp(piece1.data(), piece2.data(),
+                                                  piece1.size()));
+  // memcasecmp uses absl::ascii_tolower().
+}
+
+bool StartsWithIgnoreCase(absl::string_view text,
+                          absl::string_view prefix) noexcept {
+  return (text.size() >= prefix.size()) &&
+         EqualsIgnoreCase(text.substr(0, prefix.size()), prefix);
+}
+
+bool EndsWithIgnoreCase(absl::string_view text,
+                        absl::string_view suffix) noexcept {
+  return (text.size() >= suffix.size()) &&
+         EqualsIgnoreCase(text.substr(text.size() - suffix.size()), suffix);
+}
+
+ABSL_NAMESPACE_END
+}  // namespace absl
diff --git a/src/absl/strings/match.h b/src/absl/strings/match.h
new file mode 100644 (file)
index 0000000..038cbb3
--- /dev/null
@@ -0,0 +1,100 @@
+//
+// Copyright 2017 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// -----------------------------------------------------------------------------
+// File: match.h
+// -----------------------------------------------------------------------------
+//
+// This file contains simple utilities for performing string matching checks.
+// All of these function parameters are specified as `absl::string_view`,
+// meaning that these functions can accept `std::string`, `absl::string_view` or
+// NUL-terminated C-style strings.
+//
+// Examples:
+//   std::string s = "foo";
+//   absl::string_view sv = "f";
+//   assert(absl::StrContains(s, sv));
+//
+// Note: The order of parameters in these functions is designed to mimic the
+// order an equivalent member function would exhibit;
+// e.g. `s.Contains(x)` ==> `absl::StrContains(s, x).
+#ifndef ABSL_STRINGS_MATCH_H_
+#define ABSL_STRINGS_MATCH_H_
+
+#include <cstring>
+
+#include "absl/strings/string_view.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+
+// StrContains()
+//
+// Returns whether a given string `haystack` contains the substring `needle`.
+inline bool StrContains(absl::string_view haystack,
+                        absl::string_view needle) noexcept {
+  return haystack.find(needle, 0) != haystack.npos;
+}
+
+inline bool StrContains(absl::string_view haystack, char needle) noexcept {
+  return haystack.find(needle) != haystack.npos;
+}
+
+// StartsWith()
+//
+// Returns whether a given string `text` begins with `prefix`.
+inline bool StartsWith(absl::string_view text,
+                       absl::string_view prefix) noexcept {
+  return prefix.empty() ||
+         (text.size() >= prefix.size() &&
+          memcmp(text.data(), prefix.data(), prefix.size()) == 0);
+}
+
+// EndsWith()
+//
+// Returns whether a given string `text` ends with `suffix`.
+inline bool EndsWith(absl::string_view text,
+                     absl::string_view suffix) noexcept {
+  return suffix.empty() ||
+         (text.size() >= suffix.size() &&
+          memcmp(text.data() + (text.size() - suffix.size()), suffix.data(),
+                 suffix.size()) == 0);
+}
+
+// EqualsIgnoreCase()
+//
+// Returns whether given ASCII strings `piece1` and `piece2` are equal, ignoring
+// case in the comparison.
+bool EqualsIgnoreCase(absl::string_view piece1,
+                      absl::string_view piece2) noexcept;
+
+// StartsWithIgnoreCase()
+//
+// Returns whether a given ASCII string `text` starts with `prefix`,
+// ignoring case in the comparison.
+bool StartsWithIgnoreCase(absl::string_view text,
+                          absl::string_view prefix) noexcept;
+
+// EndsWithIgnoreCase()
+//
+// Returns whether a given ASCII string `text` ends with `suffix`, ignoring
+// case in the comparison.
+bool EndsWithIgnoreCase(absl::string_view text,
+                        absl::string_view suffix) noexcept;
+
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#endif  // ABSL_STRINGS_MATCH_H_
diff --git a/src/absl/strings/numbers.cc b/src/absl/strings/numbers.cc
new file mode 100644 (file)
index 0000000..966d94b
--- /dev/null
@@ -0,0 +1,1093 @@
+// Copyright 2017 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// This file contains string processing functions related to
+// numeric values.
+
+#include "absl/strings/numbers.h"
+
+#include <algorithm>
+#include <cassert>
+#include <cfloat>  // for DBL_DIG and FLT_DIG
+#include <cmath>   // for HUGE_VAL
+#include <cstdint>
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
+#include <iterator>
+#include <limits>
+#include <memory>
+#include <utility>
+
+#include "absl/base/attributes.h"
+#include "absl/base/internal/raw_logging.h"
+#include "absl/numeric/bits.h"
+#include "absl/strings/ascii.h"
+#include "absl/strings/charconv.h"
+#include "absl/strings/escaping.h"
+#include "absl/strings/internal/memutil.h"
+#include "absl/strings/match.h"
+#include "absl/strings/str_cat.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+
+bool SimpleAtof(absl::string_view str, float* out) {
+  *out = 0.0;
+  str = StripAsciiWhitespace(str);
+  // std::from_chars doesn't accept an initial +, but SimpleAtof does, so if one
+  // is present, skip it, while avoiding accepting "+-0" as valid.
+  if (!str.empty() && str[0] == '+') {
+    str.remove_prefix(1);
+    if (!str.empty() && str[0] == '-') {
+      return false;
+    }
+  }
+  auto result = absl::from_chars(str.data(), str.data() + str.size(), *out);
+  if (result.ec == std::errc::invalid_argument) {
+    return false;
+  }
+  if (result.ptr != str.data() + str.size()) {
+    // not all non-whitespace characters consumed
+    return false;
+  }
+  // from_chars() with DR 3081's current wording will return max() on
+  // overflow.  SimpleAtof returns infinity instead.
+  if (result.ec == std::errc::result_out_of_range) {
+    if (*out > 1.0) {
+      *out = std::numeric_limits<float>::infinity();
+    } else if (*out < -1.0) {
+      *out = -std::numeric_limits<float>::infinity();
+    }
+  }
+  return true;
+}
+
+bool SimpleAtod(absl::string_view str, double* out) {
+  *out = 0.0;
+  str = StripAsciiWhitespace(str);
+  // std::from_chars doesn't accept an initial +, but SimpleAtod does, so if one
+  // is present, skip it, while avoiding accepting "+-0" as valid.
+  if (!str.empty() && str[0] == '+') {
+    str.remove_prefix(1);
+    if (!str.empty() && str[0] == '-') {
+      return false;
+    }
+  }
+  auto result = absl::from_chars(str.data(), str.data() + str.size(), *out);
+  if (result.ec == std::errc::invalid_argument) {
+    return false;
+  }
+  if (result.ptr != str.data() + str.size()) {
+    // not all non-whitespace characters consumed
+    return false;
+  }
+  // from_chars() with DR 3081's current wording will return max() on
+  // overflow.  SimpleAtod returns infinity instead.
+  if (result.ec == std::errc::result_out_of_range) {
+    if (*out > 1.0) {
+      *out = std::numeric_limits<double>::infinity();
+    } else if (*out < -1.0) {
+      *out = -std::numeric_limits<double>::infinity();
+    }
+  }
+  return true;
+}
+
+bool SimpleAtob(absl::string_view str, bool* out) {
+  ABSL_RAW_CHECK(out != nullptr, "Output pointer must not be nullptr.");
+  if (EqualsIgnoreCase(str, "true") || EqualsIgnoreCase(str, "t") ||
+      EqualsIgnoreCase(str, "yes") || EqualsIgnoreCase(str, "y") ||
+      EqualsIgnoreCase(str, "1")) {
+    *out = true;
+    return true;
+  }
+  if (EqualsIgnoreCase(str, "false") || EqualsIgnoreCase(str, "f") ||
+      EqualsIgnoreCase(str, "no") || EqualsIgnoreCase(str, "n") ||
+      EqualsIgnoreCase(str, "0")) {
+    *out = false;
+    return true;
+  }
+  return false;
+}
+
+// ----------------------------------------------------------------------
+// FastIntToBuffer() overloads
+//
+// Like the Fast*ToBuffer() functions above, these are intended for speed.
+// Unlike the Fast*ToBuffer() functions, however, these functions write
+// their output to the beginning of the buffer.  The caller is responsible
+// for ensuring that the buffer has enough space to hold the output.
+//
+// Returns a pointer to the end of the string (i.e. the null character
+// terminating the string).
+// ----------------------------------------------------------------------
+
+namespace {
+
+// Used to optimize printing a decimal number's final digit.
+const char one_ASCII_final_digits[10][2] {
+  {'0', 0}, {'1', 0}, {'2', 0}, {'3', 0}, {'4', 0},
+  {'5', 0}, {'6', 0}, {'7', 0}, {'8', 0}, {'9', 0},
+};
+
+}  // namespace
+
+char* numbers_internal::FastIntToBuffer(uint32_t i, char* buffer) {
+  uint32_t digits;
+  // The idea of this implementation is to trim the number of divides to as few
+  // as possible, and also reducing memory stores and branches, by going in
+  // steps of two digits at a time rather than one whenever possible.
+  // The huge-number case is first, in the hopes that the compiler will output
+  // that case in one branch-free block of code, and only output conditional
+  // branches into it from below.
+  if (i >= 1000000000) {     // >= 1,000,000,000
+    digits = i / 100000000;  //      100,000,000
+    i -= digits * 100000000;
+    PutTwoDigits(digits, buffer);
+    buffer += 2;
+  lt100_000_000:
+    digits = i / 1000000;  // 1,000,000
+    i -= digits * 1000000;
+    PutTwoDigits(digits, buffer);
+    buffer += 2;
+  lt1_000_000:
+    digits = i / 10000;  // 10,000
+    i -= digits * 10000;
+    PutTwoDigits(digits, buffer);
+    buffer += 2;
+  lt10_000:
+    digits = i / 100;
+    i -= digits * 100;
+    PutTwoDigits(digits, buffer);
+    buffer += 2;
+ lt100:
+    digits = i;
+    PutTwoDigits(digits, buffer);
+    buffer += 2;
+    *buffer = 0;
+    return buffer;
+  }
+
+  if (i < 100) {
+    digits = i;
+    if (i >= 10) goto lt100;
+    memcpy(buffer, one_ASCII_final_digits[i], 2);
+    return buffer + 1;
+  }
+  if (i < 10000) {  //    10,000
+    if (i >= 1000) goto lt10_000;
+    digits = i / 100;
+    i -= digits * 100;
+    *buffer++ = '0' + digits;
+    goto lt100;
+  }
+  if (i < 1000000) {  //    1,000,000
+    if (i >= 100000) goto lt1_000_000;
+    digits = i / 10000;  //    10,000
+    i -= digits * 10000;
+    *buffer++ = '0' + digits;
+    goto lt10_000;
+  }
+  if (i < 100000000) {  //    100,000,000
+    if (i >= 10000000) goto lt100_000_000;
+    digits = i / 1000000;  //   1,000,000
+    i -= digits * 1000000;
+    *buffer++ = '0' + digits;
+    goto lt1_000_000;
+  }
+  // we already know that i < 1,000,000,000
+  digits = i / 100000000;  //   100,000,000
+  i -= digits * 100000000;
+  *buffer++ = '0' + digits;
+  goto lt100_000_000;
+}
+
+char* numbers_internal::FastIntToBuffer(int32_t i, char* buffer) {
+  uint32_t u = i;
+  if (i < 0) {
+    *buffer++ = '-';
+    // We need to do the negation in modular (i.e., "unsigned")
+    // arithmetic; MSVC++ apprently warns for plain "-u", so
+    // we write the equivalent expression "0 - u" instead.
+    u = 0 - u;
+  }
+  return numbers_internal::FastIntToBuffer(u, buffer);
+}
+
+char* numbers_internal::FastIntToBuffer(uint64_t i, char* buffer) {
+  uint32_t u32 = static_cast<uint32_t>(i);
+  if (u32 == i) return numbers_internal::FastIntToBuffer(u32, buffer);
+
+  // Here we know i has at least 10 decimal digits.
+  uint64_t top_1to11 = i / 1000000000;
+  u32 = static_cast<uint32_t>(i - top_1to11 * 1000000000);
+  uint32_t top_1to11_32 = static_cast<uint32_t>(top_1to11);
+
+  if (top_1to11_32 == top_1to11) {
+    buffer = numbers_internal::FastIntToBuffer(top_1to11_32, buffer);
+  } else {
+    // top_1to11 has more than 32 bits too; print it in two steps.
+    uint32_t top_8to9 = static_cast<uint32_t>(top_1to11 / 100);
+    uint32_t mid_2 = static_cast<uint32_t>(top_1to11 - top_8to9 * 100);
+    buffer = numbers_internal::FastIntToBuffer(top_8to9, buffer);
+    PutTwoDigits(mid_2, buffer);
+    buffer += 2;
+  }
+
+  // We have only 9 digits now, again the maximum uint32_t can handle fully.
+  uint32_t digits = u32 / 10000000;  // 10,000,000
+  u32 -= digits * 10000000;
+  PutTwoDigits(digits, buffer);
+  buffer += 2;
+  digits = u32 / 100000;  // 100,000
+  u32 -= digits * 100000;
+  PutTwoDigits(digits, buffer);
+  buffer += 2;
+  digits = u32 / 1000;  // 1,000
+  u32 -= digits * 1000;
+  PutTwoDigits(digits, buffer);
+  buffer += 2;
+  digits = u32 / 10;
+  u32 -= digits * 10;
+  PutTwoDigits(digits, buffer);
+  buffer += 2;
+  memcpy(buffer, one_ASCII_final_digits[u32], 2);
+  return buffer + 1;
+}
+
+char* numbers_internal::FastIntToBuffer(int64_t i, char* buffer) {
+  uint64_t u = i;
+  if (i < 0) {
+    *buffer++ = '-';
+    u = 0 - u;
+  }
+  return numbers_internal::FastIntToBuffer(u, buffer);
+}
+
+// Given a 128-bit number expressed as a pair of uint64_t, high half first,
+// return that number multiplied by the given 32-bit value.  If the result is
+// too large to fit in a 128-bit number, divide it by 2 until it fits.
+static std::pair<uint64_t, uint64_t> Mul32(std::pair<uint64_t, uint64_t> num,
+                                           uint32_t mul) {
+  uint64_t bits0_31 = num.second & 0xFFFFFFFF;
+  uint64_t bits32_63 = num.second >> 32;
+  uint64_t bits64_95 = num.first & 0xFFFFFFFF;
+  uint64_t bits96_127 = num.first >> 32;
+
+  // The picture so far: each of these 64-bit values has only the lower 32 bits
+  // filled in.
+  // bits96_127:          [ 00000000 xxxxxxxx ]
+  // bits64_95:                    [ 00000000 xxxxxxxx ]
+  // bits32_63:                             [ 00000000 xxxxxxxx ]
+  // bits0_31:                                       [ 00000000 xxxxxxxx ]
+
+  bits0_31 *= mul;
+  bits32_63 *= mul;
+  bits64_95 *= mul;
+  bits96_127 *= mul;
+
+  // Now the top halves may also have value, though all 64 of their bits will
+  // never be set at the same time, since they are a result of a 32x32 bit
+  // multiply.  This makes the carry calculation slightly easier.
+  // bits96_127:          [ mmmmmmmm | mmmmmmmm ]
+  // bits64_95:                    [ | mmmmmmmm mmmmmmmm | ]
+  // bits32_63:                      |        [ mmmmmmmm | mmmmmmmm ]
+  // bits0_31:                       |                 [ | mmmmmmmm mmmmmmmm ]
+  // eventually:        [ bits128_up | ...bits64_127.... | ..bits0_63... ]
+
+  uint64_t bits0_63 = bits0_31 + (bits32_63 << 32);
+  uint64_t bits64_127 = bits64_95 + (bits96_127 << 32) + (bits32_63 >> 32) +
+                        (bits0_63 < bits0_31);
+  uint64_t bits128_up = (bits96_127 >> 32) + (bits64_127 < bits64_95);
+  if (bits128_up == 0) return {bits64_127, bits0_63};
+
+  auto shift = static_cast<unsigned>(bit_width(bits128_up));
+  uint64_t lo = (bits0_63 >> shift) + (bits64_127 << (64 - shift));
+  uint64_t hi = (bits64_127 >> shift) + (bits128_up << (64 - shift));
+  return {hi, lo};
+}
+
+// Compute num * 5 ^ expfive, and return the first 128 bits of the result,
+// where the first bit is always a one.  So PowFive(1, 0) starts 0b100000,
+// PowFive(1, 1) starts 0b101000, PowFive(1, 2) starts 0b110010, etc.
+static std::pair<uint64_t, uint64_t> PowFive(uint64_t num, int expfive) {
+  std::pair<uint64_t, uint64_t> result = {num, 0};
+  while (expfive >= 13) {
+    // 5^13 is the highest power of five that will fit in a 32-bit integer.
+    result = Mul32(result, 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5);
+    expfive -= 13;
+  }
+  constexpr int powers_of_five[13] = {
+      1,
+      5,
+      5 * 5,
+      5 * 5 * 5,
+      5 * 5 * 5 * 5,
+      5 * 5 * 5 * 5 * 5,
+      5 * 5 * 5 * 5 * 5 * 5,
+      5 * 5 * 5 * 5 * 5 * 5 * 5,
+      5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
+      5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
+      5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
+      5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
+      5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5};
+  result = Mul32(result, powers_of_five[expfive & 15]);
+  int shift = countl_zero(result.first);
+  if (shift != 0) {
+    result.first = (result.first << shift) + (result.second >> (64 - shift));
+    result.second = (result.second << shift);
+  }
+  return result;
+}
+
+struct ExpDigits {
+  int32_t exponent;
+  char digits[6];
+};
+
+// SplitToSix converts value, a positive double-precision floating-point number,
+// into a base-10 exponent and 6 ASCII digits, where the first digit is never
+// zero.  For example, SplitToSix(1) returns an exponent of zero and a digits
+// array of {'1', '0', '0', '0', '0', '0'}.  If value is exactly halfway between
+// two possible representations, e.g. value = 100000.5, then "round to even" is
+// performed.
+static ExpDigits SplitToSix(const double value) {
+  ExpDigits exp_dig;
+  int exp = 5;
+  double d = value;
+  // First step: calculate a close approximation of the output, where the
+  // value d will be between 100,000 and 999,999, representing the digits
+  // in the output ASCII array, and exp is the base-10 exponent.  It would be
+  // faster to use a table here, and to look up the base-2 exponent of value,
+  // however value is an IEEE-754 64-bit number, so the table would have 2,000
+  // entries, which is not cache-friendly.
+  if (d >= 999999.5) {
+    if (d >= 1e+261) exp += 256, d *= 1e-256;
+    if (d >= 1e+133) exp += 128, d *= 1e-128;
+    if (d >= 1e+69) exp += 64, d *= 1e-64;
+    if (d >= 1e+37) exp += 32, d *= 1e-32;
+    if (d >= 1e+21) exp += 16, d *= 1e-16;
+    if (d >= 1e+13) exp += 8, d *= 1e-8;
+    if (d >= 1e+9) exp += 4, d *= 1e-4;
+    if (d >= 1e+7) exp += 2, d *= 1e-2;
+    if (d >= 1e+6) exp += 1, d *= 1e-1;
+  } else {
+    if (d < 1e-250) exp -= 256, d *= 1e256;
+    if (d < 1e-122) exp -= 128, d *= 1e128;
+    if (d < 1e-58) exp -= 64, d *= 1e64;
+    if (d < 1e-26) exp -= 32, d *= 1e32;
+    if (d < 1e-10) exp -= 16, d *= 1e16;
+    if (d < 1e-2) exp -= 8, d *= 1e8;
+    if (d < 1e+2) exp -= 4, d *= 1e4;
+    if (d < 1e+4) exp -= 2, d *= 1e2;
+    if (d < 1e+5) exp -= 1, d *= 1e1;
+  }
+  // At this point, d is in the range [99999.5..999999.5) and exp is in the
+  // range [-324..308]. Since we need to round d up, we want to add a half
+  // and truncate.
+  // However, the technique above may have lost some precision, due to its
+  // repeated multiplication by constants that each may be off by half a bit
+  // of precision.  This only matters if we're close to the edge though.
+  // Since we'd like to know if the fractional part of d is close to a half,
+  // we multiply it by 65536 and see if the fractional part is close to 32768.
+  // (The number doesn't have to be a power of two,but powers of two are faster)
+  uint64_t d64k = d * 65536;
+  int dddddd;  // A 6-digit decimal integer.
+  if ((d64k % 65536) == 32767 || (d64k % 65536) == 32768) {
+    // OK, it's fairly likely that precision was lost above, which is
+    // not a surprise given only 52 mantissa bits are available.  Therefore
+    // redo the calculation using 128-bit numbers.  (64 bits are not enough).
+
+    // Start out with digits rounded down; maybe add one below.
+    dddddd = static_cast<int>(d64k / 65536);
+
+    // mantissa is a 64-bit integer representing M.mmm... * 2^63.  The actual
+    // value we're representing, of course, is M.mmm... * 2^exp2.
+    int exp2;
+    double m = std::frexp(value, &exp2);
+    uint64_t mantissa = m * (32768.0 * 65536.0 * 65536.0 * 65536.0);
+    // std::frexp returns an m value in the range [0.5, 1.0), however we
+    // can't multiply it by 2^64 and convert to an integer because some FPUs
+    // throw an exception when converting an number higher than 2^63 into an
+    // integer - even an unsigned 64-bit integer!  Fortunately it doesn't matter
+    // since m only has 52 significant bits anyway.
+    mantissa <<= 1;
+    exp2 -= 64;  // not needed, but nice for debugging
+
+    // OK, we are here to compare:
+    //     (dddddd + 0.5) * 10^(exp-5)  vs.  mantissa * 2^exp2
+    // so we can round up dddddd if appropriate.  Those values span the full
+    // range of 600 orders of magnitude of IEE 64-bit floating-point.
+    // Fortunately, we already know they are very close, so we don't need to
+    // track the base-2 exponent of both sides.  This greatly simplifies the
+    // the math since the 2^exp2 calculation is unnecessary and the power-of-10
+    // calculation can become a power-of-5 instead.
+
+    std::pair<uint64_t, uint64_t> edge, val;
+    if (exp >= 6) {
+      // Compare (dddddd + 0.5) * 5 ^ (exp - 5) to mantissa
+      // Since we're tossing powers of two, 2 * dddddd + 1 is the
+      // same as dddddd + 0.5
+      edge = PowFive(2 * dddddd + 1, exp - 5);
+
+      val.first = mantissa;
+      val.second = 0;
+    } else {
+      // We can't compare (dddddd + 0.5) * 5 ^ (exp - 5) to mantissa as we did
+      // above because (exp - 5) is negative.  So we compare (dddddd + 0.5) to
+      // mantissa * 5 ^ (5 - exp)
+      edge = PowFive(2 * dddddd + 1, 0);
+
+      val = PowFive(mantissa, 5 - exp);
+    }
+    // printf("exp=%d %016lx %016lx vs %016lx %016lx\n", exp, val.first,
+    //        val.second, edge.first, edge.second);
+    if (val > edge) {
+      dddddd++;
+    } else if (val == edge) {
+      dddddd += (dddddd & 1);
+    }
+  } else {
+    // Here, we are not close to the edge.
+    dddddd = static_cast<int>((d64k + 32768) / 65536);
+  }
+  if (dddddd == 1000000) {
+    dddddd = 100000;
+    exp += 1;
+  }
+  exp_dig.exponent = exp;
+
+  int two_digits = dddddd / 10000;
+  dddddd -= two_digits * 10000;
+  numbers_internal::PutTwoDigits(two_digits, &exp_dig.digits[0]);
+
+  two_digits = dddddd / 100;
+  dddddd -= two_digits * 100;
+  numbers_internal::PutTwoDigits(two_digits, &exp_dig.digits[2]);
+
+  numbers_internal::PutTwoDigits(dddddd, &exp_dig.digits[4]);
+  return exp_dig;
+}
+
+// Helper function for fast formatting of floating-point.
+// The result is the same as "%g", a.k.a. "%.6g".
+size_t numbers_internal::SixDigitsToBuffer(double d, char* const buffer) {
+  static_assert(std::numeric_limits<float>::is_iec559,
+                "IEEE-754/IEC-559 support only");
+
+  char* out = buffer;  // we write data to out, incrementing as we go, but
+                       // FloatToBuffer always returns the address of the buffer
+                       // passed in.
+
+  if (std::isnan(d)) {
+    strcpy(out, "nan");  // NOLINT(runtime/printf)
+    return 3;
+  }
+  if (d == 0) {  // +0 and -0 are handled here
+    if (std::signbit(d)) *out++ = '-';
+    *out++ = '0';
+    *out = 0;
+    return out - buffer;
+  }
+  if (d < 0) {
+    *out++ = '-';
+    d = -d;
+  }
+  if (std::isinf(d)) {
+    strcpy(out, "inf");  // NOLINT(runtime/printf)
+    return out + 3 - buffer;
+  }
+
+  auto exp_dig = SplitToSix(d);
+  int exp = exp_dig.exponent;
+  const char* digits = exp_dig.digits;
+  out[0] = '0';
+  out[1] = '.';
+  switch (exp) {
+    case 5:
+      memcpy(out, &digits[0], 6), out += 6;
+      *out = 0;
+      return out - buffer;
+    case 4:
+      memcpy(out, &digits[0], 5), out += 5;
+      if (digits[5] != '0') {
+        *out++ = '.';
+        *out++ = digits[5];
+      }
+      *out = 0;
+      return out - buffer;
+    case 3:
+      memcpy(out, &digits[0], 4), out += 4;
+      if ((digits[5] | digits[4]) != '0') {
+        *out++ = '.';
+        *out++ = digits[4];
+        if (digits[5] != '0') *out++ = digits[5];
+      }
+      *out = 0;
+      return out - buffer;
+    case 2:
+      memcpy(out, &digits[0], 3), out += 3;
+      *out++ = '.';
+      memcpy(out, &digits[3], 3);
+      out += 3;
+      while (out[-1] == '0') --out;
+      if (out[-1] == '.') --out;
+      *out = 0;
+      return out - buffer;
+    case 1:
+      memcpy(out, &digits[0], 2), out += 2;
+      *out++ = '.';
+      memcpy(out, &digits[2], 4);
+      out += 4;
+      while (out[-1] == '0') --out;
+      if (out[-1] == '.') --out;
+      *out = 0;
+      return out - buffer;
+    case 0:
+      memcpy(out, &digits[0], 1), out += 1;
+      *out++ = '.';
+      memcpy(out, &digits[1], 5);
+      out += 5;
+      while (out[-1] == '0') --out;
+      if (out[-1] == '.') --out;
+      *out = 0;
+      return out - buffer;
+    case -4:
+      out[2] = '0';
+      ++out;
+      ABSL_FALLTHROUGH_INTENDED;
+    case -3:
+      out[2] = '0';
+      ++out;
+      ABSL_FALLTHROUGH_INTENDED;
+    case -2:
+      out[2] = '0';
+      ++out;
+      ABSL_FALLTHROUGH_INTENDED;
+    case -1:
+      out += 2;
+      memcpy(out, &digits[0], 6);
+      out += 6;
+      while (out[-1] == '0') --out;
+      *out = 0;
+      return out - buffer;
+  }
+  assert(exp < -4 || exp >= 6);
+  out[0] = digits[0];
+  assert(out[1] == '.');
+  out += 2;
+  memcpy(out, &digits[1], 5), out += 5;
+  while (out[-1] == '0') --out;
+  if (out[-1] == '.') --out;
+  *out++ = 'e';
+  if (exp > 0) {
+    *out++ = '+';
+  } else {
+    *out++ = '-';
+    exp = -exp;
+  }
+  if (exp > 99) {
+    int dig1 = exp / 100;
+    exp -= dig1 * 100;
+    *out++ = '0' + dig1;
+  }
+  PutTwoDigits(exp, out);
+  out += 2;
+  *out = 0;
+  return out - buffer;
+}
+
+namespace {
+// Represents integer values of digits.
+// Uses 36 to indicate an invalid character since we support
+// bases up to 36.
+static const int8_t kAsciiToInt[256] = {
+    36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,  // 16 36s.
+    36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,
+    36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 0,  1,  2,  3,  4,  5,
+    6,  7,  8,  9,  36, 36, 36, 36, 36, 36, 36, 10, 11, 12, 13, 14, 15, 16, 17,
+    18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36,
+    36, 36, 36, 36, 36, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,
+    24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 36, 36, 36, 36, 36, 36,
+    36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,
+    36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,
+    36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,
+    36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,
+    36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,
+    36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,
+    36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36};
+
+// Parse the sign and optional hex or oct prefix in text.
+inline bool safe_parse_sign_and_base(absl::string_view* text /*inout*/,
+                                     int* base_ptr /*inout*/,
+                                     bool* negative_ptr /*output*/) {
+  if (text->data() == nullptr) {
+    return false;
+  }
+
+  const char* start = text->data();
+  const char* end = start + text->size();
+  int base = *base_ptr;
+
+  // Consume whitespace.
+  while (start < end && absl::ascii_isspace(start[0])) {
+    ++start;
+  }
+  while (start < end && absl::ascii_isspace(end[-1])) {
+    --end;
+  }
+  if (start >= end) {
+    return false;
+  }
+
+  // Consume sign.
+  *negative_ptr = (start[0] == '-');
+  if (*negative_ptr || start[0] == '+') {
+    ++start;
+    if (start >= end) {
+      return false;
+    }
+  }
+
+  // Consume base-dependent prefix.
+  //  base 0: "0x" -> base 16, "0" -> base 8, default -> base 10
+  //  base 16: "0x" -> base 16
+  // Also validate the base.
+  if (base == 0) {
+    if (end - start >= 2 && start[0] == '0' &&
+        (start[1] == 'x' || start[1] == 'X')) {
+      base = 16;
+      start += 2;
+      if (start >= end) {
+        // "0x" with no digits after is invalid.
+        return false;
+      }
+    } else if (end - start >= 1 && start[0] == '0') {
+      base = 8;
+      start += 1;
+    } else {
+      base = 10;
+    }
+  } else if (base == 16) {
+    if (end - start >= 2 && start[0] == '0' &&
+        (start[1] == 'x' || start[1] == 'X')) {
+      start += 2;
+      if (start >= end) {
+        // "0x" with no digits after is invalid.
+        return false;
+      }
+    }
+  } else if (base >= 2 && base <= 36) {
+    // okay
+  } else {
+    return false;
+  }
+  *text = absl::string_view(start, end - start);
+  *base_ptr = base;
+  return true;
+}
+
+// Consume digits.
+//
+// The classic loop:
+//
+//   for each digit
+//     value = value * base + digit
+//   value *= sign
+//
+// The classic loop needs overflow checking.  It also fails on the most
+// negative integer, -2147483648 in 32-bit two's complement representation.
+//
+// My improved loop:
+//
+//  if (!negative)
+//    for each digit
+//      value = value * base
+//      value = value + digit
+//  else
+//    for each digit
+//      value = value * base
+//      value = value - digit
+//
+// Overflow checking becomes simple.
+
+// Lookup tables per IntType:
+// vmax/base and vmin/base are precomputed because division costs at least 8ns.
+// TODO(junyer): Doing this per base instead (i.e. an array of structs, not a
+// struct of arrays) would probably be better in terms of d-cache for the most
+// commonly used bases.
+template <typename IntType>
+struct LookupTables {
+  ABSL_CONST_INIT static const IntType kVmaxOverBase[];
+  ABSL_CONST_INIT static const IntType kVminOverBase[];
+};
+
+// An array initializer macro for X/base where base in [0, 36].
+// However, note that lookups for base in [0, 1] should never happen because
+// base has been validated to be in [2, 36] by safe_parse_sign_and_base().
+#define X_OVER_BASE_INITIALIZER(X)                                        \
+  {                                                                       \
+    0, 0, X / 2, X / 3, X / 4, X / 5, X / 6, X / 7, X / 8, X / 9, X / 10, \
+        X / 11, X / 12, X / 13, X / 14, X / 15, X / 16, X / 17, X / 18,   \
+        X / 19, X / 20, X / 21, X / 22, X / 23, X / 24, X / 25, X / 26,   \
+        X / 27, X / 28, X / 29, X / 30, X / 31, X / 32, X / 33, X / 34,   \
+        X / 35, X / 36,                                                   \
+  }
+
+// This kVmaxOverBase is generated with
+//  for (int base = 2; base < 37; ++base) {
+//    absl::uint128 max = std::numeric_limits<absl::uint128>::max();
+//    auto result = max / base;
+//    std::cout << "    MakeUint128(" << absl::Uint128High64(result) << "u, "
+//              << absl::Uint128Low64(result) << "u),\n";
+//  }
+// See https://godbolt.org/z/aneYsb
+//
+// uint128& operator/=(uint128) is not constexpr, so hardcode the resulting
+// array to avoid a static initializer.
+template<>
+const uint128 LookupTables<uint128>::kVmaxOverBase[] = {
+    0,
+    0,
+    MakeUint128(9223372036854775807u, 18446744073709551615u),
+    MakeUint128(6148914691236517205u, 6148914691236517205u),
+    MakeUint128(4611686018427387903u, 18446744073709551615u),
+    MakeUint128(3689348814741910323u, 3689348814741910323u),
+    MakeUint128(3074457345618258602u, 12297829382473034410u),
+    MakeUint128(2635249153387078802u, 5270498306774157604u),
+    MakeUint128(2305843009213693951u, 18446744073709551615u),
+    MakeUint128(2049638230412172401u, 14347467612885206812u),
+    MakeUint128(1844674407370955161u, 11068046444225730969u),
+    MakeUint128(1676976733973595601u, 8384883669867978007u),
+    MakeUint128(1537228672809129301u, 6148914691236517205u),
+    MakeUint128(1418980313362273201u, 4256940940086819603u),
+    MakeUint128(1317624576693539401u, 2635249153387078802u),
+    MakeUint128(1229782938247303441u, 1229782938247303441u),
+    MakeUint128(1152921504606846975u, 18446744073709551615u),
+    MakeUint128(1085102592571150095u, 1085102592571150095u),
+    MakeUint128(1024819115206086200u, 16397105843297379214u),
+    MakeUint128(970881267037344821u, 16504981539634861972u),
+    MakeUint128(922337203685477580u, 14757395258967641292u),
+    MakeUint128(878416384462359600u, 14054662151397753612u),
+    MakeUint128(838488366986797800u, 13415813871788764811u),
+    MakeUint128(802032351030850070u, 4812194106185100421u),
+    MakeUint128(768614336404564650u, 12297829382473034410u),
+    MakeUint128(737869762948382064u, 11805916207174113034u),
+    MakeUint128(709490156681136600u, 11351842506898185609u),
+    MakeUint128(683212743470724133u, 17080318586768103348u),
+    MakeUint128(658812288346769700u, 10540996613548315209u),
+    MakeUint128(636094623231363848u, 15266270957552732371u),
+    MakeUint128(614891469123651720u, 9838263505978427528u),
+    MakeUint128(595056260442243600u, 9520900167075897608u),
+    MakeUint128(576460752303423487u, 18446744073709551615u),
+    MakeUint128(558992244657865200u, 8943875914525843207u),
+    MakeUint128(542551296285575047u, 9765923333140350855u),
+    MakeUint128(527049830677415760u, 8432797290838652167u),
+    MakeUint128(512409557603043100u, 8198552921648689607u),
+};
+
+// This kVmaxOverBase generated with
+//   for (int base = 2; base < 37; ++base) {
+//    absl::int128 max = std::numeric_limits<absl::int128>::max();
+//    auto result = max / base;
+//    std::cout << "\tMakeInt128(" << absl::Int128High64(result) << ", "
+//              << absl::Int128Low64(result) << "u),\n";
+//  }
+// See https://godbolt.org/z/7djYWz
+//
+// int128& operator/=(int128) is not constexpr, so hardcode the resulting array
+// to avoid a static initializer.
+template<>
+const int128 LookupTables<int128>::kVmaxOverBase[] = {
+    0,
+    0,
+    MakeInt128(4611686018427387903, 18446744073709551615u),
+    MakeInt128(3074457345618258602, 12297829382473034410u),
+    MakeInt128(2305843009213693951, 18446744073709551615u),
+    MakeInt128(1844674407370955161, 11068046444225730969u),
+    MakeInt128(1537228672809129301, 6148914691236517205u),
+    MakeInt128(1317624576693539401, 2635249153387078802u),
+    MakeInt128(1152921504606846975, 18446744073709551615u),
+    MakeInt128(1024819115206086200, 16397105843297379214u),
+    MakeInt128(922337203685477580, 14757395258967641292u),
+    MakeInt128(838488366986797800, 13415813871788764811u),
+    MakeInt128(768614336404564650, 12297829382473034410u),
+    MakeInt128(709490156681136600, 11351842506898185609u),
+    MakeInt128(658812288346769700, 10540996613548315209u),
+    MakeInt128(614891469123651720, 9838263505978427528u),
+    MakeInt128(576460752303423487, 18446744073709551615u),
+    MakeInt128(542551296285575047, 9765923333140350855u),
+    MakeInt128(512409557603043100, 8198552921648689607u),
+    MakeInt128(485440633518672410, 17475862806672206794u),
+    MakeInt128(461168601842738790, 7378697629483820646u),
+    MakeInt128(439208192231179800, 7027331075698876806u),
+    MakeInt128(419244183493398900, 6707906935894382405u),
+    MakeInt128(401016175515425035, 2406097053092550210u),
+    MakeInt128(384307168202282325, 6148914691236517205u),
+    MakeInt128(368934881474191032, 5902958103587056517u),
+    MakeInt128(354745078340568300, 5675921253449092804u),
+    MakeInt128(341606371735362066, 17763531330238827482u),
+    MakeInt128(329406144173384850, 5270498306774157604u),
+    MakeInt128(318047311615681924, 7633135478776366185u),
+    MakeInt128(307445734561825860, 4919131752989213764u),
+    MakeInt128(297528130221121800, 4760450083537948804u),
+    MakeInt128(288230376151711743, 18446744073709551615u),
+    MakeInt128(279496122328932600, 4471937957262921603u),
+    MakeInt128(271275648142787523, 14106333703424951235u),
+    MakeInt128(263524915338707880, 4216398645419326083u),
+    MakeInt128(256204778801521550, 4099276460824344803u),
+};
+
+// This kVminOverBase generated with
+//  for (int base = 2; base < 37; ++base) {
+//    absl::int128 min = std::numeric_limits<absl::int128>::min();
+//    auto result = min / base;
+//    std::cout << "\tMakeInt128(" << absl::Int128High64(result) << ", "
+//              << absl::Int128Low64(result) << "u),\n";
+//  }
+//
+// See https://godbolt.org/z/7djYWz
+//
+// int128& operator/=(int128) is not constexpr, so hardcode the resulting array
+// to avoid a static initializer.
+template<>
+const int128 LookupTables<int128>::kVminOverBase[] = {
+    0,
+    0,
+    MakeInt128(-4611686018427387904, 0u),
+    MakeInt128(-3074457345618258603, 6148914691236517206u),
+    MakeInt128(-2305843009213693952, 0u),
+    MakeInt128(-1844674407370955162, 7378697629483820647u),
+    MakeInt128(-1537228672809129302, 12297829382473034411u),
+    MakeInt128(-1317624576693539402, 15811494920322472814u),
+    MakeInt128(-1152921504606846976, 0u),
+    MakeInt128(-1024819115206086201, 2049638230412172402u),
+    MakeInt128(-922337203685477581, 3689348814741910324u),
+    MakeInt128(-838488366986797801, 5030930201920786805u),
+    MakeInt128(-768614336404564651, 6148914691236517206u),
+    MakeInt128(-709490156681136601, 7094901566811366007u),
+    MakeInt128(-658812288346769701, 7905747460161236407u),
+    MakeInt128(-614891469123651721, 8608480567731124088u),
+    MakeInt128(-576460752303423488, 0u),
+    MakeInt128(-542551296285575048, 8680820740569200761u),
+    MakeInt128(-512409557603043101, 10248191152060862009u),
+    MakeInt128(-485440633518672411, 970881267037344822u),
+    MakeInt128(-461168601842738791, 11068046444225730970u),
+    MakeInt128(-439208192231179801, 11419412998010674810u),
+    MakeInt128(-419244183493398901, 11738837137815169211u),
+    MakeInt128(-401016175515425036, 16040647020617001406u),
+    MakeInt128(-384307168202282326, 12297829382473034411u),
+    MakeInt128(-368934881474191033, 12543785970122495099u),
+    MakeInt128(-354745078340568301, 12770822820260458812u),
+    MakeInt128(-341606371735362067, 683212743470724134u),
+    MakeInt128(-329406144173384851, 13176245766935394012u),
+    MakeInt128(-318047311615681925, 10813608594933185431u),
+    MakeInt128(-307445734561825861, 13527612320720337852u),
+    MakeInt128(-297528130221121801, 13686293990171602812u),
+    MakeInt128(-288230376151711744, 0u),
+    MakeInt128(-279496122328932601, 13974806116446630013u),
+    MakeInt128(-271275648142787524, 4340410370284600381u),
+    MakeInt128(-263524915338707881, 14230345428290225533u),
+    MakeInt128(-256204778801521551, 14347467612885206813u),
+};
+
+template <typename IntType>
+const IntType LookupTables<IntType>::kVmaxOverBase[] =
+    X_OVER_BASE_INITIALIZER(std::numeric_limits<IntType>::max());
+
+template <typename IntType>
+const IntType LookupTables<IntType>::kVminOverBase[] =
+    X_OVER_BASE_INITIALIZER(std::numeric_limits<IntType>::min());
+
+#undef X_OVER_BASE_INITIALIZER
+
+template <typename IntType>
+inline bool safe_parse_positive_int(absl::string_view text, int base,
+                                    IntType* value_p) {
+  IntType value = 0;
+  const IntType vmax = std::numeric_limits<IntType>::max();
+  assert(vmax > 0);
+  assert(base >= 0);
+  assert(vmax >= static_cast<IntType>(base));
+  const IntType vmax_over_base = LookupTables<IntType>::kVmaxOverBase[base];
+  assert(base < 2 ||
+         std::numeric_limits<IntType>::max() / base == vmax_over_base);
+  const char* start = text.data();
+  const char* end = start + text.size();
+  // loop over digits
+  for (; start < end; ++start) {
+    unsigned char c = static_cast<unsigned char>(start[0]);
+    int digit = kAsciiToInt[c];
+    if (digit >= base) {
+      *value_p = value;
+      return false;
+    }
+    if (value > vmax_over_base) {
+      *value_p = vmax;
+      return false;
+    }
+    value *= base;
+    if (value > vmax - digit) {
+      *value_p = vmax;
+      return false;
+    }
+    value += digit;
+  }
+  *value_p = value;
+  return true;
+}
+
+template <typename IntType>
+inline bool safe_parse_negative_int(absl::string_view text, int base,
+                                    IntType* value_p) {
+  IntType value = 0;
+  const IntType vmin = std::numeric_limits<IntType>::min();
+  assert(vmin < 0);
+  assert(vmin <= 0 - base);
+  IntType vmin_over_base = LookupTables<IntType>::kVminOverBase[base];
+  assert(base < 2 ||
+         std::numeric_limits<IntType>::min() / base == vmin_over_base);
+  // 2003 c++ standard [expr.mul]
+  // "... the sign of the remainder is implementation-defined."
+  // Although (vmin/base)*base + vmin%base is always vmin.
+  // 2011 c++ standard tightens the spec but we cannot rely on it.
+  // TODO(junyer): Handle this in the lookup table generation.
+  if (vmin % base > 0) {
+    vmin_over_base += 1;
+  }
+  const char* start = text.data();
+  const char* end = start + text.size();
+  // loop over digits
+  for (; start < end; ++start) {
+    unsigned char c = static_cast<unsigned char>(start[0]);
+    int digit = kAsciiToInt[c];
+    if (digit >= base) {
+      *value_p = value;
+      return false;
+    }
+    if (value < vmin_over_base) {
+      *value_p = vmin;
+      return false;
+    }
+    value *= base;
+    if (value < vmin + digit) {
+      *value_p = vmin;
+      return false;
+    }
+    value -= digit;
+  }
+  *value_p = value;
+  return true;
+}
+
+// Input format based on POSIX.1-2008 strtol
+// http://pubs.opengroup.org/onlinepubs/9699919799/functions/strtol.html
+template <typename IntType>
+inline bool safe_int_internal(absl::string_view text, IntType* value_p,
+                              int base) {
+  *value_p = 0;
+  bool negative;
+  if (!safe_parse_sign_and_base(&text, &base, &negative)) {
+    return false;
+  }
+  if (!negative) {
+    return safe_parse_positive_int(text, base, value_p);
+  } else {
+    return safe_parse_negative_int(text, base, value_p);
+  }
+}
+
+template <typename IntType>
+inline bool safe_uint_internal(absl::string_view text, IntType* value_p,
+                               int base) {
+  *value_p = 0;
+  bool negative;
+  if (!safe_parse_sign_and_base(&text, &base, &negative) || negative) {
+    return false;
+  }
+  return safe_parse_positive_int(text, base, value_p);
+}
+}  // anonymous namespace
+
+namespace numbers_internal {
+
+// Digit conversion.
+ABSL_CONST_INIT ABSL_DLL const char kHexChar[] =
+    "0123456789abcdef";
+
+ABSL_CONST_INIT ABSL_DLL const char kHexTable[513] =
+    "000102030405060708090a0b0c0d0e0f"
+    "101112131415161718191a1b1c1d1e1f"
+    "202122232425262728292a2b2c2d2e2f"
+    "303132333435363738393a3b3c3d3e3f"
+    "404142434445464748494a4b4c4d4e4f"
+    "505152535455565758595a5b5c5d5e5f"
+    "606162636465666768696a6b6c6d6e6f"
+    "707172737475767778797a7b7c7d7e7f"
+    "808182838485868788898a8b8c8d8e8f"
+    "909192939495969798999a9b9c9d9e9f"
+    "a0a1a2a3a4a5a6a7a8a9aaabacadaeaf"
+    "b0b1b2b3b4b5b6b7b8b9babbbcbdbebf"
+    "c0c1c2c3c4c5c6c7c8c9cacbcccdcecf"
+    "d0d1d2d3d4d5d6d7d8d9dadbdcdddedf"
+    "e0e1e2e3e4e5e6e7e8e9eaebecedeeef"
+    "f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff";
+
+ABSL_CONST_INIT ABSL_DLL const char two_ASCII_digits[100][2] = {
+    {'0', '0'}, {'0', '1'}, {'0', '2'}, {'0', '3'}, {'0', '4'}, {'0', '5'},
+    {'0', '6'}, {'0', '7'}, {'0', '8'}, {'0', '9'}, {'1', '0'}, {'1', '1'},
+    {'1', '2'}, {'1', '3'}, {'1', '4'}, {'1', '5'}, {'1', '6'}, {'1', '7'},
+    {'1', '8'}, {'1', '9'}, {'2', '0'}, {'2', '1'}, {'2', '2'}, {'2', '3'},
+    {'2', '4'}, {'2', '5'}, {'2', '6'}, {'2', '7'}, {'2', '8'}, {'2', '9'},
+    {'3', '0'}, {'3', '1'}, {'3', '2'}, {'3', '3'}, {'3', '4'}, {'3', '5'},
+    {'3', '6'}, {'3', '7'}, {'3', '8'}, {'3', '9'}, {'4', '0'}, {'4', '1'},
+    {'4', '2'}, {'4', '3'}, {'4', '4'}, {'4', '5'}, {'4', '6'}, {'4', '7'},
+    {'4', '8'}, {'4', '9'}, {'5', '0'}, {'5', '1'}, {'5', '2'}, {'5', '3'},
+    {'5', '4'}, {'5', '5'}, {'5', '6'}, {'5', '7'}, {'5', '8'}, {'5', '9'},
+    {'6', '0'}, {'6', '1'}, {'6', '2'}, {'6', '3'}, {'6', '4'}, {'6', '5'},
+    {'6', '6'}, {'6', '7'}, {'6', '8'}, {'6', '9'}, {'7', '0'}, {'7', '1'},
+    {'7', '2'}, {'7', '3'}, {'7', '4'}, {'7', '5'}, {'7', '6'}, {'7', '7'},
+    {'7', '8'}, {'7', '9'}, {'8', '0'}, {'8', '1'}, {'8', '2'}, {'8', '3'},
+    {'8', '4'}, {'8', '5'}, {'8', '6'}, {'8', '7'}, {'8', '8'}, {'8', '9'},
+    {'9', '0'}, {'9', '1'}, {'9', '2'}, {'9', '3'}, {'9', '4'}, {'9', '5'},
+    {'9', '6'}, {'9', '7'}, {'9', '8'}, {'9', '9'}};
+
+bool safe_strto32_base(absl::string_view text, int32_t* value, int base) {
+  return safe_int_internal<int32_t>(text, value, base);
+}
+
+bool safe_strto64_base(absl::string_view text, int64_t* value, int base) {
+  return safe_int_internal<int64_t>(text, value, base);
+}
+
+bool safe_strto128_base(absl::string_view text, int128* value, int base) {
+  return safe_int_internal<absl::int128>(text, value, base);
+}
+
+bool safe_strtou32_base(absl::string_view text, uint32_t* value, int base) {
+  return safe_uint_internal<uint32_t>(text, value, base);
+}
+
+bool safe_strtou64_base(absl::string_view text, uint64_t* value, int base) {
+  return safe_uint_internal<uint64_t>(text, value, base);
+}
+
+bool safe_strtou128_base(absl::string_view text, uint128* value, int base) {
+  return safe_uint_internal<absl::uint128>(text, value, base);
+}
+
+}  // namespace numbers_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
diff --git a/src/absl/strings/numbers.h b/src/absl/strings/numbers.h
new file mode 100644 (file)
index 0000000..1780bb4
--- /dev/null
@@ -0,0 +1,266 @@
+// Copyright 2017 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// -----------------------------------------------------------------------------
+// File: numbers.h
+// -----------------------------------------------------------------------------
+//
+// This package contains functions for converting strings to numbers. For
+// converting numbers to strings, use `StrCat()` or `StrAppend()` in str_cat.h,
+// which automatically detect and convert most number values appropriately.
+
+#ifndef ABSL_STRINGS_NUMBERS_H_
+#define ABSL_STRINGS_NUMBERS_H_
+
+#ifdef __SSE4_2__
+#include <x86intrin.h>
+#endif
+
+#include <cstddef>
+#include <cstdlib>
+#include <cstring>
+#include <ctime>
+#include <limits>
+#include <string>
+#include <type_traits>
+
+#include "absl/base/config.h"
+#ifdef __SSE4_2__
+// TODO(jorg): Remove this when we figure out the right way
+// to swap bytes on SSE 4.2 that works with the compilers
+// we claim to support.  Also, add tests for the compiler
+// that doesn't support the Intel _bswap64 intrinsic but
+// does support all the SSE 4.2 intrinsics
+#include "absl/base/internal/endian.h"
+#endif
+#include "absl/base/macros.h"
+#include "absl/base/port.h"
+#include "absl/numeric/bits.h"
+#include "absl/numeric/int128.h"
+#include "absl/strings/string_view.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+
+// SimpleAtoi()
+//
+// Converts the given string (optionally followed or preceded by ASCII
+// whitespace) into an integer value, returning `true` if successful. The string
+// must reflect a base-10 integer whose value falls within the range of the
+// integer type (optionally preceded by a `+` or `-`). If any errors are
+// encountered, this function returns `false`, leaving `out` in an unspecified
+// state.
+template <typename int_type>
+ABSL_MUST_USE_RESULT bool SimpleAtoi(absl::string_view str, int_type* out);
+
+// SimpleAtof()
+//
+// Converts the given string (optionally followed or preceded by ASCII
+// whitespace) into a float, which may be rounded on overflow or underflow,
+// returning `true` if successful.
+// See https://en.cppreference.com/w/c/string/byte/strtof for details about the
+// allowed formats for `str`, except SimpleAtof() is locale-independent and will
+// always use the "C" locale. If any errors are encountered, this function
+// returns `false`, leaving `out` in an unspecified state.
+ABSL_MUST_USE_RESULT bool SimpleAtof(absl::string_view str, float* out);
+
+// SimpleAtod()
+//
+// Converts the given string (optionally followed or preceded by ASCII
+// whitespace) into a double, which may be rounded on overflow or underflow,
+// returning `true` if successful.
+// See https://en.cppreference.com/w/c/string/byte/strtof for details about the
+// allowed formats for `str`, except SimpleAtod is locale-independent and will
+// always use the "C" locale. If any errors are encountered, this function
+// returns `false`, leaving `out` in an unspecified state.
+ABSL_MUST_USE_RESULT bool SimpleAtod(absl::string_view str, double* out);
+
+// SimpleAtob()
+//
+// Converts the given string into a boolean, returning `true` if successful.
+// The following case-insensitive strings are interpreted as boolean `true`:
+// "true", "t", "yes", "y", "1". The following case-insensitive strings
+// are interpreted as boolean `false`: "false", "f", "no", "n", "0". If any
+// errors are encountered, this function returns `false`, leaving `out` in an
+// unspecified state.
+ABSL_MUST_USE_RESULT bool SimpleAtob(absl::string_view str, bool* out);
+
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+// End of public API.  Implementation details follow.
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace numbers_internal {
+
+// Digit conversion.
+ABSL_DLL extern const char kHexChar[17];  // 0123456789abcdef
+ABSL_DLL extern const char
+    kHexTable[513];  // 000102030405060708090a0b0c0d0e0f1011...
+ABSL_DLL extern const char
+    two_ASCII_digits[100][2];  // 00, 01, 02, 03...
+
+// Writes a two-character representation of 'i' to 'buf'. 'i' must be in the
+// range 0 <= i < 100, and buf must have space for two characters. Example:
+//   char buf[2];
+//   PutTwoDigits(42, buf);
+//   // buf[0] == '4'
+//   // buf[1] == '2'
+inline void PutTwoDigits(size_t i, char* buf) {
+  assert(i < 100);
+  memcpy(buf, two_ASCII_digits[i], 2);
+}
+
+// safe_strto?() functions for implementing SimpleAtoi()
+
+bool safe_strto32_base(absl::string_view text, int32_t* value, int base);
+bool safe_strto64_base(absl::string_view text, int64_t* value, int base);
+bool safe_strto128_base(absl::string_view text, absl::int128* value,
+                         int base);
+bool safe_strtou32_base(absl::string_view text, uint32_t* value, int base);
+bool safe_strtou64_base(absl::string_view text, uint64_t* value, int base);
+bool safe_strtou128_base(absl::string_view text, absl::uint128* value,
+                         int base);
+
+static const int kFastToBufferSize = 32;
+static const int kSixDigitsToBufferSize = 16;
+
+// Helper function for fast formatting of floating-point values.
+// The result is the same as printf's "%g", a.k.a. "%.6g"; that is, six
+// significant digits are returned, trailing zeros are removed, and numbers
+// outside the range 0.0001-999999 are output using scientific notation
+// (1.23456e+06). This routine is heavily optimized.
+// Required buffer size is `kSixDigitsToBufferSize`.
+size_t SixDigitsToBuffer(double d, char* buffer);
+
+// These functions are intended for speed. All functions take an output buffer
+// as an argument and return a pointer to the last byte they wrote, which is the
+// terminating '\0'. At most `kFastToBufferSize` bytes are written.
+char* FastIntToBuffer(int32_t, char*);
+char* FastIntToBuffer(uint32_t, char*);
+char* FastIntToBuffer(int64_t, char*);
+char* FastIntToBuffer(uint64_t, char*);
+
+// For enums and integer types that are not an exact match for the types above,
+// use templates to call the appropriate one of the four overloads above.
+template <typename int_type>
+char* FastIntToBuffer(int_type i, char* buffer) {
+  static_assert(sizeof(i) <= 64 / 8,
+                "FastIntToBuffer works only with 64-bit-or-less integers.");
+  // TODO(jorg): This signed-ness check is used because it works correctly
+  // with enums, and it also serves to check that int_type is not a pointer.
+  // If one day something like std::is_signed<enum E> works, switch to it.
+  if (static_cast<int_type>(1) - 2 < 0) {  // Signed
+    if (sizeof(i) > 32 / 8) {           // 33-bit to 64-bit
+      return FastIntToBuffer(static_cast<int64_t>(i), buffer);
+    } else {  // 32-bit or less
+      return FastIntToBuffer(static_cast<int32_t>(i), buffer);
+    }
+  } else {                     // Unsigned
+    if (sizeof(i) > 32 / 8) {  // 33-bit to 64-bit
+      return FastIntToBuffer(static_cast<uint64_t>(i), buffer);
+    } else {  // 32-bit or less
+      return FastIntToBuffer(static_cast<uint32_t>(i), buffer);
+    }
+  }
+}
+
+// Implementation of SimpleAtoi, generalized to support arbitrary base (used
+// with base different from 10 elsewhere in Abseil implementation).
+template <typename int_type>
+ABSL_MUST_USE_RESULT bool safe_strtoi_base(absl::string_view s, int_type* out,
+                                           int base) {
+  static_assert(sizeof(*out) == 4 || sizeof(*out) == 8,
+                "SimpleAtoi works only with 32-bit or 64-bit integers.");
+  static_assert(!std::is_floating_point<int_type>::value,
+                "Use SimpleAtof or SimpleAtod instead.");
+  bool parsed;
+  // TODO(jorg): This signed-ness check is used because it works correctly
+  // with enums, and it also serves to check that int_type is not a pointer.
+  // If one day something like std::is_signed<enum E> works, switch to it.
+  if (static_cast<int_type>(1) - 2 < 0) {  // Signed
+    if (sizeof(*out) == 64 / 8) {       // 64-bit
+      int64_t val;
+      parsed = numbers_internal::safe_strto64_base(s, &val, base);
+      *out = static_cast<int_type>(val);
+    } else {  // 32-bit
+      int32_t val;
+      parsed = numbers_internal::safe_strto32_base(s, &val, base);
+      *out = static_cast<int_type>(val);
+    }
+  } else {                         // Unsigned
+    if (sizeof(*out) == 64 / 8) {  // 64-bit
+      uint64_t val;
+      parsed = numbers_internal::safe_strtou64_base(s, &val, base);
+      *out = static_cast<int_type>(val);
+    } else {  // 32-bit
+      uint32_t val;
+      parsed = numbers_internal::safe_strtou32_base(s, &val, base);
+      *out = static_cast<int_type>(val);
+    }
+  }
+  return parsed;
+}
+
+// FastHexToBufferZeroPad16()
+//
+// Outputs `val` into `out` as if by `snprintf(out, 17, "%016x", val)` but
+// without the terminating null character. Thus `out` must be of length >= 16.
+// Returns the number of non-pad digits of the output (it can never be zero
+// since 0 has one digit).
+inline size_t FastHexToBufferZeroPad16(uint64_t val, char* out) {
+#ifdef __SSE4_2__
+  uint64_t be = absl::big_endian::FromHost64(val);
+  const auto kNibbleMask = _mm_set1_epi8(0xf);
+  const auto kHexDigits = _mm_setr_epi8('0', '1', '2', '3', '4', '5', '6', '7',
+                                        '8', '9', 'a', 'b', 'c', 'd', 'e', 'f');
+  auto v = _mm_loadl_epi64(reinterpret_cast<__m128i*>(&be));  // load lo dword
+  auto v4 = _mm_srli_epi64(v, 4);                            // shift 4 right
+  auto il = _mm_unpacklo_epi8(v4, v);                        // interleave bytes
+  auto m = _mm_and_si128(il, kNibbleMask);                   // mask out nibbles
+  auto hexchars = _mm_shuffle_epi8(kHexDigits, m);           // hex chars
+  _mm_storeu_si128(reinterpret_cast<__m128i*>(out), hexchars);
+#else
+  for (int i = 0; i < 8; ++i) {
+    auto byte = (val >> (56 - 8 * i)) & 0xFF;
+    auto* hex = &absl::numbers_internal::kHexTable[byte * 2];
+    std::memcpy(out + 2 * i, hex, 2);
+  }
+#endif
+  // | 0x1 so that even 0 has 1 digit.
+  return 16 - countl_zero(val | 0x1) / 4;
+}
+
+}  // namespace numbers_internal
+
+template <typename int_type>
+ABSL_MUST_USE_RESULT bool SimpleAtoi(absl::string_view str, int_type* out) {
+  return numbers_internal::safe_strtoi_base(str, out, 10);
+}
+
+ABSL_MUST_USE_RESULT inline bool SimpleAtoi(absl::string_view str,
+                                            absl::int128* out) {
+  return numbers_internal::safe_strto128_base(str, out, 10);
+}
+
+ABSL_MUST_USE_RESULT inline bool SimpleAtoi(absl::string_view str,
+                                            absl::uint128* out) {
+  return numbers_internal::safe_strtou128_base(str, out, 10);
+}
+
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#endif  // ABSL_STRINGS_NUMBERS_H_
diff --git a/src/absl/strings/str_cat.cc b/src/absl/strings/str_cat.cc
new file mode 100644 (file)
index 0000000..dd5d25b
--- /dev/null
@@ -0,0 +1,246 @@
+// Copyright 2017 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "absl/strings/str_cat.h"
+
+#include <assert.h>
+
+#include <algorithm>
+#include <cstdint>
+#include <cstring>
+
+#include "absl/strings/ascii.h"
+#include "absl/strings/internal/resize_uninitialized.h"
+#include "absl/strings/numbers.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+
+AlphaNum::AlphaNum(Hex hex) {
+  static_assert(numbers_internal::kFastToBufferSize >= 32,
+                "This function only works when output buffer >= 32 bytes long");
+  char* const end = &digits_[numbers_internal::kFastToBufferSize];
+  auto real_width =
+      absl::numbers_internal::FastHexToBufferZeroPad16(hex.value, end - 16);
+  if (real_width >= hex.width) {
+    piece_ = absl::string_view(end - real_width, real_width);
+  } else {
+    // Pad first 16 chars because FastHexToBufferZeroPad16 pads only to 16 and
+    // max pad width can be up to 20.
+    std::memset(end - 32, hex.fill, 16);
+    // Patch up everything else up to the real_width.
+    std::memset(end - real_width - 16, hex.fill, 16);
+    piece_ = absl::string_view(end - hex.width, hex.width);
+  }
+}
+
+AlphaNum::AlphaNum(Dec dec) {
+  assert(dec.width <= numbers_internal::kFastToBufferSize);
+  char* const end = &digits_[numbers_internal::kFastToBufferSize];
+  char* const minfill = end - dec.width;
+  char* writer = end;
+  uint64_t value = dec.value;
+  bool neg = dec.neg;
+  while (value > 9) {
+    *--writer = '0' + (value % 10);
+    value /= 10;
+  }
+  *--writer = '0' + value;
+  if (neg) *--writer = '-';
+
+  ptrdiff_t fillers = writer - minfill;
+  if (fillers > 0) {
+    // Tricky: if the fill character is ' ', then it's <fill><+/-><digits>
+    // But...: if the fill character is '0', then it's <+/-><fill><digits>
+    bool add_sign_again = false;
+    if (neg && dec.fill == '0') {  // If filling with '0',
+      ++writer;                    // ignore the sign we just added
+      add_sign_again = true;       // and re-add the sign later.
+    }
+    writer -= fillers;
+    std::fill_n(writer, fillers, dec.fill);
+    if (add_sign_again) *--writer = '-';
+  }
+
+  piece_ = absl::string_view(writer, end - writer);
+}
+
+// ----------------------------------------------------------------------
+// StrCat()
+//    This merges the given strings or integers, with no delimiter. This
+//    is designed to be the fastest possible way to construct a string out
+//    of a mix of raw C strings, string_views, strings, and integer values.
+// ----------------------------------------------------------------------
+
+// Append is merely a version of memcpy that returns the address of the byte
+// after the area just overwritten.
+static char* Append(char* out, const AlphaNum& x) {
+  // memcpy is allowed to overwrite arbitrary memory, so doing this after the
+  // call would force an extra fetch of x.size().
+  char* after = out + x.size();
+  if (x.size() != 0) {
+    memcpy(out, x.data(), x.size());
+  }
+  return after;
+}
+
+std::string StrCat(const AlphaNum& a, const AlphaNum& b) {
+  std::string result;
+  absl::strings_internal::STLStringResizeUninitialized(&result,
+                                                       a.size() + b.size());
+  char* const begin = &result[0];
+  char* out = begin;
+  out = Append(out, a);
+  out = Append(out, b);
+  assert(out == begin + result.size());
+  return result;
+}
+
+std::string StrCat(const AlphaNum& a, const AlphaNum& b, const AlphaNum& c) {
+  std::string result;
+  strings_internal::STLStringResizeUninitialized(
+      &result, a.size() + b.size() + c.size());
+  char* const begin = &result[0];
+  char* out = begin;
+  out = Append(out, a);
+  out = Append(out, b);
+  out = Append(out, c);
+  assert(out == begin + result.size());
+  return result;
+}
+
+std::string StrCat(const AlphaNum& a, const AlphaNum& b, const AlphaNum& c,
+                   const AlphaNum& d) {
+  std::string result;
+  strings_internal::STLStringResizeUninitialized(
+      &result, a.size() + b.size() + c.size() + d.size());
+  char* const begin = &result[0];
+  char* out = begin;
+  out = Append(out, a);
+  out = Append(out, b);
+  out = Append(out, c);
+  out = Append(out, d);
+  assert(out == begin + result.size());
+  return result;
+}
+
+namespace strings_internal {
+
+// Do not call directly - these are not part of the public API.
+std::string CatPieces(std::initializer_list<absl::string_view> pieces) {
+  std::string result;
+  size_t total_size = 0;
+  for (const absl::string_view& piece : pieces) total_size += piece.size();
+  strings_internal::STLStringResizeUninitialized(&result, total_size);
+
+  char* const begin = &result[0];
+  char* out = begin;
+  for (const absl::string_view& piece : pieces) {
+    const size_t this_size = piece.size();
+    if (this_size != 0) {
+      memcpy(out, piece.data(), this_size);
+      out += this_size;
+    }
+  }
+  assert(out == begin + result.size());
+  return result;
+}
+
+// It's possible to call StrAppend with an absl::string_view that is itself a
+// fragment of the string we're appending to.  However the results of this are
+// random. Therefore, check for this in debug mode.  Use unsigned math so we
+// only have to do one comparison. Note, there's an exception case: appending an
+// empty string is always allowed.
+#define ASSERT_NO_OVERLAP(dest, src) \
+  assert(((src).size() == 0) ||      \
+         (uintptr_t((src).data() - (dest).data()) > uintptr_t((dest).size())))
+
+void AppendPieces(std::string* dest,
+                  std::initializer_list<absl::string_view> pieces) {
+  size_t old_size = dest->size();
+  size_t total_size = old_size;
+  for (const absl::string_view& piece : pieces) {
+    ASSERT_NO_OVERLAP(*dest, piece);
+    total_size += piece.size();
+  }
+  strings_internal::STLStringResizeUninitialized(dest, total_size);
+
+  char* const begin = &(*dest)[0];
+  char* out = begin + old_size;
+  for (const absl::string_view& piece : pieces) {
+    const size_t this_size = piece.size();
+    if (this_size != 0) {
+      memcpy(out, piece.data(), this_size);
+      out += this_size;
+    }
+  }
+  assert(out == begin + dest->size());
+}
+
+}  // namespace strings_internal
+
+void StrAppend(std::string* dest, const AlphaNum& a) {
+  ASSERT_NO_OVERLAP(*dest, a);
+  dest->append(a.data(), a.size());
+}
+
+void StrAppend(std::string* dest, const AlphaNum& a, const AlphaNum& b) {
+  ASSERT_NO_OVERLAP(*dest, a);
+  ASSERT_NO_OVERLAP(*dest, b);
+  std::string::size_type old_size = dest->size();
+  strings_internal::STLStringResizeUninitialized(
+      dest, old_size + a.size() + b.size());
+  char* const begin = &(*dest)[0];
+  char* out = begin + old_size;
+  out = Append(out, a);
+  out = Append(out, b);
+  assert(out == begin + dest->size());
+}
+
+void StrAppend(std::string* dest, const AlphaNum& a, const AlphaNum& b,
+               const AlphaNum& c) {
+  ASSERT_NO_OVERLAP(*dest, a);
+  ASSERT_NO_OVERLAP(*dest, b);
+  ASSERT_NO_OVERLAP(*dest, c);
+  std::string::size_type old_size = dest->size();
+  strings_internal::STLStringResizeUninitialized(
+      dest, old_size + a.size() + b.size() + c.size());
+  char* const begin = &(*dest)[0];
+  char* out = begin + old_size;
+  out = Append(out, a);
+  out = Append(out, b);
+  out = Append(out, c);
+  assert(out == begin + dest->size());
+}
+
+void StrAppend(std::string* dest, const AlphaNum& a, const AlphaNum& b,
+               const AlphaNum& c, const AlphaNum& d) {
+  ASSERT_NO_OVERLAP(*dest, a);
+  ASSERT_NO_OVERLAP(*dest, b);
+  ASSERT_NO_OVERLAP(*dest, c);
+  ASSERT_NO_OVERLAP(*dest, d);
+  std::string::size_type old_size = dest->size();
+  strings_internal::STLStringResizeUninitialized(
+      dest, old_size + a.size() + b.size() + c.size() + d.size());
+  char* const begin = &(*dest)[0];
+  char* out = begin + old_size;
+  out = Append(out, a);
+  out = Append(out, b);
+  out = Append(out, c);
+  out = Append(out, d);
+  assert(out == begin + dest->size());
+}
+
+ABSL_NAMESPACE_END
+}  // namespace absl
diff --git a/src/absl/strings/str_cat.h b/src/absl/strings/str_cat.h
new file mode 100644 (file)
index 0000000..a8a85c7
--- /dev/null
@@ -0,0 +1,408 @@
+//
+// Copyright 2017 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// -----------------------------------------------------------------------------
+// File: str_cat.h
+// -----------------------------------------------------------------------------
+//
+// This package contains functions for efficiently concatenating and appending
+// strings: `StrCat()` and `StrAppend()`. Most of the work within these routines
+// is actually handled through use of a special AlphaNum type, which was
+// designed to be used as a parameter type that efficiently manages conversion
+// to strings and avoids copies in the above operations.
+//
+// Any routine accepting either a string or a number may accept `AlphaNum`.
+// The basic idea is that by accepting a `const AlphaNum &` as an argument
+// to your function, your callers will automagically convert bools, integers,
+// and floating point values to strings for you.
+//
+// NOTE: Use of `AlphaNum` outside of the //absl/strings package is unsupported
+// except for the specific case of function parameters of type `AlphaNum` or
+// `const AlphaNum &`. In particular, instantiating `AlphaNum` directly as a
+// stack variable is not supported.
+//
+// Conversion from 8-bit values is not accepted because, if it were, then an
+// attempt to pass ':' instead of ":" might result in a 58 ending up in your
+// result.
+//
+// Bools convert to "0" or "1". Pointers to types other than `char *` are not
+// valid inputs. No output is generated for null `char *` pointers.
+//
+// Floating point numbers are formatted with six-digit precision, which is
+// the default for "std::cout <<" or printf "%g" (the same as "%.6g").
+//
+// You can convert to hexadecimal output rather than decimal output using the
+// `Hex` type contained here. To do so, pass `Hex(my_int)` as a parameter to
+// `StrCat()` or `StrAppend()`. You may specify a minimum hex field width using
+// a `PadSpec` enum.
+//
+// -----------------------------------------------------------------------------
+
+#ifndef ABSL_STRINGS_STR_CAT_H_
+#define ABSL_STRINGS_STR_CAT_H_
+
+#include <array>
+#include <cstdint>
+#include <string>
+#include <type_traits>
+#include <vector>
+
+#include "absl/base/port.h"
+#include "absl/strings/numbers.h"
+#include "absl/strings/string_view.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+
+namespace strings_internal {
+// AlphaNumBuffer allows a way to pass a string to StrCat without having to do
+// memory allocation.  It is simply a pair of a fixed-size character array, and
+// a size.  Please don't use outside of absl, yet.
+template <size_t max_size>
+struct AlphaNumBuffer {
+  std::array<char, max_size> data;
+  size_t size;
+};
+
+}  // namespace strings_internal
+
+// Enum that specifies the number of significant digits to return in a `Hex` or
+// `Dec` conversion and fill character to use. A `kZeroPad2` value, for example,
+// would produce hexadecimal strings such as "0a","0f" and a 'kSpacePad5' value
+// would produce hexadecimal strings such as "    a","    f".
+enum PadSpec : uint8_t {
+  kNoPad = 1,
+  kZeroPad2,
+  kZeroPad3,
+  kZeroPad4,
+  kZeroPad5,
+  kZeroPad6,
+  kZeroPad7,
+  kZeroPad8,
+  kZeroPad9,
+  kZeroPad10,
+  kZeroPad11,
+  kZeroPad12,
+  kZeroPad13,
+  kZeroPad14,
+  kZeroPad15,
+  kZeroPad16,
+  kZeroPad17,
+  kZeroPad18,
+  kZeroPad19,
+  kZeroPad20,
+
+  kSpacePad2 = kZeroPad2 + 64,
+  kSpacePad3,
+  kSpacePad4,
+  kSpacePad5,
+  kSpacePad6,
+  kSpacePad7,
+  kSpacePad8,
+  kSpacePad9,
+  kSpacePad10,
+  kSpacePad11,
+  kSpacePad12,
+  kSpacePad13,
+  kSpacePad14,
+  kSpacePad15,
+  kSpacePad16,
+  kSpacePad17,
+  kSpacePad18,
+  kSpacePad19,
+  kSpacePad20,
+};
+
+// -----------------------------------------------------------------------------
+// Hex
+// -----------------------------------------------------------------------------
+//
+// `Hex` stores a set of hexadecimal string conversion parameters for use
+// within `AlphaNum` string conversions.
+struct Hex {
+  uint64_t value;
+  uint8_t width;
+  char fill;
+
+  template <typename Int>
+  explicit Hex(
+      Int v, PadSpec spec = absl::kNoPad,
+      typename std::enable_if<sizeof(Int) == 1 &&
+                              !std::is_pointer<Int>::value>::type* = nullptr)
+      : Hex(spec, static_cast<uint8_t>(v)) {}
+  template <typename Int>
+  explicit Hex(
+      Int v, PadSpec spec = absl::kNoPad,
+      typename std::enable_if<sizeof(Int) == 2 &&
+                              !std::is_pointer<Int>::value>::type* = nullptr)
+      : Hex(spec, static_cast<uint16_t>(v)) {}
+  template <typename Int>
+  explicit Hex(
+      Int v, PadSpec spec = absl::kNoPad,
+      typename std::enable_if<sizeof(Int) == 4 &&
+                              !std::is_pointer<Int>::value>::type* = nullptr)
+      : Hex(spec, static_cast<uint32_t>(v)) {}
+  template <typename Int>
+  explicit Hex(
+      Int v, PadSpec spec = absl::kNoPad,
+      typename std::enable_if<sizeof(Int) == 8 &&
+                              !std::is_pointer<Int>::value>::type* = nullptr)
+      : Hex(spec, static_cast<uint64_t>(v)) {}
+  template <typename Pointee>
+  explicit Hex(Pointee* v, PadSpec spec = absl::kNoPad)
+      : Hex(spec, reinterpret_cast<uintptr_t>(v)) {}
+
+ private:
+  Hex(PadSpec spec, uint64_t v)
+      : value(v),
+        width(spec == absl::kNoPad
+                  ? 1
+                  : spec >= absl::kSpacePad2 ? spec - absl::kSpacePad2 + 2
+                                             : spec - absl::kZeroPad2 + 2),
+        fill(spec >= absl::kSpacePad2 ? ' ' : '0') {}
+};
+
+// -----------------------------------------------------------------------------
+// Dec
+// -----------------------------------------------------------------------------
+//
+// `Dec` stores a set of decimal string conversion parameters for use
+// within `AlphaNum` string conversions.  Dec is slower than the default
+// integer conversion, so use it only if you need padding.
+struct Dec {
+  uint64_t value;
+  uint8_t width;
+  char fill;
+  bool neg;
+
+  template <typename Int>
+  explicit Dec(Int v, PadSpec spec = absl::kNoPad,
+               typename std::enable_if<(sizeof(Int) <= 8)>::type* = nullptr)
+      : value(v >= 0 ? static_cast<uint64_t>(v)
+                     : uint64_t{0} - static_cast<uint64_t>(v)),
+        width(spec == absl::kNoPad
+                  ? 1
+                  : spec >= absl::kSpacePad2 ? spec - absl::kSpacePad2 + 2
+                                             : spec - absl::kZeroPad2 + 2),
+        fill(spec >= absl::kSpacePad2 ? ' ' : '0'),
+        neg(v < 0) {}
+};
+
+// -----------------------------------------------------------------------------
+// AlphaNum
+// -----------------------------------------------------------------------------
+//
+// The `AlphaNum` class acts as the main parameter type for `StrCat()` and
+// `StrAppend()`, providing efficient conversion of numeric, boolean, and
+// hexadecimal values (through the `Hex` type) into strings.
+
+class AlphaNum {
+ public:
+  // No bool ctor -- bools convert to an integral type.
+  // A bool ctor would also convert incoming pointers (bletch).
+
+  AlphaNum(int x)  // NOLINT(runtime/explicit)
+      : piece_(digits_,
+               numbers_internal::FastIntToBuffer(x, digits_) - &digits_[0]) {}
+  AlphaNum(unsigned int x)  // NOLINT(runtime/explicit)
+      : piece_(digits_,
+               numbers_internal::FastIntToBuffer(x, digits_) - &digits_[0]) {}
+  AlphaNum(long x)  // NOLINT(*)
+      : piece_(digits_,
+               numbers_internal::FastIntToBuffer(x, digits_) - &digits_[0]) {}
+  AlphaNum(unsigned long x)  // NOLINT(*)
+      : piece_(digits_,
+               numbers_internal::FastIntToBuffer(x, digits_) - &digits_[0]) {}
+  AlphaNum(long long x)  // NOLINT(*)
+      : piece_(digits_,
+               numbers_internal::FastIntToBuffer(x, digits_) - &digits_[0]) {}
+  AlphaNum(unsigned long long x)  // NOLINT(*)
+      : piece_(digits_,
+               numbers_internal::FastIntToBuffer(x, digits_) - &digits_[0]) {}
+
+  AlphaNum(float f)  // NOLINT(runtime/explicit)
+      : piece_(digits_, numbers_internal::SixDigitsToBuffer(f, digits_)) {}
+  AlphaNum(double f)  // NOLINT(runtime/explicit)
+      : piece_(digits_, numbers_internal::SixDigitsToBuffer(f, digits_)) {}
+
+  AlphaNum(Hex hex);  // NOLINT(runtime/explicit)
+  AlphaNum(Dec dec);  // NOLINT(runtime/explicit)
+
+  template <size_t size>
+  AlphaNum(  // NOLINT(runtime/explicit)
+      const strings_internal::AlphaNumBuffer<size>& buf)
+      : piece_(&buf.data[0], buf.size) {}
+
+  AlphaNum(const char* c_str) : piece_(c_str) {}  // NOLINT(runtime/explicit)
+  AlphaNum(absl::string_view pc) : piece_(pc) {}  // NOLINT(runtime/explicit)
+
+  template <typename Allocator>
+  AlphaNum(  // NOLINT(runtime/explicit)
+      const std::basic_string<char, std::char_traits<char>, Allocator>& str)
+      : piece_(str) {}
+
+  // Use string literals ":" instead of character literals ':'.
+  AlphaNum(char c) = delete;  // NOLINT(runtime/explicit)
+
+  AlphaNum(const AlphaNum&) = delete;
+  AlphaNum& operator=(const AlphaNum&) = delete;
+
+  absl::string_view::size_type size() const { return piece_.size(); }
+  const char* data() const { return piece_.data(); }
+  absl::string_view Piece() const { return piece_; }
+
+  // Normal enums are already handled by the integer formatters.
+  // This overload matches only scoped enums.
+  template <typename T,
+            typename = typename std::enable_if<
+                std::is_enum<T>{} && !std::is_convertible<T, int>{}>::type>
+  AlphaNum(T e)  // NOLINT(runtime/explicit)
+      : AlphaNum(static_cast<typename std::underlying_type<T>::type>(e)) {}
+
+  // vector<bool>::reference and const_reference require special help to
+  // convert to `AlphaNum` because it requires two user defined conversions.
+  template <
+      typename T,
+      typename std::enable_if<
+          std::is_class<T>::value &&
+          (std::is_same<T, std::vector<bool>::reference>::value ||
+           std::is_same<T, std::vector<bool>::const_reference>::value)>::type* =
+          nullptr>
+  AlphaNum(T e) : AlphaNum(static_cast<bool>(e)) {}  // NOLINT(runtime/explicit)
+
+ private:
+  absl::string_view piece_;
+  char digits_[numbers_internal::kFastToBufferSize];
+};
+
+// -----------------------------------------------------------------------------
+// StrCat()
+// -----------------------------------------------------------------------------
+//
+// Merges given strings or numbers, using no delimiter(s), returning the merged
+// result as a string.
+//
+// `StrCat()` is designed to be the fastest possible way to construct a string
+// out of a mix of raw C strings, string_views, strings, bool values,
+// and numeric values.
+//
+// Don't use `StrCat()` for user-visible strings. The localization process
+// works poorly on strings built up out of fragments.
+//
+// For clarity and performance, don't use `StrCat()` when appending to a
+// string. Use `StrAppend()` instead. In particular, avoid using any of these
+// (anti-)patterns:
+//
+//   str.append(StrCat(...))
+//   str += StrCat(...)
+//   str = StrCat(str, ...)
+//
+// The last case is the worst, with a potential to change a loop
+// from a linear time operation with O(1) dynamic allocations into a
+// quadratic time operation with O(n) dynamic allocations.
+//
+// See `StrAppend()` below for more information.
+
+namespace strings_internal {
+
+// Do not call directly - this is not part of the public API.
+std::string CatPieces(std::initializer_list<absl::string_view> pieces);
+void AppendPieces(std::string* dest,
+                  std::initializer_list<absl::string_view> pieces);
+
+}  // namespace strings_internal
+
+ABSL_MUST_USE_RESULT inline std::string StrCat() { return std::string(); }
+
+ABSL_MUST_USE_RESULT inline std::string StrCat(const AlphaNum& a) {
+  return std::string(a.data(), a.size());
+}
+
+ABSL_MUST_USE_RESULT std::string StrCat(const AlphaNum& a, const AlphaNum& b);
+ABSL_MUST_USE_RESULT std::string StrCat(const AlphaNum& a, const AlphaNum& b,
+                                        const AlphaNum& c);
+ABSL_MUST_USE_RESULT std::string StrCat(const AlphaNum& a, const AlphaNum& b,
+                                        const AlphaNum& c, const AlphaNum& d);
+
+// Support 5 or more arguments
+template <typename... AV>
+ABSL_MUST_USE_RESULT inline std::string StrCat(
+    const AlphaNum& a, const AlphaNum& b, const AlphaNum& c, const AlphaNum& d,
+    const AlphaNum& e, const AV&... args) {
+  return strings_internal::CatPieces(
+      {a.Piece(), b.Piece(), c.Piece(), d.Piece(), e.Piece(),
+       static_cast<const AlphaNum&>(args).Piece()...});
+}
+
+// -----------------------------------------------------------------------------
+// StrAppend()
+// -----------------------------------------------------------------------------
+//
+// Appends a string or set of strings to an existing string, in a similar
+// fashion to `StrCat()`.
+//
+// WARNING: `StrAppend(&str, a, b, c, ...)` requires that none of the
+// a, b, c, parameters be a reference into str. For speed, `StrAppend()` does
+// not try to check each of its input arguments to be sure that they are not
+// a subset of the string being appended to. That is, while this will work:
+//
+//   std::string s = "foo";
+//   s += s;
+//
+// This output is undefined:
+//
+//   std::string s = "foo";
+//   StrAppend(&s, s);
+//
+// This output is undefined as well, since `absl::string_view` does not own its
+// data:
+//
+//   std::string s = "foobar";
+//   absl::string_view p = s;
+//   StrAppend(&s, p);
+
+inline void StrAppend(std::string*) {}
+void StrAppend(std::string* dest, const AlphaNum& a);
+void StrAppend(std::string* dest, const AlphaNum& a, const AlphaNum& b);
+void StrAppend(std::string* dest, const AlphaNum& a, const AlphaNum& b,
+               const AlphaNum& c);
+void StrAppend(std::string* dest, const AlphaNum& a, const AlphaNum& b,
+               const AlphaNum& c, const AlphaNum& d);
+
+// Support 5 or more arguments
+template <typename... AV>
+inline void StrAppend(std::string* dest, const AlphaNum& a, const AlphaNum& b,
+                      const AlphaNum& c, const AlphaNum& d, const AlphaNum& e,
+                      const AV&... args) {
+  strings_internal::AppendPieces(
+      dest, {a.Piece(), b.Piece(), c.Piece(), d.Piece(), e.Piece(),
+             static_cast<const AlphaNum&>(args).Piece()...});
+}
+
+// Helper function for the future StrCat default floating-point format, %.6g
+// This is fast.
+inline strings_internal::AlphaNumBuffer<
+    numbers_internal::kSixDigitsToBufferSize>
+SixDigits(double d) {
+  strings_internal::AlphaNumBuffer<numbers_internal::kSixDigitsToBufferSize>
+      result;
+  result.size = numbers_internal::SixDigitsToBuffer(d, &result.data[0]);
+  return result;
+}
+
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#endif  // ABSL_STRINGS_STR_CAT_H_
diff --git a/src/absl/strings/str_format.h b/src/absl/strings/str_format.h
new file mode 100644 (file)
index 0000000..0146510
--- /dev/null
@@ -0,0 +1,813 @@
+//
+// Copyright 2018 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// -----------------------------------------------------------------------------
+// File: str_format.h
+// -----------------------------------------------------------------------------
+//
+// The `str_format` library is a typesafe replacement for the family of
+// `printf()` string formatting routines within the `<cstdio>` standard library
+// header. Like the `printf` family, `str_format` uses a "format string" to
+// perform argument substitutions based on types. See the `FormatSpec` section
+// below for format string documentation.
+//
+// Example:
+//
+//   std::string s = absl::StrFormat(
+//                      "%s %s You have $%d!", "Hello", name, dollars);
+//
+// The library consists of the following basic utilities:
+//
+//   * `absl::StrFormat()`, a type-safe replacement for `std::sprintf()`, to
+//     write a format string to a `string` value.
+//   * `absl::StrAppendFormat()` to append a format string to a `string`
+//   * `absl::StreamFormat()` to more efficiently write a format string to a
+//     stream, such as`std::cout`.
+//   * `absl::PrintF()`, `absl::FPrintF()` and `absl::SNPrintF()` as
+//     replacements for `std::printf()`, `std::fprintf()` and `std::snprintf()`.
+//
+//     Note: a version of `std::sprintf()` is not supported as it is
+//     generally unsafe due to buffer overflows.
+//
+// Additionally, you can provide a format string (and its associated arguments)
+// using one of the following abstractions:
+//
+//   * A `FormatSpec` class template fully encapsulates a format string and its
+//     type arguments and is usually provided to `str_format` functions as a
+//     variadic argument of type `FormatSpec<Arg...>`. The `FormatSpec<Args...>`
+//     template is evaluated at compile-time, providing type safety.
+//   * A `ParsedFormat` instance, which encapsulates a specific, pre-compiled
+//     format string for a specific set of type(s), and which can be passed
+//     between API boundaries. (The `FormatSpec` type should not be used
+//     directly except as an argument type for wrapper functions.)
+//
+// The `str_format` library provides the ability to output its format strings to
+// arbitrary sink types:
+//
+//   * A generic `Format()` function to write outputs to arbitrary sink types,
+//     which must implement a `FormatRawSink` interface.
+//
+//   * A `FormatUntyped()` function that is similar to `Format()` except it is
+//     loosely typed. `FormatUntyped()` is not a template and does not perform
+//     any compile-time checking of the format string; instead, it returns a
+//     boolean from a runtime check.
+//
+// In addition, the `str_format` library provides extension points for
+// augmenting formatting to new types.  See "StrFormat Extensions" below.
+
+#ifndef ABSL_STRINGS_STR_FORMAT_H_
+#define ABSL_STRINGS_STR_FORMAT_H_
+
+#include <cstdio>
+#include <string>
+
+#include "absl/strings/internal/str_format/arg.h"  // IWYU pragma: export
+#include "absl/strings/internal/str_format/bind.h"  // IWYU pragma: export
+#include "absl/strings/internal/str_format/checker.h"  // IWYU pragma: export
+#include "absl/strings/internal/str_format/extension.h"  // IWYU pragma: export
+#include "absl/strings/internal/str_format/parser.h"  // IWYU pragma: export
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+
+// UntypedFormatSpec
+//
+// A type-erased class that can be used directly within untyped API entry
+// points. An `UntypedFormatSpec` is specifically used as an argument to
+// `FormatUntyped()`.
+//
+// Example:
+//
+//   absl::UntypedFormatSpec format("%d");
+//   std::string out;
+//   CHECK(absl::FormatUntyped(&out, format, {absl::FormatArg(1)}));
+class UntypedFormatSpec {
+ public:
+  UntypedFormatSpec() = delete;
+  UntypedFormatSpec(const UntypedFormatSpec&) = delete;
+  UntypedFormatSpec& operator=(const UntypedFormatSpec&) = delete;
+
+  explicit UntypedFormatSpec(string_view s) : spec_(s) {}
+
+ protected:
+  explicit UntypedFormatSpec(const str_format_internal::ParsedFormatBase* pc)
+      : spec_(pc) {}
+
+ private:
+  friend str_format_internal::UntypedFormatSpecImpl;
+  str_format_internal::UntypedFormatSpecImpl spec_;
+};
+
+// FormatStreamed()
+//
+// Takes a streamable argument and returns an object that can print it
+// with '%s'. Allows printing of types that have an `operator<<` but no
+// intrinsic type support within `StrFormat()` itself.
+//
+// Example:
+//
+//   absl::StrFormat("%s", absl::FormatStreamed(obj));
+template <typename T>
+str_format_internal::StreamedWrapper<T> FormatStreamed(const T& v) {
+  return str_format_internal::StreamedWrapper<T>(v);
+}
+
+// FormatCountCapture
+//
+// This class provides a way to safely wrap `StrFormat()` captures of `%n`
+// conversions, which denote the number of characters written by a formatting
+// operation to this point, into an integer value.
+//
+// This wrapper is designed to allow safe usage of `%n` within `StrFormat(); in
+// the `printf()` family of functions, `%n` is not safe to use, as the `int *`
+// buffer can be used to capture arbitrary data.
+//
+// Example:
+//
+//   int n = 0;
+//   std::string s = absl::StrFormat("%s%d%n", "hello", 123,
+//                       absl::FormatCountCapture(&n));
+//   EXPECT_EQ(8, n);
+class FormatCountCapture {
+ public:
+  explicit FormatCountCapture(int* p) : p_(p) {}
+
+ private:
+  // FormatCountCaptureHelper is used to define FormatConvertImpl() for this
+  // class.
+  friend struct str_format_internal::FormatCountCaptureHelper;
+  // Unused() is here because of the false positive from -Wunused-private-field
+  // p_ is used in the templated function of the friend FormatCountCaptureHelper
+  // class.
+  int* Unused() { return p_; }
+  int* p_;
+};
+
+// FormatSpec
+//
+// The `FormatSpec` type defines the makeup of a format string within the
+// `str_format` library. It is a variadic class template that is evaluated at
+// compile-time, according to the format string and arguments that are passed to
+// it.
+//
+// You should not need to manipulate this type directly. You should only name it
+// if you are writing wrapper functions which accept format arguments that will
+// be provided unmodified to functions in this library. Such a wrapper function
+// might be a class method that provides format arguments and/or internally uses
+// the result of formatting.
+//
+// For a `FormatSpec` to be valid at compile-time, it must be provided as
+// either:
+//
+// * A `constexpr` literal or `absl::string_view`, which is how it most often
+//   used.
+// * A `ParsedFormat` instantiation, which ensures the format string is
+//   valid before use. (See below.)
+//
+// Example:
+//
+//   // Provided as a string literal.
+//   absl::StrFormat("Welcome to %s, Number %d!", "The Village", 6);
+//
+//   // Provided as a constexpr absl::string_view.
+//   constexpr absl::string_view formatString = "Welcome to %s, Number %d!";
+//   absl::StrFormat(formatString, "The Village", 6);
+//
+//   // Provided as a pre-compiled ParsedFormat object.
+//   // Note that this example is useful only for illustration purposes.
+//   absl::ParsedFormat<'s', 'd'> formatString("Welcome to %s, Number %d!");
+//   absl::StrFormat(formatString, "TheVillage", 6);
+//
+// A format string generally follows the POSIX syntax as used within the POSIX
+// `printf` specification.
+//
+// (See http://pubs.opengroup.org/onlinepubs/9699919799/functions/fprintf.html.)
+//
+// In specific, the `FormatSpec` supports the following type specifiers:
+//   * `c` for characters
+//   * `s` for strings
+//   * `d` or `i` for integers
+//   * `o` for unsigned integer conversions into octal
+//   * `x` or `X` for unsigned integer conversions into hex
+//   * `u` for unsigned integers
+//   * `f` or `F` for floating point values into decimal notation
+//   * `e` or `E` for floating point values into exponential notation
+//   * `a` or `A` for floating point values into hex exponential notation
+//   * `g` or `G` for floating point values into decimal or exponential
+//     notation based on their precision
+//   * `p` for pointer address values
+//   * `n` for the special case of writing out the number of characters
+//     written to this point. The resulting value must be captured within an
+//     `absl::FormatCountCapture` type.
+//
+// Implementation-defined behavior:
+//   * A null pointer provided to "%s" or "%p" is output as "(nil)".
+//   * A non-null pointer provided to "%p" is output in hex as if by %#x or
+//     %#lx.
+//
+// NOTE: `o`, `x\X` and `u` will convert signed values to their unsigned
+// counterpart before formatting.
+//
+// Examples:
+//     "%c", 'a'                -> "a"
+//     "%c", 32                 -> " "
+//     "%s", "C"                -> "C"
+//     "%s", std::string("C++") -> "C++"
+//     "%d", -10                -> "-10"
+//     "%o", 10                 -> "12"
+//     "%x", 16                 -> "10"
+//     "%f", 123456789          -> "123456789.000000"
+//     "%e", .01                -> "1.00000e-2"
+//     "%a", -3.0               -> "-0x1.8p+1"
+//     "%g", .01                -> "1e-2"
+//     "%p", (void*)&value      -> "0x7ffdeb6ad2a4"
+//
+//     int n = 0;
+//     std::string s = absl::StrFormat(
+//         "%s%d%n", "hello", 123, absl::FormatCountCapture(&n));
+//     EXPECT_EQ(8, n);
+//
+// The `FormatSpec` intrinsically supports all of these fundamental C++ types:
+//
+// *   Characters: `char`, `signed char`, `unsigned char`
+// *   Integers: `int`, `short`, `unsigned short`, `unsigned`, `long`,
+//         `unsigned long`, `long long`, `unsigned long long`
+// *   Floating-point: `float`, `double`, `long double`
+//
+// However, in the `str_format` library, a format conversion specifies a broader
+// C++ conceptual category instead of an exact type. For example, `%s` binds to
+// any string-like argument, so `std::string`, `absl::string_view`, and
+// `const char*` are all accepted. Likewise, `%d` accepts any integer-like
+// argument, etc.
+
+template <typename... Args>
+using FormatSpec = str_format_internal::FormatSpecTemplate<
+    str_format_internal::ArgumentToConv<Args>()...>;
+
+// ParsedFormat
+//
+// A `ParsedFormat` is a class template representing a preparsed `FormatSpec`,
+// with template arguments specifying the conversion characters used within the
+// format string. Such characters must be valid format type specifiers, and
+// these type specifiers are checked at compile-time.
+//
+// Instances of `ParsedFormat` can be created, copied, and reused to speed up
+// formatting loops. A `ParsedFormat` may either be constructed statically, or
+// dynamically through its `New()` factory function, which only constructs a
+// runtime object if the format is valid at that time.
+//
+// Example:
+//
+//   // Verified at compile time.
+//   absl::ParsedFormat<'s', 'd'> formatString("Welcome to %s, Number %d!");
+//   absl::StrFormat(formatString, "TheVillage", 6);
+//
+//   // Verified at runtime.
+//   auto format_runtime = absl::ParsedFormat<'d'>::New(format_string);
+//   if (format_runtime) {
+//     value = absl::StrFormat(*format_runtime, i);
+//   } else {
+//     ... error case ...
+//   }
+
+#if defined(__cpp_nontype_template_parameter_auto)
+// If C++17 is available, an 'extended' format is also allowed that can specify
+// multiple conversion characters per format argument, using a combination of
+// `absl::FormatConversionCharSet` enum values (logically a set union)
+//  via the `|` operator. (Single character-based arguments are still accepted,
+// but cannot be combined). Some common conversions also have predefined enum
+// values, such as `absl::FormatConversionCharSet::kIntegral`.
+//
+// Example:
+//   // Extended format supports multiple conversion characters per argument,
+//   // specified via a combination of `FormatConversionCharSet` enums.
+//   using MyFormat = absl::ParsedFormat<absl::FormatConversionCharSet::d |
+//                                       absl::FormatConversionCharSet::x>;
+//   MyFormat GetFormat(bool use_hex) {
+//     if (use_hex) return MyFormat("foo %x bar");
+//     return MyFormat("foo %d bar");
+//   }
+//   // `format` can be used with any value that supports 'd' and 'x',
+//   // like `int`.
+//   auto format = GetFormat(use_hex);
+//   value = StringF(format, i);
+template <auto... Conv>
+using ParsedFormat = absl::str_format_internal::ExtendedParsedFormat<
+    absl::str_format_internal::ToFormatConversionCharSet(Conv)...>;
+#else
+template <char... Conv>
+using ParsedFormat = str_format_internal::ExtendedParsedFormat<
+    absl::str_format_internal::ToFormatConversionCharSet(Conv)...>;
+#endif  // defined(__cpp_nontype_template_parameter_auto)
+
+// StrFormat()
+//
+// Returns a `string` given a `printf()`-style format string and zero or more
+// additional arguments. Use it as you would `sprintf()`. `StrFormat()` is the
+// primary formatting function within the `str_format` library, and should be
+// used in most cases where you need type-safe conversion of types into
+// formatted strings.
+//
+// The format string generally consists of ordinary character data along with
+// one or more format conversion specifiers (denoted by the `%` character).
+// Ordinary character data is returned unchanged into the result string, while
+// each conversion specification performs a type substitution from
+// `StrFormat()`'s other arguments. See the comments for `FormatSpec` for full
+// information on the makeup of this format string.
+//
+// Example:
+//
+//   std::string s = absl::StrFormat(
+//       "Welcome to %s, Number %d!", "The Village", 6);
+//   EXPECT_EQ("Welcome to The Village, Number 6!", s);
+//
+// Returns an empty string in case of error.
+template <typename... Args>
+ABSL_MUST_USE_RESULT std::string StrFormat(const FormatSpec<Args...>& format,
+                                           const Args&... args) {
+  return str_format_internal::FormatPack(
+      str_format_internal::UntypedFormatSpecImpl::Extract(format),
+      {str_format_internal::FormatArgImpl(args)...});
+}
+
+// StrAppendFormat()
+//
+// Appends to a `dst` string given a format string, and zero or more additional
+// arguments, returning `*dst` as a convenience for chaining purposes. Appends
+// nothing in case of error (but possibly alters its capacity).
+//
+// Example:
+//
+//   std::string orig("For example PI is approximately ");
+//   std::cout << StrAppendFormat(&orig, "%12.6f", 3.14);
+template <typename... Args>
+std::string& StrAppendFormat(std::string* dst,
+                             const FormatSpec<Args...>& format,
+                             const Args&... args) {
+  return str_format_internal::AppendPack(
+      dst, str_format_internal::UntypedFormatSpecImpl::Extract(format),
+      {str_format_internal::FormatArgImpl(args)...});
+}
+
+// StreamFormat()
+//
+// Writes to an output stream given a format string and zero or more arguments,
+// generally in a manner that is more efficient than streaming the result of
+// `absl:: StrFormat()`. The returned object must be streamed before the full
+// expression ends.
+//
+// Example:
+//
+//   std::cout << StreamFormat("%12.6f", 3.14);
+template <typename... Args>
+ABSL_MUST_USE_RESULT str_format_internal::Streamable StreamFormat(
+    const FormatSpec<Args...>& format, const Args&... args) {
+  return str_format_internal::Streamable(
+      str_format_internal::UntypedFormatSpecImpl::Extract(format),
+      {str_format_internal::FormatArgImpl(args)...});
+}
+
+// PrintF()
+//
+// Writes to stdout given a format string and zero or more arguments. This
+// function is functionally equivalent to `std::printf()` (and type-safe);
+// prefer `absl::PrintF()` over `std::printf()`.
+//
+// Example:
+//
+//   std::string_view s = "Ulaanbaatar";
+//   absl::PrintF("The capital of Mongolia is %s", s);
+//
+//   Outputs: "The capital of Mongolia is Ulaanbaatar"
+//
+template <typename... Args>
+int PrintF(const FormatSpec<Args...>& format, const Args&... args) {
+  return str_format_internal::FprintF(
+      stdout, str_format_internal::UntypedFormatSpecImpl::Extract(format),
+      {str_format_internal::FormatArgImpl(args)...});
+}
+
+// FPrintF()
+//
+// Writes to a file given a format string and zero or more arguments. This
+// function is functionally equivalent to `std::fprintf()` (and type-safe);
+// prefer `absl::FPrintF()` over `std::fprintf()`.
+//
+// Example:
+//
+//   std::string_view s = "Ulaanbaatar";
+//   absl::FPrintF(stdout, "The capital of Mongolia is %s", s);
+//
+//   Outputs: "The capital of Mongolia is Ulaanbaatar"
+//
+template <typename... Args>
+int FPrintF(std::FILE* output, const FormatSpec<Args...>& format,
+            const Args&... args) {
+  return str_format_internal::FprintF(
+      output, str_format_internal::UntypedFormatSpecImpl::Extract(format),
+      {str_format_internal::FormatArgImpl(args)...});
+}
+
+// SNPrintF()
+//
+// Writes to a sized buffer given a format string and zero or more arguments.
+// This function is functionally equivalent to `std::snprintf()` (and
+// type-safe); prefer `absl::SNPrintF()` over `std::snprintf()`.
+//
+// In particular, a successful call to `absl::SNPrintF()` writes at most `size`
+// bytes of the formatted output to `output`, including a NUL-terminator, and
+// returns the number of bytes that would have been written if truncation did
+// not occur. In the event of an error, a negative value is returned and `errno`
+// is set.
+//
+// Example:
+//
+//   std::string_view s = "Ulaanbaatar";
+//   char output[128];
+//   absl::SNPrintF(output, sizeof(output),
+//                  "The capital of Mongolia is %s", s);
+//
+//   Post-condition: output == "The capital of Mongolia is Ulaanbaatar"
+//
+template <typename... Args>
+int SNPrintF(char* output, std::size_t size, const FormatSpec<Args...>& format,
+             const Args&... args) {
+  return str_format_internal::SnprintF(
+      output, size, str_format_internal::UntypedFormatSpecImpl::Extract(format),
+      {str_format_internal::FormatArgImpl(args)...});
+}
+
+// -----------------------------------------------------------------------------
+// Custom Output Formatting Functions
+// -----------------------------------------------------------------------------
+
+// FormatRawSink
+//
+// FormatRawSink is a type erased wrapper around arbitrary sink objects
+// specifically used as an argument to `Format()`.
+//
+// All the object has to do define an overload of `AbslFormatFlush()` for the
+// sink, usually by adding a ADL-based free function in the same namespace as
+// the sink:
+//
+//   void AbslFormatFlush(MySink* dest, absl::string_view part);
+//
+// where `dest` is the pointer passed to `absl::Format()`. The function should
+// append `part` to `dest`.
+//
+// FormatRawSink does not own the passed sink object. The passed object must
+// outlive the FormatRawSink.
+class FormatRawSink {
+ public:
+  // Implicitly convert from any type that provides the hook function as
+  // described above.
+  template <typename T,
+            typename = typename std::enable_if<std::is_constructible<
+                str_format_internal::FormatRawSinkImpl, T*>::value>::type>
+  FormatRawSink(T* raw)  // NOLINT
+      : sink_(raw) {}
+
+ private:
+  friend str_format_internal::FormatRawSinkImpl;
+  str_format_internal::FormatRawSinkImpl sink_;
+};
+
+// Format()
+//
+// Writes a formatted string to an arbitrary sink object (implementing the
+// `absl::FormatRawSink` interface), using a format string and zero or more
+// additional arguments.
+//
+// By default, `std::string`, `std::ostream`, and `absl::Cord` are supported as
+// destination objects. If a `std::string` is used the formatted string is
+// appended to it.
+//
+// `absl::Format()` is a generic version of `absl::StrAppendFormat()`, for
+// custom sinks. The format string, like format strings for `StrFormat()`, is
+// checked at compile-time.
+//
+// On failure, this function returns `false` and the state of the sink is
+// unspecified.
+template <typename... Args>
+bool Format(FormatRawSink raw_sink, const FormatSpec<Args...>& format,
+            const Args&... args) {
+  return str_format_internal::FormatUntyped(
+      str_format_internal::FormatRawSinkImpl::Extract(raw_sink),
+      str_format_internal::UntypedFormatSpecImpl::Extract(format),
+      {str_format_internal::FormatArgImpl(args)...});
+}
+
+// FormatArg
+//
+// A type-erased handle to a format argument specifically used as an argument to
+// `FormatUntyped()`. You may construct `FormatArg` by passing
+// reference-to-const of any printable type. `FormatArg` is both copyable and
+// assignable. The source data must outlive the `FormatArg` instance. See
+// example below.
+//
+using FormatArg = str_format_internal::FormatArgImpl;
+
+// FormatUntyped()
+//
+// Writes a formatted string to an arbitrary sink object (implementing the
+// `absl::FormatRawSink` interface), using an `UntypedFormatSpec` and zero or
+// more additional arguments.
+//
+// This function acts as the most generic formatting function in the
+// `str_format` library. The caller provides a raw sink, an unchecked format
+// string, and (usually) a runtime specified list of arguments; no compile-time
+// checking of formatting is performed within this function. As a result, a
+// caller should check the return value to verify that no error occurred.
+// On failure, this function returns `false` and the state of the sink is
+// unspecified.
+//
+// The arguments are provided in an `absl::Span<const absl::FormatArg>`.
+// Each `absl::FormatArg` object binds to a single argument and keeps a
+// reference to it. The values used to create the `FormatArg` objects must
+// outlive this function call. (See `str_format_arg.h` for information on
+// the `FormatArg` class.)_
+//
+// Example:
+//
+//   std::optional<std::string> FormatDynamic(
+//       const std::string& in_format,
+//       const vector<std::string>& in_args) {
+//     std::string out;
+//     std::vector<absl::FormatArg> args;
+//     for (const auto& v : in_args) {
+//       // It is important that 'v' is a reference to the objects in in_args.
+//       // The values we pass to FormatArg must outlive the call to
+//       // FormatUntyped.
+//       args.emplace_back(v);
+//     }
+//     absl::UntypedFormatSpec format(in_format);
+//     if (!absl::FormatUntyped(&out, format, args)) {
+//       return std::nullopt;
+//     }
+//     return std::move(out);
+//   }
+//
+ABSL_MUST_USE_RESULT inline bool FormatUntyped(
+    FormatRawSink raw_sink, const UntypedFormatSpec& format,
+    absl::Span<const FormatArg> args) {
+  return str_format_internal::FormatUntyped(
+      str_format_internal::FormatRawSinkImpl::Extract(raw_sink),
+      str_format_internal::UntypedFormatSpecImpl::Extract(format), args);
+}
+
+//------------------------------------------------------------------------------
+// StrFormat Extensions
+//------------------------------------------------------------------------------
+//
+// AbslFormatConvert()
+//
+// The StrFormat library provides a customization API for formatting
+// user-defined types using absl::StrFormat(). The API relies on detecting an
+// overload in the user-defined type's namespace of a free (non-member)
+// `AbslFormatConvert()` function, usually as a friend definition with the
+// following signature:
+//
+// absl::FormatConvertResult<...> AbslFormatConvert(
+//     const X& value,
+//     const absl::FormatConversionSpec& spec,
+//     absl::FormatSink *sink);
+//
+// An `AbslFormatConvert()` overload for a type should only be declared in the
+// same file and namespace as said type.
+//
+// The abstractions within this definition include:
+//
+// * An `absl::FormatConversionSpec` to specify the fields to pull from a
+//   user-defined type's format string
+// * An `absl::FormatSink` to hold the converted string data during the
+//   conversion process.
+// * An `absl::FormatConvertResult` to hold the status of the returned
+//   formatting operation
+//
+// The return type encodes all the conversion characters that your
+// AbslFormatConvert() routine accepts.  The return value should be {true}.
+// A return value of {false} will result in `StrFormat()` returning
+// an empty string.  This result will be propagated to the result of
+// `FormatUntyped`.
+//
+// Example:
+//
+// struct Point {
+//   // To add formatting support to `Point`, we simply need to add a free
+//   // (non-member) function `AbslFormatConvert()`.  This method interprets
+//   // `spec` to print in the request format. The allowed conversion characters
+//   // can be restricted via the type of the result, in this example
+//   // string and integral formatting are allowed (but not, for instance
+//   // floating point characters like "%f").  You can add such a free function
+//   // using a friend declaration within the body of the class:
+//   friend absl::FormatConvertResult<absl::FormatConversionCharSet::kString |
+//                                    absl::FormatConversionCharSet::kIntegral>
+//   AbslFormatConvert(const Point& p, const absl::FormatConversionSpec& spec,
+//                     absl::FormatSink* s) {
+//     if (spec.conversion_char() == absl::FormatConversionChar::s) {
+//       s->Append(absl::StrCat("x=", p.x, " y=", p.y));
+//     } else {
+//       s->Append(absl::StrCat(p.x, ",", p.y));
+//     }
+//     return {true};
+//   }
+//
+//   int x;
+//   int y;
+// };
+
+// clang-format off
+
+// FormatConversionChar
+//
+// Specifies the formatting character provided in the format string
+// passed to `StrFormat()`.
+enum class FormatConversionChar : uint8_t {
+  c, s,                    // text
+  d, i, o, u, x, X,        // int
+  f, F, e, E, g, G, a, A,  // float
+  n, p                     // misc
+};
+// clang-format on
+
+// FormatConversionSpec
+//
+// Specifies modifications to the conversion of the format string, through use
+// of one or more format flags in the source format string.
+class FormatConversionSpec {
+ public:
+  // FormatConversionSpec::is_basic()
+  //
+  // Indicates that width and precision are not specified, and no additional
+  // flags are set for this conversion character in the format string.
+  bool is_basic() const { return impl_.is_basic(); }
+
+  // FormatConversionSpec::has_left_flag()
+  //
+  // Indicates whether the result should be left justified for this conversion
+  // character in the format string. This flag is set through use of a '-'
+  // character in the format string. E.g. "%-s"
+  bool has_left_flag() const { return impl_.has_left_flag(); }
+
+  // FormatConversionSpec::has_show_pos_flag()
+  //
+  // Indicates whether a sign column is prepended to the result for this
+  // conversion character in the format string, even if the result is positive.
+  // This flag is set through use of a '+' character in the format string.
+  // E.g. "%+d"
+  bool has_show_pos_flag() const { return impl_.has_show_pos_flag(); }
+
+  // FormatConversionSpec::has_sign_col_flag()
+  //
+  // Indicates whether a mandatory sign column is added to the result for this
+  // conversion character. This flag is set through use of a space character
+  // (' ') in the format string. E.g. "% i"
+  bool has_sign_col_flag() const { return impl_.has_sign_col_flag(); }
+
+  // FormatConversionSpec::has_alt_flag()
+  //
+  // Indicates whether an "alternate" format is applied to the result for this
+  // conversion character. Alternative forms depend on the type of conversion
+  // character, and unallowed alternatives are undefined. This flag is set
+  // through use of a '#' character in the format string. E.g. "%#h"
+  bool has_alt_flag() const { return impl_.has_alt_flag(); }
+
+  // FormatConversionSpec::has_zero_flag()
+  //
+  // Indicates whether zeroes should be prepended to the result for this
+  // conversion character instead of spaces. This flag is set through use of the
+  // '0' character in the format string. E.g. "%0f"
+  bool has_zero_flag() const { return impl_.has_zero_flag(); }
+
+  // FormatConversionSpec::conversion_char()
+  //
+  // Returns the underlying conversion character.
+  FormatConversionChar conversion_char() const {
+    return impl_.conversion_char();
+  }
+
+  // FormatConversionSpec::width()
+  //
+  // Returns the specified width (indicated through use of a non-zero integer
+  // value or '*' character) of the conversion character. If width is
+  // unspecified, it returns a negative value.
+  int width() const { return impl_.width(); }
+
+  // FormatConversionSpec::precision()
+  //
+  // Returns the specified precision (through use of the '.' character followed
+  // by a non-zero integer value or '*' character) of the conversion character.
+  // If precision is unspecified, it returns a negative value.
+  int precision() const { return impl_.precision(); }
+
+ private:
+  explicit FormatConversionSpec(
+      str_format_internal::FormatConversionSpecImpl impl)
+      : impl_(impl) {}
+
+  friend str_format_internal::FormatConversionSpecImpl;
+
+  absl::str_format_internal::FormatConversionSpecImpl impl_;
+};
+
+// Type safe OR operator for FormatConversionCharSet to allow accepting multiple
+// conversion chars in custom format converters.
+constexpr FormatConversionCharSet operator|(FormatConversionCharSet a,
+                                            FormatConversionCharSet b) {
+  return static_cast<FormatConversionCharSet>(static_cast<uint64_t>(a) |
+                                              static_cast<uint64_t>(b));
+}
+
+// FormatConversionCharSet
+//
+// Specifies the _accepted_ conversion types as a template parameter to
+// FormatConvertResult for custom implementations of `AbslFormatConvert`.
+// Note the helper predefined alias definitions (kIntegral, etc.) below.
+enum class FormatConversionCharSet : uint64_t {
+  // text
+  c = str_format_internal::FormatConversionCharToConvInt('c'),
+  s = str_format_internal::FormatConversionCharToConvInt('s'),
+  // integer
+  d = str_format_internal::FormatConversionCharToConvInt('d'),
+  i = str_format_internal::FormatConversionCharToConvInt('i'),
+  o = str_format_internal::FormatConversionCharToConvInt('o'),
+  u = str_format_internal::FormatConversionCharToConvInt('u'),
+  x = str_format_internal::FormatConversionCharToConvInt('x'),
+  X = str_format_internal::FormatConversionCharToConvInt('X'),
+  // Float
+  f = str_format_internal::FormatConversionCharToConvInt('f'),
+  F = str_format_internal::FormatConversionCharToConvInt('F'),
+  e = str_format_internal::FormatConversionCharToConvInt('e'),
+  E = str_format_internal::FormatConversionCharToConvInt('E'),
+  g = str_format_internal::FormatConversionCharToConvInt('g'),
+  G = str_format_internal::FormatConversionCharToConvInt('G'),
+  a = str_format_internal::FormatConversionCharToConvInt('a'),
+  A = str_format_internal::FormatConversionCharToConvInt('A'),
+  // misc
+  n = str_format_internal::FormatConversionCharToConvInt('n'),
+  p = str_format_internal::FormatConversionCharToConvInt('p'),
+
+  // Used for width/precision '*' specification.
+  kStar = static_cast<uint64_t>(
+      absl::str_format_internal::FormatConversionCharSetInternal::kStar),
+  // Some predefined values:
+  kIntegral = d | i | u | o | x | X,
+  kFloating = a | e | f | g | A | E | F | G,
+  kNumeric = kIntegral | kFloating,
+  kString = s,
+  kPointer = p,
+};
+
+// FormatSink
+//
+// An abstraction to which conversions write their string data.
+//
+class FormatSink {
+ public:
+  // Appends `count` copies of `ch`.
+  void Append(size_t count, char ch) { sink_->Append(count, ch); }
+
+  void Append(string_view v) { sink_->Append(v); }
+
+  // Appends the first `precision` bytes of `v`. If this is less than
+  // `width`, spaces will be appended first (if `left` is false), or
+  // after (if `left` is true) to ensure the total amount appended is
+  // at least `width`.
+  bool PutPaddedString(string_view v, int width, int precision, bool left) {
+    return sink_->PutPaddedString(v, width, precision, left);
+  }
+
+ private:
+  friend str_format_internal::FormatSinkImpl;
+  explicit FormatSink(str_format_internal::FormatSinkImpl* s) : sink_(s) {}
+  str_format_internal::FormatSinkImpl* sink_;
+};
+
+// FormatConvertResult
+//
+// Indicates whether a call to AbslFormatConvert() was successful.
+// This return type informs the StrFormat extension framework (through
+// ADL but using the return type) of what conversion characters are supported.
+// It is strongly discouraged to return {false}, as this will result in an
+// empty string in StrFormat.
+template <FormatConversionCharSet C>
+struct FormatConvertResult {
+  bool value;
+};
+
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#endif  // ABSL_STRINGS_STR_FORMAT_H_
diff --git a/src/absl/strings/str_join.h b/src/absl/strings/str_join.h
new file mode 100644 (file)
index 0000000..3353453
--- /dev/null
@@ -0,0 +1,293 @@
+//
+// Copyright 2017 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// -----------------------------------------------------------------------------
+// File: str_join.h
+// -----------------------------------------------------------------------------
+//
+// This header file contains functions for joining a range of elements and
+// returning the result as a std::string. StrJoin operations are specified by
+// passing a range, a separator string to use between the elements joined, and
+// an optional Formatter responsible for converting each argument in the range
+// to a string. If omitted, a default `AlphaNumFormatter()` is called on the
+// elements to be joined, using the same formatting that `absl::StrCat()` uses.
+// This package defines a number of default formatters, and you can define your
+// own implementations.
+//
+// Ranges are specified by passing a container with `std::begin()` and
+// `std::end()` iterators, container-specific `begin()` and `end()` iterators, a
+// brace-initialized `std::initializer_list`, or a `std::tuple` of heterogeneous
+// objects. The separator string is specified as an `absl::string_view`.
+//
+// Because the default formatter uses the `absl::AlphaNum` class,
+// `absl::StrJoin()`, like `absl::StrCat()`, will work out-of-the-box on
+// collections of strings, ints, floats, doubles, etc.
+//
+// Example:
+//
+//   std::vector<std::string> v = {"foo", "bar", "baz"};
+//   std::string s = absl::StrJoin(v, "-");
+//   EXPECT_EQ("foo-bar-baz", s);
+//
+// See comments on the `absl::StrJoin()` function for more examples.
+
+#ifndef ABSL_STRINGS_STR_JOIN_H_
+#define ABSL_STRINGS_STR_JOIN_H_
+
+#include <cstdio>
+#include <cstring>
+#include <initializer_list>
+#include <iterator>
+#include <string>
+#include <tuple>
+#include <type_traits>
+#include <utility>
+
+#include "absl/base/macros.h"
+#include "absl/strings/internal/str_join_internal.h"
+#include "absl/strings/string_view.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+
+// -----------------------------------------------------------------------------
+// Concept: Formatter
+// -----------------------------------------------------------------------------
+//
+// A Formatter is a function object that is responsible for formatting its
+// argument as a string and appending it to a given output std::string.
+// Formatters may be implemented as function objects, lambdas, or normal
+// functions. You may provide your own Formatter to enable `absl::StrJoin()` to
+// work with arbitrary types.
+//
+// The following is an example of a custom Formatter that simply uses
+// `std::to_string()` to format an integer as a std::string.
+//
+//   struct MyFormatter {
+//     void operator()(std::string* out, int i) const {
+//       out->append(std::to_string(i));
+//     }
+//   };
+//
+// You would use the above formatter by passing an instance of it as the final
+// argument to `absl::StrJoin()`:
+//
+//   std::vector<int> v = {1, 2, 3, 4};
+//   std::string s = absl::StrJoin(v, "-", MyFormatter());
+//   EXPECT_EQ("1-2-3-4", s);
+//
+// The following standard formatters are provided within this file:
+//
+// - `AlphaNumFormatter()` (the default)
+// - `StreamFormatter()`
+// - `PairFormatter()`
+// - `DereferenceFormatter()`
+
+// AlphaNumFormatter()
+//
+// Default formatter used if none is specified. Uses `absl::AlphaNum` to convert
+// numeric arguments to strings.
+inline strings_internal::AlphaNumFormatterImpl AlphaNumFormatter() {
+  return strings_internal::AlphaNumFormatterImpl();
+}
+
+// StreamFormatter()
+//
+// Formats its argument using the << operator.
+inline strings_internal::StreamFormatterImpl StreamFormatter() {
+  return strings_internal::StreamFormatterImpl();
+}
+
+// Function Template: PairFormatter(Formatter, absl::string_view, Formatter)
+//
+// Formats a `std::pair` by putting a given separator between the pair's
+// `.first` and `.second` members. This formatter allows you to specify
+// custom Formatters for both the first and second member of each pair.
+template <typename FirstFormatter, typename SecondFormatter>
+inline strings_internal::PairFormatterImpl<FirstFormatter, SecondFormatter>
+PairFormatter(FirstFormatter f1, absl::string_view sep, SecondFormatter f2) {
+  return strings_internal::PairFormatterImpl<FirstFormatter, SecondFormatter>(
+      std::move(f1), sep, std::move(f2));
+}
+
+// Function overload of PairFormatter() for using a default
+// `AlphaNumFormatter()` for each Formatter in the pair.
+inline strings_internal::PairFormatterImpl<
+    strings_internal::AlphaNumFormatterImpl,
+    strings_internal::AlphaNumFormatterImpl>
+PairFormatter(absl::string_view sep) {
+  return PairFormatter(AlphaNumFormatter(), sep, AlphaNumFormatter());
+}
+
+// Function Template: DereferenceFormatter(Formatter)
+//
+// Formats its argument by dereferencing it and then applying the given
+// formatter. This formatter is useful for formatting a container of
+// pointer-to-T. This pattern often shows up when joining repeated fields in
+// protocol buffers.
+template <typename Formatter>
+strings_internal::DereferenceFormatterImpl<Formatter> DereferenceFormatter(
+    Formatter&& f) {
+  return strings_internal::DereferenceFormatterImpl<Formatter>(
+      std::forward<Formatter>(f));
+}
+
+// Function overload of `DereferenceFormatter()` for using a default
+// `AlphaNumFormatter()`.
+inline strings_internal::DereferenceFormatterImpl<
+    strings_internal::AlphaNumFormatterImpl>
+DereferenceFormatter() {
+  return strings_internal::DereferenceFormatterImpl<
+      strings_internal::AlphaNumFormatterImpl>(AlphaNumFormatter());
+}
+
+// -----------------------------------------------------------------------------
+// StrJoin()
+// -----------------------------------------------------------------------------
+//
+// Joins a range of elements and returns the result as a std::string.
+// `absl::StrJoin()` takes a range, a separator string to use between the
+// elements joined, and an optional Formatter responsible for converting each
+// argument in the range to a string.
+//
+// If omitted, the default `AlphaNumFormatter()` is called on the elements to be
+// joined.
+//
+// Example 1:
+//   // Joins a collection of strings. This pattern also works with a collection
+//   // of `absl::string_view` or even `const char*`.
+//   std::vector<std::string> v = {"foo", "bar", "baz"};
+//   std::string s = absl::StrJoin(v, "-");
+//   EXPECT_EQ("foo-bar-baz", s);
+//
+// Example 2:
+//   // Joins the values in the given `std::initializer_list<>` specified using
+//   // brace initialization. This pattern also works with an initializer_list
+//   // of ints or `absl::string_view` -- any `AlphaNum`-compatible type.
+//   std::string s = absl::StrJoin({"foo", "bar", "baz"}, "-");
+//   EXPECT_EQ("foo-bar-baz", s);
+//
+// Example 3:
+//   // Joins a collection of ints. This pattern also works with floats,
+//   // doubles, int64s -- any `StrCat()`-compatible type.
+//   std::vector<int> v = {1, 2, 3, -4};
+//   std::string s = absl::StrJoin(v, "-");
+//   EXPECT_EQ("1-2-3--4", s);
+//
+// Example 4:
+//   // Joins a collection of pointer-to-int. By default, pointers are
+//   // dereferenced and the pointee is formatted using the default format for
+//   // that type; such dereferencing occurs for all levels of indirection, so
+//   // this pattern works just as well for `std::vector<int**>` as for
+//   // `std::vector<int*>`.
+//   int x = 1, y = 2, z = 3;
+//   std::vector<int*> v = {&x, &y, &z};
+//   std::string s = absl::StrJoin(v, "-");
+//   EXPECT_EQ("1-2-3", s);
+//
+// Example 5:
+//   // Dereferencing of `std::unique_ptr<>` is also supported:
+//   std::vector<std::unique_ptr<int>> v
+//   v.emplace_back(new int(1));
+//   v.emplace_back(new int(2));
+//   v.emplace_back(new int(3));
+//   std::string s = absl::StrJoin(v, "-");
+//   EXPECT_EQ("1-2-3", s);
+//
+// Example 6:
+//   // Joins a `std::map`, with each key-value pair separated by an equals
+//   // sign. This pattern would also work with, say, a
+//   // `std::vector<std::pair<>>`.
+//   std::map<std::string, int> m = {
+//       std::make_pair("a", 1),
+//       std::make_pair("b", 2),
+//       std::make_pair("c", 3)};
+//   std::string s = absl::StrJoin(m, ",", absl::PairFormatter("="));
+//   EXPECT_EQ("a=1,b=2,c=3", s);
+//
+// Example 7:
+//   // These examples show how `absl::StrJoin()` handles a few common edge
+//   // cases:
+//   std::vector<std::string> v_empty;
+//   EXPECT_EQ("", absl::StrJoin(v_empty, "-"));
+//
+//   std::vector<std::string> v_one_item = {"foo"};
+//   EXPECT_EQ("foo", absl::StrJoin(v_one_item, "-"));
+//
+//   std::vector<std::string> v_empty_string = {""};
+//   EXPECT_EQ("", absl::StrJoin(v_empty_string, "-"));
+//
+//   std::vector<std::string> v_one_item_empty_string = {"a", ""};
+//   EXPECT_EQ("a-", absl::StrJoin(v_one_item_empty_string, "-"));
+//
+//   std::vector<std::string> v_two_empty_string = {"", ""};
+//   EXPECT_EQ("-", absl::StrJoin(v_two_empty_string, "-"));
+//
+// Example 8:
+//   // Joins a `std::tuple<T...>` of heterogeneous types, converting each to
+//   // a std::string using the `absl::AlphaNum` class.
+//   std::string s = absl::StrJoin(std::make_tuple(123, "abc", 0.456), "-");
+//   EXPECT_EQ("123-abc-0.456", s);
+
+template <typename Iterator, typename Formatter>
+std::string StrJoin(Iterator start, Iterator end, absl::string_view sep,
+                    Formatter&& fmt) {
+  return strings_internal::JoinAlgorithm(start, end, sep, fmt);
+}
+
+template <typename Range, typename Formatter>
+std::string StrJoin(const Range& range, absl::string_view separator,
+                    Formatter&& fmt) {
+  return strings_internal::JoinRange(range, separator, fmt);
+}
+
+template <typename T, typename Formatter>
+std::string StrJoin(std::initializer_list<T> il, absl::string_view separator,
+                    Formatter&& fmt) {
+  return strings_internal::JoinRange(il, separator, fmt);
+}
+
+template <typename... T, typename Formatter>
+std::string StrJoin(const std::tuple<T...>& value, absl::string_view separator,
+                    Formatter&& fmt) {
+  return strings_internal::JoinAlgorithm(value, separator, fmt);
+}
+
+template <typename Iterator>
+std::string StrJoin(Iterator start, Iterator end, absl::string_view separator) {
+  return strings_internal::JoinRange(start, end, separator);
+}
+
+template <typename Range>
+std::string StrJoin(const Range& range, absl::string_view separator) {
+  return strings_internal::JoinRange(range, separator);
+}
+
+template <typename T>
+std::string StrJoin(std::initializer_list<T> il,
+                    absl::string_view separator) {
+  return strings_internal::JoinRange(il, separator);
+}
+
+template <typename... T>
+std::string StrJoin(const std::tuple<T...>& value,
+                    absl::string_view separator) {
+  return strings_internal::JoinAlgorithm(value, separator, AlphaNumFormatter());
+}
+
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#endif  // ABSL_STRINGS_STR_JOIN_H_
diff --git a/src/absl/strings/str_replace.cc b/src/absl/strings/str_replace.cc
new file mode 100644 (file)
index 0000000..2bd5fa9
--- /dev/null
@@ -0,0 +1,82 @@
+// Copyright 2017 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "absl/strings/str_replace.h"
+
+#include "absl/strings/str_cat.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace strings_internal {
+
+using FixedMapping =
+    std::initializer_list<std::pair<absl::string_view, absl::string_view>>;
+
+// Applies the ViableSubstitutions in subs_ptr to the absl::string_view s, and
+// stores the result in *result_ptr. Returns the number of substitutions that
+// occurred.
+int ApplySubstitutions(
+    absl::string_view s,
+    std::vector<strings_internal::ViableSubstitution>* subs_ptr,
+    std::string* result_ptr) {
+  auto& subs = *subs_ptr;
+  int substitutions = 0;
+  size_t pos = 0;
+  while (!subs.empty()) {
+    auto& sub = subs.back();
+    if (sub.offset >= pos) {
+      if (pos <= s.size()) {
+        StrAppend(result_ptr, s.substr(pos, sub.offset - pos), sub.replacement);
+      }
+      pos = sub.offset + sub.old.size();
+      substitutions += 1;
+    }
+    sub.offset = s.find(sub.old, pos);
+    if (sub.offset == s.npos) {
+      subs.pop_back();
+    } else {
+      // Insertion sort to ensure the last ViableSubstitution continues to be
+      // before all the others.
+      size_t index = subs.size();
+      while (--index && subs[index - 1].OccursBefore(subs[index])) {
+        std::swap(subs[index], subs[index - 1]);
+      }
+    }
+  }
+  result_ptr->append(s.data() + pos, s.size() - pos);
+  return substitutions;
+}
+
+}  // namespace strings_internal
+
+// We can implement this in terms of the generic StrReplaceAll, but
+// we must specify the template overload because C++ cannot deduce the type
+// of an initializer_list parameter to a function, and also if we don't specify
+// the type, we just call ourselves.
+//
+// Note that we implement them here, rather than in the header, so that they
+// aren't inlined.
+
+std::string StrReplaceAll(absl::string_view s,
+                          strings_internal::FixedMapping replacements) {
+  return StrReplaceAll<strings_internal::FixedMapping>(s, replacements);
+}
+
+int StrReplaceAll(strings_internal::FixedMapping replacements,
+                  std::string* target) {
+  return StrReplaceAll<strings_internal::FixedMapping>(replacements, target);
+}
+
+ABSL_NAMESPACE_END
+}  // namespace absl
diff --git a/src/absl/strings/str_replace.h b/src/absl/strings/str_replace.h
new file mode 100644 (file)
index 0000000..273c707
--- /dev/null
@@ -0,0 +1,219 @@
+//
+// Copyright 2017 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// -----------------------------------------------------------------------------
+// File: str_replace.h
+// -----------------------------------------------------------------------------
+//
+// This file defines `absl::StrReplaceAll()`, a general-purpose string
+// replacement function designed for large, arbitrary text substitutions,
+// especially on strings which you are receiving from some other system for
+// further processing (e.g. processing regular expressions, escaping HTML
+// entities, etc.). `StrReplaceAll` is designed to be efficient even when only
+// one substitution is being performed, or when substitution is rare.
+//
+// If the string being modified is known at compile-time, and the substitutions
+// vary, `absl::Substitute()` may be a better choice.
+//
+// Example:
+//
+// std::string html_escaped = absl::StrReplaceAll(user_input, {
+//                                                {"&", "&amp;"},
+//                                                {"<", "&lt;"},
+//                                                {">", "&gt;"},
+//                                                {"\"", "&quot;"},
+//                                                {"'", "&#39;"}});
+#ifndef ABSL_STRINGS_STR_REPLACE_H_
+#define ABSL_STRINGS_STR_REPLACE_H_
+
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "absl/base/attributes.h"
+#include "absl/strings/string_view.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+
+// StrReplaceAll()
+//
+// Replaces character sequences within a given string with replacements provided
+// within an initializer list of key/value pairs. Candidate replacements are
+// considered in order as they occur within the string, with earlier matches
+// taking precedence, and longer matches taking precedence for candidates
+// starting at the same position in the string. Once a substitution is made, the
+// replaced text is not considered for any further substitutions.
+//
+// Example:
+//
+//   std::string s = absl::StrReplaceAll(
+//       "$who bought $count #Noun. Thanks $who!",
+//       {{"$count", absl::StrCat(5)},
+//        {"$who", "Bob"},
+//        {"#Noun", "Apples"}});
+//   EXPECT_EQ("Bob bought 5 Apples. Thanks Bob!", s);
+ABSL_MUST_USE_RESULT std::string StrReplaceAll(
+    absl::string_view s,
+    std::initializer_list<std::pair<absl::string_view, absl::string_view>>
+        replacements);
+
+// Overload of `StrReplaceAll()` to accept a container of key/value replacement
+// pairs (typically either an associative map or a `std::vector` of `std::pair`
+// elements). A vector of pairs is generally more efficient.
+//
+// Examples:
+//
+//   std::map<const absl::string_view, const absl::string_view> replacements;
+//   replacements["$who"] = "Bob";
+//   replacements["$count"] = "5";
+//   replacements["#Noun"] = "Apples";
+//   std::string s = absl::StrReplaceAll(
+//       "$who bought $count #Noun. Thanks $who!",
+//       replacements);
+//   EXPECT_EQ("Bob bought 5 Apples. Thanks Bob!", s);
+//
+//   // A std::vector of std::pair elements can be more efficient.
+//   std::vector<std::pair<const absl::string_view, std::string>> replacements;
+//   replacements.push_back({"&", "&amp;"});
+//   replacements.push_back({"<", "&lt;"});
+//   replacements.push_back({">", "&gt;"});
+//   std::string s = absl::StrReplaceAll("if (ptr < &foo)",
+//                                  replacements);
+//   EXPECT_EQ("if (ptr &lt; &amp;foo)", s);
+template <typename StrToStrMapping>
+std::string StrReplaceAll(absl::string_view s,
+                          const StrToStrMapping& replacements);
+
+// Overload of `StrReplaceAll()` to replace character sequences within a given
+// output string *in place* with replacements provided within an initializer
+// list of key/value pairs, returning the number of substitutions that occurred.
+//
+// Example:
+//
+//   std::string s = std::string("$who bought $count #Noun. Thanks $who!");
+//   int count;
+//   count = absl::StrReplaceAll({{"$count", absl::StrCat(5)},
+//                               {"$who", "Bob"},
+//                               {"#Noun", "Apples"}}, &s);
+//  EXPECT_EQ(count, 4);
+//  EXPECT_EQ("Bob bought 5 Apples. Thanks Bob!", s);
+int StrReplaceAll(
+    std::initializer_list<std::pair<absl::string_view, absl::string_view>>
+        replacements,
+    std::string* target);
+
+// Overload of `StrReplaceAll()` to replace patterns within a given output
+// string *in place* with replacements provided within a container of key/value
+// pairs.
+//
+// Example:
+//
+//   std::string s = std::string("if (ptr < &foo)");
+//   int count = absl::StrReplaceAll({{"&", "&amp;"},
+//                                    {"<", "&lt;"},
+//                                    {">", "&gt;"}}, &s);
+//  EXPECT_EQ(count, 2);
+//  EXPECT_EQ("if (ptr &lt; &amp;foo)", s);
+template <typename StrToStrMapping>
+int StrReplaceAll(const StrToStrMapping& replacements, std::string* target);
+
+// Implementation details only, past this point.
+namespace strings_internal {
+
+struct ViableSubstitution {
+  absl::string_view old;
+  absl::string_view replacement;
+  size_t offset;
+
+  ViableSubstitution(absl::string_view old_str,
+                     absl::string_view replacement_str, size_t offset_val)
+      : old(old_str), replacement(replacement_str), offset(offset_val) {}
+
+  // One substitution occurs "before" another (takes priority) if either
+  // it has the lowest offset, or it has the same offset but a larger size.
+  bool OccursBefore(const ViableSubstitution& y) const {
+    if (offset != y.offset) return offset < y.offset;
+    return old.size() > y.old.size();
+  }
+};
+
+// Build a vector of ViableSubstitutions based on the given list of
+// replacements. subs can be implemented as a priority_queue. However, it turns
+// out that most callers have small enough a list of substitutions that the
+// overhead of such a queue isn't worth it.
+template <typename StrToStrMapping>
+std::vector<ViableSubstitution> FindSubstitutions(
+    absl::string_view s, const StrToStrMapping& replacements) {
+  std::vector<ViableSubstitution> subs;
+  subs.reserve(replacements.size());
+
+  for (const auto& rep : replacements) {
+    using std::get;
+    absl::string_view old(get<0>(rep));
+
+    size_t pos = s.find(old);
+    if (pos == s.npos) continue;
+
+    // Ignore attempts to replace "". This condition is almost never true,
+    // but above condition is frequently true. That's why we test for this
+    // now and not before.
+    if (old.empty()) continue;
+
+    subs.emplace_back(old, get<1>(rep), pos);
+
+    // Insertion sort to ensure the last ViableSubstitution comes before
+    // all the others.
+    size_t index = subs.size();
+    while (--index && subs[index - 1].OccursBefore(subs[index])) {
+      std::swap(subs[index], subs[index - 1]);
+    }
+  }
+  return subs;
+}
+
+int ApplySubstitutions(absl::string_view s,
+                       std::vector<ViableSubstitution>* subs_ptr,
+                       std::string* result_ptr);
+
+}  // namespace strings_internal
+
+template <typename StrToStrMapping>
+std::string StrReplaceAll(absl::string_view s,
+                          const StrToStrMapping& replacements) {
+  auto subs = strings_internal::FindSubstitutions(s, replacements);
+  std::string result;
+  result.reserve(s.size());
+  strings_internal::ApplySubstitutions(s, &subs, &result);
+  return result;
+}
+
+template <typename StrToStrMapping>
+int StrReplaceAll(const StrToStrMapping& replacements, std::string* target) {
+  auto subs = strings_internal::FindSubstitutions(*target, replacements);
+  if (subs.empty()) return 0;
+
+  std::string result;
+  result.reserve(target->size());
+  int substitutions =
+      strings_internal::ApplySubstitutions(*target, &subs, &result);
+  target->swap(result);
+  return substitutions;
+}
+
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#endif  // ABSL_STRINGS_STR_REPLACE_H_
diff --git a/src/absl/strings/str_split.cc b/src/absl/strings/str_split.cc
new file mode 100644 (file)
index 0000000..e08c26b
--- /dev/null
@@ -0,0 +1,139 @@
+// Copyright 2017 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "absl/strings/str_split.h"
+
+#include <algorithm>
+#include <cassert>
+#include <cstdint>
+#include <cstdlib>
+#include <cstring>
+#include <iterator>
+#include <limits>
+#include <memory>
+
+#include "absl/base/internal/raw_logging.h"
+#include "absl/strings/ascii.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+
+namespace {
+
+// This GenericFind() template function encapsulates the finding algorithm
+// shared between the ByString and ByAnyChar delimiters. The FindPolicy
+// template parameter allows each delimiter to customize the actual find
+// function to use and the length of the found delimiter. For example, the
+// Literal delimiter will ultimately use absl::string_view::find(), and the
+// AnyOf delimiter will use absl::string_view::find_first_of().
+template <typename FindPolicy>
+absl::string_view GenericFind(absl::string_view text,
+                              absl::string_view delimiter, size_t pos,
+                              FindPolicy find_policy) {
+  if (delimiter.empty() && text.length() > 0) {
+    // Special case for empty string delimiters: always return a zero-length
+    // absl::string_view referring to the item at position 1 past pos.
+    return absl::string_view(text.data() + pos + 1, 0);
+  }
+  size_t found_pos = absl::string_view::npos;
+  absl::string_view found(text.data() + text.size(),
+                          0);  // By default, not found
+  found_pos = find_policy.Find(text, delimiter, pos);
+  if (found_pos != absl::string_view::npos) {
+    found = absl::string_view(text.data() + found_pos,
+                              find_policy.Length(delimiter));
+  }
+  return found;
+}
+
+// Finds using absl::string_view::find(), therefore the length of the found
+// delimiter is delimiter.length().
+struct LiteralPolicy {
+  size_t Find(absl::string_view text, absl::string_view delimiter, size_t pos) {
+    return text.find(delimiter, pos);
+  }
+  size_t Length(absl::string_view delimiter) { return delimiter.length(); }
+};
+
+// Finds using absl::string_view::find_first_of(), therefore the length of the
+// found delimiter is 1.
+struct AnyOfPolicy {
+  size_t Find(absl::string_view text, absl::string_view delimiter, size_t pos) {
+    return text.find_first_of(delimiter, pos);
+  }
+  size_t Length(absl::string_view /* delimiter */) { return 1; }
+};
+
+}  // namespace
+
+//
+// ByString
+//
+
+ByString::ByString(absl::string_view sp) : delimiter_(sp) {}
+
+absl::string_view ByString::Find(absl::string_view text, size_t pos) const {
+  if (delimiter_.length() == 1) {
+    // Much faster to call find on a single character than on an
+    // absl::string_view.
+    size_t found_pos = text.find(delimiter_[0], pos);
+    if (found_pos == absl::string_view::npos)
+      return absl::string_view(text.data() + text.size(), 0);
+    return text.substr(found_pos, 1);
+  }
+  return GenericFind(text, delimiter_, pos, LiteralPolicy());
+}
+
+//
+// ByChar
+//
+
+absl::string_view ByChar::Find(absl::string_view text, size_t pos) const {
+  size_t found_pos = text.find(c_, pos);
+  if (found_pos == absl::string_view::npos)
+    return absl::string_view(text.data() + text.size(), 0);
+  return text.substr(found_pos, 1);
+}
+
+//
+// ByAnyChar
+//
+
+ByAnyChar::ByAnyChar(absl::string_view sp) : delimiters_(sp) {}
+
+absl::string_view ByAnyChar::Find(absl::string_view text, size_t pos) const {
+  return GenericFind(text, delimiters_, pos, AnyOfPolicy());
+}
+
+//
+// ByLength
+//
+ByLength::ByLength(ptrdiff_t length) : length_(length) {
+  ABSL_RAW_CHECK(length > 0, "");
+}
+
+absl::string_view ByLength::Find(absl::string_view text,
+                                      size_t pos) const {
+  pos = std::min(pos, text.size());  // truncate `pos`
+  absl::string_view substr = text.substr(pos);
+  // If the string is shorter than the chunk size we say we
+  // "can't find the delimiter" so this will be the last chunk.
+  if (substr.length() <= static_cast<size_t>(length_))
+    return absl::string_view(text.data() + text.size(), 0);
+
+  return absl::string_view(substr.data() + length_, 0);
+}
+
+ABSL_NAMESPACE_END
+}  // namespace absl
diff --git a/src/absl/strings/str_split.h b/src/absl/strings/str_split.h
new file mode 100644 (file)
index 0000000..bfbca42
--- /dev/null
@@ -0,0 +1,548 @@
+//
+// Copyright 2017 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// -----------------------------------------------------------------------------
+// File: str_split.h
+// -----------------------------------------------------------------------------
+//
+// This file contains functions for splitting strings. It defines the main
+// `StrSplit()` function, several delimiters for determining the boundaries on
+// which to split the string, and predicates for filtering delimited results.
+// `StrSplit()` adapts the returned collection to the type specified by the
+// caller.
+//
+// Example:
+//
+//   // Splits the given string on commas. Returns the results in a
+//   // vector of strings.
+//   std::vector<std::string> v = absl::StrSplit("a,b,c", ',');
+//   // Can also use ","
+//   // v[0] == "a", v[1] == "b", v[2] == "c"
+//
+// See StrSplit() below for more information.
+#ifndef ABSL_STRINGS_STR_SPLIT_H_
+#define ABSL_STRINGS_STR_SPLIT_H_
+
+#include <algorithm>
+#include <cstddef>
+#include <map>
+#include <set>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "absl/base/internal/raw_logging.h"
+#include "absl/base/macros.h"
+#include "absl/strings/internal/str_split_internal.h"
+#include "absl/strings/string_view.h"
+#include "absl/strings/strip.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+
+//------------------------------------------------------------------------------
+// Delimiters
+//------------------------------------------------------------------------------
+//
+// `StrSplit()` uses delimiters to define the boundaries between elements in the
+// provided input. Several `Delimiter` types are defined below. If a string
+// (`const char*`, `std::string`, or `absl::string_view`) is passed in place of
+// an explicit `Delimiter` object, `StrSplit()` treats it the same way as if it
+// were passed a `ByString` delimiter.
+//
+// A `Delimiter` is an object with a `Find()` function that knows how to find
+// the first occurrence of itself in a given `absl::string_view`.
+//
+// The following `Delimiter` types are available for use within `StrSplit()`:
+//
+//   - `ByString` (default for string arguments)
+//   - `ByChar` (default for a char argument)
+//   - `ByAnyChar`
+//   - `ByLength`
+//   - `MaxSplits`
+//
+// A Delimiter's `Find()` member function will be passed an input `text` that is
+// to be split and a position (`pos`) to begin searching for the next delimiter
+// in `text`. The returned absl::string_view should refer to the next occurrence
+// (after `pos`) of the represented delimiter; this returned absl::string_view
+// represents the next location where the input `text` should be broken.
+//
+// The returned absl::string_view may be zero-length if the Delimiter does not
+// represent a part of the string (e.g., a fixed-length delimiter). If no
+// delimiter is found in the input `text`, a zero-length absl::string_view
+// referring to `text.end()` should be returned (e.g.,
+// `text.substr(text.size())`). It is important that the returned
+// absl::string_view always be within the bounds of the input `text` given as an
+// argument--it must not refer to a string that is physically located outside of
+// the given string.
+//
+// The following example is a simple Delimiter object that is created with a
+// single char and will look for that char in the text passed to the `Find()`
+// function:
+//
+//   struct SimpleDelimiter {
+//     const char c_;
+//     explicit SimpleDelimiter(char c) : c_(c) {}
+//     absl::string_view Find(absl::string_view text, size_t pos) {
+//       auto found = text.find(c_, pos);
+//       if (found == absl::string_view::npos)
+//         return text.substr(text.size());
+//
+//       return text.substr(found, 1);
+//     }
+//   };
+
+// ByString
+//
+// A sub-string delimiter. If `StrSplit()` is passed a string in place of a
+// `Delimiter` object, the string will be implicitly converted into a
+// `ByString` delimiter.
+//
+// Example:
+//
+//   // Because a string literal is converted to an `absl::ByString`,
+//   // the following two splits are equivalent.
+//
+//   std::vector<std::string> v1 = absl::StrSplit("a, b, c", ", ");
+//
+//   using absl::ByString;
+//   std::vector<std::string> v2 = absl::StrSplit("a, b, c",
+//                                                ByString(", "));
+//   // v[0] == "a", v[1] == "b", v[2] == "c"
+class ByString {
+ public:
+  explicit ByString(absl::string_view sp);
+  absl::string_view Find(absl::string_view text, size_t pos) const;
+
+ private:
+  const std::string delimiter_;
+};
+
+// ByChar
+//
+// A single character delimiter. `ByChar` is functionally equivalent to a
+// 1-char string within a `ByString` delimiter, but slightly more efficient.
+//
+// Example:
+//
+//   // Because a char literal is converted to a absl::ByChar,
+//   // the following two splits are equivalent.
+//   std::vector<std::string> v1 = absl::StrSplit("a,b,c", ',');
+//   using absl::ByChar;
+//   std::vector<std::string> v2 = absl::StrSplit("a,b,c", ByChar(','));
+//   // v[0] == "a", v[1] == "b", v[2] == "c"
+//
+// `ByChar` is also the default delimiter if a single character is given
+// as the delimiter to `StrSplit()`. For example, the following calls are
+// equivalent:
+//
+//   std::vector<std::string> v = absl::StrSplit("a-b", '-');
+//
+//   using absl::ByChar;
+//   std::vector<std::string> v = absl::StrSplit("a-b", ByChar('-'));
+//
+class ByChar {
+ public:
+  explicit ByChar(char c) : c_(c) {}
+  absl::string_view Find(absl::string_view text, size_t pos) const;
+
+ private:
+  char c_;
+};
+
+// ByAnyChar
+//
+// A delimiter that will match any of the given byte-sized characters within
+// its provided string.
+//
+// Note: this delimiter works with single-byte string data, but does not work
+// with variable-width encodings, such as UTF-8.
+//
+// Example:
+//
+//   using absl::ByAnyChar;
+//   std::vector<std::string> v = absl::StrSplit("a,b=c", ByAnyChar(",="));
+//   // v[0] == "a", v[1] == "b", v[2] == "c"
+//
+// If `ByAnyChar` is given the empty string, it behaves exactly like
+// `ByString` and matches each individual character in the input string.
+//
+class ByAnyChar {
+ public:
+  explicit ByAnyChar(absl::string_view sp);
+  absl::string_view Find(absl::string_view text, size_t pos) const;
+
+ private:
+  const std::string delimiters_;
+};
+
+// ByLength
+//
+// A delimiter for splitting into equal-length strings. The length argument to
+// the constructor must be greater than 0.
+//
+// Note: this delimiter works with single-byte string data, but does not work
+// with variable-width encodings, such as UTF-8.
+//
+// Example:
+//
+//   using absl::ByLength;
+//   std::vector<std::string> v = absl::StrSplit("123456789", ByLength(3));
+
+//   // v[0] == "123", v[1] == "456", v[2] == "789"
+//
+// Note that the string does not have to be a multiple of the fixed split
+// length. In such a case, the last substring will be shorter.
+//
+//   using absl::ByLength;
+//   std::vector<std::string> v = absl::StrSplit("12345", ByLength(2));
+//
+//   // v[0] == "12", v[1] == "34", v[2] == "5"
+class ByLength {
+ public:
+  explicit ByLength(ptrdiff_t length);
+  absl::string_view Find(absl::string_view text, size_t pos) const;
+
+ private:
+  const ptrdiff_t length_;
+};
+
+namespace strings_internal {
+
+// A traits-like metafunction for selecting the default Delimiter object type
+// for a particular Delimiter type. The base case simply exposes type Delimiter
+// itself as the delimiter's Type. However, there are specializations for
+// string-like objects that map them to the ByString delimiter object.
+// This allows functions like absl::StrSplit() and absl::MaxSplits() to accept
+// string-like objects (e.g., ',') as delimiter arguments but they will be
+// treated as if a ByString delimiter was given.
+template <typename Delimiter>
+struct SelectDelimiter {
+  using type = Delimiter;
+};
+
+template <>
+struct SelectDelimiter<char> {
+  using type = ByChar;
+};
+template <>
+struct SelectDelimiter<char*> {
+  using type = ByString;
+};
+template <>
+struct SelectDelimiter<const char*> {
+  using type = ByString;
+};
+template <>
+struct SelectDelimiter<absl::string_view> {
+  using type = ByString;
+};
+template <>
+struct SelectDelimiter<std::string> {
+  using type = ByString;
+};
+
+// Wraps another delimiter and sets a max number of matches for that delimiter.
+template <typename Delimiter>
+class MaxSplitsImpl {
+ public:
+  MaxSplitsImpl(Delimiter delimiter, int limit)
+      : delimiter_(delimiter), limit_(limit), count_(0) {}
+  absl::string_view Find(absl::string_view text, size_t pos) {
+    if (count_++ == limit_) {
+      return absl::string_view(text.data() + text.size(),
+                               0);  // No more matches.
+    }
+    return delimiter_.Find(text, pos);
+  }
+
+ private:
+  Delimiter delimiter_;
+  const int limit_;
+  int count_;
+};
+
+}  // namespace strings_internal
+
+// MaxSplits()
+//
+// A delimiter that limits the number of matches which can occur to the passed
+// `limit`. The last element in the returned collection will contain all
+// remaining unsplit pieces, which may contain instances of the delimiter.
+// The collection will contain at most `limit` + 1 elements.
+// Example:
+//
+//   using absl::MaxSplits;
+//   std::vector<std::string> v = absl::StrSplit("a,b,c", MaxSplits(',', 1));
+//
+//   // v[0] == "a", v[1] == "b,c"
+template <typename Delimiter>
+inline strings_internal::MaxSplitsImpl<
+    typename strings_internal::SelectDelimiter<Delimiter>::type>
+MaxSplits(Delimiter delimiter, int limit) {
+  typedef
+      typename strings_internal::SelectDelimiter<Delimiter>::type DelimiterType;
+  return strings_internal::MaxSplitsImpl<DelimiterType>(
+      DelimiterType(delimiter), limit);
+}
+
+//------------------------------------------------------------------------------
+// Predicates
+//------------------------------------------------------------------------------
+//
+// Predicates filter the results of a `StrSplit()` by determining whether or not
+// a resultant element is included in the result set. A predicate may be passed
+// as an optional third argument to the `StrSplit()` function.
+//
+// Predicates are unary functions (or functors) that take a single
+// `absl::string_view` argument and return a bool indicating whether the
+// argument should be included (`true`) or excluded (`false`).
+//
+// Predicates are useful when filtering out empty substrings. By default, empty
+// substrings may be returned by `StrSplit()`, which is similar to the way split
+// functions work in other programming languages.
+
+// AllowEmpty()
+//
+// Always returns `true`, indicating that all strings--including empty
+// strings--should be included in the split output. This predicate is not
+// strictly needed because this is the default behavior of `StrSplit()`;
+// however, it might be useful at some call sites to make the intent explicit.
+//
+// Example:
+//
+//  std::vector<std::string> v = absl::StrSplit(" a , ,,b,", ',', AllowEmpty());
+//
+//  // v[0] == " a ", v[1] == " ", v[2] == "", v[3] = "b", v[4] == ""
+struct AllowEmpty {
+  bool operator()(absl::string_view) const { return true; }
+};
+
+// SkipEmpty()
+//
+// Returns `false` if the given `absl::string_view` is empty, indicating that
+// `StrSplit()` should omit the empty string.
+//
+// Example:
+//
+//   std::vector<std::string> v = absl::StrSplit(",a,,b,", ',', SkipEmpty());
+//
+//   // v[0] == "a", v[1] == "b"
+//
+// Note: `SkipEmpty()` does not consider a string containing only whitespace
+// to be empty. To skip such whitespace as well, use the `SkipWhitespace()`
+// predicate.
+struct SkipEmpty {
+  bool operator()(absl::string_view sp) const { return !sp.empty(); }
+};
+
+// SkipWhitespace()
+//
+// Returns `false` if the given `absl::string_view` is empty *or* contains only
+// whitespace, indicating that `StrSplit()` should omit the string.
+//
+// Example:
+//
+//   std::vector<std::string> v = absl::StrSplit(" a , ,,b,",
+//                                               ',', SkipWhitespace());
+//   // v[0] == " a ", v[1] == "b"
+//
+//   // SkipEmpty() would return whitespace elements
+//   std::vector<std::string> v = absl::StrSplit(" a , ,,b,", ',', SkipEmpty());
+//   // v[0] == " a ", v[1] == " ", v[2] == "b"
+struct SkipWhitespace {
+  bool operator()(absl::string_view sp) const {
+    sp = absl::StripAsciiWhitespace(sp);
+    return !sp.empty();
+  }
+};
+
+template <typename T>
+using EnableSplitIfString =
+    typename std::enable_if<std::is_same<T, std::string>::value ||
+                            std::is_same<T, const std::string>::value,
+                            int>::type;
+
+//------------------------------------------------------------------------------
+//                                  StrSplit()
+//------------------------------------------------------------------------------
+
+// StrSplit()
+//
+// Splits a given string based on the provided `Delimiter` object, returning the
+// elements within the type specified by the caller. Optionally, you may pass a
+// `Predicate` to `StrSplit()` indicating whether to include or exclude the
+// resulting element within the final result set. (See the overviews for
+// Delimiters and Predicates above.)
+//
+// Example:
+//
+//   std::vector<std::string> v = absl::StrSplit("a,b,c,d", ',');
+//   // v[0] == "a", v[1] == "b", v[2] == "c", v[3] == "d"
+//
+// You can also provide an explicit `Delimiter` object:
+//
+// Example:
+//
+//   using absl::ByAnyChar;
+//   std::vector<std::string> v = absl::StrSplit("a,b=c", ByAnyChar(",="));
+//   // v[0] == "a", v[1] == "b", v[2] == "c"
+//
+// See above for more information on delimiters.
+//
+// By default, empty strings are included in the result set. You can optionally
+// include a third `Predicate` argument to apply a test for whether the
+// resultant element should be included in the result set:
+//
+// Example:
+//
+//   std::vector<std::string> v = absl::StrSplit(" a , ,,b,",
+//                                               ',', SkipWhitespace());
+//   // v[0] == " a ", v[1] == "b"
+//
+// See above for more information on predicates.
+//
+//------------------------------------------------------------------------------
+// StrSplit() Return Types
+//------------------------------------------------------------------------------
+//
+// The `StrSplit()` function adapts the returned collection to the collection
+// specified by the caller (e.g. `std::vector` above). The returned collections
+// may contain `std::string`, `absl::string_view` (in which case the original
+// string being split must ensure that it outlives the collection), or any
+// object that can be explicitly created from an `absl::string_view`. This
+// behavior works for:
+//
+// 1) All standard STL containers including `std::vector`, `std::list`,
+//    `std::deque`, `std::set`,`std::multiset`, 'std::map`, and `std::multimap`
+// 2) `std::pair` (which is not actually a container). See below.
+//
+// Example:
+//
+//   // The results are returned as `absl::string_view` objects. Note that we
+//   // have to ensure that the input string outlives any results.
+//   std::vector<absl::string_view> v = absl::StrSplit("a,b,c", ',');
+//
+//   // Stores results in a std::set<std::string>, which also performs
+//   // de-duplication and orders the elements in ascending order.
+//   std::set<std::string> a = absl::StrSplit("b,a,c,a,b", ',');
+//   // v[0] == "a", v[1] == "b", v[2] = "c"
+//
+//   // `StrSplit()` can be used within a range-based for loop, in which case
+//   // each element will be of type `absl::string_view`.
+//   std::vector<std::string> v;
+//   for (const auto sv : absl::StrSplit("a,b,c", ',')) {
+//     if (sv != "b") v.emplace_back(sv);
+//   }
+//   // v[0] == "a", v[1] == "c"
+//
+//   // Stores results in a map. The map implementation assumes that the input
+//   // is provided as a series of key/value pairs. For example, the 0th element
+//   // resulting from the split will be stored as a key to the 1st element. If
+//   // an odd number of elements are resolved, the last element is paired with
+//   // a default-constructed value (e.g., empty string).
+//   std::map<std::string, std::string> m = absl::StrSplit("a,b,c", ',');
+//   // m["a"] == "b", m["c"] == ""     // last component value equals ""
+//
+// Splitting to `std::pair` is an interesting case because it can hold only two
+// elements and is not a collection type. When splitting to a `std::pair` the
+// first two split strings become the `std::pair` `.first` and `.second`
+// members, respectively. The remaining split substrings are discarded. If there
+// are less than two split substrings, the empty string is used for the
+// corresponding
+// `std::pair` member.
+//
+// Example:
+//
+//   // Stores first two split strings as the members in a std::pair.
+//   std::pair<std::string, std::string> p = absl::StrSplit("a,b,c", ',');
+//   // p.first == "a", p.second == "b"       // "c" is omitted.
+//
+// The `StrSplit()` function can be used multiple times to perform more
+// complicated splitting logic, such as intelligently parsing key-value pairs.
+//
+// Example:
+//
+//   // The input string "a=b=c,d=e,f=,g" becomes
+//   // { "a" => "b=c", "d" => "e", "f" => "", "g" => "" }
+//   std::map<std::string, std::string> m;
+//   for (absl::string_view sp : absl::StrSplit("a=b=c,d=e,f=,g", ',')) {
+//     m.insert(absl::StrSplit(sp, absl::MaxSplits('=', 1)));
+//   }
+//   EXPECT_EQ("b=c", m.find("a")->second);
+//   EXPECT_EQ("e", m.find("d")->second);
+//   EXPECT_EQ("", m.find("f")->second);
+//   EXPECT_EQ("", m.find("g")->second);
+//
+// WARNING: Due to a legacy bug that is maintained for backward compatibility,
+// splitting the following empty string_views produces different results:
+//
+//   absl::StrSplit(absl::string_view(""), '-');  // {""}
+//   absl::StrSplit(absl::string_view(), '-');    // {}, but should be {""}
+//
+// Try not to depend on this distinction because the bug may one day be fixed.
+template <typename Delimiter>
+strings_internal::Splitter<
+    typename strings_internal::SelectDelimiter<Delimiter>::type, AllowEmpty,
+    absl::string_view>
+StrSplit(strings_internal::ConvertibleToStringView text, Delimiter d) {
+  using DelimiterType =
+      typename strings_internal::SelectDelimiter<Delimiter>::type;
+  return strings_internal::Splitter<DelimiterType, AllowEmpty,
+                                    absl::string_view>(
+      text.value(), DelimiterType(d), AllowEmpty());
+}
+
+template <typename Delimiter, typename StringType,
+          EnableSplitIfString<StringType> = 0>
+strings_internal::Splitter<
+    typename strings_internal::SelectDelimiter<Delimiter>::type, AllowEmpty,
+    std::string>
+StrSplit(StringType&& text, Delimiter d) {
+  using DelimiterType =
+      typename strings_internal::SelectDelimiter<Delimiter>::type;
+  return strings_internal::Splitter<DelimiterType, AllowEmpty, std::string>(
+      std::move(text), DelimiterType(d), AllowEmpty());
+}
+
+template <typename Delimiter, typename Predicate>
+strings_internal::Splitter<
+    typename strings_internal::SelectDelimiter<Delimiter>::type, Predicate,
+    absl::string_view>
+StrSplit(strings_internal::ConvertibleToStringView text, Delimiter d,
+         Predicate p) {
+  using DelimiterType =
+      typename strings_internal::SelectDelimiter<Delimiter>::type;
+  return strings_internal::Splitter<DelimiterType, Predicate,
+                                    absl::string_view>(
+      text.value(), DelimiterType(d), std::move(p));
+}
+
+template <typename Delimiter, typename Predicate, typename StringType,
+          EnableSplitIfString<StringType> = 0>
+strings_internal::Splitter<
+    typename strings_internal::SelectDelimiter<Delimiter>::type, Predicate,
+    std::string>
+StrSplit(StringType&& text, Delimiter d, Predicate p) {
+  using DelimiterType =
+      typename strings_internal::SelectDelimiter<Delimiter>::type;
+  return strings_internal::Splitter<DelimiterType, Predicate, std::string>(
+      std::move(text), DelimiterType(d), std::move(p));
+}
+
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#endif  // ABSL_STRINGS_STR_SPLIT_H_
diff --git a/src/absl/strings/string_view.cc b/src/absl/strings/string_view.cc
new file mode 100644 (file)
index 0000000..c5f5de9
--- /dev/null
@@ -0,0 +1,235 @@
+// Copyright 2017 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "absl/strings/string_view.h"
+
+#ifndef ABSL_USES_STD_STRING_VIEW
+
+#include <algorithm>
+#include <climits>
+#include <cstring>
+#include <ostream>
+
+#include "absl/strings/internal/memutil.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+
+namespace {
+void WritePadding(std::ostream& o, size_t pad) {
+  char fill_buf[32];
+  memset(fill_buf, o.fill(), sizeof(fill_buf));
+  while (pad) {
+    size_t n = std::min(pad, sizeof(fill_buf));
+    o.write(fill_buf, n);
+    pad -= n;
+  }
+}
+
+class LookupTable {
+ public:
+  // For each character in wanted, sets the index corresponding
+  // to the ASCII code of that character. This is used by
+  // the find_.*_of methods below to tell whether or not a character is in
+  // the lookup table in constant time.
+  explicit LookupTable(string_view wanted) {
+    for (char c : wanted) {
+      table_[Index(c)] = true;
+    }
+  }
+  bool operator[](char c) const { return table_[Index(c)]; }
+
+ private:
+  static unsigned char Index(char c) { return static_cast<unsigned char>(c); }
+  bool table_[UCHAR_MAX + 1] = {};
+};
+
+}  // namespace
+
+std::ostream& operator<<(std::ostream& o, string_view piece) {
+  std::ostream::sentry sentry(o);
+  if (sentry) {
+    size_t lpad = 0;
+    size_t rpad = 0;
+    if (static_cast<size_t>(o.width()) > piece.size()) {
+      size_t pad = o.width() - piece.size();
+      if ((o.flags() & o.adjustfield) == o.left) {
+        rpad = pad;
+      } else {
+        lpad = pad;
+      }
+    }
+    if (lpad) WritePadding(o, lpad);
+    o.write(piece.data(), piece.size());
+    if (rpad) WritePadding(o, rpad);
+    o.width(0);
+  }
+  return o;
+}
+
+string_view::size_type string_view::find(string_view s, size_type pos) const
+    noexcept {
+  if (empty() || pos > length_) {
+    if (empty() && pos == 0 && s.empty()) return 0;
+    return npos;
+  }
+  const char* result =
+      strings_internal::memmatch(ptr_ + pos, length_ - pos, s.ptr_, s.length_);
+  return result ? result - ptr_ : npos;
+}
+
+string_view::size_type string_view::find(char c, size_type pos) const noexcept {
+  if (empty() || pos >= length_) {
+    return npos;
+  }
+  const char* result =
+      static_cast<const char*>(memchr(ptr_ + pos, c, length_ - pos));
+  return result != nullptr ? result - ptr_ : npos;
+}
+
+string_view::size_type string_view::rfind(string_view s, size_type pos) const
+    noexcept {
+  if (length_ < s.length_) return npos;
+  if (s.empty()) return std::min(length_, pos);
+  const char* last = ptr_ + std::min(length_ - s.length_, pos) + s.length_;
+  const char* result = std::find_end(ptr_, last, s.ptr_, s.ptr_ + s.length_);
+  return result != last ? result - ptr_ : npos;
+}
+
+// Search range is [0..pos] inclusive.  If pos == npos, search everything.
+string_view::size_type string_view::rfind(char c, size_type pos) const
+    noexcept {
+  // Note: memrchr() is not available on Windows.
+  if (empty()) return npos;
+  for (size_type i = std::min(pos, length_ - 1);; --i) {
+    if (ptr_[i] == c) {
+      return i;
+    }
+    if (i == 0) break;
+  }
+  return npos;
+}
+
+string_view::size_type string_view::find_first_of(string_view s,
+                                                  size_type pos) const
+    noexcept {
+  if (empty() || s.empty()) {
+    return npos;
+  }
+  // Avoid the cost of LookupTable() for a single-character search.
+  if (s.length_ == 1) return find_first_of(s.ptr_[0], pos);
+  LookupTable tbl(s);
+  for (size_type i = pos; i < length_; ++i) {
+    if (tbl[ptr_[i]]) {
+      return i;
+    }
+  }
+  return npos;
+}
+
+string_view::size_type string_view::find_first_not_of(string_view s,
+                                                      size_type pos) const
+    noexcept {
+  if (empty()) return npos;
+  // Avoid the cost of LookupTable() for a single-character search.
+  if (s.length_ == 1) return find_first_not_of(s.ptr_[0], pos);
+  LookupTable tbl(s);
+  for (size_type i = pos; i < length_; ++i) {
+    if (!tbl[ptr_[i]]) {
+      return i;
+    }
+  }
+  return npos;
+}
+
+string_view::size_type string_view::find_first_not_of(char c,
+                                                      size_type pos) const
+    noexcept {
+  if (empty()) return npos;
+  for (; pos < length_; ++pos) {
+    if (ptr_[pos] != c) {
+      return pos;
+    }
+  }
+  return npos;
+}
+
+string_view::size_type string_view::find_last_of(string_view s,
+                                                 size_type pos) const noexcept {
+  if (empty() || s.empty()) return npos;
+  // Avoid the cost of LookupTable() for a single-character search.
+  if (s.length_ == 1) return find_last_of(s.ptr_[0], pos);
+  LookupTable tbl(s);
+  for (size_type i = std::min(pos, length_ - 1);; --i) {
+    if (tbl[ptr_[i]]) {
+      return i;
+    }
+    if (i == 0) break;
+  }
+  return npos;
+}
+
+string_view::size_type string_view::find_last_not_of(string_view s,
+                                                     size_type pos) const
+    noexcept {
+  if (empty()) return npos;
+  size_type i = std::min(pos, length_ - 1);
+  if (s.empty()) return i;
+  // Avoid the cost of LookupTable() for a single-character search.
+  if (s.length_ == 1) return find_last_not_of(s.ptr_[0], pos);
+  LookupTable tbl(s);
+  for (;; --i) {
+    if (!tbl[ptr_[i]]) {
+      return i;
+    }
+    if (i == 0) break;
+  }
+  return npos;
+}
+
+string_view::size_type string_view::find_last_not_of(char c,
+                                                     size_type pos) const
+    noexcept {
+  if (empty()) return npos;
+  size_type i = std::min(pos, length_ - 1);
+  for (;; --i) {
+    if (ptr_[i] != c) {
+      return i;
+    }
+    if (i == 0) break;
+  }
+  return npos;
+}
+
+// MSVC has non-standard behavior that implicitly creates definitions for static
+// const members. These implicit definitions conflict with explicit out-of-class
+// member definitions that are required by the C++ standard, resulting in
+// LNK1169 "multiply defined" errors at link time. __declspec(selectany) asks
+// MSVC to choose only one definition for the symbol it decorates. See details
+// at https://msdn.microsoft.com/en-us/library/34h23df8(v=vs.100).aspx
+#ifdef _MSC_VER
+#define ABSL_STRING_VIEW_SELECTANY __declspec(selectany)
+#else
+#define ABSL_STRING_VIEW_SELECTANY
+#endif
+
+ABSL_STRING_VIEW_SELECTANY
+constexpr string_view::size_type string_view::npos;
+ABSL_STRING_VIEW_SELECTANY
+constexpr string_view::size_type string_view::kMaxSize;
+
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#endif  // ABSL_USES_STD_STRING_VIEW
diff --git a/src/absl/strings/string_view.h b/src/absl/strings/string_view.h
new file mode 100644 (file)
index 0000000..5260b5b
--- /dev/null
@@ -0,0 +1,629 @@
+//
+// Copyright 2017 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// -----------------------------------------------------------------------------
+// File: string_view.h
+// -----------------------------------------------------------------------------
+//
+// This file contains the definition of the `absl::string_view` class. A
+// `string_view` points to a contiguous span of characters, often part or all of
+// another `std::string`, double-quoted string literal, character array, or even
+// another `string_view`.
+//
+// This `absl::string_view` abstraction is designed to be a drop-in
+// replacement for the C++17 `std::string_view` abstraction.
+#ifndef ABSL_STRINGS_STRING_VIEW_H_
+#define ABSL_STRINGS_STRING_VIEW_H_
+
+#include <algorithm>
+#include <cassert>
+#include <cstddef>
+#include <cstring>
+#include <iosfwd>
+#include <iterator>
+#include <limits>
+#include <string>
+
+#include "absl/base/config.h"
+#include "absl/base/internal/throw_delegate.h"
+#include "absl/base/macros.h"
+#include "absl/base/optimization.h"
+#include "absl/base/port.h"
+
+#ifdef ABSL_USES_STD_STRING_VIEW
+
+#include <string_view>  // IWYU pragma: export
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+using string_view = std::string_view;
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#else  // ABSL_USES_STD_STRING_VIEW
+
+#if ABSL_HAVE_BUILTIN(__builtin_memcmp) || \
+    (defined(__GNUC__) && !defined(__clang__))
+#define ABSL_INTERNAL_STRING_VIEW_MEMCMP __builtin_memcmp
+#else  // ABSL_HAVE_BUILTIN(__builtin_memcmp)
+#define ABSL_INTERNAL_STRING_VIEW_MEMCMP memcmp
+#endif  // ABSL_HAVE_BUILTIN(__builtin_memcmp)
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+
+// absl::string_view
+//
+// A `string_view` provides a lightweight view into the string data provided by
+// a `std::string`, double-quoted string literal, character array, or even
+// another `string_view`. A `string_view` does *not* own the string to which it
+// points, and that data cannot be modified through the view.
+//
+// You can use `string_view` as a function or method parameter anywhere a
+// parameter can receive a double-quoted string literal, `const char*`,
+// `std::string`, or another `absl::string_view` argument with no need to copy
+// the string data. Systematic use of `string_view` within function arguments
+// reduces data copies and `strlen()` calls.
+//
+// Because of its small size, prefer passing `string_view` by value:
+//
+//   void MyFunction(absl::string_view arg);
+//
+// If circumstances require, you may also pass one by const reference:
+//
+//   void MyFunction(const absl::string_view& arg);  // not preferred
+//
+// Passing by value generates slightly smaller code for many architectures.
+//
+// In either case, the source data of the `string_view` must outlive the
+// `string_view` itself.
+//
+// A `string_view` is also suitable for local variables if you know that the
+// lifetime of the underlying object is longer than the lifetime of your
+// `string_view` variable. However, beware of binding a `string_view` to a
+// temporary value:
+//
+//   // BAD use of string_view: lifetime problem
+//   absl::string_view sv = obj.ReturnAString();
+//
+//   // GOOD use of string_view: str outlives sv
+//   std::string str = obj.ReturnAString();
+//   absl::string_view sv = str;
+//
+// Due to lifetime issues, a `string_view` is sometimes a poor choice for a
+// return value and usually a poor choice for a data member. If you do use a
+// `string_view` this way, it is your responsibility to ensure that the object
+// pointed to by the `string_view` outlives the `string_view`.
+//
+// A `string_view` may represent a whole string or just part of a string. For
+// example, when splitting a string, `std::vector<absl::string_view>` is a
+// natural data type for the output.
+//
+// For another example, a Cord is a non-contiguous, potentially very
+// long string-like object.  The Cord class has an interface that iteratively
+// provides string_view objects that point to the successive pieces of a Cord
+// object.
+//
+// When constructed from a source which is NUL-terminated, the `string_view`
+// itself will not include the NUL-terminator unless a specific size (including
+// the NUL) is passed to the constructor. As a result, common idioms that work
+// on NUL-terminated strings do not work on `string_view` objects. If you write
+// code that scans a `string_view`, you must check its length rather than test
+// for nul, for example. Note, however, that nuls may still be embedded within
+// a `string_view` explicitly.
+//
+// You may create a null `string_view` in two ways:
+//
+//   absl::string_view sv;
+//   absl::string_view sv(nullptr, 0);
+//
+// For the above, `sv.data() == nullptr`, `sv.length() == 0`, and
+// `sv.empty() == true`. Also, if you create a `string_view` with a non-null
+// pointer then `sv.data() != nullptr`. Thus, you can use `string_view()` to
+// signal an undefined value that is different from other `string_view` values
+// in a similar fashion to how `const char* p1 = nullptr;` is different from
+// `const char* p2 = "";`. However, in practice, it is not recommended to rely
+// on this behavior.
+//
+// Be careful not to confuse a null `string_view` with an empty one. A null
+// `string_view` is an empty `string_view`, but some empty `string_view`s are
+// not null. Prefer checking for emptiness over checking for null.
+//
+// There are many ways to create an empty string_view:
+//
+//   const char* nullcp = nullptr;
+//   // string_view.size() will return 0 in all cases.
+//   absl::string_view();
+//   absl::string_view(nullcp, 0);
+//   absl::string_view("");
+//   absl::string_view("", 0);
+//   absl::string_view("abcdef", 0);
+//   absl::string_view("abcdef" + 6, 0);
+//
+// All empty `string_view` objects whether null or not, are equal:
+//
+//   absl::string_view() == absl::string_view("", 0)
+//   absl::string_view(nullptr, 0) == absl::string_view("abcdef"+6, 0)
+class string_view {
+ public:
+  using traits_type = std::char_traits<char>;
+  using value_type = char;
+  using pointer = char*;
+  using const_pointer = const char*;
+  using reference = char&;
+  using const_reference = const char&;
+  using const_iterator = const char*;
+  using iterator = const_iterator;
+  using const_reverse_iterator = std::reverse_iterator<const_iterator>;
+  using reverse_iterator = const_reverse_iterator;
+  using size_type = size_t;
+  using difference_type = std::ptrdiff_t;
+
+  static constexpr size_type npos = static_cast<size_type>(-1);
+
+  // Null `string_view` constructor
+  constexpr string_view() noexcept : ptr_(nullptr), length_(0) {}
+
+  // Implicit constructors
+
+  template <typename Allocator>
+  string_view(  // NOLINT(runtime/explicit)
+      const std::basic_string<char, std::char_traits<char>, Allocator>&
+          str) noexcept
+      // This is implemented in terms of `string_view(p, n)` so `str.size()`
+      // doesn't need to be reevaluated after `ptr_` is set.
+      : string_view(str.data(), str.size()) {}
+
+  // Implicit constructor of a `string_view` from NUL-terminated `str`. When
+  // accepting possibly null strings, use `absl::NullSafeStringView(str)`
+  // instead (see below).
+  constexpr string_view(const char* str)  // NOLINT(runtime/explicit)
+      : ptr_(str),
+        length_(str ? CheckLengthInternal(StrlenInternal(str)) : 0) {}
+
+  // Implicit constructor of a `string_view` from a `const char*` and length.
+  constexpr string_view(const char* data, size_type len)
+      : ptr_(data), length_(CheckLengthInternal(len)) {}
+
+  // NOTE: Harmlessly omitted to work around gdb bug.
+  //   constexpr string_view(const string_view&) noexcept = default;
+  //   string_view& operator=(const string_view&) noexcept = default;
+
+  // Iterators
+
+  // string_view::begin()
+  //
+  // Returns an iterator pointing to the first character at the beginning of the
+  // `string_view`, or `end()` if the `string_view` is empty.
+  constexpr const_iterator begin() const noexcept { return ptr_; }
+
+  // string_view::end()
+  //
+  // Returns an iterator pointing just beyond the last character at the end of
+  // the `string_view`. This iterator acts as a placeholder; attempting to
+  // access it results in undefined behavior.
+  constexpr const_iterator end() const noexcept { return ptr_ + length_; }
+
+  // string_view::cbegin()
+  //
+  // Returns a const iterator pointing to the first character at the beginning
+  // of the `string_view`, or `end()` if the `string_view` is empty.
+  constexpr const_iterator cbegin() const noexcept { return begin(); }
+
+  // string_view::cend()
+  //
+  // Returns a const iterator pointing just beyond the last character at the end
+  // of the `string_view`. This pointer acts as a placeholder; attempting to
+  // access its element results in undefined behavior.
+  constexpr const_iterator cend() const noexcept { return end(); }
+
+  // string_view::rbegin()
+  //
+  // Returns a reverse iterator pointing to the last character at the end of the
+  // `string_view`, or `rend()` if the `string_view` is empty.
+  const_reverse_iterator rbegin() const noexcept {
+    return const_reverse_iterator(end());
+  }
+
+  // string_view::rend()
+  //
+  // Returns a reverse iterator pointing just before the first character at the
+  // beginning of the `string_view`. This pointer acts as a placeholder;
+  // attempting to access its element results in undefined behavior.
+  const_reverse_iterator rend() const noexcept {
+    return const_reverse_iterator(begin());
+  }
+
+  // string_view::crbegin()
+  //
+  // Returns a const reverse iterator pointing to the last character at the end
+  // of the `string_view`, or `crend()` if the `string_view` is empty.
+  const_reverse_iterator crbegin() const noexcept { return rbegin(); }
+
+  // string_view::crend()
+  //
+  // Returns a const reverse iterator pointing just before the first character
+  // at the beginning of the `string_view`. This pointer acts as a placeholder;
+  // attempting to access its element results in undefined behavior.
+  const_reverse_iterator crend() const noexcept { return rend(); }
+
+  // Capacity Utilities
+
+  // string_view::size()
+  //
+  // Returns the number of characters in the `string_view`.
+  constexpr size_type size() const noexcept {
+    return length_;
+  }
+
+  // string_view::length()
+  //
+  // Returns the number of characters in the `string_view`. Alias for `size()`.
+  constexpr size_type length() const noexcept { return size(); }
+
+  // string_view::max_size()
+  //
+  // Returns the maximum number of characters the `string_view` can hold.
+  constexpr size_type max_size() const noexcept { return kMaxSize; }
+
+  // string_view::empty()
+  //
+  // Checks if the `string_view` is empty (refers to no characters).
+  constexpr bool empty() const noexcept { return length_ == 0; }
+
+  // string_view::operator[]
+  //
+  // Returns the ith element of the `string_view` using the array operator.
+  // Note that this operator does not perform any bounds checking.
+  constexpr const_reference operator[](size_type i) const {
+    return ABSL_HARDENING_ASSERT(i < size()), ptr_[i];
+  }
+
+  // string_view::at()
+  //
+  // Returns the ith element of the `string_view`. Bounds checking is performed,
+  // and an exception of type `std::out_of_range` will be thrown on invalid
+  // access.
+  constexpr const_reference at(size_type i) const {
+    return ABSL_PREDICT_TRUE(i < size())
+               ? ptr_[i]
+               : ((void)base_internal::ThrowStdOutOfRange(
+                      "absl::string_view::at"),
+                  ptr_[i]);
+  }
+
+  // string_view::front()
+  //
+  // Returns the first element of a `string_view`.
+  constexpr const_reference front() const {
+    return ABSL_HARDENING_ASSERT(!empty()), ptr_[0];
+  }
+
+  // string_view::back()
+  //
+  // Returns the last element of a `string_view`.
+  constexpr const_reference back() const {
+    return ABSL_HARDENING_ASSERT(!empty()), ptr_[size() - 1];
+  }
+
+  // string_view::data()
+  //
+  // Returns a pointer to the underlying character array (which is of course
+  // stored elsewhere). Note that `string_view::data()` may contain embedded nul
+  // characters, but the returned buffer may or may not be NUL-terminated;
+  // therefore, do not pass `data()` to a routine that expects a NUL-terminated
+  // string.
+  constexpr const_pointer data() const noexcept { return ptr_; }
+
+  // Modifiers
+
+  // string_view::remove_prefix()
+  //
+  // Removes the first `n` characters from the `string_view`. Note that the
+  // underlying string is not changed, only the view.
+  void remove_prefix(size_type n) {
+    ABSL_HARDENING_ASSERT(n <= length_);
+    ptr_ += n;
+    length_ -= n;
+  }
+
+  // string_view::remove_suffix()
+  //
+  // Removes the last `n` characters from the `string_view`. Note that the
+  // underlying string is not changed, only the view.
+  void remove_suffix(size_type n) {
+    ABSL_HARDENING_ASSERT(n <= length_);
+    length_ -= n;
+  }
+
+  // string_view::swap()
+  //
+  // Swaps this `string_view` with another `string_view`.
+  void swap(string_view& s) noexcept {
+    auto t = *this;
+    *this = s;
+    s = t;
+  }
+
+  // Explicit conversion operators
+
+  // Converts to `std::basic_string`.
+  template <typename A>
+  explicit operator std::basic_string<char, traits_type, A>() const {
+    if (!data()) return {};
+    return std::basic_string<char, traits_type, A>(data(), size());
+  }
+
+  // string_view::copy()
+  //
+  // Copies the contents of the `string_view` at offset `pos` and length `n`
+  // into `buf`.
+  size_type copy(char* buf, size_type n, size_type pos = 0) const {
+    if (ABSL_PREDICT_FALSE(pos > length_)) {
+      base_internal::ThrowStdOutOfRange("absl::string_view::copy");
+    }
+    size_type rlen = (std::min)(length_ - pos, n);
+    if (rlen > 0) {
+      const char* start = ptr_ + pos;
+      traits_type::copy(buf, start, rlen);
+    }
+    return rlen;
+  }
+
+  // string_view::substr()
+  //
+  // Returns a "substring" of the `string_view` (at offset `pos` and length
+  // `n`) as another string_view. This function throws `std::out_of_bounds` if
+  // `pos > size`.
+  // Use absl::ClippedSubstr if you need a truncating substr operation.
+  constexpr string_view substr(size_type pos, size_type n = npos) const {
+    return ABSL_PREDICT_FALSE(pos > length_)
+               ? (base_internal::ThrowStdOutOfRange(
+                      "absl::string_view::substr"),
+                  string_view())
+               : string_view(ptr_ + pos, Min(n, length_ - pos));
+  }
+
+  // string_view::compare()
+  //
+  // Performs a lexicographical comparison between the `string_view` and
+  // another `absl::string_view`, returning -1 if `this` is less than, 0 if
+  // `this` is equal to, and 1 if `this` is greater than the passed string
+  // view. Note that in the case of data equality, a further comparison is made
+  // on the respective sizes of the two `string_view`s to determine which is
+  // smaller, equal, or greater.
+  constexpr int compare(string_view x) const noexcept {
+    return CompareImpl(length_, x.length_,
+                       Min(length_, x.length_) == 0
+                           ? 0
+                           : ABSL_INTERNAL_STRING_VIEW_MEMCMP(
+                                 ptr_, x.ptr_, Min(length_, x.length_)));
+  }
+
+  // Overload of `string_view::compare()` for comparing a substring of the
+  // 'string_view` and another `absl::string_view`.
+  int compare(size_type pos1, size_type count1, string_view v) const {
+    return substr(pos1, count1).compare(v);
+  }
+
+  // Overload of `string_view::compare()` for comparing a substring of the
+  // `string_view` and a substring of another `absl::string_view`.
+  int compare(size_type pos1, size_type count1, string_view v, size_type pos2,
+              size_type count2) const {
+    return substr(pos1, count1).compare(v.substr(pos2, count2));
+  }
+
+  // Overload of `string_view::compare()` for comparing a `string_view` and a
+  // a different  C-style string `s`.
+  int compare(const char* s) const { return compare(string_view(s)); }
+
+  // Overload of `string_view::compare()` for comparing a substring of the
+  // `string_view` and a different string C-style string `s`.
+  int compare(size_type pos1, size_type count1, const char* s) const {
+    return substr(pos1, count1).compare(string_view(s));
+  }
+
+  // Overload of `string_view::compare()` for comparing a substring of the
+  // `string_view` and a substring of a different C-style string `s`.
+  int compare(size_type pos1, size_type count1, const char* s,
+              size_type count2) const {
+    return substr(pos1, count1).compare(string_view(s, count2));
+  }
+
+  // Find Utilities
+
+  // string_view::find()
+  //
+  // Finds the first occurrence of the substring `s` within the `string_view`,
+  // returning the position of the first character's match, or `npos` if no
+  // match was found.
+  size_type find(string_view s, size_type pos = 0) const noexcept;
+
+  // Overload of `string_view::find()` for finding the given character `c`
+  // within the `string_view`.
+  size_type find(char c, size_type pos = 0) const noexcept;
+
+  // string_view::rfind()
+  //
+  // Finds the last occurrence of a substring `s` within the `string_view`,
+  // returning the position of the first character's match, or `npos` if no
+  // match was found.
+  size_type rfind(string_view s, size_type pos = npos) const
+      noexcept;
+
+  // Overload of `string_view::rfind()` for finding the last given character `c`
+  // within the `string_view`.
+  size_type rfind(char c, size_type pos = npos) const noexcept;
+
+  // string_view::find_first_of()
+  //
+  // Finds the first occurrence of any of the characters in `s` within the
+  // `string_view`, returning the start position of the match, or `npos` if no
+  // match was found.
+  size_type find_first_of(string_view s, size_type pos = 0) const
+      noexcept;
+
+  // Overload of `string_view::find_first_of()` for finding a character `c`
+  // within the `string_view`.
+  size_type find_first_of(char c, size_type pos = 0) const
+      noexcept {
+    return find(c, pos);
+  }
+
+  // string_view::find_last_of()
+  //
+  // Finds the last occurrence of any of the characters in `s` within the
+  // `string_view`, returning the start position of the match, or `npos` if no
+  // match was found.
+  size_type find_last_of(string_view s, size_type pos = npos) const
+      noexcept;
+
+  // Overload of `string_view::find_last_of()` for finding a character `c`
+  // within the `string_view`.
+  size_type find_last_of(char c, size_type pos = npos) const
+      noexcept {
+    return rfind(c, pos);
+  }
+
+  // string_view::find_first_not_of()
+  //
+  // Finds the first occurrence of any of the characters not in `s` within the
+  // `string_view`, returning the start position of the first non-match, or
+  // `npos` if no non-match was found.
+  size_type find_first_not_of(string_view s, size_type pos = 0) const noexcept;
+
+  // Overload of `string_view::find_first_not_of()` for finding a character
+  // that is not `c` within the `string_view`.
+  size_type find_first_not_of(char c, size_type pos = 0) const noexcept;
+
+  // string_view::find_last_not_of()
+  //
+  // Finds the last occurrence of any of the characters not in `s` within the
+  // `string_view`, returning the start position of the last non-match, or
+  // `npos` if no non-match was found.
+  size_type find_last_not_of(string_view s,
+                                          size_type pos = npos) const noexcept;
+
+  // Overload of `string_view::find_last_not_of()` for finding a character
+  // that is not `c` within the `string_view`.
+  size_type find_last_not_of(char c, size_type pos = npos) const
+      noexcept;
+
+ private:
+  static constexpr size_type kMaxSize =
+      (std::numeric_limits<difference_type>::max)();
+
+  static constexpr size_type CheckLengthInternal(size_type len) {
+    return ABSL_HARDENING_ASSERT(len <= kMaxSize), len;
+  }
+
+  static constexpr size_type StrlenInternal(const char* str) {
+#if defined(_MSC_VER) && _MSC_VER >= 1910 && !defined(__clang__)
+    // MSVC 2017+ can evaluate this at compile-time.
+    const char* begin = str;
+    while (*str != '\0') ++str;
+    return str - begin;
+#elif ABSL_HAVE_BUILTIN(__builtin_strlen) || \
+    (defined(__GNUC__) && !defined(__clang__))
+    // GCC has __builtin_strlen according to
+    // https://gcc.gnu.org/onlinedocs/gcc-4.7.0/gcc/Other-Builtins.html, but
+    // ABSL_HAVE_BUILTIN doesn't detect that, so we use the extra checks above.
+    // __builtin_strlen is constexpr.
+    return __builtin_strlen(str);
+#else
+    return str ? strlen(str) : 0;
+#endif
+  }
+
+  static constexpr size_t Min(size_type length_a, size_type length_b) {
+    return length_a < length_b ? length_a : length_b;
+  }
+
+  static constexpr int CompareImpl(size_type length_a, size_type length_b,
+                                   int compare_result) {
+    return compare_result == 0 ? static_cast<int>(length_a > length_b) -
+                                     static_cast<int>(length_a < length_b)
+                               : (compare_result < 0 ? -1 : 1);
+  }
+
+  const char* ptr_;
+  size_type length_;
+};
+
+// This large function is defined inline so that in a fairly common case where
+// one of the arguments is a literal, the compiler can elide a lot of the
+// following comparisons.
+constexpr bool operator==(string_view x, string_view y) noexcept {
+  return x.size() == y.size() &&
+         (x.empty() ||
+          ABSL_INTERNAL_STRING_VIEW_MEMCMP(x.data(), y.data(), x.size()) == 0);
+}
+
+constexpr bool operator!=(string_view x, string_view y) noexcept {
+  return !(x == y);
+}
+
+constexpr bool operator<(string_view x, string_view y) noexcept {
+  return x.compare(y) < 0;
+}
+
+constexpr bool operator>(string_view x, string_view y) noexcept {
+  return y < x;
+}
+
+constexpr bool operator<=(string_view x, string_view y) noexcept {
+  return !(y < x);
+}
+
+constexpr bool operator>=(string_view x, string_view y) noexcept {
+  return !(x < y);
+}
+
+// IO Insertion Operator
+std::ostream& operator<<(std::ostream& o, string_view piece);
+
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#undef ABSL_INTERNAL_STRING_VIEW_MEMCMP
+
+#endif  // ABSL_USES_STD_STRING_VIEW
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+
+// ClippedSubstr()
+//
+// Like `s.substr(pos, n)`, but clips `pos` to an upper bound of `s.size()`.
+// Provided because std::string_view::substr throws if `pos > size()`
+inline string_view ClippedSubstr(string_view s, size_t pos,
+                                 size_t n = string_view::npos) {
+  pos = (std::min)(pos, static_cast<size_t>(s.size()));
+  return s.substr(pos, n);
+}
+
+// NullSafeStringView()
+//
+// Creates an `absl::string_view` from a pointer `p` even if it's null-valued.
+// This function should be used where an `absl::string_view` can be created from
+// a possibly-null pointer.
+constexpr string_view NullSafeStringView(const char* p) {
+  return p ? string_view(p) : string_view();
+}
+
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#endif  // ABSL_STRINGS_STRING_VIEW_H_
diff --git a/src/absl/strings/strip.h b/src/absl/strings/strip.h
new file mode 100644 (file)
index 0000000..111872c
--- /dev/null
@@ -0,0 +1,91 @@
+//
+// Copyright 2017 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// -----------------------------------------------------------------------------
+// File: strip.h
+// -----------------------------------------------------------------------------
+//
+// This file contains various functions for stripping substrings from a string.
+#ifndef ABSL_STRINGS_STRIP_H_
+#define ABSL_STRINGS_STRIP_H_
+
+#include <cstddef>
+#include <string>
+
+#include "absl/base/macros.h"
+#include "absl/strings/ascii.h"
+#include "absl/strings/match.h"
+#include "absl/strings/string_view.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+
+// ConsumePrefix()
+//
+// Strips the `expected` prefix from the start of the given string, returning
+// `true` if the strip operation succeeded or false otherwise.
+//
+// Example:
+//
+//   absl::string_view input("abc");
+//   EXPECT_TRUE(absl::ConsumePrefix(&input, "a"));
+//   EXPECT_EQ(input, "bc");
+inline bool ConsumePrefix(absl::string_view* str, absl::string_view expected) {
+  if (!absl::StartsWith(*str, expected)) return false;
+  str->remove_prefix(expected.size());
+  return true;
+}
+// ConsumeSuffix()
+//
+// Strips the `expected` suffix from the end of the given string, returning
+// `true` if the strip operation succeeded or false otherwise.
+//
+// Example:
+//
+//   absl::string_view input("abcdef");
+//   EXPECT_TRUE(absl::ConsumeSuffix(&input, "def"));
+//   EXPECT_EQ(input, "abc");
+inline bool ConsumeSuffix(absl::string_view* str, absl::string_view expected) {
+  if (!absl::EndsWith(*str, expected)) return false;
+  str->remove_suffix(expected.size());
+  return true;
+}
+
+// StripPrefix()
+//
+// Returns a view into the input string 'str' with the given 'prefix' removed,
+// but leaving the original string intact. If the prefix does not match at the
+// start of the string, returns the original string instead.
+ABSL_MUST_USE_RESULT inline absl::string_view StripPrefix(
+    absl::string_view str, absl::string_view prefix) {
+  if (absl::StartsWith(str, prefix)) str.remove_prefix(prefix.size());
+  return str;
+}
+
+// StripSuffix()
+//
+// Returns a view into the input string 'str' with the given 'suffix' removed,
+// but leaving the original string intact. If the suffix does not match at the
+// end of the string, returns the original string instead.
+ABSL_MUST_USE_RESULT inline absl::string_view StripSuffix(
+    absl::string_view str, absl::string_view suffix) {
+  if (absl::EndsWith(str, suffix)) str.remove_suffix(suffix.size());
+  return str;
+}
+
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#endif  // ABSL_STRINGS_STRIP_H_
diff --git a/src/absl/strings/substitute.cc b/src/absl/strings/substitute.cc
new file mode 100644 (file)
index 0000000..1f3c740
--- /dev/null
@@ -0,0 +1,171 @@
+// Copyright 2017 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "absl/strings/substitute.h"
+
+#include <algorithm>
+
+#include "absl/base/internal/raw_logging.h"
+#include "absl/strings/ascii.h"
+#include "absl/strings/escaping.h"
+#include "absl/strings/internal/resize_uninitialized.h"
+#include "absl/strings/string_view.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace substitute_internal {
+
+void SubstituteAndAppendArray(std::string* output, absl::string_view format,
+                              const absl::string_view* args_array,
+                              size_t num_args) {
+  // Determine total size needed.
+  size_t size = 0;
+  for (size_t i = 0; i < format.size(); i++) {
+    if (format[i] == '$') {
+      if (i + 1 >= format.size()) {
+#ifndef NDEBUG
+        ABSL_RAW_LOG(FATAL,
+                     "Invalid absl::Substitute() format string: \"%s\".",
+                     absl::CEscape(format).c_str());
+#endif
+        return;
+      } else if (absl::ascii_isdigit(format[i + 1])) {
+        int index = format[i + 1] - '0';
+        if (static_cast<size_t>(index) >= num_args) {
+#ifndef NDEBUG
+          ABSL_RAW_LOG(
+              FATAL,
+              "Invalid absl::Substitute() format string: asked for \"$"
+              "%d\", but only %d args were given.  Full format string was: "
+              "\"%s\".",
+              index, static_cast<int>(num_args), absl::CEscape(format).c_str());
+#endif
+          return;
+        }
+        size += args_array[index].size();
+        ++i;  // Skip next char.
+      } else if (format[i + 1] == '$') {
+        ++size;
+        ++i;  // Skip next char.
+      } else {
+#ifndef NDEBUG
+        ABSL_RAW_LOG(FATAL,
+                     "Invalid absl::Substitute() format string: \"%s\".",
+                     absl::CEscape(format).c_str());
+#endif
+        return;
+      }
+    } else {
+      ++size;
+    }
+  }
+
+  if (size == 0) return;
+
+  // Build the string.
+  size_t original_size = output->size();
+  strings_internal::STLStringResizeUninitialized(output, original_size + size);
+  char* target = &(*output)[original_size];
+  for (size_t i = 0; i < format.size(); i++) {
+    if (format[i] == '$') {
+      if (absl::ascii_isdigit(format[i + 1])) {
+        const absl::string_view src = args_array[format[i + 1] - '0'];
+        target = std::copy(src.begin(), src.end(), target);
+        ++i;  // Skip next char.
+      } else if (format[i + 1] == '$') {
+        *target++ = '$';
+        ++i;  // Skip next char.
+      }
+    } else {
+      *target++ = format[i];
+    }
+  }
+
+  assert(target == output->data() + output->size());
+}
+
+Arg::Arg(const void* value) {
+  static_assert(sizeof(scratch_) >= sizeof(value) * 2 + 2,
+                "fix sizeof(scratch_)");
+  if (value == nullptr) {
+    piece_ = "NULL";
+  } else {
+    char* ptr = scratch_ + sizeof(scratch_);
+    uintptr_t num = reinterpret_cast<uintptr_t>(value);
+    do {
+      *--ptr = absl::numbers_internal::kHexChar[num & 0xf];
+      num >>= 4;
+    } while (num != 0);
+    *--ptr = 'x';
+    *--ptr = '0';
+    piece_ = absl::string_view(ptr, scratch_ + sizeof(scratch_) - ptr);
+  }
+}
+
+// TODO(jorg): Don't duplicate so much code between here and str_cat.cc
+Arg::Arg(Hex hex) {
+  char* const end = &scratch_[numbers_internal::kFastToBufferSize];
+  char* writer = end;
+  uint64_t value = hex.value;
+  do {
+    *--writer = absl::numbers_internal::kHexChar[value & 0xF];
+    value >>= 4;
+  } while (value != 0);
+
+  char* beg;
+  if (end - writer < hex.width) {
+    beg = end - hex.width;
+    std::fill_n(beg, writer - beg, hex.fill);
+  } else {
+    beg = writer;
+  }
+
+  piece_ = absl::string_view(beg, end - beg);
+}
+
+// TODO(jorg): Don't duplicate so much code between here and str_cat.cc
+Arg::Arg(Dec dec) {
+  assert(dec.width <= numbers_internal::kFastToBufferSize);
+  char* const end = &scratch_[numbers_internal::kFastToBufferSize];
+  char* const minfill = end - dec.width;
+  char* writer = end;
+  uint64_t value = dec.value;
+  bool neg = dec.neg;
+  while (value > 9) {
+    *--writer = '0' + (value % 10);
+    value /= 10;
+  }
+  *--writer = '0' + value;
+  if (neg) *--writer = '-';
+
+  ptrdiff_t fillers = writer - minfill;
+  if (fillers > 0) {
+    // Tricky: if the fill character is ' ', then it's <fill><+/-><digits>
+    // But...: if the fill character is '0', then it's <+/-><fill><digits>
+    bool add_sign_again = false;
+    if (neg && dec.fill == '0') {  // If filling with '0',
+      ++writer;                    // ignore the sign we just added
+      add_sign_again = true;       // and re-add the sign later.
+    }
+    writer -= fillers;
+    std::fill_n(writer, fillers, dec.fill);
+    if (add_sign_again) *--writer = '-';
+  }
+
+  piece_ = absl::string_view(writer, end - writer);
+}
+
+}  // namespace substitute_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
diff --git a/src/absl/strings/substitute.h b/src/absl/strings/substitute.h
new file mode 100644 (file)
index 0000000..c6da4dc
--- /dev/null
@@ -0,0 +1,696 @@
+//
+// Copyright 2017 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// -----------------------------------------------------------------------------
+// File: substitute.h
+// -----------------------------------------------------------------------------
+//
+// This package contains functions for efficiently performing string
+// substitutions using a format string with positional notation:
+// `Substitute()` and `SubstituteAndAppend()`.
+//
+// Unlike printf-style format specifiers, `Substitute()` functions do not need
+// to specify the type of the substitution arguments. Supported arguments
+// following the format string, such as strings, string_views, ints,
+// floats, and bools, are automatically converted to strings during the
+// substitution process. (See below for a full list of supported types.)
+//
+// `Substitute()` does not allow you to specify *how* to format a value, beyond
+// the default conversion to string. For example, you cannot format an integer
+// in hex.
+//
+// The format string uses positional identifiers indicated by a dollar sign ($)
+// and single digit positional ids to indicate which substitution arguments to
+// use at that location within the format string.
+//
+// A '$$' sequence in the format string causes a literal '$' character to be
+// output.
+//
+// Example 1:
+//   std::string s = Substitute("$1 purchased $0 $2 for $$10. Thanks $1!",
+//                              5, "Bob", "Apples");
+//   EXPECT_EQ("Bob purchased 5 Apples for $10. Thanks Bob!", s);
+//
+// Example 2:
+//   std::string s = "Hi. ";
+//   SubstituteAndAppend(&s, "My name is $0 and I am $1 years old.", "Bob", 5);
+//   EXPECT_EQ("Hi. My name is Bob and I am 5 years old.", s);
+//
+// Supported types:
+//   * absl::string_view, std::string, const char* (null is equivalent to "")
+//   * int32_t, int64_t, uint32_t, uint64_t
+//   * float, double
+//   * bool (Printed as "true" or "false")
+//   * pointer types other than char* (Printed as "0x<lower case hex string>",
+//     except that null is printed as "NULL")
+//
+// If an invalid format string is provided, Substitute returns an empty string
+// and SubstituteAndAppend does not change the provided output string.
+// A format string is invalid if it:
+//   * ends in an unescaped $ character,
+//     e.g. "Hello $", or
+//   * calls for a position argument which is not provided,
+//     e.g. Substitute("Hello $2", "world"), or
+//   * specifies a non-digit, non-$ character after an unescaped $ character,
+//     e.g. "Hello $f".
+// In debug mode, i.e. #ifndef NDEBUG, such errors terminate the program.
+
+#ifndef ABSL_STRINGS_SUBSTITUTE_H_
+#define ABSL_STRINGS_SUBSTITUTE_H_
+
+#include <cstring>
+#include <string>
+#include <type_traits>
+#include <vector>
+
+#include "absl/base/macros.h"
+#include "absl/base/port.h"
+#include "absl/strings/ascii.h"
+#include "absl/strings/escaping.h"
+#include "absl/strings/numbers.h"
+#include "absl/strings/str_cat.h"
+#include "absl/strings/str_split.h"
+#include "absl/strings/string_view.h"
+#include "absl/strings/strip.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace substitute_internal {
+
+// Arg
+//
+// This class provides an argument type for `absl::Substitute()` and
+// `absl::SubstituteAndAppend()`. `Arg` handles implicit conversion of various
+// types to a string. (`Arg` is very similar to the `AlphaNum` class in
+// `StrCat()`.)
+//
+// This class has implicit constructors.
+class Arg {
+ public:
+  // Overloads for string-y things
+  //
+  // Explicitly overload `const char*` so the compiler doesn't cast to `bool`.
+  Arg(const char* value)  // NOLINT(runtime/explicit)
+      : piece_(absl::NullSafeStringView(value)) {}
+  template <typename Allocator>
+  Arg(  // NOLINT
+      const std::basic_string<char, std::char_traits<char>, Allocator>&
+          value) noexcept
+      : piece_(value) {}
+  Arg(absl::string_view value)  // NOLINT(runtime/explicit)
+      : piece_(value) {}
+
+  // Overloads for primitives
+  //
+  // No overloads are available for signed and unsigned char because if people
+  // are explicitly declaring their chars as signed or unsigned then they are
+  // probably using them as 8-bit integers and would probably prefer an integer
+  // representation. However, we can't really know, so we make the caller decide
+  // what to do.
+  Arg(char value)  // NOLINT(runtime/explicit)
+      : piece_(scratch_, 1) {
+    scratch_[0] = value;
+  }
+  Arg(short value)  // NOLINT(*)
+      : piece_(scratch_,
+               numbers_internal::FastIntToBuffer(value, scratch_) - scratch_) {}
+  Arg(unsigned short value)  // NOLINT(*)
+      : piece_(scratch_,
+               numbers_internal::FastIntToBuffer(value, scratch_) - scratch_) {}
+  Arg(int value)  // NOLINT(runtime/explicit)
+      : piece_(scratch_,
+               numbers_internal::FastIntToBuffer(value, scratch_) - scratch_) {}
+  Arg(unsigned int value)  // NOLINT(runtime/explicit)
+      : piece_(scratch_,
+               numbers_internal::FastIntToBuffer(value, scratch_) - scratch_) {}
+  Arg(long value)  // NOLINT(*)
+      : piece_(scratch_,
+               numbers_internal::FastIntToBuffer(value, scratch_) - scratch_) {}
+  Arg(unsigned long value)  // NOLINT(*)
+      : piece_(scratch_,
+               numbers_internal::FastIntToBuffer(value, scratch_) - scratch_) {}
+  Arg(long long value)  // NOLINT(*)
+      : piece_(scratch_,
+               numbers_internal::FastIntToBuffer(value, scratch_) - scratch_) {}
+  Arg(unsigned long long value)  // NOLINT(*)
+      : piece_(scratch_,
+               numbers_internal::FastIntToBuffer(value, scratch_) - scratch_) {}
+  Arg(float value)  // NOLINT(runtime/explicit)
+      : piece_(scratch_, numbers_internal::SixDigitsToBuffer(value, scratch_)) {
+  }
+  Arg(double value)  // NOLINT(runtime/explicit)
+      : piece_(scratch_, numbers_internal::SixDigitsToBuffer(value, scratch_)) {
+  }
+  Arg(bool value)  // NOLINT(runtime/explicit)
+      : piece_(value ? "true" : "false") {}
+
+  Arg(Hex hex);  // NOLINT(runtime/explicit)
+  Arg(Dec dec);  // NOLINT(runtime/explicit)
+
+  // vector<bool>::reference and const_reference require special help to
+  // convert to `AlphaNum` because it requires two user defined conversions.
+  template <typename T,
+            absl::enable_if_t<
+                std::is_class<T>::value &&
+                (std::is_same<T, std::vector<bool>::reference>::value ||
+                 std::is_same<T, std::vector<bool>::const_reference>::value)>* =
+                nullptr>
+  Arg(T value)  // NOLINT(google-explicit-constructor)
+      : Arg(static_cast<bool>(value)) {}
+
+  // `void*` values, with the exception of `char*`, are printed as
+  // "0x<hex value>". However, in the case of `nullptr`, "NULL" is printed.
+  Arg(const void* value);  // NOLINT(runtime/explicit)
+
+  Arg(const Arg&) = delete;
+  Arg& operator=(const Arg&) = delete;
+
+  absl::string_view piece() const { return piece_; }
+
+ private:
+  absl::string_view piece_;
+  char scratch_[numbers_internal::kFastToBufferSize];
+};
+
+// Internal helper function. Don't call this from outside this implementation.
+// This interface may change without notice.
+void SubstituteAndAppendArray(std::string* output, absl::string_view format,
+                              const absl::string_view* args_array,
+                              size_t num_args);
+
+#if defined(ABSL_BAD_CALL_IF)
+constexpr int CalculateOneBit(const char* format) {
+  // Returns:
+  // * 2^N for '$N' when N is in [0-9]
+  // * 0 for correct '$' escaping: '$$'.
+  // * -1 otherwise.
+  return (*format < '0' || *format > '9') ? (*format == '$' ? 0 : -1)
+                                          : (1 << (*format - '0'));
+}
+
+constexpr const char* SkipNumber(const char* format) {
+  return !*format ? format : (format + 1);
+}
+
+constexpr int PlaceholderBitmask(const char* format) {
+  return !*format
+             ? 0
+             : *format != '$' ? PlaceholderBitmask(format + 1)
+                              : (CalculateOneBit(format + 1) |
+                                 PlaceholderBitmask(SkipNumber(format + 1)));
+}
+#endif  // ABSL_BAD_CALL_IF
+
+}  // namespace substitute_internal
+
+//
+// PUBLIC API
+//
+
+// SubstituteAndAppend()
+//
+// Substitutes variables into a given format string and appends to a given
+// output string. See file comments above for usage.
+//
+// The declarations of `SubstituteAndAppend()` below consist of overloads
+// for passing 0 to 10 arguments, respectively.
+//
+// NOTE: A zero-argument `SubstituteAndAppend()` may be used within variadic
+// templates to allow a variable number of arguments.
+//
+// Example:
+//  template <typename... Args>
+//  void VarMsg(std::string* boilerplate, absl::string_view format,
+//      const Args&... args) {
+//    absl::SubstituteAndAppend(boilerplate, format, args...);
+//  }
+//
+inline void SubstituteAndAppend(std::string* output, absl::string_view format) {
+  substitute_internal::SubstituteAndAppendArray(output, format, nullptr, 0);
+}
+
+inline void SubstituteAndAppend(std::string* output, absl::string_view format,
+                                const substitute_internal::Arg& a0) {
+  const absl::string_view args[] = {a0.piece()};
+  substitute_internal::SubstituteAndAppendArray(output, format, args,
+                                                ABSL_ARRAYSIZE(args));
+}
+
+inline void SubstituteAndAppend(std::string* output, absl::string_view format,
+                                const substitute_internal::Arg& a0,
+                                const substitute_internal::Arg& a1) {
+  const absl::string_view args[] = {a0.piece(), a1.piece()};
+  substitute_internal::SubstituteAndAppendArray(output, format, args,
+                                                ABSL_ARRAYSIZE(args));
+}
+
+inline void SubstituteAndAppend(std::string* output, absl::string_view format,
+                                const substitute_internal::Arg& a0,
+                                const substitute_internal::Arg& a1,
+                                const substitute_internal::Arg& a2) {
+  const absl::string_view args[] = {a0.piece(), a1.piece(), a2.piece()};
+  substitute_internal::SubstituteAndAppendArray(output, format, args,
+                                                ABSL_ARRAYSIZE(args));
+}
+
+inline void SubstituteAndAppend(std::string* output, absl::string_view format,
+                                const substitute_internal::Arg& a0,
+                                const substitute_internal::Arg& a1,
+                                const substitute_internal::Arg& a2,
+                                const substitute_internal::Arg& a3) {
+  const absl::string_view args[] = {a0.piece(), a1.piece(), a2.piece(),
+                                    a3.piece()};
+  substitute_internal::SubstituteAndAppendArray(output, format, args,
+                                                ABSL_ARRAYSIZE(args));
+}
+
+inline void SubstituteAndAppend(std::string* output, absl::string_view format,
+                                const substitute_internal::Arg& a0,
+                                const substitute_internal::Arg& a1,
+                                const substitute_internal::Arg& a2,
+                                const substitute_internal::Arg& a3,
+                                const substitute_internal::Arg& a4) {
+  const absl::string_view args[] = {a0.piece(), a1.piece(), a2.piece(),
+                                    a3.piece(), a4.piece()};
+  substitute_internal::SubstituteAndAppendArray(output, format, args,
+                                                ABSL_ARRAYSIZE(args));
+}
+
+inline void SubstituteAndAppend(std::string* output, absl::string_view format,
+                                const substitute_internal::Arg& a0,
+                                const substitute_internal::Arg& a1,
+                                const substitute_internal::Arg& a2,
+                                const substitute_internal::Arg& a3,
+                                const substitute_internal::Arg& a4,
+                                const substitute_internal::Arg& a5) {
+  const absl::string_view args[] = {a0.piece(), a1.piece(), a2.piece(),
+                                    a3.piece(), a4.piece(), a5.piece()};
+  substitute_internal::SubstituteAndAppendArray(output, format, args,
+                                                ABSL_ARRAYSIZE(args));
+}
+
+inline void SubstituteAndAppend(std::string* output, absl::string_view format,
+                                const substitute_internal::Arg& a0,
+                                const substitute_internal::Arg& a1,
+                                const substitute_internal::Arg& a2,
+                                const substitute_internal::Arg& a3,
+                                const substitute_internal::Arg& a4,
+                                const substitute_internal::Arg& a5,
+                                const substitute_internal::Arg& a6) {
+  const absl::string_view args[] = {a0.piece(), a1.piece(), a2.piece(),
+                                    a3.piece(), a4.piece(), a5.piece(),
+                                    a6.piece()};
+  substitute_internal::SubstituteAndAppendArray(output, format, args,
+                                                ABSL_ARRAYSIZE(args));
+}
+
+inline void SubstituteAndAppend(
+    std::string* output, absl::string_view format,
+    const substitute_internal::Arg& a0, const substitute_internal::Arg& a1,
+    const substitute_internal::Arg& a2, const substitute_internal::Arg& a3,
+    const substitute_internal::Arg& a4, const substitute_internal::Arg& a5,
+    const substitute_internal::Arg& a6, const substitute_internal::Arg& a7) {
+  const absl::string_view args[] = {a0.piece(), a1.piece(), a2.piece(),
+                                    a3.piece(), a4.piece(), a5.piece(),
+                                    a6.piece(), a7.piece()};
+  substitute_internal::SubstituteAndAppendArray(output, format, args,
+                                                ABSL_ARRAYSIZE(args));
+}
+
+inline void SubstituteAndAppend(
+    std::string* output, absl::string_view format,
+    const substitute_internal::Arg& a0, const substitute_internal::Arg& a1,
+    const substitute_internal::Arg& a2, const substitute_internal::Arg& a3,
+    const substitute_internal::Arg& a4, const substitute_internal::Arg& a5,
+    const substitute_internal::Arg& a6, const substitute_internal::Arg& a7,
+    const substitute_internal::Arg& a8) {
+  const absl::string_view args[] = {a0.piece(), a1.piece(), a2.piece(),
+                                    a3.piece(), a4.piece(), a5.piece(),
+                                    a6.piece(), a7.piece(), a8.piece()};
+  substitute_internal::SubstituteAndAppendArray(output, format, args,
+                                                ABSL_ARRAYSIZE(args));
+}
+
+inline void SubstituteAndAppend(
+    std::string* output, absl::string_view format,
+    const substitute_internal::Arg& a0, const substitute_internal::Arg& a1,
+    const substitute_internal::Arg& a2, const substitute_internal::Arg& a3,
+    const substitute_internal::Arg& a4, const substitute_internal::Arg& a5,
+    const substitute_internal::Arg& a6, const substitute_internal::Arg& a7,
+    const substitute_internal::Arg& a8, const substitute_internal::Arg& a9) {
+  const absl::string_view args[] = {
+      a0.piece(), a1.piece(), a2.piece(), a3.piece(), a4.piece(),
+      a5.piece(), a6.piece(), a7.piece(), a8.piece(), a9.piece()};
+  substitute_internal::SubstituteAndAppendArray(output, format, args,
+                                                ABSL_ARRAYSIZE(args));
+}
+
+#if defined(ABSL_BAD_CALL_IF)
+// This body of functions catches cases where the number of placeholders
+// doesn't match the number of data arguments.
+void SubstituteAndAppend(std::string* output, const char* format)
+    ABSL_BAD_CALL_IF(substitute_internal::PlaceholderBitmask(format) != 0,
+                     "There were no substitution arguments "
+                     "but this format string has a $[0-9] in it");
+
+void SubstituteAndAppend(std::string* output, const char* format,
+                         const substitute_internal::Arg& a0)
+    ABSL_BAD_CALL_IF(substitute_internal::PlaceholderBitmask(format) != 1,
+                     "There was 1 substitution argument given, but "
+                     "this format string is either missing its $0, or "
+                     "contains one of $1-$9");
+
+void SubstituteAndAppend(std::string* output, const char* format,
+                         const substitute_internal::Arg& a0,
+                         const substitute_internal::Arg& a1)
+    ABSL_BAD_CALL_IF(substitute_internal::PlaceholderBitmask(format) != 3,
+                     "There were 2 substitution arguments given, but "
+                     "this format string is either missing its $0/$1, or "
+                     "contains one of $2-$9");
+
+void SubstituteAndAppend(std::string* output, const char* format,
+                         const substitute_internal::Arg& a0,
+                         const substitute_internal::Arg& a1,
+                         const substitute_internal::Arg& a2)
+    ABSL_BAD_CALL_IF(substitute_internal::PlaceholderBitmask(format) != 7,
+                     "There were 3 substitution arguments given, but "
+                     "this format string is either missing its $0/$1/$2, or "
+                     "contains one of $3-$9");
+
+void SubstituteAndAppend(std::string* output, const char* format,
+                         const substitute_internal::Arg& a0,
+                         const substitute_internal::Arg& a1,
+                         const substitute_internal::Arg& a2,
+                         const substitute_internal::Arg& a3)
+    ABSL_BAD_CALL_IF(substitute_internal::PlaceholderBitmask(format) != 15,
+                     "There were 4 substitution arguments given, but "
+                     "this format string is either missing its $0-$3, or "
+                     "contains one of $4-$9");
+
+void SubstituteAndAppend(std::string* output, const char* format,
+                         const substitute_internal::Arg& a0,
+                         const substitute_internal::Arg& a1,
+                         const substitute_internal::Arg& a2,
+                         const substitute_internal::Arg& a3,
+                         const substitute_internal::Arg& a4)
+    ABSL_BAD_CALL_IF(substitute_internal::PlaceholderBitmask(format) != 31,
+                     "There were 5 substitution arguments given, but "
+                     "this format string is either missing its $0-$4, or "
+                     "contains one of $5-$9");
+
+void SubstituteAndAppend(std::string* output, const char* format,
+                         const substitute_internal::Arg& a0,
+                         const substitute_internal::Arg& a1,
+                         const substitute_internal::Arg& a2,
+                         const substitute_internal::Arg& a3,
+                         const substitute_internal::Arg& a4,
+                         const substitute_internal::Arg& a5)
+    ABSL_BAD_CALL_IF(substitute_internal::PlaceholderBitmask(format) != 63,
+                     "There were 6 substitution arguments given, but "
+                     "this format string is either missing its $0-$5, or "
+                     "contains one of $6-$9");
+
+void SubstituteAndAppend(
+    std::string* output, const char* format, const substitute_internal::Arg& a0,
+    const substitute_internal::Arg& a1, const substitute_internal::Arg& a2,
+    const substitute_internal::Arg& a3, const substitute_internal::Arg& a4,
+    const substitute_internal::Arg& a5, const substitute_internal::Arg& a6)
+    ABSL_BAD_CALL_IF(substitute_internal::PlaceholderBitmask(format) != 127,
+                     "There were 7 substitution arguments given, but "
+                     "this format string is either missing its $0-$6, or "
+                     "contains one of $7-$9");
+
+void SubstituteAndAppend(
+    std::string* output, const char* format, const substitute_internal::Arg& a0,
+    const substitute_internal::Arg& a1, const substitute_internal::Arg& a2,
+    const substitute_internal::Arg& a3, const substitute_internal::Arg& a4,
+    const substitute_internal::Arg& a5, const substitute_internal::Arg& a6,
+    const substitute_internal::Arg& a7)
+    ABSL_BAD_CALL_IF(substitute_internal::PlaceholderBitmask(format) != 255,
+                     "There were 8 substitution arguments given, but "
+                     "this format string is either missing its $0-$7, or "
+                     "contains one of $8-$9");
+
+void SubstituteAndAppend(
+    std::string* output, const char* format, const substitute_internal::Arg& a0,
+    const substitute_internal::Arg& a1, const substitute_internal::Arg& a2,
+    const substitute_internal::Arg& a3, const substitute_internal::Arg& a4,
+    const substitute_internal::Arg& a5, const substitute_internal::Arg& a6,
+    const substitute_internal::Arg& a7, const substitute_internal::Arg& a8)
+    ABSL_BAD_CALL_IF(
+        substitute_internal::PlaceholderBitmask(format) != 511,
+        "There were 9 substitution arguments given, but "
+        "this format string is either missing its $0-$8, or contains a $9");
+
+void SubstituteAndAppend(
+    std::string* output, const char* format, const substitute_internal::Arg& a0,
+    const substitute_internal::Arg& a1, const substitute_internal::Arg& a2,
+    const substitute_internal::Arg& a3, const substitute_internal::Arg& a4,
+    const substitute_internal::Arg& a5, const substitute_internal::Arg& a6,
+    const substitute_internal::Arg& a7, const substitute_internal::Arg& a8,
+    const substitute_internal::Arg& a9)
+    ABSL_BAD_CALL_IF(substitute_internal::PlaceholderBitmask(format) != 1023,
+                     "There were 10 substitution arguments given, but this "
+                     "format string doesn't contain all of $0 through $9");
+#endif  // ABSL_BAD_CALL_IF
+
+// Substitute()
+//
+// Substitutes variables into a given format string. See file comments above
+// for usage.
+//
+// The declarations of `Substitute()` below consist of overloads for passing 0
+// to 10 arguments, respectively.
+//
+// NOTE: A zero-argument `Substitute()` may be used within variadic templates to
+// allow a variable number of arguments.
+//
+// Example:
+//  template <typename... Args>
+//  void VarMsg(absl::string_view format, const Args&... args) {
+//    std::string s = absl::Substitute(format, args...);
+
+ABSL_MUST_USE_RESULT inline std::string Substitute(absl::string_view format) {
+  std::string result;
+  SubstituteAndAppend(&result, format);
+  return result;
+}
+
+ABSL_MUST_USE_RESULT inline std::string Substitute(
+    absl::string_view format, const substitute_internal::Arg& a0) {
+  std::string result;
+  SubstituteAndAppend(&result, format, a0);
+  return result;
+}
+
+ABSL_MUST_USE_RESULT inline std::string Substitute(
+    absl::string_view format, const substitute_internal::Arg& a0,
+    const substitute_internal::Arg& a1) {
+  std::string result;
+  SubstituteAndAppend(&result, format, a0, a1);
+  return result;
+}
+
+ABSL_MUST_USE_RESULT inline std::string Substitute(
+    absl::string_view format, const substitute_internal::Arg& a0,
+    const substitute_internal::Arg& a1, const substitute_internal::Arg& a2) {
+  std::string result;
+  SubstituteAndAppend(&result, format, a0, a1, a2);
+  return result;
+}
+
+ABSL_MUST_USE_RESULT inline std::string Substitute(
+    absl::string_view format, const substitute_internal::Arg& a0,
+    const substitute_internal::Arg& a1, const substitute_internal::Arg& a2,
+    const substitute_internal::Arg& a3) {
+  std::string result;
+  SubstituteAndAppend(&result, format, a0, a1, a2, a3);
+  return result;
+}
+
+ABSL_MUST_USE_RESULT inline std::string Substitute(
+    absl::string_view format, const substitute_internal::Arg& a0,
+    const substitute_internal::Arg& a1, const substitute_internal::Arg& a2,
+    const substitute_internal::Arg& a3, const substitute_internal::Arg& a4) {
+  std::string result;
+  SubstituteAndAppend(&result, format, a0, a1, a2, a3, a4);
+  return result;
+}
+
+ABSL_MUST_USE_RESULT inline std::string Substitute(
+    absl::string_view format, const substitute_internal::Arg& a0,
+    const substitute_internal::Arg& a1, const substitute_internal::Arg& a2,
+    const substitute_internal::Arg& a3, const substitute_internal::Arg& a4,
+    const substitute_internal::Arg& a5) {
+  std::string result;
+  SubstituteAndAppend(&result, format, a0, a1, a2, a3, a4, a5);
+  return result;
+}
+
+ABSL_MUST_USE_RESULT inline std::string Substitute(
+    absl::string_view format, const substitute_internal::Arg& a0,
+    const substitute_internal::Arg& a1, const substitute_internal::Arg& a2,
+    const substitute_internal::Arg& a3, const substitute_internal::Arg& a4,
+    const substitute_internal::Arg& a5, const substitute_internal::Arg& a6) {
+  std::string result;
+  SubstituteAndAppend(&result, format, a0, a1, a2, a3, a4, a5, a6);
+  return result;
+}
+
+ABSL_MUST_USE_RESULT inline std::string Substitute(
+    absl::string_view format, const substitute_internal::Arg& a0,
+    const substitute_internal::Arg& a1, const substitute_internal::Arg& a2,
+    const substitute_internal::Arg& a3, const substitute_internal::Arg& a4,
+    const substitute_internal::Arg& a5, const substitute_internal::Arg& a6,
+    const substitute_internal::Arg& a7) {
+  std::string result;
+  SubstituteAndAppend(&result, format, a0, a1, a2, a3, a4, a5, a6, a7);
+  return result;
+}
+
+ABSL_MUST_USE_RESULT inline std::string Substitute(
+    absl::string_view format, const substitute_internal::Arg& a0,
+    const substitute_internal::Arg& a1, const substitute_internal::Arg& a2,
+    const substitute_internal::Arg& a3, const substitute_internal::Arg& a4,
+    const substitute_internal::Arg& a5, const substitute_internal::Arg& a6,
+    const substitute_internal::Arg& a7, const substitute_internal::Arg& a8) {
+  std::string result;
+  SubstituteAndAppend(&result, format, a0, a1, a2, a3, a4, a5, a6, a7, a8);
+  return result;
+}
+
+ABSL_MUST_USE_RESULT inline std::string Substitute(
+    absl::string_view format, const substitute_internal::Arg& a0,
+    const substitute_internal::Arg& a1, const substitute_internal::Arg& a2,
+    const substitute_internal::Arg& a3, const substitute_internal::Arg& a4,
+    const substitute_internal::Arg& a5, const substitute_internal::Arg& a6,
+    const substitute_internal::Arg& a7, const substitute_internal::Arg& a8,
+    const substitute_internal::Arg& a9) {
+  std::string result;
+  SubstituteAndAppend(&result, format, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);
+  return result;
+}
+
+#if defined(ABSL_BAD_CALL_IF)
+// This body of functions catches cases where the number of placeholders
+// doesn't match the number of data arguments.
+std::string Substitute(const char* format)
+    ABSL_BAD_CALL_IF(substitute_internal::PlaceholderBitmask(format) != 0,
+                     "There were no substitution arguments "
+                     "but this format string has a $[0-9] in it");
+
+std::string Substitute(const char* format, const substitute_internal::Arg& a0)
+    ABSL_BAD_CALL_IF(substitute_internal::PlaceholderBitmask(format) != 1,
+                     "There was 1 substitution argument given, but "
+                     "this format string is either missing its $0, or "
+                     "contains one of $1-$9");
+
+std::string Substitute(const char* format, const substitute_internal::Arg& a0,
+                       const substitute_internal::Arg& a1)
+    ABSL_BAD_CALL_IF(substitute_internal::PlaceholderBitmask(format) != 3,
+                     "There were 2 substitution arguments given, but "
+                     "this format string is either missing its $0/$1, or "
+                     "contains one of $2-$9");
+
+std::string Substitute(const char* format, const substitute_internal::Arg& a0,
+                       const substitute_internal::Arg& a1,
+                       const substitute_internal::Arg& a2)
+    ABSL_BAD_CALL_IF(substitute_internal::PlaceholderBitmask(format) != 7,
+                     "There were 3 substitution arguments given, but "
+                     "this format string is either missing its $0/$1/$2, or "
+                     "contains one of $3-$9");
+
+std::string Substitute(const char* format, const substitute_internal::Arg& a0,
+                       const substitute_internal::Arg& a1,
+                       const substitute_internal::Arg& a2,
+                       const substitute_internal::Arg& a3)
+    ABSL_BAD_CALL_IF(substitute_internal::PlaceholderBitmask(format) != 15,
+                     "There were 4 substitution arguments given, but "
+                     "this format string is either missing its $0-$3, or "
+                     "contains one of $4-$9");
+
+std::string Substitute(const char* format, const substitute_internal::Arg& a0,
+                       const substitute_internal::Arg& a1,
+                       const substitute_internal::Arg& a2,
+                       const substitute_internal::Arg& a3,
+                       const substitute_internal::Arg& a4)
+    ABSL_BAD_CALL_IF(substitute_internal::PlaceholderBitmask(format) != 31,
+                     "There were 5 substitution arguments given, but "
+                     "this format string is either missing its $0-$4, or "
+                     "contains one of $5-$9");
+
+std::string Substitute(const char* format, const substitute_internal::Arg& a0,
+                       const substitute_internal::Arg& a1,
+                       const substitute_internal::Arg& a2,
+                       const substitute_internal::Arg& a3,
+                       const substitute_internal::Arg& a4,
+                       const substitute_internal::Arg& a5)
+    ABSL_BAD_CALL_IF(substitute_internal::PlaceholderBitmask(format) != 63,
+                     "There were 6 substitution arguments given, but "
+                     "this format string is either missing its $0-$5, or "
+                     "contains one of $6-$9");
+
+std::string Substitute(const char* format, const substitute_internal::Arg& a0,
+                       const substitute_internal::Arg& a1,
+                       const substitute_internal::Arg& a2,
+                       const substitute_internal::Arg& a3,
+                       const substitute_internal::Arg& a4,
+                       const substitute_internal::Arg& a5,
+                       const substitute_internal::Arg& a6)
+    ABSL_BAD_CALL_IF(substitute_internal::PlaceholderBitmask(format) != 127,
+                     "There were 7 substitution arguments given, but "
+                     "this format string is either missing its $0-$6, or "
+                     "contains one of $7-$9");
+
+std::string Substitute(const char* format, const substitute_internal::Arg& a0,
+                       const substitute_internal::Arg& a1,
+                       const substitute_internal::Arg& a2,
+                       const substitute_internal::Arg& a3,
+                       const substitute_internal::Arg& a4,
+                       const substitute_internal::Arg& a5,
+                       const substitute_internal::Arg& a6,
+                       const substitute_internal::Arg& a7)
+    ABSL_BAD_CALL_IF(substitute_internal::PlaceholderBitmask(format) != 255,
+                     "There were 8 substitution arguments given, but "
+                     "this format string is either missing its $0-$7, or "
+                     "contains one of $8-$9");
+
+std::string Substitute(
+    const char* format, const substitute_internal::Arg& a0,
+    const substitute_internal::Arg& a1, const substitute_internal::Arg& a2,
+    const substitute_internal::Arg& a3, const substitute_internal::Arg& a4,
+    const substitute_internal::Arg& a5, const substitute_internal::Arg& a6,
+    const substitute_internal::Arg& a7, const substitute_internal::Arg& a8)
+    ABSL_BAD_CALL_IF(
+        substitute_internal::PlaceholderBitmask(format) != 511,
+        "There were 9 substitution arguments given, but "
+        "this format string is either missing its $0-$8, or contains a $9");
+
+std::string Substitute(
+    const char* format, const substitute_internal::Arg& a0,
+    const substitute_internal::Arg& a1, const substitute_internal::Arg& a2,
+    const substitute_internal::Arg& a3, const substitute_internal::Arg& a4,
+    const substitute_internal::Arg& a5, const substitute_internal::Arg& a6,
+    const substitute_internal::Arg& a7, const substitute_internal::Arg& a8,
+    const substitute_internal::Arg& a9)
+    ABSL_BAD_CALL_IF(substitute_internal::PlaceholderBitmask(format) != 1023,
+                     "There were 10 substitution arguments given, but this "
+                     "format string doesn't contain all of $0 through $9");
+#endif  // ABSL_BAD_CALL_IF
+
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#endif  // ABSL_STRINGS_SUBSTITUTE_H_
diff --git a/src/absl/synchronization/barrier.cc b/src/absl/synchronization/barrier.cc
new file mode 100644 (file)
index 0000000..0dfd795
--- /dev/null
@@ -0,0 +1,52 @@
+// Copyright 2017 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "absl/synchronization/barrier.h"
+
+#include "absl/base/internal/raw_logging.h"
+#include "absl/synchronization/mutex.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+
+// Return whether int *arg is zero.
+static bool IsZero(void *arg) {
+  return 0 == *reinterpret_cast<int *>(arg);
+}
+
+bool Barrier::Block() {
+  MutexLock l(&this->lock_);
+
+  this->num_to_block_--;
+  if (this->num_to_block_ < 0) {
+    ABSL_RAW_LOG(
+        FATAL,
+        "Block() called too many times.  num_to_block_=%d out of total=%d",
+        this->num_to_block_, this->num_to_exit_);
+  }
+
+  this->lock_.Await(Condition(IsZero, &this->num_to_block_));
+
+  // Determine which thread can safely delete this Barrier object
+  this->num_to_exit_--;
+  ABSL_RAW_CHECK(this->num_to_exit_ >= 0, "barrier underflow");
+
+  // If num_to_exit_ == 0 then all other threads in the barrier have
+  // exited the Wait() and have released the Mutex so this thread is
+  // free to delete the barrier.
+  return this->num_to_exit_ == 0;
+}
+
+ABSL_NAMESPACE_END
+}  // namespace absl
diff --git a/src/absl/synchronization/barrier.h b/src/absl/synchronization/barrier.h
new file mode 100644 (file)
index 0000000..d8e7544
--- /dev/null
@@ -0,0 +1,79 @@
+// Copyright 2017 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// -----------------------------------------------------------------------------
+// barrier.h
+// -----------------------------------------------------------------------------
+
+#ifndef ABSL_SYNCHRONIZATION_BARRIER_H_
+#define ABSL_SYNCHRONIZATION_BARRIER_H_
+
+#include "absl/base/thread_annotations.h"
+#include "absl/synchronization/mutex.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+
+// Barrier
+//
+// This class creates a barrier which blocks threads until a prespecified
+// threshold of threads (`num_threads`) utilizes the barrier. A thread utilizes
+// the `Barrier` by calling `Block()` on the barrier, which will block that
+// thread; no call to `Block()` will return until `num_threads` threads have
+// called it.
+//
+// Exactly one call to `Block()` will return `true`, which is then responsible
+// for destroying the barrier; because stack allocation will cause the barrier
+// to be deleted when it is out of scope, barriers should not be stack
+// allocated.
+//
+// Example:
+//
+//   // Main thread creates a `Barrier`:
+//   barrier = new Barrier(num_threads);
+//
+//   // Each participating thread could then call:
+//   if (barrier->Block()) delete barrier;  // Exactly one call to `Block()`
+//                                          // returns `true`; that call
+//                                          // deletes the barrier.
+class Barrier {
+ public:
+  // `num_threads` is the number of threads that will participate in the barrier
+  explicit Barrier(int num_threads)
+      : num_to_block_(num_threads), num_to_exit_(num_threads) {}
+
+  Barrier(const Barrier&) = delete;
+  Barrier& operator=(const Barrier&) = delete;
+
+  // Barrier::Block()
+  //
+  // Blocks the current thread, and returns only when the `num_threads`
+  // threshold of threads utilizing this barrier has been reached. `Block()`
+  // returns `true` for precisely one caller, which may then destroy the
+  // barrier.
+  //
+  // Memory ordering: For any threads X and Y, any action taken by X
+  // before X calls `Block()` will be visible to Y after Y returns from
+  // `Block()`.
+  bool Block();
+
+ private:
+  Mutex lock_;
+  int num_to_block_ ABSL_GUARDED_BY(lock_);
+  int num_to_exit_ ABSL_GUARDED_BY(lock_);
+};
+
+ABSL_NAMESPACE_END
+}  // namespace absl
+#endif  // ABSL_SYNCHRONIZATION_BARRIER_H_
diff --git a/src/absl/synchronization/blocking_counter.cc b/src/absl/synchronization/blocking_counter.cc
new file mode 100644 (file)
index 0000000..3cea7ae
--- /dev/null
@@ -0,0 +1,57 @@
+// Copyright 2017 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "absl/synchronization/blocking_counter.h"
+
+#include "absl/base/internal/raw_logging.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+
+// Return whether int *arg is zero.
+static bool IsZero(void *arg) {
+  return 0 == *reinterpret_cast<int *>(arg);
+}
+
+bool BlockingCounter::DecrementCount() {
+  MutexLock l(&lock_);
+  count_--;
+  if (count_ < 0) {
+    ABSL_RAW_LOG(
+        FATAL,
+        "BlockingCounter::DecrementCount() called too many times.  count=%d",
+        count_);
+  }
+  return count_ == 0;
+}
+
+void BlockingCounter::Wait() {
+  MutexLock l(&this->lock_);
+  ABSL_RAW_CHECK(count_ >= 0, "BlockingCounter underflow");
+
+  // only one thread may call Wait(). To support more than one thread,
+  // implement a counter num_to_exit, like in the Barrier class.
+  ABSL_RAW_CHECK(num_waiting_ == 0, "multiple threads called Wait()");
+  num_waiting_++;
+
+  this->lock_.Await(Condition(IsZero, &this->count_));
+
+  // At this point, We know that all threads executing DecrementCount have
+  // released the lock, and so will not touch this object again.
+  // Therefore, the thread calling this method is free to delete the object
+  // after we return from this method.
+}
+
+ABSL_NAMESPACE_END
+}  // namespace absl
diff --git a/src/absl/synchronization/blocking_counter.h b/src/absl/synchronization/blocking_counter.h
new file mode 100644 (file)
index 0000000..1f53f9f
--- /dev/null
@@ -0,0 +1,99 @@
+//
+// Copyright 2017 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// -----------------------------------------------------------------------------
+// blocking_counter.h
+// -----------------------------------------------------------------------------
+
+#ifndef ABSL_SYNCHRONIZATION_BLOCKING_COUNTER_H_
+#define ABSL_SYNCHRONIZATION_BLOCKING_COUNTER_H_
+
+#include "absl/base/thread_annotations.h"
+#include "absl/synchronization/mutex.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+
+// BlockingCounter
+//
+// This class allows a thread to block for a pre-specified number of actions.
+// `BlockingCounter` maintains a single non-negative abstract integer "count"
+// with an initial value `initial_count`. A thread can then call `Wait()` on
+// this blocking counter to block until the specified number of events occur;
+// worker threads then call 'DecrementCount()` on the counter upon completion of
+// their work. Once the counter's internal "count" reaches zero, the blocked
+// thread unblocks.
+//
+// A `BlockingCounter` requires the following:
+//     - its `initial_count` is non-negative.
+//     - the number of calls to `DecrementCount()` on it is at most
+//       `initial_count`.
+//     - `Wait()` is called at most once on it.
+//
+// Given the above requirements, a `BlockingCounter` provides the following
+// guarantees:
+//     - Once its internal "count" reaches zero, no legal action on the object
+//       can further change the value of "count".
+//     - When `Wait()` returns, it is legal to destroy the `BlockingCounter`.
+//     - When `Wait()` returns, the number of calls to `DecrementCount()` on
+//       this blocking counter exactly equals `initial_count`.
+//
+// Example:
+//     BlockingCounter bcount(N);         // there are N items of work
+//     ... Allow worker threads to start.
+//     ... On completing each work item, workers do:
+//     ... bcount.DecrementCount();      // an item of work has been completed
+//
+//     bcount.Wait();                    // wait for all work to be complete
+//
+class BlockingCounter {
+ public:
+  explicit BlockingCounter(int initial_count)
+      : count_(initial_count), num_waiting_(0) {}
+
+  BlockingCounter(const BlockingCounter&) = delete;
+  BlockingCounter& operator=(const BlockingCounter&) = delete;
+
+  // BlockingCounter::DecrementCount()
+  //
+  // Decrements the counter's "count" by one, and return "count == 0". This
+  // function requires that "count != 0" when it is called.
+  //
+  // Memory ordering: For any threads X and Y, any action taken by X
+  // before it calls `DecrementCount()` is visible to thread Y after
+  // Y's call to `DecrementCount()`, provided Y's call returns `true`.
+  bool DecrementCount();
+
+  // BlockingCounter::Wait()
+  //
+  // Blocks until the counter reaches zero. This function may be called at most
+  // once. On return, `DecrementCount()` will have been called "initial_count"
+  // times and the blocking counter may be destroyed.
+  //
+  // Memory ordering: For any threads X and Y, any action taken by X
+  // before X calls `DecrementCount()` is visible to Y after Y returns
+  // from `Wait()`.
+  void Wait();
+
+ private:
+  Mutex lock_;
+  int count_ ABSL_GUARDED_BY(lock_);
+  int num_waiting_ ABSL_GUARDED_BY(lock_);
+};
+
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#endif  // ABSL_SYNCHRONIZATION_BLOCKING_COUNTER_H_
diff --git a/src/absl/synchronization/internal/create_thread_identity.cc b/src/absl/synchronization/internal/create_thread_identity.cc
new file mode 100644 (file)
index 0000000..53a71b3
--- /dev/null
@@ -0,0 +1,140 @@
+// Copyright 2017 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <stdint.h>
+#include <new>
+
+// This file is a no-op if the required LowLevelAlloc support is missing.
+#include "absl/base/internal/low_level_alloc.h"
+#ifndef ABSL_LOW_LEVEL_ALLOC_MISSING
+
+#include <string.h>
+
+#include "absl/base/attributes.h"
+#include "absl/base/internal/spinlock.h"
+#include "absl/base/internal/thread_identity.h"
+#include "absl/synchronization/internal/per_thread_sem.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace synchronization_internal {
+
+// ThreadIdentity storage is persistent, we maintain a free-list of previously
+// released ThreadIdentity objects.
+ABSL_CONST_INIT static base_internal::SpinLock freelist_lock(
+    absl::kConstInit, base_internal::SCHEDULE_KERNEL_ONLY);
+ABSL_CONST_INIT static base_internal::ThreadIdentity* thread_identity_freelist;
+
+// A per-thread destructor for reclaiming associated ThreadIdentity objects.
+// Since we must preserve their storage we cache them for re-use.
+void ReclaimThreadIdentity(void* v) {
+  base_internal::ThreadIdentity* identity =
+      static_cast<base_internal::ThreadIdentity*>(v);
+
+  // all_locks might have been allocated by the Mutex implementation.
+  // We free it here when we are notified that our thread is dying.
+  if (identity->per_thread_synch.all_locks != nullptr) {
+    base_internal::LowLevelAlloc::Free(identity->per_thread_synch.all_locks);
+  }
+
+  PerThreadSem::Destroy(identity);
+
+  // We must explicitly clear the current thread's identity:
+  // (a) Subsequent (unrelated) per-thread destructors may require an identity.
+  //     We must guarantee a new identity is used in this case (this instructor
+  //     will be reinvoked up to PTHREAD_DESTRUCTOR_ITERATIONS in this case).
+  // (b) ThreadIdentity implementations may depend on memory that is not
+  //     reinitialized before reuse.  We must allow explicit clearing of the
+  //     association state in this case.
+  base_internal::ClearCurrentThreadIdentity();
+  {
+    base_internal::SpinLockHolder l(&freelist_lock);
+    identity->next = thread_identity_freelist;
+    thread_identity_freelist = identity;
+  }
+}
+
+// Return value rounded up to next multiple of align.
+// Align must be a power of two.
+static intptr_t RoundUp(intptr_t addr, intptr_t align) {
+  return (addr + align - 1) & ~(align - 1);
+}
+
+static void ResetThreadIdentity(base_internal::ThreadIdentity* identity) {
+  base_internal::PerThreadSynch* pts = &identity->per_thread_synch;
+  pts->next = nullptr;
+  pts->skip = nullptr;
+  pts->may_skip = false;
+  pts->waitp = nullptr;
+  pts->suppress_fatal_errors = false;
+  pts->readers = 0;
+  pts->priority = 0;
+  pts->next_priority_read_cycles = 0;
+  pts->state.store(base_internal::PerThreadSynch::State::kAvailable,
+                   std::memory_order_relaxed);
+  pts->maybe_unlocking = false;
+  pts->wake = false;
+  pts->cond_waiter = false;
+  pts->all_locks = nullptr;
+  identity->blocked_count_ptr = nullptr;
+  identity->ticker.store(0, std::memory_order_relaxed);
+  identity->wait_start.store(0, std::memory_order_relaxed);
+  identity->is_idle.store(false, std::memory_order_relaxed);
+  identity->next = nullptr;
+}
+
+static base_internal::ThreadIdentity* NewThreadIdentity() {
+  base_internal::ThreadIdentity* identity = nullptr;
+
+  {
+    // Re-use a previously released object if possible.
+    base_internal::SpinLockHolder l(&freelist_lock);
+    if (thread_identity_freelist) {
+      identity = thread_identity_freelist;  // Take list-head.
+      thread_identity_freelist = thread_identity_freelist->next;
+    }
+  }
+
+  if (identity == nullptr) {
+    // Allocate enough space to align ThreadIdentity to a multiple of
+    // PerThreadSynch::kAlignment. This space is never released (it is
+    // added to a freelist by ReclaimThreadIdentity instead).
+    void* allocation = base_internal::LowLevelAlloc::Alloc(
+        sizeof(*identity) + base_internal::PerThreadSynch::kAlignment - 1);
+    // Round up the address to the required alignment.
+    identity = reinterpret_cast<base_internal::ThreadIdentity*>(
+        RoundUp(reinterpret_cast<intptr_t>(allocation),
+                base_internal::PerThreadSynch::kAlignment));
+  }
+  ResetThreadIdentity(identity);
+
+  return identity;
+}
+
+// Allocates and attaches ThreadIdentity object for the calling thread.  Returns
+// the new identity.
+// REQUIRES: CurrentThreadIdentity(false) == nullptr
+base_internal::ThreadIdentity* CreateThreadIdentity() {
+  base_internal::ThreadIdentity* identity = NewThreadIdentity();
+  PerThreadSem::Init(identity);
+  // Associate the value with the current thread, and attach our destructor.
+  base_internal::SetCurrentThreadIdentity(identity, ReclaimThreadIdentity);
+  return identity;
+}
+
+}  // namespace synchronization_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#endif  // ABSL_LOW_LEVEL_ALLOC_MISSING
diff --git a/src/absl/synchronization/internal/create_thread_identity.h b/src/absl/synchronization/internal/create_thread_identity.h
new file mode 100644 (file)
index 0000000..e121f68
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2017 The Abseil Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// Interface for getting the current ThreadIdentity, creating one if necessary.
+// See thread_identity.h.
+//
+// This file is separate from thread_identity.h because creating a new
+// ThreadIdentity requires slightly higher level libraries (per_thread_sem
+// and low_level_alloc) than accessing an existing one.  This separation allows
+// us to have a smaller //absl/base:base.
+
+#ifndef ABSL_SYNCHRONIZATION_INTERNAL_CREATE_THREAD_IDENTITY_H_
+#define ABSL_SYNCHRONIZATION_INTERNAL_CREATE_THREAD_IDENTITY_H_
+
+#include "absl/base/internal/thread_identity.h"
+#include "absl/base/port.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace synchronization_internal {
+
+// Allocates and attaches a ThreadIdentity object for the calling thread.
+// For private use only.
+base_internal::ThreadIdentity* CreateThreadIdentity();
+
+// A per-thread destructor for reclaiming associated ThreadIdentity objects.
+// For private use only.
+void ReclaimThreadIdentity(void* v);
+
+// Returns the ThreadIdentity object representing the calling thread; guaranteed
+// to be unique for its lifetime.  The returned object will remain valid for the
+// program's lifetime; although it may be re-assigned to a subsequent thread.
+// If one does not exist for the calling thread, allocate it now.
+inline base_internal::ThreadIdentity* GetOrCreateCurrentThreadIdentity() {
+  base_internal::ThreadIdentity* identity =
+      base_internal::CurrentThreadIdentityIfPresent();
+  if (ABSL_PREDICT_FALSE(identity == nullptr)) {
+    return CreateThreadIdentity();
+  }
+  return identity;
+}
+
+}  // namespace synchronization_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#endif  // ABSL_SYNCHRONIZATION_INTERNAL_CREATE_THREAD_IDENTITY_H_
diff --git a/src/absl/synchronization/internal/futex.h b/src/absl/synchronization/internal/futex.h
new file mode 100644 (file)
index 0000000..06fbd6d
--- /dev/null
@@ -0,0 +1,154 @@
+// Copyright 2020 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+#ifndef ABSL_SYNCHRONIZATION_INTERNAL_FUTEX_H_
+#define ABSL_SYNCHRONIZATION_INTERNAL_FUTEX_H_
+
+#include "absl/base/config.h"
+
+#ifdef _WIN32
+#include <windows.h>
+#else
+#include <sys/time.h>
+#include <unistd.h>
+#endif
+
+#ifdef __linux__
+#include <linux/futex.h>
+#include <sys/syscall.h>
+#endif
+
+#include <errno.h>
+#include <stdio.h>
+#include <time.h>
+
+#include <atomic>
+#include <cstdint>
+
+#include "absl/base/optimization.h"
+#include "absl/synchronization/internal/kernel_timeout.h"
+
+#ifdef ABSL_INTERNAL_HAVE_FUTEX
+#error ABSL_INTERNAL_HAVE_FUTEX may not be set on the command line
+#elif defined(__BIONIC__)
+// Bionic supports all the futex operations we need even when some of the futex
+// definitions are missing.
+#define ABSL_INTERNAL_HAVE_FUTEX
+#elif defined(__linux__) && defined(FUTEX_CLOCK_REALTIME)
+// FUTEX_CLOCK_REALTIME requires Linux >= 2.6.28.
+#define ABSL_INTERNAL_HAVE_FUTEX
+#endif
+
+#ifdef ABSL_INTERNAL_HAVE_FUTEX
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace synchronization_internal {
+
+// Some Android headers are missing these definitions even though they
+// support these futex operations.
+#ifdef __BIONIC__
+#ifndef SYS_futex
+#define SYS_futex __NR_futex
+#endif
+#ifndef FUTEX_WAIT_BITSET
+#define FUTEX_WAIT_BITSET 9
+#endif
+#ifndef FUTEX_PRIVATE_FLAG
+#define FUTEX_PRIVATE_FLAG 128
+#endif
+#ifndef FUTEX_CLOCK_REALTIME
+#define FUTEX_CLOCK_REALTIME 256
+#endif
+#ifndef FUTEX_BITSET_MATCH_ANY
+#define FUTEX_BITSET_MATCH_ANY 0xFFFFFFFF
+#endif
+#endif
+
+#if defined(__NR_futex_time64) && !defined(SYS_futex_time64)
+#define SYS_futex_time64 __NR_futex_time64
+#endif
+
+#if defined(SYS_futex_time64) && !defined(SYS_futex)
+#define SYS_futex SYS_futex_time64
+#endif
+
+class FutexImpl {
+ public:
+  static int WaitUntil(std::atomic<int32_t> *v, int32_t val,
+                       KernelTimeout t) {
+    int err = 0;
+    if (t.has_timeout()) {
+      // https://locklessinc.com/articles/futex_cheat_sheet/
+      // Unlike FUTEX_WAIT, FUTEX_WAIT_BITSET uses absolute time.
+      struct timespec abs_timeout = t.MakeAbsTimespec();
+      // Atomically check that the futex value is still 0, and if it
+      // is, sleep until abs_timeout or until woken by FUTEX_WAKE.
+      err = syscall(
+          SYS_futex, reinterpret_cast<int32_t *>(v),
+          FUTEX_WAIT_BITSET | FUTEX_PRIVATE_FLAG | FUTEX_CLOCK_REALTIME, val,
+          &abs_timeout, nullptr, FUTEX_BITSET_MATCH_ANY);
+    } else {
+      // Atomically check that the futex value is still 0, and if it
+      // is, sleep until woken by FUTEX_WAKE.
+      err = syscall(SYS_futex, reinterpret_cast<int32_t *>(v),
+                    FUTEX_WAIT | FUTEX_PRIVATE_FLAG, val, nullptr);
+    }
+    if (ABSL_PREDICT_FALSE(err != 0)) {
+      err = -errno;
+    }
+    return err;
+  }
+
+  static int WaitBitsetAbsoluteTimeout(std::atomic<int32_t> *v, int32_t val,
+                                       int32_t bits,
+                                       const struct timespec *abstime) {
+    int err = syscall(SYS_futex, reinterpret_cast<int32_t *>(v),
+                      FUTEX_WAIT_BITSET | FUTEX_PRIVATE_FLAG, val, abstime,
+                      nullptr, bits);
+    if (ABSL_PREDICT_FALSE(err != 0)) {
+      err = -errno;
+    }
+    return err;
+  }
+
+  static int Wake(std::atomic<int32_t> *v, int32_t count) {
+    int err = syscall(SYS_futex, reinterpret_cast<int32_t *>(v),
+                      FUTEX_WAKE | FUTEX_PRIVATE_FLAG, count);
+    if (ABSL_PREDICT_FALSE(err < 0)) {
+      err = -errno;
+    }
+    return err;
+  }
+
+  // FUTEX_WAKE_BITSET
+  static int WakeBitset(std::atomic<int32_t> *v, int32_t count, int32_t bits) {
+    int err = syscall(SYS_futex, reinterpret_cast<int32_t *>(v),
+                      FUTEX_WAKE_BITSET | FUTEX_PRIVATE_FLAG, count, nullptr,
+                      nullptr, bits);
+    if (ABSL_PREDICT_FALSE(err < 0)) {
+      err = -errno;
+    }
+    return err;
+  }
+};
+
+class Futex : public FutexImpl {};
+
+}  // namespace synchronization_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#endif  // ABSL_INTERNAL_HAVE_FUTEX
+
+#endif  // ABSL_SYNCHRONIZATION_INTERNAL_FUTEX_H_
diff --git a/src/absl/synchronization/internal/graphcycles.cc b/src/absl/synchronization/internal/graphcycles.cc
new file mode 100644 (file)
index 0000000..27fec21
--- /dev/null
@@ -0,0 +1,698 @@
+// Copyright 2017 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// GraphCycles provides incremental cycle detection on a dynamic
+// graph using the following algorithm:
+//
+// A dynamic topological sort algorithm for directed acyclic graphs
+// David J. Pearce, Paul H. J. Kelly
+// Journal of Experimental Algorithmics (JEA) JEA Homepage archive
+// Volume 11, 2006, Article No. 1.7
+//
+// Brief summary of the algorithm:
+//
+// (1) Maintain a rank for each node that is consistent
+//     with the topological sort of the graph. I.e., path from x to y
+//     implies rank[x] < rank[y].
+// (2) When a new edge (x->y) is inserted, do nothing if rank[x] < rank[y].
+// (3) Otherwise: adjust ranks in the neighborhood of x and y.
+
+#include "absl/base/attributes.h"
+// This file is a no-op if the required LowLevelAlloc support is missing.
+#include "absl/base/internal/low_level_alloc.h"
+#ifndef ABSL_LOW_LEVEL_ALLOC_MISSING
+
+#include "absl/synchronization/internal/graphcycles.h"
+
+#include <algorithm>
+#include <array>
+#include <limits>
+#include "absl/base/internal/hide_ptr.h"
+#include "absl/base/internal/raw_logging.h"
+#include "absl/base/internal/spinlock.h"
+
+// Do not use STL.   This module does not use standard memory allocation.
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace synchronization_internal {
+
+namespace {
+
+// Avoid LowLevelAlloc's default arena since it calls malloc hooks in
+// which people are doing things like acquiring Mutexes.
+ABSL_CONST_INIT static absl::base_internal::SpinLock arena_mu(
+    absl::kConstInit, base_internal::SCHEDULE_KERNEL_ONLY);
+ABSL_CONST_INIT static base_internal::LowLevelAlloc::Arena* arena;
+
+static void InitArenaIfNecessary() {
+  arena_mu.Lock();
+  if (arena == nullptr) {
+    arena = base_internal::LowLevelAlloc::NewArena(0);
+  }
+  arena_mu.Unlock();
+}
+
+// Number of inlined elements in Vec.  Hash table implementation
+// relies on this being a power of two.
+static const uint32_t kInline = 8;
+
+// A simple LowLevelAlloc based resizable vector with inlined storage
+// for a few elements.  T must be a plain type since constructor
+// and destructor are not run on elements of type T managed by Vec.
+template <typename T>
+class Vec {
+ public:
+  Vec() { Init(); }
+  ~Vec() { Discard(); }
+
+  void clear() {
+    Discard();
+    Init();
+  }
+
+  bool empty() const { return size_ == 0; }
+  uint32_t size() const { return size_; }
+  T* begin() { return ptr_; }
+  T* end() { return ptr_ + size_; }
+  const T& operator[](uint32_t i) const { return ptr_[i]; }
+  T& operator[](uint32_t i) { return ptr_[i]; }
+  const T& back() const { return ptr_[size_-1]; }
+  void pop_back() { size_--; }
+
+  void push_back(const T& v) {
+    if (size_ == capacity_) Grow(size_ + 1);
+    ptr_[size_] = v;
+    size_++;
+  }
+
+  void resize(uint32_t n) {
+    if (n > capacity_) Grow(n);
+    size_ = n;
+  }
+
+  void fill(const T& val) {
+    for (uint32_t i = 0; i < size(); i++) {
+      ptr_[i] = val;
+    }
+  }
+
+  // Guarantees src is empty at end.
+  // Provided for the hash table resizing code below.
+  void MoveFrom(Vec<T>* src) {
+    if (src->ptr_ == src->space_) {
+      // Need to actually copy
+      resize(src->size_);
+      std::copy(src->ptr_, src->ptr_ + src->size_, ptr_);
+      src->size_ = 0;
+    } else {
+      Discard();
+      ptr_ = src->ptr_;
+      size_ = src->size_;
+      capacity_ = src->capacity_;
+      src->Init();
+    }
+  }
+
+ private:
+  T* ptr_;
+  T space_[kInline];
+  uint32_t size_;
+  uint32_t capacity_;
+
+  void Init() {
+    ptr_ = space_;
+    size_ = 0;
+    capacity_ = kInline;
+  }
+
+  void Discard() {
+    if (ptr_ != space_) base_internal::LowLevelAlloc::Free(ptr_);
+  }
+
+  void Grow(uint32_t n) {
+    while (capacity_ < n) {
+      capacity_ *= 2;
+    }
+    size_t request = static_cast<size_t>(capacity_) * sizeof(T);
+    T* copy = static_cast<T*>(
+        base_internal::LowLevelAlloc::AllocWithArena(request, arena));
+    std::copy(ptr_, ptr_ + size_, copy);
+    Discard();
+    ptr_ = copy;
+  }
+
+  Vec(const Vec&) = delete;
+  Vec& operator=(const Vec&) = delete;
+};
+
+// A hash set of non-negative int32_t that uses Vec for its underlying storage.
+class NodeSet {
+ public:
+  NodeSet() { Init(); }
+
+  void clear() { Init(); }
+  bool contains(int32_t v) const { return table_[FindIndex(v)] == v; }
+
+  bool insert(int32_t v) {
+    uint32_t i = FindIndex(v);
+    if (table_[i] == v) {
+      return false;
+    }
+    if (table_[i] == kEmpty) {
+      // Only inserting over an empty cell increases the number of occupied
+      // slots.
+      occupied_++;
+    }
+    table_[i] = v;
+    // Double when 75% full.
+    if (occupied_ >= table_.size() - table_.size()/4) Grow();
+    return true;
+  }
+
+  void erase(uint32_t v) {
+    uint32_t i = FindIndex(v);
+    if (static_cast<uint32_t>(table_[i]) == v) {
+      table_[i] = kDel;
+    }
+  }
+
+  // Iteration: is done via HASH_FOR_EACH
+  // Example:
+  //    HASH_FOR_EACH(elem, node->out) { ... }
+#define HASH_FOR_EACH(elem, eset) \
+  for (int32_t elem, _cursor = 0; (eset).Next(&_cursor, &elem); )
+  bool Next(int32_t* cursor, int32_t* elem) {
+    while (static_cast<uint32_t>(*cursor) < table_.size()) {
+      int32_t v = table_[*cursor];
+      (*cursor)++;
+      if (v >= 0) {
+        *elem = v;
+        return true;
+      }
+    }
+    return false;
+  }
+
+ private:
+  enum : int32_t { kEmpty = -1, kDel = -2 };
+  Vec<int32_t> table_;
+  uint32_t occupied_;     // Count of non-empty slots (includes deleted slots)
+
+  static uint32_t Hash(uint32_t a) { return a * 41; }
+
+  // Return index for storing v.  May return an empty index or deleted index
+  int FindIndex(int32_t v) const {
+    // Search starting at hash index.
+    const uint32_t mask = table_.size() - 1;
+    uint32_t i = Hash(v) & mask;
+    int deleted_index = -1;  // If >= 0, index of first deleted element we see
+    while (true) {
+      int32_t e = table_[i];
+      if (v == e) {
+        return i;
+      } else if (e == kEmpty) {
+        // Return any previously encountered deleted slot.
+        return (deleted_index >= 0) ? deleted_index : i;
+      } else if (e == kDel && deleted_index < 0) {
+        // Keep searching since v might be present later.
+        deleted_index = i;
+      }
+      i = (i + 1) & mask;  // Linear probing; quadratic is slightly slower.
+    }
+  }
+
+  void Init() {
+    table_.clear();
+    table_.resize(kInline);
+    table_.fill(kEmpty);
+    occupied_ = 0;
+  }
+
+  void Grow() {
+    Vec<int32_t> copy;
+    copy.MoveFrom(&table_);
+    occupied_ = 0;
+    table_.resize(copy.size() * 2);
+    table_.fill(kEmpty);
+
+    for (const auto& e : copy) {
+      if (e >= 0) insert(e);
+    }
+  }
+
+  NodeSet(const NodeSet&) = delete;
+  NodeSet& operator=(const NodeSet&) = delete;
+};
+
+// We encode a node index and a node version in GraphId.  The version
+// number is incremented when the GraphId is freed which automatically
+// invalidates all copies of the GraphId.
+
+inline GraphId MakeId(int32_t index, uint32_t version) {
+  GraphId g;
+  g.handle =
+      (static_cast<uint64_t>(version) << 32) | static_cast<uint32_t>(index);
+  return g;
+}
+
+inline int32_t NodeIndex(GraphId id) {
+  return static_cast<uint32_t>(id.handle & 0xfffffffful);
+}
+
+inline uint32_t NodeVersion(GraphId id) {
+  return static_cast<uint32_t>(id.handle >> 32);
+}
+
+struct Node {
+  int32_t rank;               // rank number assigned by Pearce-Kelly algorithm
+  uint32_t version;           // Current version number
+  int32_t next_hash;          // Next entry in hash table
+  bool visited;               // Temporary marker used by depth-first-search
+  uintptr_t masked_ptr;       // User-supplied pointer
+  NodeSet in;                 // List of immediate predecessor nodes in graph
+  NodeSet out;                // List of immediate successor nodes in graph
+  int priority;               // Priority of recorded stack trace.
+  int nstack;                 // Depth of recorded stack trace.
+  void* stack[40];            // stack[0,nstack-1] holds stack trace for node.
+};
+
+// Hash table for pointer to node index lookups.
+class PointerMap {
+ public:
+  explicit PointerMap(const Vec<Node*>* nodes) : nodes_(nodes) {
+    table_.fill(-1);
+  }
+
+  int32_t Find(void* ptr) {
+    auto masked = base_internal::HidePtr(ptr);
+    for (int32_t i = table_[Hash(ptr)]; i != -1;) {
+      Node* n = (*nodes_)[i];
+      if (n->masked_ptr == masked) return i;
+      i = n->next_hash;
+    }
+    return -1;
+  }
+
+  void Add(void* ptr, int32_t i) {
+    int32_t* head = &table_[Hash(ptr)];
+    (*nodes_)[i]->next_hash = *head;
+    *head = i;
+  }
+
+  int32_t Remove(void* ptr) {
+    // Advance through linked list while keeping track of the
+    // predecessor slot that points to the current entry.
+    auto masked = base_internal::HidePtr(ptr);
+    for (int32_t* slot = &table_[Hash(ptr)]; *slot != -1; ) {
+      int32_t index = *slot;
+      Node* n = (*nodes_)[index];
+      if (n->masked_ptr == masked) {
+        *slot = n->next_hash;  // Remove n from linked list
+        n->next_hash = -1;
+        return index;
+      }
+      slot = &n->next_hash;
+    }
+    return -1;
+  }
+
+ private:
+  // Number of buckets in hash table for pointer lookups.
+  static constexpr uint32_t kHashTableSize = 8171;  // should be prime
+
+  const Vec<Node*>* nodes_;
+  std::array<int32_t, kHashTableSize> table_;
+
+  static uint32_t Hash(void* ptr) {
+    return reinterpret_cast<uintptr_t>(ptr) % kHashTableSize;
+  }
+};
+
+}  // namespace
+
+struct GraphCycles::Rep {
+  Vec<Node*> nodes_;
+  Vec<int32_t> free_nodes_;  // Indices for unused entries in nodes_
+  PointerMap ptrmap_;
+
+  // Temporary state.
+  Vec<int32_t> deltaf_;  // Results of forward DFS
+  Vec<int32_t> deltab_;  // Results of backward DFS
+  Vec<int32_t> list_;    // All nodes to reprocess
+  Vec<int32_t> merged_;  // Rank values to assign to list_ entries
+  Vec<int32_t> stack_;   // Emulates recursion stack for depth-first searches
+
+  Rep() : ptrmap_(&nodes_) {}
+};
+
+static Node* FindNode(GraphCycles::Rep* rep, GraphId id) {
+  Node* n = rep->nodes_[NodeIndex(id)];
+  return (n->version == NodeVersion(id)) ? n : nullptr;
+}
+
+GraphCycles::GraphCycles() {
+  InitArenaIfNecessary();
+  rep_ = new (base_internal::LowLevelAlloc::AllocWithArena(sizeof(Rep), arena))
+      Rep;
+}
+
+GraphCycles::~GraphCycles() {
+  for (auto* node : rep_->nodes_) {
+    node->Node::~Node();
+    base_internal::LowLevelAlloc::Free(node);
+  }
+  rep_->Rep::~Rep();
+  base_internal::LowLevelAlloc::Free(rep_);
+}
+
+bool GraphCycles::CheckInvariants() const {
+  Rep* r = rep_;
+  NodeSet ranks;  // Set of ranks seen so far.
+  for (uint32_t x = 0; x < r->nodes_.size(); x++) {
+    Node* nx = r->nodes_[x];
+    void* ptr = base_internal::UnhidePtr<void>(nx->masked_ptr);
+    if (ptr != nullptr && static_cast<uint32_t>(r->ptrmap_.Find(ptr)) != x) {
+      ABSL_RAW_LOG(FATAL, "Did not find live node in hash table %u %p", x, ptr);
+    }
+    if (nx->visited) {
+      ABSL_RAW_LOG(FATAL, "Did not clear visited marker on node %u", x);
+    }
+    if (!ranks.insert(nx->rank)) {
+      ABSL_RAW_LOG(FATAL, "Duplicate occurrence of rank %d", nx->rank);
+    }
+    HASH_FOR_EACH(y, nx->out) {
+      Node* ny = r->nodes_[y];
+      if (nx->rank >= ny->rank) {
+        ABSL_RAW_LOG(FATAL, "Edge %u->%d has bad rank assignment %d->%d", x, y,
+                     nx->rank, ny->rank);
+      }
+    }
+  }
+  return true;
+}
+
+GraphId GraphCycles::GetId(void* ptr) {
+  int32_t i = rep_->ptrmap_.Find(ptr);
+  if (i != -1) {
+    return MakeId(i, rep_->nodes_[i]->version);
+  } else if (rep_->free_nodes_.empty()) {
+    Node* n =
+        new (base_internal::LowLevelAlloc::AllocWithArena(sizeof(Node), arena))
+            Node;
+    n->version = 1;  // Avoid 0 since it is used by InvalidGraphId()
+    n->visited = false;
+    n->rank = rep_->nodes_.size();
+    n->masked_ptr = base_internal::HidePtr(ptr);
+    n->nstack = 0;
+    n->priority = 0;
+    rep_->nodes_.push_back(n);
+    rep_->ptrmap_.Add(ptr, n->rank);
+    return MakeId(n->rank, n->version);
+  } else {
+    // Preserve preceding rank since the set of ranks in use must be
+    // a permutation of [0,rep_->nodes_.size()-1].
+    int32_t r = rep_->free_nodes_.back();
+    rep_->free_nodes_.pop_back();
+    Node* n = rep_->nodes_[r];
+    n->masked_ptr = base_internal::HidePtr(ptr);
+    n->nstack = 0;
+    n->priority = 0;
+    rep_->ptrmap_.Add(ptr, r);
+    return MakeId(r, n->version);
+  }
+}
+
+void GraphCycles::RemoveNode(void* ptr) {
+  int32_t i = rep_->ptrmap_.Remove(ptr);
+  if (i == -1) {
+    return;
+  }
+  Node* x = rep_->nodes_[i];
+  HASH_FOR_EACH(y, x->out) {
+    rep_->nodes_[y]->in.erase(i);
+  }
+  HASH_FOR_EACH(y, x->in) {
+    rep_->nodes_[y]->out.erase(i);
+  }
+  x->in.clear();
+  x->out.clear();
+  x->masked_ptr = base_internal::HidePtr<void>(nullptr);
+  if (x->version == std::numeric_limits<uint32_t>::max()) {
+    // Cannot use x any more
+  } else {
+    x->version++;  // Invalidates all copies of node.
+    rep_->free_nodes_.push_back(i);
+  }
+}
+
+void* GraphCycles::Ptr(GraphId id) {
+  Node* n = FindNode(rep_, id);
+  return n == nullptr ? nullptr
+                      : base_internal::UnhidePtr<void>(n->masked_ptr);
+}
+
+bool GraphCycles::HasNode(GraphId node) {
+  return FindNode(rep_, node) != nullptr;
+}
+
+bool GraphCycles::HasEdge(GraphId x, GraphId y) const {
+  Node* xn = FindNode(rep_, x);
+  return xn && FindNode(rep_, y) && xn->out.contains(NodeIndex(y));
+}
+
+void GraphCycles::RemoveEdge(GraphId x, GraphId y) {
+  Node* xn = FindNode(rep_, x);
+  Node* yn = FindNode(rep_, y);
+  if (xn && yn) {
+    xn->out.erase(NodeIndex(y));
+    yn->in.erase(NodeIndex(x));
+    // No need to update the rank assignment since a previous valid
+    // rank assignment remains valid after an edge deletion.
+  }
+}
+
+static bool ForwardDFS(GraphCycles::Rep* r, int32_t n, int32_t upper_bound);
+static void BackwardDFS(GraphCycles::Rep* r, int32_t n, int32_t lower_bound);
+static void Reorder(GraphCycles::Rep* r);
+static void Sort(const Vec<Node*>&, Vec<int32_t>* delta);
+static void MoveToList(
+    GraphCycles::Rep* r, Vec<int32_t>* src, Vec<int32_t>* dst);
+
+bool GraphCycles::InsertEdge(GraphId idx, GraphId idy) {
+  Rep* r = rep_;
+  const int32_t x = NodeIndex(idx);
+  const int32_t y = NodeIndex(idy);
+  Node* nx = FindNode(r, idx);
+  Node* ny = FindNode(r, idy);
+  if (nx == nullptr || ny == nullptr) return true;  // Expired ids
+
+  if (nx == ny) return false;  // Self edge
+  if (!nx->out.insert(y)) {
+    // Edge already exists.
+    return true;
+  }
+
+  ny->in.insert(x);
+
+  if (nx->rank <= ny->rank) {
+    // New edge is consistent with existing rank assignment.
+    return true;
+  }
+
+  // Current rank assignments are incompatible with the new edge.  Recompute.
+  // We only need to consider nodes that fall in the range [ny->rank,nx->rank].
+  if (!ForwardDFS(r, y, nx->rank)) {
+    // Found a cycle.  Undo the insertion and tell caller.
+    nx->out.erase(y);
+    ny->in.erase(x);
+    // Since we do not call Reorder() on this path, clear any visited
+    // markers left by ForwardDFS.
+    for (const auto& d : r->deltaf_) {
+      r->nodes_[d]->visited = false;
+    }
+    return false;
+  }
+  BackwardDFS(r, x, ny->rank);
+  Reorder(r);
+  return true;
+}
+
+static bool ForwardDFS(GraphCycles::Rep* r, int32_t n, int32_t upper_bound) {
+  // Avoid recursion since stack space might be limited.
+  // We instead keep a stack of nodes to visit.
+  r->deltaf_.clear();
+  r->stack_.clear();
+  r->stack_.push_back(n);
+  while (!r->stack_.empty()) {
+    n = r->stack_.back();
+    r->stack_.pop_back();
+    Node* nn = r->nodes_[n];
+    if (nn->visited) continue;
+
+    nn->visited = true;
+    r->deltaf_.push_back(n);
+
+    HASH_FOR_EACH(w, nn->out) {
+      Node* nw = r->nodes_[w];
+      if (nw->rank == upper_bound) {
+        return false;  // Cycle
+      }
+      if (!nw->visited && nw->rank < upper_bound) {
+        r->stack_.push_back(w);
+      }
+    }
+  }
+  return true;
+}
+
+static void BackwardDFS(GraphCycles::Rep* r, int32_t n, int32_t lower_bound) {
+  r->deltab_.clear();
+  r->stack_.clear();
+  r->stack_.push_back(n);
+  while (!r->stack_.empty()) {
+    n = r->stack_.back();
+    r->stack_.pop_back();
+    Node* nn = r->nodes_[n];
+    if (nn->visited) continue;
+
+    nn->visited = true;
+    r->deltab_.push_back(n);
+
+    HASH_FOR_EACH(w, nn->in) {
+      Node* nw = r->nodes_[w];
+      if (!nw->visited && lower_bound < nw->rank) {
+        r->stack_.push_back(w);
+      }
+    }
+  }
+}
+
+static void Reorder(GraphCycles::Rep* r) {
+  Sort(r->nodes_, &r->deltab_);
+  Sort(r->nodes_, &r->deltaf_);
+
+  // Adds contents of delta lists to list_ (backwards deltas first).
+  r->list_.clear();
+  MoveToList(r, &r->deltab_, &r->list_);
+  MoveToList(r, &r->deltaf_, &r->list_);
+
+  // Produce sorted list of all ranks that will be reassigned.
+  r->merged_.resize(r->deltab_.size() + r->deltaf_.size());
+  std::merge(r->deltab_.begin(), r->deltab_.end(),
+             r->deltaf_.begin(), r->deltaf_.end(),
+             r->merged_.begin());
+
+  // Assign the ranks in order to the collected list.
+  for (uint32_t i = 0; i < r->list_.size(); i++) {
+    r->nodes_[r->list_[i]]->rank = r->merged_[i];
+  }
+}
+
+static void Sort(const Vec<Node*>& nodes, Vec<int32_t>* delta) {
+  struct ByRank {
+    const Vec<Node*>* nodes;
+    bool operator()(int32_t a, int32_t b) const {
+      return (*nodes)[a]->rank < (*nodes)[b]->rank;
+    }
+  };
+  ByRank cmp;
+  cmp.nodes = &nodes;
+  std::sort(delta->begin(), delta->end(), cmp);
+}
+
+static void MoveToList(
+    GraphCycles::Rep* r, Vec<int32_t>* src, Vec<int32_t>* dst) {
+  for (auto& v : *src) {
+    int32_t w = v;
+    v = r->nodes_[w]->rank;         // Replace v entry with its rank
+    r->nodes_[w]->visited = false;  // Prepare for future DFS calls
+    dst->push_back(w);
+  }
+}
+
+int GraphCycles::FindPath(GraphId idx, GraphId idy, int max_path_len,
+                          GraphId path[]) const {
+  Rep* r = rep_;
+  if (FindNode(r, idx) == nullptr || FindNode(r, idy) == nullptr) return 0;
+  const int32_t x = NodeIndex(idx);
+  const int32_t y = NodeIndex(idy);
+
+  // Forward depth first search starting at x until we hit y.
+  // As we descend into a node, we push it onto the path.
+  // As we leave a node, we remove it from the path.
+  int path_len = 0;
+
+  NodeSet seen;
+  r->stack_.clear();
+  r->stack_.push_back(x);
+  while (!r->stack_.empty()) {
+    int32_t n = r->stack_.back();
+    r->stack_.pop_back();
+    if (n < 0) {
+      // Marker to indicate that we are leaving a node
+      path_len--;
+      continue;
+    }
+
+    if (path_len < max_path_len) {
+      path[path_len] = MakeId(n, rep_->nodes_[n]->version);
+    }
+    path_len++;
+    r->stack_.push_back(-1);  // Will remove tentative path entry
+
+    if (n == y) {
+      return path_len;
+    }
+
+    HASH_FOR_EACH(w, r->nodes_[n]->out) {
+      if (seen.insert(w)) {
+        r->stack_.push_back(w);
+      }
+    }
+  }
+
+  return 0;
+}
+
+bool GraphCycles::IsReachable(GraphId x, GraphId y) const {
+  return FindPath(x, y, 0, nullptr) > 0;
+}
+
+void GraphCycles::UpdateStackTrace(GraphId id, int priority,
+                                   int (*get_stack_trace)(void** stack, int)) {
+  Node* n = FindNode(rep_, id);
+  if (n == nullptr || n->priority >= priority) {
+    return;
+  }
+  n->nstack = (*get_stack_trace)(n->stack, ABSL_ARRAYSIZE(n->stack));
+  n->priority = priority;
+}
+
+int GraphCycles::GetStackTrace(GraphId id, void*** ptr) {
+  Node* n = FindNode(rep_, id);
+  if (n == nullptr) {
+    *ptr = nullptr;
+    return 0;
+  } else {
+    *ptr = n->stack;
+    return n->nstack;
+  }
+}
+
+}  // namespace synchronization_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#endif  // ABSL_LOW_LEVEL_ALLOC_MISSING
diff --git a/src/absl/synchronization/internal/graphcycles.h b/src/absl/synchronization/internal/graphcycles.h
new file mode 100644 (file)
index 0000000..ceba33e
--- /dev/null
@@ -0,0 +1,141 @@
+// Copyright 2017 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#ifndef ABSL_SYNCHRONIZATION_INTERNAL_GRAPHCYCLES_H_
+#define ABSL_SYNCHRONIZATION_INTERNAL_GRAPHCYCLES_H_
+
+// GraphCycles detects the introduction of a cycle into a directed
+// graph that is being built up incrementally.
+//
+// Nodes are identified by small integers.  It is not possible to
+// record multiple edges with the same (source, destination) pair;
+// requests to add an edge where one already exists are silently
+// ignored.
+//
+// It is also not possible to introduce a cycle; an attempt to insert
+// an edge that would introduce a cycle fails and returns false.
+//
+// GraphCycles uses no internal locking; calls into it should be
+// serialized externally.
+
+// Performance considerations:
+//   Works well on sparse graphs, poorly on dense graphs.
+//   Extra information is maintained incrementally to detect cycles quickly.
+//   InsertEdge() is very fast when the edge already exists, and reasonably fast
+//   otherwise.
+//   FindPath() is linear in the size of the graph.
+// The current implementation uses O(|V|+|E|) space.
+
+#include <cstdint>
+
+#include "absl/base/config.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace synchronization_internal {
+
+// Opaque identifier for a graph node.
+struct GraphId {
+  uint64_t handle;
+
+  bool operator==(const GraphId& x) const { return handle == x.handle; }
+  bool operator!=(const GraphId& x) const { return handle != x.handle; }
+};
+
+// Return an invalid graph id that will never be assigned by GraphCycles.
+inline GraphId InvalidGraphId() {
+  return GraphId{0};
+}
+
+class GraphCycles {
+ public:
+  GraphCycles();
+  ~GraphCycles();
+
+  // Return the id to use for ptr, assigning one if necessary.
+  // Subsequent calls with the same ptr value will return the same id
+  // until Remove().
+  GraphId GetId(void* ptr);
+
+  // Remove "ptr" from the graph.  Its corresponding node and all
+  // edges to and from it are removed.
+  void RemoveNode(void* ptr);
+
+  // Return the pointer associated with id, or nullptr if id is not
+  // currently in the graph.
+  void* Ptr(GraphId id);
+
+  // Attempt to insert an edge from source_node to dest_node.  If the
+  // edge would introduce a cycle, return false without making any
+  // changes. Otherwise add the edge and return true.
+  bool InsertEdge(GraphId source_node, GraphId dest_node);
+
+  // Remove any edge that exists from source_node to dest_node.
+  void RemoveEdge(GraphId source_node, GraphId dest_node);
+
+  // Return whether node exists in the graph.
+  bool HasNode(GraphId node);
+
+  // Return whether there is an edge directly from source_node to dest_node.
+  bool HasEdge(GraphId source_node, GraphId dest_node) const;
+
+  // Return whether dest_node is reachable from source_node
+  // by following edges.
+  bool IsReachable(GraphId source_node, GraphId dest_node) const;
+
+  // Find a path from "source" to "dest".  If such a path exists,
+  // place the nodes on the path in the array path[], and return
+  // the number of nodes on the path.  If the path is longer than
+  // max_path_len nodes, only the first max_path_len nodes are placed
+  // in path[].  The client should compare the return value with
+  // max_path_len" to see when this occurs.  If no path exists, return
+  // 0.  Any valid path stored in path[] will start with "source" and
+  // end with "dest".  There is no guarantee that the path is the
+  // shortest, but no node will appear twice in the path, except the
+  // source and destination node if they are identical; therefore, the
+  // return value is at most one greater than the number of nodes in
+  // the graph.
+  int FindPath(GraphId source, GraphId dest, int max_path_len,
+               GraphId path[]) const;
+
+  // Update the stack trace recorded for id with the current stack
+  // trace if the last time it was updated had a smaller priority
+  // than the priority passed on this call.
+  //
+  // *get_stack_trace is called to get the stack trace.
+  void UpdateStackTrace(GraphId id, int priority,
+                        int (*get_stack_trace)(void**, int));
+
+  // Set *ptr to the beginning of the array that holds the recorded
+  // stack trace for id and return the depth of the stack trace.
+  int GetStackTrace(GraphId id, void*** ptr);
+
+  // Check internal invariants. Crashes on failure, returns true on success.
+  // Expensive: should only be called from graphcycles_test.cc.
+  bool CheckInvariants() const;
+
+  // ----------------------------------------------------
+  struct Rep;
+ private:
+  Rep *rep_;      // opaque representation
+  GraphCycles(const GraphCycles&) = delete;
+  GraphCycles& operator=(const GraphCycles&) = delete;
+};
+
+}  // namespace synchronization_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#endif
diff --git a/src/absl/synchronization/internal/kernel_timeout.h b/src/absl/synchronization/internal/kernel_timeout.h
new file mode 100644 (file)
index 0000000..bbd4d2d
--- /dev/null
@@ -0,0 +1,156 @@
+// Copyright 2017 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// An optional absolute timeout, with nanosecond granularity,
+// compatible with absl::Time. Suitable for in-register
+// parameter-passing (e.g. syscalls.)
+// Constructible from a absl::Time (for a timeout to be respected) or {}
+// (for "no timeout".)
+// This is a private low-level API for use by a handful of low-level
+// components that are friends of this class. Higher-level components
+// should build APIs based on absl::Time and absl::Duration.
+
+#ifndef ABSL_SYNCHRONIZATION_INTERNAL_KERNEL_TIMEOUT_H_
+#define ABSL_SYNCHRONIZATION_INTERNAL_KERNEL_TIMEOUT_H_
+
+#include <time.h>
+
+#include <algorithm>
+#include <limits>
+
+#include "absl/base/internal/raw_logging.h"
+#include "absl/time/clock.h"
+#include "absl/time/time.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace synchronization_internal {
+
+class Futex;
+class Waiter;
+
+class KernelTimeout {
+ public:
+  // A timeout that should expire at <t>.  Any value, in the full
+  // InfinitePast() to InfiniteFuture() range, is valid here and will be
+  // respected.
+  explicit KernelTimeout(absl::Time t) : ns_(MakeNs(t)) {}
+  // No timeout.
+  KernelTimeout() : ns_(0) {}
+
+  // A more explicit factory for those who prefer it.  Equivalent to {}.
+  static KernelTimeout Never() { return {}; }
+
+  // We explicitly do not support other custom formats: timespec, int64_t nanos.
+  // Unify on this and absl::Time, please.
+
+  bool has_timeout() const { return ns_ != 0; }
+
+  // Convert to parameter for sem_timedwait/futex/similar.  Only for approved
+  // users.  Do not call if !has_timeout.
+  struct timespec MakeAbsTimespec();
+
+ private:
+  // internal rep, not user visible: ns after unix epoch.
+  // zero = no timeout.
+  // Negative we treat as an unlikely (and certainly expired!) but valid
+  // timeout.
+  int64_t ns_;
+
+  static int64_t MakeNs(absl::Time t) {
+    // optimization--InfiniteFuture is common "no timeout" value
+    // and cheaper to compare than convert.
+    if (t == absl::InfiniteFuture()) return 0;
+    int64_t x = ToUnixNanos(t);
+
+    // A timeout that lands exactly on the epoch (x=0) needs to be respected,
+    // so we alter it unnoticably to 1.  Negative timeouts are in
+    // theory supported, but handled poorly by the kernel (long
+    // delays) so push them forward too; since all such times have
+    // already passed, it's indistinguishable.
+    if (x <= 0) x = 1;
+    // A time larger than what can be represented to the kernel is treated
+    // as no timeout.
+    if (x == (std::numeric_limits<int64_t>::max)()) x = 0;
+    return x;
+  }
+
+#ifdef _WIN32
+  // Converts to milliseconds from now, or INFINITE when
+  // !has_timeout(). For use by SleepConditionVariableSRW on
+  // Windows. Callers should recognize that the return value is a
+  // relative duration (it should be recomputed by calling this method
+  // in the case of a spurious wakeup).
+  // This header file may be included transitively by public header files,
+  // so we define our own DWORD and INFINITE instead of getting them from
+  // <intsafe.h> and <WinBase.h>.
+  typedef unsigned long DWord;  // NOLINT
+  DWord InMillisecondsFromNow() const {
+    constexpr DWord kInfinite = (std::numeric_limits<DWord>::max)();
+    if (!has_timeout()) {
+      return kInfinite;
+    }
+    // The use of absl::Now() to convert from absolute time to
+    // relative time means that absl::Now() cannot use anything that
+    // depends on KernelTimeout (for example, Mutex) on Windows.
+    int64_t now = ToUnixNanos(absl::Now());
+    if (ns_ >= now) {
+      // Round up so that Now() + ms_from_now >= ns_.
+      constexpr uint64_t max_nanos =
+          (std::numeric_limits<int64_t>::max)() - 999999u;
+      uint64_t ms_from_now =
+          (std::min<uint64_t>(max_nanos, ns_ - now) + 999999u) / 1000000u;
+      if (ms_from_now > kInfinite) {
+        return kInfinite;
+      }
+      return static_cast<DWord>(ms_from_now);
+    }
+    return 0;
+  }
+#endif
+
+  friend class Futex;
+  friend class Waiter;
+};
+
+inline struct timespec KernelTimeout::MakeAbsTimespec() {
+  int64_t n = ns_;
+  static const int64_t kNanosPerSecond = 1000 * 1000 * 1000;
+  if (n == 0) {
+    ABSL_RAW_LOG(
+        ERROR, "Tried to create a timespec from a non-timeout; never do this.");
+    // But we'll try to continue sanely.  no-timeout ~= saturated timeout.
+    n = (std::numeric_limits<int64_t>::max)();
+  }
+
+  // Kernel APIs validate timespecs as being at or after the epoch,
+  // despite the kernel time type being signed.  However, no one can
+  // tell the difference between a timeout at or before the epoch (since
+  // all such timeouts have expired!)
+  if (n < 0) n = 0;
+
+  struct timespec abstime;
+  int64_t seconds = (std::min)(n / kNanosPerSecond,
+                               int64_t{(std::numeric_limits<time_t>::max)()});
+  abstime.tv_sec = static_cast<time_t>(seconds);
+  abstime.tv_nsec = static_cast<decltype(abstime.tv_nsec)>(n % kNanosPerSecond);
+  return abstime;
+}
+
+}  // namespace synchronization_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#endif  // ABSL_SYNCHRONIZATION_INTERNAL_KERNEL_TIMEOUT_H_
diff --git a/src/absl/synchronization/internal/per_thread_sem.cc b/src/absl/synchronization/internal/per_thread_sem.cc
new file mode 100644 (file)
index 0000000..a603178
--- /dev/null
@@ -0,0 +1,106 @@
+// Copyright 2017 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// This file is a no-op if the required LowLevelAlloc support is missing.
+#include "absl/base/internal/low_level_alloc.h"
+#ifndef ABSL_LOW_LEVEL_ALLOC_MISSING
+
+#include "absl/synchronization/internal/per_thread_sem.h"
+
+#include <atomic>
+
+#include "absl/base/attributes.h"
+#include "absl/base/internal/thread_identity.h"
+#include "absl/synchronization/internal/waiter.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace synchronization_internal {
+
+void PerThreadSem::SetThreadBlockedCounter(std::atomic<int> *counter) {
+  base_internal::ThreadIdentity *identity;
+  identity = GetOrCreateCurrentThreadIdentity();
+  identity->blocked_count_ptr = counter;
+}
+
+std::atomic<int> *PerThreadSem::GetThreadBlockedCounter() {
+  base_internal::ThreadIdentity *identity;
+  identity = GetOrCreateCurrentThreadIdentity();
+  return identity->blocked_count_ptr;
+}
+
+void PerThreadSem::Init(base_internal::ThreadIdentity *identity) {
+  new (Waiter::GetWaiter(identity)) Waiter();
+  identity->ticker.store(0, std::memory_order_relaxed);
+  identity->wait_start.store(0, std::memory_order_relaxed);
+  identity->is_idle.store(false, std::memory_order_relaxed);
+}
+
+void PerThreadSem::Destroy(base_internal::ThreadIdentity *identity) {
+  Waiter::GetWaiter(identity)->~Waiter();
+}
+
+void PerThreadSem::Tick(base_internal::ThreadIdentity *identity) {
+  const int ticker =
+      identity->ticker.fetch_add(1, std::memory_order_relaxed) + 1;
+  const int wait_start = identity->wait_start.load(std::memory_order_relaxed);
+  const bool is_idle = identity->is_idle.load(std::memory_order_relaxed);
+  if (wait_start && (ticker - wait_start > Waiter::kIdlePeriods) && !is_idle) {
+    // Wakeup the waiting thread since it is time for it to become idle.
+    Waiter::GetWaiter(identity)->Poke();
+  }
+}
+
+}  // namespace synchronization_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+extern "C" {
+
+ABSL_ATTRIBUTE_WEAK void ABSL_INTERNAL_C_SYMBOL(AbslInternalPerThreadSemPost)(
+    absl::base_internal::ThreadIdentity *identity) {
+  absl::synchronization_internal::Waiter::GetWaiter(identity)->Post();
+}
+
+ABSL_ATTRIBUTE_WEAK bool ABSL_INTERNAL_C_SYMBOL(AbslInternalPerThreadSemWait)(
+    absl::synchronization_internal::KernelTimeout t) {
+  bool timeout = false;
+  absl::base_internal::ThreadIdentity *identity;
+  identity = absl::synchronization_internal::GetOrCreateCurrentThreadIdentity();
+
+  // Ensure wait_start != 0.
+  int ticker = identity->ticker.load(std::memory_order_relaxed);
+  identity->wait_start.store(ticker ? ticker : 1, std::memory_order_relaxed);
+  identity->is_idle.store(false, std::memory_order_relaxed);
+
+  if (identity->blocked_count_ptr != nullptr) {
+    // Increment count of threads blocked in a given thread pool.
+    identity->blocked_count_ptr->fetch_add(1, std::memory_order_relaxed);
+  }
+
+  timeout =
+      !absl::synchronization_internal::Waiter::GetWaiter(identity)->Wait(t);
+
+  if (identity->blocked_count_ptr != nullptr) {
+    identity->blocked_count_ptr->fetch_sub(1, std::memory_order_relaxed);
+  }
+
+  identity->is_idle.store(false, std::memory_order_relaxed);
+  identity->wait_start.store(0, std::memory_order_relaxed);
+  return !timeout;
+}
+
+}  // extern "C"
+
+#endif  // ABSL_LOW_LEVEL_ALLOC_MISSING
diff --git a/src/absl/synchronization/internal/per_thread_sem.h b/src/absl/synchronization/internal/per_thread_sem.h
new file mode 100644 (file)
index 0000000..7beae8e
--- /dev/null
@@ -0,0 +1,115 @@
+// Copyright 2017 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// PerThreadSem is a low-level synchronization primitive controlling the
+// runnability of a single thread, used internally by Mutex and CondVar.
+//
+// This is NOT a general-purpose synchronization mechanism, and should not be
+// used directly by applications.  Applications should use Mutex and CondVar.
+//
+// The semantics of PerThreadSem are the same as that of a counting semaphore.
+// Each thread maintains an abstract "count" value associated with its identity.
+
+#ifndef ABSL_SYNCHRONIZATION_INTERNAL_PER_THREAD_SEM_H_
+#define ABSL_SYNCHRONIZATION_INTERNAL_PER_THREAD_SEM_H_
+
+#include <atomic>
+
+#include "absl/base/internal/thread_identity.h"
+#include "absl/synchronization/internal/create_thread_identity.h"
+#include "absl/synchronization/internal/kernel_timeout.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+
+class Mutex;
+
+namespace synchronization_internal {
+
+class PerThreadSem {
+ public:
+  PerThreadSem() = delete;
+  PerThreadSem(const PerThreadSem&) = delete;
+  PerThreadSem& operator=(const PerThreadSem&) = delete;
+
+  // Routine invoked periodically (once a second) by a background thread.
+  // Has no effect on user-visible state.
+  static void Tick(base_internal::ThreadIdentity* identity);
+
+  // ---------------------------------------------------------------------------
+  // Routines used by autosizing threadpools to detect when threads are
+  // blocked.  Each thread has a counter pointer, initially zero.  If non-zero,
+  // the implementation atomically increments the counter when it blocks on a
+  // semaphore, a decrements it again when it wakes.  This allows a threadpool
+  // to keep track of how many of its threads are blocked.
+  // SetThreadBlockedCounter() should be used only by threadpool
+  // implementations.  GetThreadBlockedCounter() should be used by modules that
+  // block threads; if the pointer returned is non-zero, the location should be
+  // incremented before the thread blocks, and decremented after it wakes.
+  static void SetThreadBlockedCounter(std::atomic<int> *counter);
+  static std::atomic<int> *GetThreadBlockedCounter();
+
+ private:
+  // Create the PerThreadSem associated with "identity".  Initializes count=0.
+  // REQUIRES: May only be called by ThreadIdentity.
+  static void Init(base_internal::ThreadIdentity* identity);
+
+  // Destroy the PerThreadSem associated with "identity".
+  // REQUIRES: May only be called by ThreadIdentity.
+  static void Destroy(base_internal::ThreadIdentity* identity);
+
+  // Increments "identity"'s count.
+  static inline void Post(base_internal::ThreadIdentity* identity);
+
+  // Waits until either our count > 0 or t has expired.
+  // If count > 0, decrements count and returns true.  Otherwise returns false.
+  // !t.has_timeout() => Wait(t) will return true.
+  static inline bool Wait(KernelTimeout t);
+
+  // Permitted callers.
+  friend class PerThreadSemTest;
+  friend class absl::Mutex;
+  friend absl::base_internal::ThreadIdentity* CreateThreadIdentity();
+  friend void ReclaimThreadIdentity(void* v);
+};
+
+}  // namespace synchronization_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+// In some build configurations we pass --detect-odr-violations to the
+// gold linker.  This causes it to flag weak symbol overrides as ODR
+// violations.  Because ODR only applies to C++ and not C,
+// --detect-odr-violations ignores symbols not mangled with C++ names.
+// By changing our extension points to be extern "C", we dodge this
+// check.
+extern "C" {
+void ABSL_INTERNAL_C_SYMBOL(AbslInternalPerThreadSemPost)(
+    absl::base_internal::ThreadIdentity* identity);
+bool ABSL_INTERNAL_C_SYMBOL(AbslInternalPerThreadSemWait)(
+    absl::synchronization_internal::KernelTimeout t);
+}  // extern "C"
+
+void absl::synchronization_internal::PerThreadSem::Post(
+    absl::base_internal::ThreadIdentity* identity) {
+  ABSL_INTERNAL_C_SYMBOL(AbslInternalPerThreadSemPost)(identity);
+}
+
+bool absl::synchronization_internal::PerThreadSem::Wait(
+    absl::synchronization_internal::KernelTimeout t) {
+  return ABSL_INTERNAL_C_SYMBOL(AbslInternalPerThreadSemWait)(t);
+}
+
+#endif  // ABSL_SYNCHRONIZATION_INTERNAL_PER_THREAD_SEM_H_
diff --git a/src/absl/synchronization/internal/thread_pool.h b/src/absl/synchronization/internal/thread_pool.h
new file mode 100644 (file)
index 0000000..0cb96da
--- /dev/null
@@ -0,0 +1,93 @@
+// Copyright 2017 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef ABSL_SYNCHRONIZATION_INTERNAL_THREAD_POOL_H_
+#define ABSL_SYNCHRONIZATION_INTERNAL_THREAD_POOL_H_
+
+#include <cassert>
+#include <cstddef>
+#include <functional>
+#include <queue>
+#include <thread>  // NOLINT(build/c++11)
+#include <vector>
+
+#include "absl/base/thread_annotations.h"
+#include "absl/synchronization/mutex.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace synchronization_internal {
+
+// A simple ThreadPool implementation for tests.
+class ThreadPool {
+ public:
+  explicit ThreadPool(int num_threads) {
+    for (int i = 0; i < num_threads; ++i) {
+      threads_.push_back(std::thread(&ThreadPool::WorkLoop, this));
+    }
+  }
+
+  ThreadPool(const ThreadPool &) = delete;
+  ThreadPool &operator=(const ThreadPool &) = delete;
+
+  ~ThreadPool() {
+    {
+      absl::MutexLock l(&mu_);
+      for (size_t i = 0; i < threads_.size(); i++) {
+        queue_.push(nullptr);  // Shutdown signal.
+      }
+    }
+    for (auto &t : threads_) {
+      t.join();
+    }
+  }
+
+  // Schedule a function to be run on a ThreadPool thread immediately.
+  void Schedule(std::function<void()> func) {
+    assert(func != nullptr);
+    absl::MutexLock l(&mu_);
+    queue_.push(std::move(func));
+  }
+
+ private:
+  bool WorkAvailable() const ABSL_EXCLUSIVE_LOCKS_REQUIRED(mu_) {
+    return !queue_.empty();
+  }
+
+  void WorkLoop() {
+    while (true) {
+      std::function<void()> func;
+      {
+        absl::MutexLock l(&mu_);
+        mu_.Await(absl::Condition(this, &ThreadPool::WorkAvailable));
+        func = std::move(queue_.front());
+        queue_.pop();
+      }
+      if (func == nullptr) {  // Shutdown signal.
+        break;
+      }
+      func();
+    }
+  }
+
+  absl::Mutex mu_;
+  std::queue<std::function<void()>> queue_ ABSL_GUARDED_BY(mu_);
+  std::vector<std::thread> threads_;
+};
+
+}  // namespace synchronization_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#endif  // ABSL_SYNCHRONIZATION_INTERNAL_THREAD_POOL_H_
diff --git a/src/absl/synchronization/internal/waiter.cc b/src/absl/synchronization/internal/waiter.cc
new file mode 100644 (file)
index 0000000..2123be6
--- /dev/null
@@ -0,0 +1,428 @@
+// Copyright 2017 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "absl/synchronization/internal/waiter.h"
+
+#include "absl/base/config.h"
+
+#ifdef _WIN32
+#include <windows.h>
+#else
+#include <pthread.h>
+#include <sys/time.h>
+#include <unistd.h>
+#endif
+
+#ifdef __linux__
+#include <linux/futex.h>
+#include <sys/syscall.h>
+#endif
+
+#ifdef ABSL_HAVE_SEMAPHORE_H
+#include <semaphore.h>
+#endif
+
+#include <errno.h>
+#include <stdio.h>
+#include <time.h>
+
+#include <atomic>
+#include <cassert>
+#include <cstdint>
+#include <new>
+#include <type_traits>
+
+#include "absl/base/internal/raw_logging.h"
+#include "absl/base/internal/thread_identity.h"
+#include "absl/base/optimization.h"
+#include "absl/synchronization/internal/kernel_timeout.h"
+
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace synchronization_internal {
+
+static void MaybeBecomeIdle() {
+  base_internal::ThreadIdentity *identity =
+      base_internal::CurrentThreadIdentityIfPresent();
+  assert(identity != nullptr);
+  const bool is_idle = identity->is_idle.load(std::memory_order_relaxed);
+  const int ticker = identity->ticker.load(std::memory_order_relaxed);
+  const int wait_start = identity->wait_start.load(std::memory_order_relaxed);
+  if (!is_idle && ticker - wait_start > Waiter::kIdlePeriods) {
+    identity->is_idle.store(true, std::memory_order_relaxed);
+  }
+}
+
+#if ABSL_WAITER_MODE == ABSL_WAITER_MODE_FUTEX
+
+Waiter::Waiter() {
+  futex_.store(0, std::memory_order_relaxed);
+}
+
+Waiter::~Waiter() = default;
+
+bool Waiter::Wait(KernelTimeout t) {
+  // Loop until we can atomically decrement futex from a positive
+  // value, waiting on a futex while we believe it is zero.
+  // Note that, since the thread ticker is just reset, we don't need to check
+  // whether the thread is idle on the very first pass of the loop.
+  bool first_pass = true;
+  while (true) {
+    int32_t x = futex_.load(std::memory_order_relaxed);
+    while (x != 0) {
+      if (!futex_.compare_exchange_weak(x, x - 1,
+                                        std::memory_order_acquire,
+                                        std::memory_order_relaxed)) {
+        continue;  // Raced with someone, retry.
+      }
+      return true;  // Consumed a wakeup, we are done.
+    }
+
+
+    if (!first_pass) MaybeBecomeIdle();
+    const int err = Futex::WaitUntil(&futex_, 0, t);
+    if (err != 0) {
+      if (err == -EINTR || err == -EWOULDBLOCK) {
+        // Do nothing, the loop will retry.
+      } else if (err == -ETIMEDOUT) {
+        return false;
+      } else {
+        ABSL_RAW_LOG(FATAL, "Futex operation failed with error %d\n", err);
+      }
+    }
+    first_pass = false;
+  }
+}
+
+void Waiter::Post() {
+  if (futex_.fetch_add(1, std::memory_order_release) == 0) {
+    // We incremented from 0, need to wake a potential waiter.
+    Poke();
+  }
+}
+
+void Waiter::Poke() {
+  // Wake one thread waiting on the futex.
+  const int err = Futex::Wake(&futex_, 1);
+  if (ABSL_PREDICT_FALSE(err < 0)) {
+    ABSL_RAW_LOG(FATAL, "Futex operation failed with error %d\n", err);
+  }
+}
+
+#elif ABSL_WAITER_MODE == ABSL_WAITER_MODE_CONDVAR
+
+class PthreadMutexHolder {
+ public:
+  explicit PthreadMutexHolder(pthread_mutex_t *mu) : mu_(mu) {
+    const int err = pthread_mutex_lock(mu_);
+    if (err != 0) {
+      ABSL_RAW_LOG(FATAL, "pthread_mutex_lock failed: %d", err);
+    }
+  }
+
+  PthreadMutexHolder(const PthreadMutexHolder &rhs) = delete;
+  PthreadMutexHolder &operator=(const PthreadMutexHolder &rhs) = delete;
+
+  ~PthreadMutexHolder() {
+    const int err = pthread_mutex_unlock(mu_);
+    if (err != 0) {
+      ABSL_RAW_LOG(FATAL, "pthread_mutex_unlock failed: %d", err);
+    }
+  }
+
+ private:
+  pthread_mutex_t *mu_;
+};
+
+Waiter::Waiter() {
+  const int err = pthread_mutex_init(&mu_, 0);
+  if (err != 0) {
+    ABSL_RAW_LOG(FATAL, "pthread_mutex_init failed: %d", err);
+  }
+
+  const int err2 = pthread_cond_init(&cv_, 0);
+  if (err2 != 0) {
+    ABSL_RAW_LOG(FATAL, "pthread_cond_init failed: %d", err2);
+  }
+
+  waiter_count_ = 0;
+  wakeup_count_ = 0;
+}
+
+Waiter::~Waiter() {
+  const int err = pthread_mutex_destroy(&mu_);
+  if (err != 0) {
+    ABSL_RAW_LOG(FATAL, "pthread_mutex_destroy failed: %d", err);
+  }
+
+  const int err2 = pthread_cond_destroy(&cv_);
+  if (err2 != 0) {
+    ABSL_RAW_LOG(FATAL, "pthread_cond_destroy failed: %d", err2);
+  }
+}
+
+bool Waiter::Wait(KernelTimeout t) {
+  struct timespec abs_timeout;
+  if (t.has_timeout()) {
+    abs_timeout = t.MakeAbsTimespec();
+  }
+
+  PthreadMutexHolder h(&mu_);
+  ++waiter_count_;
+  // Loop until we find a wakeup to consume or timeout.
+  // Note that, since the thread ticker is just reset, we don't need to check
+  // whether the thread is idle on the very first pass of the loop.
+  bool first_pass = true;
+  while (wakeup_count_ == 0) {
+    if (!first_pass) MaybeBecomeIdle();
+    // No wakeups available, time to wait.
+    if (!t.has_timeout()) {
+      const int err = pthread_cond_wait(&cv_, &mu_);
+      if (err != 0) {
+        ABSL_RAW_LOG(FATAL, "pthread_cond_wait failed: %d", err);
+      }
+    } else {
+      const int err = pthread_cond_timedwait(&cv_, &mu_, &abs_timeout);
+      if (err == ETIMEDOUT) {
+        --waiter_count_;
+        return false;
+      }
+      if (err != 0) {
+        ABSL_RAW_LOG(FATAL, "pthread_cond_timedwait failed: %d", err);
+      }
+    }
+    first_pass = false;
+  }
+  // Consume a wakeup and we're done.
+  --wakeup_count_;
+  --waiter_count_;
+  return true;
+}
+
+void Waiter::Post() {
+  PthreadMutexHolder h(&mu_);
+  ++wakeup_count_;
+  InternalCondVarPoke();
+}
+
+void Waiter::Poke() {
+  PthreadMutexHolder h(&mu_);
+  InternalCondVarPoke();
+}
+
+void Waiter::InternalCondVarPoke() {
+  if (waiter_count_ != 0) {
+    const int err = pthread_cond_signal(&cv_);
+    if (ABSL_PREDICT_FALSE(err != 0)) {
+      ABSL_RAW_LOG(FATAL, "pthread_cond_signal failed: %d", err);
+    }
+  }
+}
+
+#elif ABSL_WAITER_MODE == ABSL_WAITER_MODE_SEM
+
+Waiter::Waiter() {
+  if (sem_init(&sem_, 0, 0) != 0) {
+    ABSL_RAW_LOG(FATAL, "sem_init failed with errno %d\n", errno);
+  }
+  wakeups_.store(0, std::memory_order_relaxed);
+}
+
+Waiter::~Waiter() {
+  if (sem_destroy(&sem_) != 0) {
+    ABSL_RAW_LOG(FATAL, "sem_destroy failed with errno %d\n", errno);
+  }
+}
+
+bool Waiter::Wait(KernelTimeout t) {
+  struct timespec abs_timeout;
+  if (t.has_timeout()) {
+    abs_timeout = t.MakeAbsTimespec();
+  }
+
+  // Loop until we timeout or consume a wakeup.
+  // Note that, since the thread ticker is just reset, we don't need to check
+  // whether the thread is idle on the very first pass of the loop.
+  bool first_pass = true;
+  while (true) {
+    int x = wakeups_.load(std::memory_order_relaxed);
+    while (x != 0) {
+      if (!wakeups_.compare_exchange_weak(x, x - 1,
+                                          std::memory_order_acquire,
+                                          std::memory_order_relaxed)) {
+        continue;  // Raced with someone, retry.
+      }
+      // Successfully consumed a wakeup, we're done.
+      return true;
+    }
+
+    if (!first_pass) MaybeBecomeIdle();
+    // Nothing to consume, wait (looping on EINTR).
+    while (true) {
+      if (!t.has_timeout()) {
+        if (sem_wait(&sem_) == 0) break;
+        if (errno == EINTR) continue;
+        ABSL_RAW_LOG(FATAL, "sem_wait failed: %d", errno);
+      } else {
+        if (sem_timedwait(&sem_, &abs_timeout) == 0) break;
+        if (errno == EINTR) continue;
+        if (errno == ETIMEDOUT) return false;
+        ABSL_RAW_LOG(FATAL, "sem_timedwait failed: %d", errno);
+      }
+    }
+    first_pass = false;
+  }
+}
+
+void Waiter::Post() {
+  // Post a wakeup.
+  if (wakeups_.fetch_add(1, std::memory_order_release) == 0) {
+    // We incremented from 0, need to wake a potential waiter.
+    Poke();
+  }
+}
+
+void Waiter::Poke() {
+  if (sem_post(&sem_) != 0) {  // Wake any semaphore waiter.
+    ABSL_RAW_LOG(FATAL, "sem_post failed with errno %d\n", errno);
+  }
+}
+
+#elif ABSL_WAITER_MODE == ABSL_WAITER_MODE_WIN32
+
+class Waiter::WinHelper {
+ public:
+  static SRWLOCK *GetLock(Waiter *w) {
+    return reinterpret_cast<SRWLOCK *>(&w->mu_storage_);
+  }
+
+  static CONDITION_VARIABLE *GetCond(Waiter *w) {
+    return reinterpret_cast<CONDITION_VARIABLE *>(&w->cv_storage_);
+  }
+
+  static_assert(sizeof(SRWLOCK) == sizeof(void *),
+                "`mu_storage_` does not have the same size as SRWLOCK");
+  static_assert(alignof(SRWLOCK) == alignof(void *),
+                "`mu_storage_` does not have the same alignment as SRWLOCK");
+
+  static_assert(sizeof(CONDITION_VARIABLE) == sizeof(void *),
+                "`ABSL_CONDITION_VARIABLE_STORAGE` does not have the same size "
+                "as `CONDITION_VARIABLE`");
+  static_assert(
+      alignof(CONDITION_VARIABLE) == alignof(void *),
+      "`cv_storage_` does not have the same alignment as `CONDITION_VARIABLE`");
+
+  // The SRWLOCK and CONDITION_VARIABLE types must be trivially constructible
+  // and destructible because we never call their constructors or destructors.
+  static_assert(std::is_trivially_constructible<SRWLOCK>::value,
+                "The `SRWLOCK` type must be trivially constructible");
+  static_assert(
+      std::is_trivially_constructible<CONDITION_VARIABLE>::value,
+      "The `CONDITION_VARIABLE` type must be trivially constructible");
+  static_assert(std::is_trivially_destructible<SRWLOCK>::value,
+                "The `SRWLOCK` type must be trivially destructible");
+  static_assert(std::is_trivially_destructible<CONDITION_VARIABLE>::value,
+                "The `CONDITION_VARIABLE` type must be trivially destructible");
+};
+
+class LockHolder {
+ public:
+  explicit LockHolder(SRWLOCK* mu) : mu_(mu) {
+    AcquireSRWLockExclusive(mu_);
+  }
+
+  LockHolder(const LockHolder&) = delete;
+  LockHolder& operator=(const LockHolder&) = delete;
+
+  ~LockHolder() {
+    ReleaseSRWLockExclusive(mu_);
+  }
+
+ private:
+  SRWLOCK* mu_;
+};
+
+Waiter::Waiter() {
+  auto *mu = ::new (static_cast<void *>(&mu_storage_)) SRWLOCK;
+  auto *cv = ::new (static_cast<void *>(&cv_storage_)) CONDITION_VARIABLE;
+  InitializeSRWLock(mu);
+  InitializeConditionVariable(cv);
+  waiter_count_ = 0;
+  wakeup_count_ = 0;
+}
+
+// SRW locks and condition variables do not need to be explicitly destroyed.
+// https://docs.microsoft.com/en-us/windows/win32/api/synchapi/nf-synchapi-initializesrwlock
+// https://stackoverflow.com/questions/28975958/why-does-windows-have-no-deleteconditionvariable-function-to-go-together-with
+Waiter::~Waiter() = default;
+
+bool Waiter::Wait(KernelTimeout t) {
+  SRWLOCK *mu = WinHelper::GetLock(this);
+  CONDITION_VARIABLE *cv = WinHelper::GetCond(this);
+
+  LockHolder h(mu);
+  ++waiter_count_;
+
+  // Loop until we find a wakeup to consume or timeout.
+  // Note that, since the thread ticker is just reset, we don't need to check
+  // whether the thread is idle on the very first pass of the loop.
+  bool first_pass = true;
+  while (wakeup_count_ == 0) {
+    if (!first_pass) MaybeBecomeIdle();
+    // No wakeups available, time to wait.
+    if (!SleepConditionVariableSRW(cv, mu, t.InMillisecondsFromNow(), 0)) {
+      // GetLastError() returns a Win32 DWORD, but we assign to
+      // unsigned long to simplify the ABSL_RAW_LOG case below.  The uniform
+      // initialization guarantees this is not a narrowing conversion.
+      const unsigned long err{GetLastError()};  // NOLINT(runtime/int)
+      if (err == ERROR_TIMEOUT) {
+        --waiter_count_;
+        return false;
+      } else {
+        ABSL_RAW_LOG(FATAL, "SleepConditionVariableSRW failed: %lu", err);
+      }
+    }
+    first_pass = false;
+  }
+  // Consume a wakeup and we're done.
+  --wakeup_count_;
+  --waiter_count_;
+  return true;
+}
+
+void Waiter::Post() {
+  LockHolder h(WinHelper::GetLock(this));
+  ++wakeup_count_;
+  InternalCondVarPoke();
+}
+
+void Waiter::Poke() {
+  LockHolder h(WinHelper::GetLock(this));
+  InternalCondVarPoke();
+}
+
+void Waiter::InternalCondVarPoke() {
+  if (waiter_count_ != 0) {
+    WakeConditionVariable(WinHelper::GetCond(this));
+  }
+}
+
+#else
+#error Unknown ABSL_WAITER_MODE
+#endif
+
+}  // namespace synchronization_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
diff --git a/src/absl/synchronization/internal/waiter.h b/src/absl/synchronization/internal/waiter.h
new file mode 100644 (file)
index 0000000..be3df18
--- /dev/null
@@ -0,0 +1,155 @@
+// Copyright 2017 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#ifndef ABSL_SYNCHRONIZATION_INTERNAL_WAITER_H_
+#define ABSL_SYNCHRONIZATION_INTERNAL_WAITER_H_
+
+#include "absl/base/config.h"
+
+#ifdef _WIN32
+#include <sdkddkver.h>
+#else
+#include <pthread.h>
+#endif
+
+#ifdef __linux__
+#include <linux/futex.h>
+#endif
+
+#ifdef ABSL_HAVE_SEMAPHORE_H
+#include <semaphore.h>
+#endif
+
+#include <atomic>
+#include <cstdint>
+
+#include "absl/base/internal/thread_identity.h"
+#include "absl/synchronization/internal/futex.h"
+#include "absl/synchronization/internal/kernel_timeout.h"
+
+// May be chosen at compile time via -DABSL_FORCE_WAITER_MODE=<index>
+#define ABSL_WAITER_MODE_FUTEX 0
+#define ABSL_WAITER_MODE_SEM 1
+#define ABSL_WAITER_MODE_CONDVAR 2
+#define ABSL_WAITER_MODE_WIN32 3
+
+#if defined(ABSL_FORCE_WAITER_MODE)
+#define ABSL_WAITER_MODE ABSL_FORCE_WAITER_MODE
+#elif defined(_WIN32) && _WIN32_WINNT >= _WIN32_WINNT_VISTA
+#define ABSL_WAITER_MODE ABSL_WAITER_MODE_WIN32
+#elif defined(ABSL_INTERNAL_HAVE_FUTEX)
+#define ABSL_WAITER_MODE ABSL_WAITER_MODE_FUTEX
+#elif defined(ABSL_HAVE_SEMAPHORE_H)
+#define ABSL_WAITER_MODE ABSL_WAITER_MODE_SEM
+#else
+#define ABSL_WAITER_MODE ABSL_WAITER_MODE_CONDVAR
+#endif
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace synchronization_internal {
+
+// Waiter is an OS-specific semaphore.
+class Waiter {
+ public:
+  // Prepare any data to track waits.
+  Waiter();
+
+  // Not copyable or movable
+  Waiter(const Waiter&) = delete;
+  Waiter& operator=(const Waiter&) = delete;
+
+  // Destroy any data to track waits.
+  ~Waiter();
+
+  // Blocks the calling thread until a matching call to `Post()` or
+  // `t` has passed. Returns `true` if woken (`Post()` called),
+  // `false` on timeout.
+  bool Wait(KernelTimeout t);
+
+  // Restart the caller of `Wait()` as with a normal semaphore.
+  void Post();
+
+  // If anyone is waiting, wake them up temporarily and cause them to
+  // call `MaybeBecomeIdle()`. They will then return to waiting for a
+  // `Post()` or timeout.
+  void Poke();
+
+  // Returns the Waiter associated with the identity.
+  static Waiter* GetWaiter(base_internal::ThreadIdentity* identity) {
+    static_assert(
+        sizeof(Waiter) <= sizeof(base_internal::ThreadIdentity::WaiterState),
+        "Insufficient space for Waiter");
+    return reinterpret_cast<Waiter*>(identity->waiter_state.data);
+  }
+
+  // How many periods to remain idle before releasing resources
+#ifndef ABSL_HAVE_THREAD_SANITIZER
+  static constexpr int kIdlePeriods = 60;
+#else
+  // Memory consumption under ThreadSanitizer is a serious concern,
+  // so we release resources sooner. The value of 1 leads to 1 to 2 second
+  // delay before marking a thread as idle.
+  static const int kIdlePeriods = 1;
+#endif
+
+ private:
+#if ABSL_WAITER_MODE == ABSL_WAITER_MODE_FUTEX
+  // Futexes are defined by specification to be 32-bits.
+  // Thus std::atomic<int32_t> must be just an int32_t with lockfree methods.
+  std::atomic<int32_t> futex_;
+  static_assert(sizeof(int32_t) == sizeof(futex_), "Wrong size for futex");
+
+#elif ABSL_WAITER_MODE == ABSL_WAITER_MODE_CONDVAR
+  // REQUIRES: mu_ must be held.
+  void InternalCondVarPoke();
+
+  pthread_mutex_t mu_;
+  pthread_cond_t cv_;
+  int waiter_count_;
+  int wakeup_count_;  // Unclaimed wakeups.
+
+#elif ABSL_WAITER_MODE == ABSL_WAITER_MODE_SEM
+  sem_t sem_;
+  // This seems superfluous, but for Poke() we need to cause spurious
+  // wakeups on the semaphore. Hence we can't actually use the
+  // semaphore's count.
+  std::atomic<int> wakeups_;
+
+#elif ABSL_WAITER_MODE == ABSL_WAITER_MODE_WIN32
+  // WinHelper - Used to define utilities for accessing the lock and
+  // condition variable storage once the types are complete.
+  class WinHelper;
+
+  // REQUIRES: WinHelper::GetLock(this) must be held.
+  void InternalCondVarPoke();
+
+  // We can't include Windows.h in our headers, so we use aligned charachter
+  // buffers to define the storage of SRWLOCK and CONDITION_VARIABLE.
+  alignas(void*) unsigned char mu_storage_[sizeof(void*)];
+  alignas(void*) unsigned char cv_storage_[sizeof(void*)];
+  int waiter_count_;
+  int wakeup_count_;
+
+#else
+  #error Unknown ABSL_WAITER_MODE
+#endif
+};
+
+}  // namespace synchronization_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#endif  // ABSL_SYNCHRONIZATION_INTERNAL_WAITER_H_
diff --git a/src/absl/synchronization/mutex.cc b/src/absl/synchronization/mutex.cc
new file mode 100644 (file)
index 0000000..76ad41f
--- /dev/null
@@ -0,0 +1,2751 @@
+// Copyright 2017 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "absl/synchronization/mutex.h"
+
+#ifdef _WIN32
+#include <windows.h>
+#ifdef ERROR
+#undef ERROR
+#endif
+#else
+#include <fcntl.h>
+#include <pthread.h>
+#include <sched.h>
+#include <sys/time.h>
+#endif
+
+#include <assert.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+#include <algorithm>
+#include <atomic>
+#include <cinttypes>
+#include <thread>  // NOLINT(build/c++11)
+
+#include "absl/base/attributes.h"
+#include "absl/base/call_once.h"
+#include "absl/base/config.h"
+#include "absl/base/dynamic_annotations.h"
+#include "absl/base/internal/atomic_hook.h"
+#include "absl/base/internal/cycleclock.h"
+#include "absl/base/internal/hide_ptr.h"
+#include "absl/base/internal/low_level_alloc.h"
+#include "absl/base/internal/raw_logging.h"
+#include "absl/base/internal/spinlock.h"
+#include "absl/base/internal/sysinfo.h"
+#include "absl/base/internal/thread_identity.h"
+#include "absl/base/internal/tsan_mutex_interface.h"
+#include "absl/base/port.h"
+#include "absl/debugging/stacktrace.h"
+#include "absl/debugging/symbolize.h"
+#include "absl/synchronization/internal/graphcycles.h"
+#include "absl/synchronization/internal/per_thread_sem.h"
+#include "absl/time/time.h"
+
+using absl::base_internal::CurrentThreadIdentityIfPresent;
+using absl::base_internal::PerThreadSynch;
+using absl::base_internal::SchedulingGuard;
+using absl::base_internal::ThreadIdentity;
+using absl::synchronization_internal::GetOrCreateCurrentThreadIdentity;
+using absl::synchronization_internal::GraphCycles;
+using absl::synchronization_internal::GraphId;
+using absl::synchronization_internal::InvalidGraphId;
+using absl::synchronization_internal::KernelTimeout;
+using absl::synchronization_internal::PerThreadSem;
+
+extern "C" {
+ABSL_ATTRIBUTE_WEAK void ABSL_INTERNAL_C_SYMBOL(AbslInternalMutexYield)() {
+  std::this_thread::yield();
+}
+}  // extern "C"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+
+namespace {
+
+#if defined(ABSL_HAVE_THREAD_SANITIZER)
+constexpr OnDeadlockCycle kDeadlockDetectionDefault = OnDeadlockCycle::kIgnore;
+#else
+constexpr OnDeadlockCycle kDeadlockDetectionDefault = OnDeadlockCycle::kAbort;
+#endif
+
+ABSL_CONST_INIT std::atomic<OnDeadlockCycle> synch_deadlock_detection(
+    kDeadlockDetectionDefault);
+ABSL_CONST_INIT std::atomic<bool> synch_check_invariants(false);
+
+ABSL_INTERNAL_ATOMIC_HOOK_ATTRIBUTES
+absl::base_internal::AtomicHook<void (*)(int64_t wait_cycles)>
+    submit_profile_data;
+ABSL_INTERNAL_ATOMIC_HOOK_ATTRIBUTES absl::base_internal::AtomicHook<void (*)(
+    const char *msg, const void *obj, int64_t wait_cycles)>
+    mutex_tracer;
+ABSL_INTERNAL_ATOMIC_HOOK_ATTRIBUTES
+    absl::base_internal::AtomicHook<void (*)(const char *msg, const void *cv)>
+        cond_var_tracer;
+ABSL_INTERNAL_ATOMIC_HOOK_ATTRIBUTES absl::base_internal::AtomicHook<
+    bool (*)(const void *pc, char *out, int out_size)>
+    symbolizer(absl::Symbolize);
+
+}  // namespace
+
+static inline bool EvalConditionAnnotated(const Condition *cond, Mutex *mu,
+                                          bool locking, bool trylock,
+                                          bool read_lock);
+
+void RegisterMutexProfiler(void (*fn)(int64_t wait_timestamp)) {
+  submit_profile_data.Store(fn);
+}
+
+void RegisterMutexTracer(void (*fn)(const char *msg, const void *obj,
+                                    int64_t wait_cycles)) {
+  mutex_tracer.Store(fn);
+}
+
+void RegisterCondVarTracer(void (*fn)(const char *msg, const void *cv)) {
+  cond_var_tracer.Store(fn);
+}
+
+void RegisterSymbolizer(bool (*fn)(const void *pc, char *out, int out_size)) {
+  symbolizer.Store(fn);
+}
+
+namespace {
+// Represents the strategy for spin and yield.
+// See the comment in GetMutexGlobals() for more information.
+enum DelayMode { AGGRESSIVE, GENTLE };
+
+struct ABSL_CACHELINE_ALIGNED MutexGlobals {
+  absl::once_flag once;
+  int spinloop_iterations = 0;
+  int32_t mutex_sleep_limit[2] = {};
+};
+
+const MutexGlobals &GetMutexGlobals() {
+  ABSL_CONST_INIT static MutexGlobals data;
+  absl::base_internal::LowLevelCallOnce(&data.once, [&]() {
+    const int num_cpus = absl::base_internal::NumCPUs();
+    data.spinloop_iterations = num_cpus > 1 ? 1500 : 0;
+    // If this a uniprocessor, only yield/sleep.  Otherwise, if the mode is
+    // aggressive then spin many times before yielding.  If the mode is
+    // gentle then spin only a few times before yielding.  Aggressive spinning
+    // is used to ensure that an Unlock() call, which must get the spin lock
+    // for any thread to make progress gets it without undue delay.
+    if (num_cpus > 1) {
+      data.mutex_sleep_limit[AGGRESSIVE] = 5000;
+      data.mutex_sleep_limit[GENTLE] = 250;
+    } else {
+      data.mutex_sleep_limit[AGGRESSIVE] = 0;
+      data.mutex_sleep_limit[GENTLE] = 0;
+    }
+  });
+  return data;
+}
+}  // namespace
+
+namespace synchronization_internal {
+// Returns the Mutex delay on iteration `c` depending on the given `mode`.
+// The returned value should be used as `c` for the next call to `MutexDelay`.
+int MutexDelay(int32_t c, int mode) {
+  const int32_t limit = GetMutexGlobals().mutex_sleep_limit[mode];
+  if (c < limit) {
+    // Spin.
+    c++;
+  } else {
+    SchedulingGuard::ScopedEnable enable_rescheduling;
+    ABSL_TSAN_MUTEX_PRE_DIVERT(nullptr, 0);
+    if (c == limit) {
+      // Yield once.
+      ABSL_INTERNAL_C_SYMBOL(AbslInternalMutexYield)();
+      c++;
+    } else {
+      // Then wait.
+      absl::SleepFor(absl::Microseconds(10));
+      c = 0;
+    }
+    ABSL_TSAN_MUTEX_POST_DIVERT(nullptr, 0);
+  }
+  return c;
+}
+}  // namespace synchronization_internal
+
+// --------------------------Generic atomic ops
+// Ensure that "(*pv & bits) == bits" by doing an atomic update of "*pv" to
+// "*pv | bits" if necessary.  Wait until (*pv & wait_until_clear)==0
+// before making any change.
+// This is used to set flags in mutex and condition variable words.
+static void AtomicSetBits(std::atomic<intptr_t>* pv, intptr_t bits,
+                          intptr_t wait_until_clear) {
+  intptr_t v;
+  do {
+    v = pv->load(std::memory_order_relaxed);
+  } while ((v & bits) != bits &&
+           ((v & wait_until_clear) != 0 ||
+            !pv->compare_exchange_weak(v, v | bits,
+                                       std::memory_order_release,
+                                       std::memory_order_relaxed)));
+}
+
+// Ensure that "(*pv & bits) == 0" by doing an atomic update of "*pv" to
+// "*pv & ~bits" if necessary.  Wait until (*pv & wait_until_clear)==0
+// before making any change.
+// This is used to unset flags in mutex and condition variable words.
+static void AtomicClearBits(std::atomic<intptr_t>* pv, intptr_t bits,
+                            intptr_t wait_until_clear) {
+  intptr_t v;
+  do {
+    v = pv->load(std::memory_order_relaxed);
+  } while ((v & bits) != 0 &&
+           ((v & wait_until_clear) != 0 ||
+            !pv->compare_exchange_weak(v, v & ~bits,
+                                       std::memory_order_release,
+                                       std::memory_order_relaxed)));
+}
+
+//------------------------------------------------------------------
+
+// Data for doing deadlock detection.
+ABSL_CONST_INIT static absl::base_internal::SpinLock deadlock_graph_mu(
+    absl::kConstInit, base_internal::SCHEDULE_KERNEL_ONLY);
+
+// Graph used to detect deadlocks.
+ABSL_CONST_INIT static GraphCycles *deadlock_graph
+    ABSL_GUARDED_BY(deadlock_graph_mu) ABSL_PT_GUARDED_BY(deadlock_graph_mu);
+
+//------------------------------------------------------------------
+// An event mechanism for debugging mutex use.
+// It also allows mutexes to be given names for those who can't handle
+// addresses, and instead like to give their data structures names like
+// "Henry", "Fido", or "Rupert IV, King of Yondavia".
+
+namespace {  // to prevent name pollution
+enum {       // Mutex and CondVar events passed as "ev" to PostSynchEvent
+             // Mutex events
+  SYNCH_EV_TRYLOCK_SUCCESS,
+  SYNCH_EV_TRYLOCK_FAILED,
+  SYNCH_EV_READERTRYLOCK_SUCCESS,
+  SYNCH_EV_READERTRYLOCK_FAILED,
+  SYNCH_EV_LOCK,
+  SYNCH_EV_LOCK_RETURNING,
+  SYNCH_EV_READERLOCK,
+  SYNCH_EV_READERLOCK_RETURNING,
+  SYNCH_EV_UNLOCK,
+  SYNCH_EV_READERUNLOCK,
+
+  // CondVar events
+  SYNCH_EV_WAIT,
+  SYNCH_EV_WAIT_RETURNING,
+  SYNCH_EV_SIGNAL,
+  SYNCH_EV_SIGNALALL,
+};
+
+enum {                    // Event flags
+  SYNCH_F_R = 0x01,       // reader event
+  SYNCH_F_LCK = 0x02,     // PostSynchEvent called with mutex held
+  SYNCH_F_TRY = 0x04,     // TryLock or ReaderTryLock
+  SYNCH_F_UNLOCK = 0x08,  // Unlock or ReaderUnlock
+
+  SYNCH_F_LCK_W = SYNCH_F_LCK,
+  SYNCH_F_LCK_R = SYNCH_F_LCK | SYNCH_F_R,
+};
+}  // anonymous namespace
+
+// Properties of the events.
+static const struct {
+  int flags;
+  const char *msg;
+} event_properties[] = {
+    {SYNCH_F_LCK_W | SYNCH_F_TRY, "TryLock succeeded "},
+    {0, "TryLock failed "},
+    {SYNCH_F_LCK_R | SYNCH_F_TRY, "ReaderTryLock succeeded "},
+    {0, "ReaderTryLock failed "},
+    {0, "Lock blocking "},
+    {SYNCH_F_LCK_W, "Lock returning "},
+    {0, "ReaderLock blocking "},
+    {SYNCH_F_LCK_R, "ReaderLock returning "},
+    {SYNCH_F_LCK_W | SYNCH_F_UNLOCK, "Unlock "},
+    {SYNCH_F_LCK_R | SYNCH_F_UNLOCK, "ReaderUnlock "},
+    {0, "Wait on "},
+    {0, "Wait unblocked "},
+    {0, "Signal on "},
+    {0, "SignalAll on "},
+};
+
+ABSL_CONST_INIT static absl::base_internal::SpinLock synch_event_mu(
+    absl::kConstInit, base_internal::SCHEDULE_KERNEL_ONLY);
+
+// Hash table size; should be prime > 2.
+// Can't be too small, as it's used for deadlock detection information.
+static constexpr uint32_t kNSynchEvent = 1031;
+
+static struct SynchEvent {     // this is a trivial hash table for the events
+  // struct is freed when refcount reaches 0
+  int refcount ABSL_GUARDED_BY(synch_event_mu);
+
+  // buckets have linear, 0-terminated  chains
+  SynchEvent *next ABSL_GUARDED_BY(synch_event_mu);
+
+  // Constant after initialization
+  uintptr_t masked_addr;  // object at this address is called "name"
+
+  // No explicit synchronization used.  Instead we assume that the
+  // client who enables/disables invariants/logging on a Mutex does so
+  // while the Mutex is not being concurrently accessed by others.
+  void (*invariant)(void *arg);  // called on each event
+  void *arg;            // first arg to (*invariant)()
+  bool log;             // logging turned on
+
+  // Constant after initialization
+  char name[1];         // actually longer---NUL-terminated string
+} * synch_event[kNSynchEvent] ABSL_GUARDED_BY(synch_event_mu);
+
+// Ensure that the object at "addr" has a SynchEvent struct associated with it,
+// set "bits" in the word there (waiting until lockbit is clear before doing
+// so), and return a refcounted reference that will remain valid until
+// UnrefSynchEvent() is called.  If a new SynchEvent is allocated,
+// the string name is copied into it.
+// When used with a mutex, the caller should also ensure that kMuEvent
+// is set in the mutex word, and similarly for condition variables and kCVEvent.
+static SynchEvent *EnsureSynchEvent(std::atomic<intptr_t> *addr,
+                                    const char *name, intptr_t bits,
+                                    intptr_t lockbit) {
+  uint32_t h = reinterpret_cast<intptr_t>(addr) % kNSynchEvent;
+  SynchEvent *e;
+  // first look for existing SynchEvent struct..
+  synch_event_mu.Lock();
+  for (e = synch_event[h];
+       e != nullptr && e->masked_addr != base_internal::HidePtr(addr);
+       e = e->next) {
+  }
+  if (e == nullptr) {  // no SynchEvent struct found; make one.
+    if (name == nullptr) {
+      name = "";
+    }
+    size_t l = strlen(name);
+    e = reinterpret_cast<SynchEvent *>(
+        base_internal::LowLevelAlloc::Alloc(sizeof(*e) + l));
+    e->refcount = 2;    // one for return value, one for linked list
+    e->masked_addr = base_internal::HidePtr(addr);
+    e->invariant = nullptr;
+    e->arg = nullptr;
+    e->log = false;
+    strcpy(e->name, name);  // NOLINT(runtime/printf)
+    e->next = synch_event[h];
+    AtomicSetBits(addr, bits, lockbit);
+    synch_event[h] = e;
+  } else {
+    e->refcount++;      // for return value
+  }
+  synch_event_mu.Unlock();
+  return e;
+}
+
+// Deallocate the SynchEvent *e, whose refcount has fallen to zero.
+static void DeleteSynchEvent(SynchEvent *e) {
+  base_internal::LowLevelAlloc::Free(e);
+}
+
+// Decrement the reference count of *e, or do nothing if e==null.
+static void UnrefSynchEvent(SynchEvent *e) {
+  if (e != nullptr) {
+    synch_event_mu.Lock();
+    bool del = (--(e->refcount) == 0);
+    synch_event_mu.Unlock();
+    if (del) {
+      DeleteSynchEvent(e);
+    }
+  }
+}
+
+// Forget the mapping from the object (Mutex or CondVar) at address addr
+// to SynchEvent object, and clear "bits" in its word (waiting until lockbit
+// is clear before doing so).
+static void ForgetSynchEvent(std::atomic<intptr_t> *addr, intptr_t bits,
+                             intptr_t lockbit) {
+  uint32_t h = reinterpret_cast<intptr_t>(addr) % kNSynchEvent;
+  SynchEvent **pe;
+  SynchEvent *e;
+  synch_event_mu.Lock();
+  for (pe = &synch_event[h];
+       (e = *pe) != nullptr && e->masked_addr != base_internal::HidePtr(addr);
+       pe = &e->next) {
+  }
+  bool del = false;
+  if (e != nullptr) {
+    *pe = e->next;
+    del = (--(e->refcount) == 0);
+  }
+  AtomicClearBits(addr, bits, lockbit);
+  synch_event_mu.Unlock();
+  if (del) {
+    DeleteSynchEvent(e);
+  }
+}
+
+// Return a refcounted reference to the SynchEvent of the object at address
+// "addr", if any.  The pointer returned is valid until the UnrefSynchEvent() is
+// called.
+static SynchEvent *GetSynchEvent(const void *addr) {
+  uint32_t h = reinterpret_cast<intptr_t>(addr) % kNSynchEvent;
+  SynchEvent *e;
+  synch_event_mu.Lock();
+  for (e = synch_event[h];
+       e != nullptr && e->masked_addr != base_internal::HidePtr(addr);
+       e = e->next) {
+  }
+  if (e != nullptr) {
+    e->refcount++;
+  }
+  synch_event_mu.Unlock();
+  return e;
+}
+
+// Called when an event "ev" occurs on a Mutex of CondVar "obj"
+// if event recording is on
+static void PostSynchEvent(void *obj, int ev) {
+  SynchEvent *e = GetSynchEvent(obj);
+  // logging is on if event recording is on and either there's no event struct,
+  // or it explicitly says to log
+  if (e == nullptr || e->log) {
+    void *pcs[40];
+    int n = absl::GetStackTrace(pcs, ABSL_ARRAYSIZE(pcs), 1);
+    // A buffer with enough space for the ASCII for all the PCs, even on a
+    // 64-bit machine.
+    char buffer[ABSL_ARRAYSIZE(pcs) * 24];
+    int pos = snprintf(buffer, sizeof (buffer), " @");
+    for (int i = 0; i != n; i++) {
+      pos += snprintf(&buffer[pos], sizeof (buffer) - pos, " %p", pcs[i]);
+    }
+    ABSL_RAW_LOG(INFO, "%s%p %s %s", event_properties[ev].msg, obj,
+                 (e == nullptr ? "" : e->name), buffer);
+  }
+  const int flags = event_properties[ev].flags;
+  if ((flags & SYNCH_F_LCK) != 0 && e != nullptr && e->invariant != nullptr) {
+    // Calling the invariant as is causes problems under ThreadSanitizer.
+    // We are currently inside of Mutex Lock/Unlock and are ignoring all
+    // memory accesses and synchronization. If the invariant transitively
+    // synchronizes something else and we ignore the synchronization, we will
+    // get false positive race reports later.
+    // Reuse EvalConditionAnnotated to properly call into user code.
+    struct local {
+      static bool pred(SynchEvent *ev) {
+        (*ev->invariant)(ev->arg);
+        return false;
+      }
+    };
+    Condition cond(&local::pred, e);
+    Mutex *mu = static_cast<Mutex *>(obj);
+    const bool locking = (flags & SYNCH_F_UNLOCK) == 0;
+    const bool trylock = (flags & SYNCH_F_TRY) != 0;
+    const bool read_lock = (flags & SYNCH_F_R) != 0;
+    EvalConditionAnnotated(&cond, mu, locking, trylock, read_lock);
+  }
+  UnrefSynchEvent(e);
+}
+
+//------------------------------------------------------------------
+
+// The SynchWaitParams struct encapsulates the way in which a thread is waiting:
+// whether it has a timeout, the condition, exclusive/shared, and whether a
+// condition variable wait has an associated Mutex (as opposed to another
+// type of lock).  It also points to the PerThreadSynch struct of its thread.
+// cv_word tells Enqueue() to enqueue on a CondVar using CondVarEnqueue().
+//
+// This structure is held on the stack rather than directly in
+// PerThreadSynch because a thread can be waiting on multiple Mutexes if,
+// while waiting on one Mutex, the implementation calls a client callback
+// (such as a Condition function) that acquires another Mutex. We don't
+// strictly need to allow this, but programmers become confused if we do not
+// allow them to use functions such a LOG() within Condition functions.  The
+// PerThreadSynch struct points at the most recent SynchWaitParams struct when
+// the thread is on a Mutex's waiter queue.
+struct SynchWaitParams {
+  SynchWaitParams(Mutex::MuHow how_arg, const Condition *cond_arg,
+                  KernelTimeout timeout_arg, Mutex *cvmu_arg,
+                  PerThreadSynch *thread_arg,
+                  std::atomic<intptr_t> *cv_word_arg)
+      : how(how_arg),
+        cond(cond_arg),
+        timeout(timeout_arg),
+        cvmu(cvmu_arg),
+        thread(thread_arg),
+        cv_word(cv_word_arg),
+        contention_start_cycles(base_internal::CycleClock::Now()) {}
+
+  const Mutex::MuHow how;  // How this thread needs to wait.
+  const Condition *cond;  // The condition that this thread is waiting for.
+                          // In Mutex, this field is set to zero if a timeout
+                          // expires.
+  KernelTimeout timeout;  // timeout expiry---absolute time
+                          // In Mutex, this field is set to zero if a timeout
+                          // expires.
+  Mutex *const cvmu;      // used for transfer from cond var to mutex
+  PerThreadSynch *const thread;  // thread that is waiting
+
+  // If not null, thread should be enqueued on the CondVar whose state
+  // word is cv_word instead of queueing normally on the Mutex.
+  std::atomic<intptr_t> *cv_word;
+
+  int64_t contention_start_cycles;  // Time (in cycles) when this thread started
+                                    // to contend for the mutex.
+};
+
+struct SynchLocksHeld {
+  int n;              // number of valid entries in locks[]
+  bool overflow;      // true iff we overflowed the array at some point
+  struct {
+    Mutex *mu;        // lock acquired
+    int32_t count;      // times acquired
+    GraphId id;       // deadlock_graph id of acquired lock
+  } locks[40];
+  // If a thread overfills the array during deadlock detection, we
+  // continue, discarding information as needed.  If no overflow has
+  // taken place, we can provide more error checking, such as
+  // detecting when a thread releases a lock it does not hold.
+};
+
+// A sentinel value in lists that is not 0.
+// A 0 value is used to mean "not on a list".
+static PerThreadSynch *const kPerThreadSynchNull =
+  reinterpret_cast<PerThreadSynch *>(1);
+
+static SynchLocksHeld *LocksHeldAlloc() {
+  SynchLocksHeld *ret = reinterpret_cast<SynchLocksHeld *>(
+      base_internal::LowLevelAlloc::Alloc(sizeof(SynchLocksHeld)));
+  ret->n = 0;
+  ret->overflow = false;
+  return ret;
+}
+
+// Return the PerThreadSynch-struct for this thread.
+static PerThreadSynch *Synch_GetPerThread() {
+  ThreadIdentity *identity = GetOrCreateCurrentThreadIdentity();
+  return &identity->per_thread_synch;
+}
+
+static PerThreadSynch *Synch_GetPerThreadAnnotated(Mutex *mu) {
+  if (mu) {
+    ABSL_TSAN_MUTEX_PRE_DIVERT(mu, 0);
+  }
+  PerThreadSynch *w = Synch_GetPerThread();
+  if (mu) {
+    ABSL_TSAN_MUTEX_POST_DIVERT(mu, 0);
+  }
+  return w;
+}
+
+static SynchLocksHeld *Synch_GetAllLocks() {
+  PerThreadSynch *s = Synch_GetPerThread();
+  if (s->all_locks == nullptr) {
+    s->all_locks = LocksHeldAlloc();  // Freed by ReclaimThreadIdentity.
+  }
+  return s->all_locks;
+}
+
+// Post on "w"'s associated PerThreadSem.
+void Mutex::IncrementSynchSem(Mutex *mu, PerThreadSynch *w) {
+  if (mu) {
+    ABSL_TSAN_MUTEX_PRE_DIVERT(mu, 0);
+  }
+  PerThreadSem::Post(w->thread_identity());
+  if (mu) {
+    ABSL_TSAN_MUTEX_POST_DIVERT(mu, 0);
+  }
+}
+
+// Wait on "w"'s associated PerThreadSem; returns false if timeout expired.
+bool Mutex::DecrementSynchSem(Mutex *mu, PerThreadSynch *w, KernelTimeout t) {
+  if (mu) {
+    ABSL_TSAN_MUTEX_PRE_DIVERT(mu, 0);
+  }
+  assert(w == Synch_GetPerThread());
+  static_cast<void>(w);
+  bool res = PerThreadSem::Wait(t);
+  if (mu) {
+    ABSL_TSAN_MUTEX_POST_DIVERT(mu, 0);
+  }
+  return res;
+}
+
+// We're in a fatal signal handler that hopes to use Mutex and to get
+// lucky by not deadlocking.  We try to improve its chances of success
+// by effectively disabling some of the consistency checks.  This will
+// prevent certain ABSL_RAW_CHECK() statements from being triggered when
+// re-rentry is detected.  The ABSL_RAW_CHECK() statements are those in the
+// Mutex code checking that the "waitp" field has not been reused.
+void Mutex::InternalAttemptToUseMutexInFatalSignalHandler() {
+  // Fix the per-thread state only if it exists.
+  ThreadIdentity *identity = CurrentThreadIdentityIfPresent();
+  if (identity != nullptr) {
+    identity->per_thread_synch.suppress_fatal_errors = true;
+  }
+  // Don't do deadlock detection when we are already failing.
+  synch_deadlock_detection.store(OnDeadlockCycle::kIgnore,
+                                 std::memory_order_release);
+}
+
+// --------------------------time support
+
+// Return the current time plus the timeout.  Use the same clock as
+// PerThreadSem::Wait() for consistency.  Unfortunately, we don't have
+// such a choice when a deadline is given directly.
+static absl::Time DeadlineFromTimeout(absl::Duration timeout) {
+#ifndef _WIN32
+  struct timeval tv;
+  gettimeofday(&tv, nullptr);
+  return absl::TimeFromTimeval(tv) + timeout;
+#else
+  return absl::Now() + timeout;
+#endif
+}
+
+// --------------------------Mutexes
+
+// In the layout below, the msb of the bottom byte is currently unused.  Also,
+// the following constraints were considered in choosing the layout:
+//  o Both the debug allocator's "uninitialized" and "freed" patterns (0xab and
+//    0xcd) are illegal: reader and writer lock both held.
+//  o kMuWriter and kMuEvent should exceed kMuDesig and kMuWait, to enable the
+//    bit-twiddling trick in Mutex::Unlock().
+//  o kMuWriter / kMuReader == kMuWrWait / kMuWait,
+//    to enable the bit-twiddling trick in CheckForMutexCorruption().
+static const intptr_t kMuReader      = 0x0001L;  // a reader holds the lock
+static const intptr_t kMuDesig       = 0x0002L;  // there's a designated waker
+static const intptr_t kMuWait        = 0x0004L;  // threads are waiting
+static const intptr_t kMuWriter      = 0x0008L;  // a writer holds the lock
+static const intptr_t kMuEvent       = 0x0010L;  // record this mutex's events
+// INVARIANT1:  there's a thread that was blocked on the mutex, is
+// no longer, yet has not yet acquired the mutex.  If there's a
+// designated waker, all threads can avoid taking the slow path in
+// unlock because the designated waker will subsequently acquire
+// the lock and wake someone.  To maintain INVARIANT1 the bit is
+// set when a thread is unblocked(INV1a), and threads that were
+// unblocked reset the bit when they either acquire or re-block
+// (INV1b).
+static const intptr_t kMuWrWait      = 0x0020L;  // runnable writer is waiting
+                                                 // for a reader
+static const intptr_t kMuSpin        = 0x0040L;  // spinlock protects wait list
+static const intptr_t kMuLow         = 0x00ffL;  // mask all mutex bits
+static const intptr_t kMuHigh        = ~kMuLow;  // mask pointer/reader count
+
+// Hack to make constant values available to gdb pretty printer
+enum {
+  kGdbMuSpin = kMuSpin,
+  kGdbMuEvent = kMuEvent,
+  kGdbMuWait = kMuWait,
+  kGdbMuWriter = kMuWriter,
+  kGdbMuDesig = kMuDesig,
+  kGdbMuWrWait = kMuWrWait,
+  kGdbMuReader = kMuReader,
+  kGdbMuLow = kMuLow,
+};
+
+// kMuWrWait implies kMuWait.
+// kMuReader and kMuWriter are mutually exclusive.
+// If kMuReader is zero, there are no readers.
+// Otherwise, if kMuWait is zero, the high order bits contain a count of the
+// number of readers.  Otherwise, the reader count is held in
+// PerThreadSynch::readers of the most recently queued waiter, again in the
+// bits above kMuLow.
+static const intptr_t kMuOne = 0x0100;  // a count of one reader
+
+// flags passed to Enqueue and LockSlow{,WithTimeout,Loop}
+static const int kMuHasBlocked = 0x01;  // already blocked (MUST == 1)
+static const int kMuIsCond = 0x02;      // conditional waiter (CV or Condition)
+
+static_assert(PerThreadSynch::kAlignment > kMuLow,
+              "PerThreadSynch::kAlignment must be greater than kMuLow");
+
+// This struct contains various bitmasks to be used in
+// acquiring and releasing a mutex in a particular mode.
+struct MuHowS {
+  // if all the bits in fast_need_zero are zero, the lock can be acquired by
+  // adding fast_add and oring fast_or.  The bit kMuDesig should be reset iff
+  // this is the designated waker.
+  intptr_t fast_need_zero;
+  intptr_t fast_or;
+  intptr_t fast_add;
+
+  intptr_t slow_need_zero;  // fast_need_zero with events (e.g. logging)
+
+  intptr_t slow_inc_need_zero;  // if all the bits in slow_inc_need_zero are
+                                // zero a reader can acquire a read share by
+                                // setting the reader bit and incrementing
+                                // the reader count (in last waiter since
+                                // we're now slow-path).  kMuWrWait be may
+                                // be ignored if we already waited once.
+};
+
+static const MuHowS kSharedS = {
+    // shared or read lock
+    kMuWriter | kMuWait | kMuEvent,   // fast_need_zero
+    kMuReader,                        // fast_or
+    kMuOne,                           // fast_add
+    kMuWriter | kMuWait,              // slow_need_zero
+    kMuSpin | kMuWriter | kMuWrWait,  // slow_inc_need_zero
+};
+static const MuHowS kExclusiveS = {
+    // exclusive or write lock
+    kMuWriter | kMuReader | kMuEvent,  // fast_need_zero
+    kMuWriter,                         // fast_or
+    0,                                 // fast_add
+    kMuWriter | kMuReader,             // slow_need_zero
+    ~static_cast<intptr_t>(0),         // slow_inc_need_zero
+};
+static const Mutex::MuHow kShared = &kSharedS;        // shared lock
+static const Mutex::MuHow kExclusive = &kExclusiveS;  // exclusive lock
+
+#ifdef NDEBUG
+static constexpr bool kDebugMode = false;
+#else
+static constexpr bool kDebugMode = true;
+#endif
+
+#ifdef ABSL_INTERNAL_HAVE_TSAN_INTERFACE
+static unsigned TsanFlags(Mutex::MuHow how) {
+  return how == kShared ? __tsan_mutex_read_lock : 0;
+}
+#endif
+
+static bool DebugOnlyIsExiting() {
+  return false;
+}
+
+Mutex::~Mutex() {
+  intptr_t v = mu_.load(std::memory_order_relaxed);
+  if ((v & kMuEvent) != 0 && !DebugOnlyIsExiting()) {
+    ForgetSynchEvent(&this->mu_, kMuEvent, kMuSpin);
+  }
+  if (kDebugMode) {
+    this->ForgetDeadlockInfo();
+  }
+  ABSL_TSAN_MUTEX_DESTROY(this, __tsan_mutex_not_static);
+}
+
+void Mutex::EnableDebugLog(const char *name) {
+  SynchEvent *e = EnsureSynchEvent(&this->mu_, name, kMuEvent, kMuSpin);
+  e->log = true;
+  UnrefSynchEvent(e);
+}
+
+void EnableMutexInvariantDebugging(bool enabled) {
+  synch_check_invariants.store(enabled, std::memory_order_release);
+}
+
+void Mutex::EnableInvariantDebugging(void (*invariant)(void *),
+                                     void *arg) {
+  if (synch_check_invariants.load(std::memory_order_acquire) &&
+      invariant != nullptr) {
+    SynchEvent *e = EnsureSynchEvent(&this->mu_, nullptr, kMuEvent, kMuSpin);
+    e->invariant = invariant;
+    e->arg = arg;
+    UnrefSynchEvent(e);
+  }
+}
+
+void SetMutexDeadlockDetectionMode(OnDeadlockCycle mode) {
+  synch_deadlock_detection.store(mode, std::memory_order_release);
+}
+
+// Return true iff threads x and y are part of the same equivalence
+// class of waiters. An equivalence class is defined as the set of
+// waiters with the same condition, type of lock, and thread priority.
+//
+// Requires that x and y be waiting on the same Mutex queue.
+static bool MuEquivalentWaiter(PerThreadSynch *x, PerThreadSynch *y) {
+  return x->waitp->how == y->waitp->how && x->priority == y->priority &&
+         Condition::GuaranteedEqual(x->waitp->cond, y->waitp->cond);
+}
+
+// Given the contents of a mutex word containing a PerThreadSynch pointer,
+// return the pointer.
+static inline PerThreadSynch *GetPerThreadSynch(intptr_t v) {
+  return reinterpret_cast<PerThreadSynch *>(v & kMuHigh);
+}
+
+// The next several routines maintain the per-thread next and skip fields
+// used in the Mutex waiter queue.
+// The queue is a circular singly-linked list, of which the "head" is the
+// last element, and head->next if the first element.
+// The skip field has the invariant:
+//   For thread x, x->skip is one of:
+//     - invalid (iff x is not in a Mutex wait queue),
+//     - null, or
+//     - a pointer to a distinct thread waiting later in the same Mutex queue
+//       such that all threads in [x, x->skip] have the same condition, priority
+//       and lock type (MuEquivalentWaiter() is true for all pairs in [x,
+//       x->skip]).
+// In addition, if x->skip is  valid, (x->may_skip || x->skip == null)
+//
+// By the spec of MuEquivalentWaiter(), it is not necessary when removing the
+// first runnable thread y from the front a Mutex queue to adjust the skip
+// field of another thread x because if x->skip==y, x->skip must (have) become
+// invalid before y is removed.  The function TryRemove can remove a specified
+// thread from an arbitrary position in the queue whether runnable or not, so
+// it fixes up skip fields that would otherwise be left dangling.
+// The statement
+//     if (x->may_skip && MuEquivalentWaiter(x, x->next)) { x->skip = x->next; }
+// maintains the invariant provided x is not the last waiter in a Mutex queue
+// The statement
+//          if (x->skip != null) { x->skip = x->skip->skip; }
+// maintains the invariant.
+
+// Returns the last thread y in a mutex waiter queue such that all threads in
+// [x, y] inclusive share the same condition.  Sets skip fields of some threads
+// in that range to optimize future evaluation of Skip() on x values in
+// the range.  Requires thread x is in a mutex waiter queue.
+// The locking is unusual.  Skip() is called under these conditions:
+//   - spinlock is held in call from Enqueue(), with maybe_unlocking == false
+//   - Mutex is held in call from UnlockSlow() by last unlocker, with
+//     maybe_unlocking == true
+//   - both Mutex and spinlock are held in call from DequeueAllWakeable() (from
+//     UnlockSlow()) and TryRemove()
+// These cases are mutually exclusive, so Skip() never runs concurrently
+// with itself on the same Mutex.   The skip chain is used in these other places
+// that cannot occur concurrently:
+//   - FixSkip() (from TryRemove()) - spinlock and Mutex are held)
+//   - Dequeue() (with spinlock and Mutex held)
+//   - UnlockSlow() (with spinlock and Mutex held)
+// A more complex case is Enqueue()
+//   - Enqueue() (with spinlock held and maybe_unlocking == false)
+//               This is the first case in which Skip is called, above.
+//   - Enqueue() (without spinlock held; but queue is empty and being freshly
+//                formed)
+//   - Enqueue() (with spinlock held and maybe_unlocking == true)
+// The first case has mutual exclusion, and the second isolation through
+// working on an otherwise unreachable data structure.
+// In the last case, Enqueue() is required to change no skip/next pointers
+// except those in the added node and the former "head" node.  This implies
+// that the new node is added after head, and so must be the new head or the
+// new front of the queue.
+static PerThreadSynch *Skip(PerThreadSynch *x) {
+  PerThreadSynch *x0 = nullptr;
+  PerThreadSynch *x1 = x;
+  PerThreadSynch *x2 = x->skip;
+  if (x2 != nullptr) {
+    // Each iteration attempts to advance sequence (x0,x1,x2) to next sequence
+    // such that   x1 == x0->skip && x2 == x1->skip
+    while ((x0 = x1, x1 = x2, x2 = x2->skip) != nullptr) {
+      x0->skip = x2;      // short-circuit skip from x0 to x2
+    }
+    x->skip = x1;         // short-circuit skip from x to result
+  }
+  return x1;
+}
+
+// "ancestor" appears before "to_be_removed" in the same Mutex waiter queue.
+// The latter is going to be removed out of order, because of a timeout.
+// Check whether "ancestor" has a skip field pointing to "to_be_removed",
+// and fix it if it does.
+static void FixSkip(PerThreadSynch *ancestor, PerThreadSynch *to_be_removed) {
+  if (ancestor->skip == to_be_removed) {  // ancestor->skip left dangling
+    if (to_be_removed->skip != nullptr) {
+      ancestor->skip = to_be_removed->skip;  // can skip past to_be_removed
+    } else if (ancestor->next != to_be_removed) {  // they are not adjacent
+      ancestor->skip = ancestor->next;             // can skip one past ancestor
+    } else {
+      ancestor->skip = nullptr;  // can't skip at all
+    }
+  }
+}
+
+static void CondVarEnqueue(SynchWaitParams *waitp);
+
+// Enqueue thread "waitp->thread" on a waiter queue.
+// Called with mutex spinlock held if head != nullptr
+// If head==nullptr and waitp->cv_word==nullptr, then Enqueue() is
+// idempotent; it alters no state associated with the existing (empty)
+// queue.
+//
+// If waitp->cv_word == nullptr, queue the thread at either the front or
+// the end (according to its priority) of the circular mutex waiter queue whose
+// head is "head", and return the new head.  mu is the previous mutex state,
+// which contains the reader count (perhaps adjusted for the operation in
+// progress) if the list was empty and a read lock held, and the holder hint if
+// the list was empty and a write lock held.  (flags & kMuIsCond) indicates
+// whether this thread was transferred from a CondVar or is waiting for a
+// non-trivial condition.  In this case, Enqueue() never returns nullptr
+//
+// If waitp->cv_word != nullptr, CondVarEnqueue() is called, and "head" is
+// returned. This mechanism is used by CondVar to queue a thread on the
+// condition variable queue instead of the mutex queue in implementing Wait().
+// In this case, Enqueue() can return nullptr (if head==nullptr).
+static PerThreadSynch *Enqueue(PerThreadSynch *head,
+                               SynchWaitParams *waitp, intptr_t mu, int flags) {
+  // If we have been given a cv_word, call CondVarEnqueue() and return
+  // the previous head of the Mutex waiter queue.
+  if (waitp->cv_word != nullptr) {
+    CondVarEnqueue(waitp);
+    return head;
+  }
+
+  PerThreadSynch *s = waitp->thread;
+  ABSL_RAW_CHECK(
+      s->waitp == nullptr ||    // normal case
+          s->waitp == waitp ||  // Fer()---transfer from condition variable
+          s->suppress_fatal_errors,
+      "detected illegal recursion into Mutex code");
+  s->waitp = waitp;
+  s->skip = nullptr;             // maintain skip invariant (see above)
+  s->may_skip = true;            // always true on entering queue
+  s->wake = false;               // not being woken
+  s->cond_waiter = ((flags & kMuIsCond) != 0);
+  if (head == nullptr) {         // s is the only waiter
+    s->next = s;                 // it's the only entry in the cycle
+    s->readers = mu;             // reader count is from mu word
+    s->maybe_unlocking = false;  // no one is searching an empty list
+    head = s;                    // s is new head
+  } else {
+    PerThreadSynch *enqueue_after = nullptr;  // we'll put s after this element
+#ifdef ABSL_HAVE_PTHREAD_GETSCHEDPARAM
+    int64_t now_cycles = base_internal::CycleClock::Now();
+    if (s->next_priority_read_cycles < now_cycles) {
+      // Every so often, update our idea of the thread's priority.
+      // pthread_getschedparam() is 5% of the block/wakeup time;
+      // base_internal::CycleClock::Now() is 0.5%.
+      int policy;
+      struct sched_param param;
+      const int err = pthread_getschedparam(pthread_self(), &policy, &param);
+      if (err != 0) {
+        ABSL_RAW_LOG(ERROR, "pthread_getschedparam failed: %d", err);
+      } else {
+        s->priority = param.sched_priority;
+        s->next_priority_read_cycles =
+            now_cycles +
+            static_cast<int64_t>(base_internal::CycleClock::Frequency());
+      }
+    }
+    if (s->priority > head->priority) {  // s's priority is above head's
+      // try to put s in priority-fifo order, or failing that at the front.
+      if (!head->maybe_unlocking) {
+        // No unlocker can be scanning the queue, so we can insert into the
+        // middle of the queue.
+        //
+        // Within a skip chain, all waiters have the same priority, so we can
+        // skip forward through the chains until we find one with a lower
+        // priority than the waiter to be enqueued.
+        PerThreadSynch *advance_to = head;    // next value of enqueue_after
+        do {
+          enqueue_after = advance_to;
+          // (side-effect: optimizes skip chain)
+          advance_to = Skip(enqueue_after->next);
+        } while (s->priority <= advance_to->priority);
+              // termination guaranteed because s->priority > head->priority
+              // and head is the end of a skip chain
+      } else if (waitp->how == kExclusive &&
+                 Condition::GuaranteedEqual(waitp->cond, nullptr)) {
+        // An unlocker could be scanning the queue, but we know it will recheck
+        // the queue front for writers that have no condition, which is what s
+        // is, so an insert at front is safe.
+        enqueue_after = head;       // add after head, at front
+      }
+    }
+#endif
+    if (enqueue_after != nullptr) {
+      s->next = enqueue_after->next;
+      enqueue_after->next = s;
+
+      // enqueue_after can be: head, Skip(...), or cur.
+      // The first two imply enqueue_after->skip == nullptr, and
+      // the last is used only if MuEquivalentWaiter(s, cur).
+      // We require this because clearing enqueue_after->skip
+      // is impossible; enqueue_after's predecessors might also
+      // incorrectly skip over s if we were to allow other
+      // insertion points.
+      ABSL_RAW_CHECK(enqueue_after->skip == nullptr ||
+                         MuEquivalentWaiter(enqueue_after, s),
+                     "Mutex Enqueue failure");
+
+      if (enqueue_after != head && enqueue_after->may_skip &&
+          MuEquivalentWaiter(enqueue_after, enqueue_after->next)) {
+        // enqueue_after can skip to its new successor, s
+        enqueue_after->skip = enqueue_after->next;
+      }
+      if (MuEquivalentWaiter(s, s->next)) {  // s->may_skip is known to be true
+        s->skip = s->next;                // s may skip to its successor
+      }
+    } else {   // enqueue not done any other way, so
+               // we're inserting s at the back
+      // s will become new head; copy data from head into it
+      s->next = head->next;        // add s after head
+      head->next = s;
+      s->readers = head->readers;  // reader count is from previous head
+      s->maybe_unlocking = head->maybe_unlocking;  // same for unlock hint
+      if (head->may_skip && MuEquivalentWaiter(head, s)) {
+        // head now has successor; may skip
+        head->skip = s;
+      }
+      head = s;  // s is new head
+    }
+  }
+  s->state.store(PerThreadSynch::kQueued, std::memory_order_relaxed);
+  return head;
+}
+
+// Dequeue the successor pw->next of thread pw from the Mutex waiter queue
+// whose last element is head.  The new head element is returned, or null
+// if the list is made empty.
+// Dequeue is called with both spinlock and Mutex held.
+static PerThreadSynch *Dequeue(PerThreadSynch *head, PerThreadSynch *pw) {
+  PerThreadSynch *w = pw->next;
+  pw->next = w->next;         // snip w out of list
+  if (head == w) {            // we removed the head
+    head = (pw == w) ? nullptr : pw;  // either emptied list, or pw is new head
+  } else if (pw != head && MuEquivalentWaiter(pw, pw->next)) {
+    // pw can skip to its new successor
+    if (pw->next->skip !=
+        nullptr) {  // either skip to its successors skip target
+      pw->skip = pw->next->skip;
+    } else {                   // or to pw's successor
+      pw->skip = pw->next;
+    }
+  }
+  return head;
+}
+
+// Traverse the elements [ pw->next, h] of the circular list whose last element
+// is head.
+// Remove all elements with wake==true and place them in the
+// singly-linked list wake_list in the order found.   Assumes that
+// there is only one such element if the element has how == kExclusive.
+// Return the new head.
+static PerThreadSynch *DequeueAllWakeable(PerThreadSynch *head,
+                                          PerThreadSynch *pw,
+                                          PerThreadSynch **wake_tail) {
+  PerThreadSynch *orig_h = head;
+  PerThreadSynch *w = pw->next;
+  bool skipped = false;
+  do {
+    if (w->wake) {                    // remove this element
+      ABSL_RAW_CHECK(pw->skip == nullptr, "bad skip in DequeueAllWakeable");
+      // we're removing pw's successor so either pw->skip is zero or we should
+      // already have removed pw since if pw->skip!=null, pw has the same
+      // condition as w.
+      head = Dequeue(head, pw);
+      w->next = *wake_tail;           // keep list terminated
+      *wake_tail = w;                 // add w to wake_list;
+      wake_tail = &w->next;           // next addition to end
+      if (w->waitp->how == kExclusive) {  // wake at most 1 writer
+        break;
+      }
+    } else {                // not waking this one; skip
+      pw = Skip(w);       // skip as much as possible
+      skipped = true;
+    }
+    w = pw->next;
+    // We want to stop processing after we've considered the original head,
+    // orig_h.  We can't test for w==orig_h in the loop because w may skip over
+    // it; we are guaranteed only that w's predecessor will not skip over
+    // orig_h.  When we've considered orig_h, either we've processed it and
+    // removed it (so orig_h != head), or we considered it and skipped it (so
+    // skipped==true && pw == head because skipping from head always skips by
+    // just one, leaving pw pointing at head).  So we want to
+    // continue the loop with the negation of that expression.
+  } while (orig_h == head && (pw != head || !skipped));
+  return head;
+}
+
+// Try to remove thread s from the list of waiters on this mutex.
+// Does nothing if s is not on the waiter list.
+void Mutex::TryRemove(PerThreadSynch *s) {
+  SchedulingGuard::ScopedDisable disable_rescheduling;
+  intptr_t v = mu_.load(std::memory_order_relaxed);
+  // acquire spinlock & lock
+  if ((v & (kMuWait | kMuSpin | kMuWriter | kMuReader)) == kMuWait &&
+      mu_.compare_exchange_strong(v, v | kMuSpin | kMuWriter,
+                                  std::memory_order_acquire,
+                                  std::memory_order_relaxed)) {
+    PerThreadSynch *h = GetPerThreadSynch(v);
+    if (h != nullptr) {
+      PerThreadSynch *pw = h;   // pw is w's predecessor
+      PerThreadSynch *w;
+      if ((w = pw->next) != s) {  // search for thread,
+        do {                      // processing at least one element
+          // If the current element isn't equivalent to the waiter to be
+          // removed, we can skip the entire chain.
+          if (!MuEquivalentWaiter(s, w)) {
+            pw = Skip(w);                // so skip all that won't match
+            // we don't have to worry about dangling skip fields
+            // in the threads we skipped; none can point to s
+            // because they are in a different equivalence class.
+          } else {          // seeking same condition
+            FixSkip(w, s);  // fix up any skip pointer from w to s
+            pw = w;
+          }
+          // don't search further if we found the thread, or we're about to
+          // process the first thread again.
+        } while ((w = pw->next) != s && pw != h);
+      }
+      if (w == s) {                 // found thread; remove it
+        // pw->skip may be non-zero here; the loop above ensured that
+        // no ancestor of s can skip to s, so removal is safe anyway.
+        h = Dequeue(h, pw);
+        s->next = nullptr;
+        s->state.store(PerThreadSynch::kAvailable, std::memory_order_release);
+      }
+    }
+    intptr_t nv;
+    do {                        // release spinlock and lock
+      v = mu_.load(std::memory_order_relaxed);
+      nv = v & (kMuDesig | kMuEvent);
+      if (h != nullptr) {
+        nv |= kMuWait | reinterpret_cast<intptr_t>(h);
+        h->readers = 0;            // we hold writer lock
+        h->maybe_unlocking = false;  // finished unlocking
+      }
+    } while (!mu_.compare_exchange_weak(v, nv,
+                                        std::memory_order_release,
+                                        std::memory_order_relaxed));
+  }
+}
+
+// Wait until thread "s", which must be the current thread, is removed from the
+// this mutex's waiter queue.  If "s->waitp->timeout" has a timeout, wake up
+// if the wait extends past the absolute time specified, even if "s" is still
+// on the mutex queue.  In this case, remove "s" from the queue and return
+// true, otherwise return false.
+ABSL_XRAY_LOG_ARGS(1) void Mutex::Block(PerThreadSynch *s) {
+  while (s->state.load(std::memory_order_acquire) == PerThreadSynch::kQueued) {
+    if (!DecrementSynchSem(this, s, s->waitp->timeout)) {
+      // After a timeout, we go into a spin loop until we remove ourselves
+      // from the queue, or someone else removes us.  We can't be sure to be
+      // able to remove ourselves in a single lock acquisition because this
+      // mutex may be held, and the holder has the right to read the centre
+      // of the waiter queue without holding the spinlock.
+      this->TryRemove(s);
+      int c = 0;
+      while (s->next != nullptr) {
+        c = synchronization_internal::MutexDelay(c, GENTLE);
+        this->TryRemove(s);
+      }
+      if (kDebugMode) {
+        // This ensures that we test the case that TryRemove() is called when s
+        // is not on the queue.
+        this->TryRemove(s);
+      }
+      s->waitp->timeout = KernelTimeout::Never();      // timeout is satisfied
+      s->waitp->cond = nullptr;  // condition no longer relevant for wakeups
+    }
+  }
+  ABSL_RAW_CHECK(s->waitp != nullptr || s->suppress_fatal_errors,
+                 "detected illegal recursion in Mutex code");
+  s->waitp = nullptr;
+}
+
+// Wake thread w, and return the next thread in the list.
+PerThreadSynch *Mutex::Wakeup(PerThreadSynch *w) {
+  PerThreadSynch *next = w->next;
+  w->next = nullptr;
+  w->state.store(PerThreadSynch::kAvailable, std::memory_order_release);
+  IncrementSynchSem(this, w);
+
+  return next;
+}
+
+static GraphId GetGraphIdLocked(Mutex *mu)
+    ABSL_EXCLUSIVE_LOCKS_REQUIRED(deadlock_graph_mu) {
+  if (!deadlock_graph) {  // (re)create the deadlock graph.
+    deadlock_graph =
+        new (base_internal::LowLevelAlloc::Alloc(sizeof(*deadlock_graph)))
+            GraphCycles;
+  }
+  return deadlock_graph->GetId(mu);
+}
+
+static GraphId GetGraphId(Mutex *mu) ABSL_LOCKS_EXCLUDED(deadlock_graph_mu) {
+  deadlock_graph_mu.Lock();
+  GraphId id = GetGraphIdLocked(mu);
+  deadlock_graph_mu.Unlock();
+  return id;
+}
+
+// Record a lock acquisition.  This is used in debug mode for deadlock
+// detection.  The held_locks pointer points to the relevant data
+// structure for each case.
+static void LockEnter(Mutex* mu, GraphId id, SynchLocksHeld *held_locks) {
+  int n = held_locks->n;
+  int i = 0;
+  while (i != n && held_locks->locks[i].id != id) {
+    i++;
+  }
+  if (i == n) {
+    if (n == ABSL_ARRAYSIZE(held_locks->locks)) {
+      held_locks->overflow = true;  // lost some data
+    } else {                        // we have room for lock
+      held_locks->locks[i].mu = mu;
+      held_locks->locks[i].count = 1;
+      held_locks->locks[i].id = id;
+      held_locks->n = n + 1;
+    }
+  } else {
+    held_locks->locks[i].count++;
+  }
+}
+
+// Record a lock release.  Each call to LockEnter(mu, id, x) should be
+// eventually followed by a call to LockLeave(mu, id, x) by the same thread.
+// It does not process the event if is not needed when deadlock detection is
+// disabled.
+static void LockLeave(Mutex* mu, GraphId id, SynchLocksHeld *held_locks) {
+  int n = held_locks->n;
+  int i = 0;
+  while (i != n && held_locks->locks[i].id != id) {
+    i++;
+  }
+  if (i == n) {
+    if (!held_locks->overflow) {
+      // The deadlock id may have been reassigned after ForgetDeadlockInfo,
+      // but in that case mu should still be present.
+      i = 0;
+      while (i != n && held_locks->locks[i].mu != mu) {
+        i++;
+      }
+      if (i == n) {  // mu missing means releasing unheld lock
+        SynchEvent *mu_events = GetSynchEvent(mu);
+        ABSL_RAW_LOG(FATAL,
+                     "thread releasing lock it does not hold: %p %s; "
+                     ,
+                     static_cast<void *>(mu),
+                     mu_events == nullptr ? "" : mu_events->name);
+      }
+    }
+  } else if (held_locks->locks[i].count == 1) {
+    held_locks->n = n - 1;
+    held_locks->locks[i] = held_locks->locks[n - 1];
+    held_locks->locks[n - 1].id = InvalidGraphId();
+    held_locks->locks[n - 1].mu =
+        nullptr;  // clear mu to please the leak detector.
+  } else {
+    assert(held_locks->locks[i].count > 0);
+    held_locks->locks[i].count--;
+  }
+}
+
+// Call LockEnter() if in debug mode and deadlock detection is enabled.
+static inline void DebugOnlyLockEnter(Mutex *mu) {
+  if (kDebugMode) {
+    if (synch_deadlock_detection.load(std::memory_order_acquire) !=
+        OnDeadlockCycle::kIgnore) {
+      LockEnter(mu, GetGraphId(mu), Synch_GetAllLocks());
+    }
+  }
+}
+
+// Call LockEnter() if in debug mode and deadlock detection is enabled.
+static inline void DebugOnlyLockEnter(Mutex *mu, GraphId id) {
+  if (kDebugMode) {
+    if (synch_deadlock_detection.load(std::memory_order_acquire) !=
+        OnDeadlockCycle::kIgnore) {
+      LockEnter(mu, id, Synch_GetAllLocks());
+    }
+  }
+}
+
+// Call LockLeave() if in debug mode and deadlock detection is enabled.
+static inline void DebugOnlyLockLeave(Mutex *mu) {
+  if (kDebugMode) {
+    if (synch_deadlock_detection.load(std::memory_order_acquire) !=
+        OnDeadlockCycle::kIgnore) {
+      LockLeave(mu, GetGraphId(mu), Synch_GetAllLocks());
+    }
+  }
+}
+
+static char *StackString(void **pcs, int n, char *buf, int maxlen,
+                         bool symbolize) {
+  static const int kSymLen = 200;
+  char sym[kSymLen];
+  int len = 0;
+  for (int i = 0; i != n; i++) {
+    if (symbolize) {
+      if (!symbolizer(pcs[i], sym, kSymLen)) {
+        sym[0] = '\0';
+      }
+      snprintf(buf + len, maxlen - len, "%s\t@ %p %s\n",
+               (i == 0 ? "\n" : ""),
+               pcs[i], sym);
+    } else {
+      snprintf(buf + len, maxlen - len, " %p", pcs[i]);
+    }
+    len += strlen(&buf[len]);
+  }
+  return buf;
+}
+
+static char *CurrentStackString(char *buf, int maxlen, bool symbolize) {
+  void *pcs[40];
+  return StackString(pcs, absl::GetStackTrace(pcs, ABSL_ARRAYSIZE(pcs), 2), buf,
+                     maxlen, symbolize);
+}
+
+namespace {
+enum { kMaxDeadlockPathLen = 10 };  // maximum length of a deadlock cycle;
+                                    // a path this long would be remarkable
+// Buffers required to report a deadlock.
+// We do not allocate them on stack to avoid large stack frame.
+struct DeadlockReportBuffers {
+  char buf[6100];
+  GraphId path[kMaxDeadlockPathLen];
+};
+
+struct ScopedDeadlockReportBuffers {
+  ScopedDeadlockReportBuffers() {
+    b = reinterpret_cast<DeadlockReportBuffers *>(
+        base_internal::LowLevelAlloc::Alloc(sizeof(*b)));
+  }
+  ~ScopedDeadlockReportBuffers() { base_internal::LowLevelAlloc::Free(b); }
+  DeadlockReportBuffers *b;
+};
+
+// Helper to pass to GraphCycles::UpdateStackTrace.
+int GetStack(void** stack, int max_depth) {
+  return absl::GetStackTrace(stack, max_depth, 3);
+}
+}  // anonymous namespace
+
+// Called in debug mode when a thread is about to acquire a lock in a way that
+// may block.
+static GraphId DeadlockCheck(Mutex *mu) {
+  if (synch_deadlock_detection.load(std::memory_order_acquire) ==
+      OnDeadlockCycle::kIgnore) {
+    return InvalidGraphId();
+  }
+
+  SynchLocksHeld *all_locks = Synch_GetAllLocks();
+
+  absl::base_internal::SpinLockHolder lock(&deadlock_graph_mu);
+  const GraphId mu_id = GetGraphIdLocked(mu);
+
+  if (all_locks->n == 0) {
+    // There are no other locks held. Return now so that we don't need to
+    // call GetSynchEvent(). This way we do not record the stack trace
+    // for this Mutex. It's ok, since if this Mutex is involved in a deadlock,
+    // it can't always be the first lock acquired by a thread.
+    return mu_id;
+  }
+
+  // We prefer to keep stack traces that show a thread holding and acquiring
+  // as many locks as possible.  This increases the chances that a given edge
+  // in the acquires-before graph will be represented in the stack traces
+  // recorded for the locks.
+  deadlock_graph->UpdateStackTrace(mu_id, all_locks->n + 1, GetStack);
+
+  // For each other mutex already held by this thread:
+  for (int i = 0; i != all_locks->n; i++) {
+    const GraphId other_node_id = all_locks->locks[i].id;
+    const Mutex *other =
+        static_cast<const Mutex *>(deadlock_graph->Ptr(other_node_id));
+    if (other == nullptr) {
+      // Ignore stale lock
+      continue;
+    }
+
+    // Add the acquired-before edge to the graph.
+    if (!deadlock_graph->InsertEdge(other_node_id, mu_id)) {
+      ScopedDeadlockReportBuffers scoped_buffers;
+      DeadlockReportBuffers *b = scoped_buffers.b;
+      static int number_of_reported_deadlocks = 0;
+      number_of_reported_deadlocks++;
+      // Symbolize only 2 first deadlock report to avoid huge slowdowns.
+      bool symbolize = number_of_reported_deadlocks <= 2;
+      ABSL_RAW_LOG(ERROR, "Potential Mutex deadlock: %s",
+                   CurrentStackString(b->buf, sizeof (b->buf), symbolize));
+      int len = 0;
+      for (int j = 0; j != all_locks->n; j++) {
+        void* pr = deadlock_graph->Ptr(all_locks->locks[j].id);
+        if (pr != nullptr) {
+          snprintf(b->buf + len, sizeof (b->buf) - len, " %p", pr);
+          len += static_cast<int>(strlen(&b->buf[len]));
+        }
+      }
+      ABSL_RAW_LOG(ERROR,
+                   "Acquiring absl::Mutex %p while holding %s; a cycle in the "
+                   "historical lock ordering graph has been observed",
+                   static_cast<void *>(mu), b->buf);
+      ABSL_RAW_LOG(ERROR, "Cycle: ");
+      int path_len = deadlock_graph->FindPath(
+          mu_id, other_node_id, ABSL_ARRAYSIZE(b->path), b->path);
+      for (int j = 0; j != path_len; j++) {
+        GraphId id = b->path[j];
+        Mutex *path_mu = static_cast<Mutex *>(deadlock_graph->Ptr(id));
+        if (path_mu == nullptr) continue;
+        void** stack;
+        int depth = deadlock_graph->GetStackTrace(id, &stack);
+        snprintf(b->buf, sizeof(b->buf),
+                 "mutex@%p stack: ", static_cast<void *>(path_mu));
+        StackString(stack, depth, b->buf + strlen(b->buf),
+                    static_cast<int>(sizeof(b->buf) - strlen(b->buf)),
+                    symbolize);
+        ABSL_RAW_LOG(ERROR, "%s", b->buf);
+      }
+      if (synch_deadlock_detection.load(std::memory_order_acquire) ==
+          OnDeadlockCycle::kAbort) {
+        deadlock_graph_mu.Unlock();  // avoid deadlock in fatal sighandler
+        ABSL_RAW_LOG(FATAL, "dying due to potential deadlock");
+        return mu_id;
+      }
+      break;   // report at most one potential deadlock per acquisition
+    }
+  }
+
+  return mu_id;
+}
+
+// Invoke DeadlockCheck() iff we're in debug mode and
+// deadlock checking has been enabled.
+static inline GraphId DebugOnlyDeadlockCheck(Mutex *mu) {
+  if (kDebugMode && synch_deadlock_detection.load(std::memory_order_acquire) !=
+                        OnDeadlockCycle::kIgnore) {
+    return DeadlockCheck(mu);
+  } else {
+    return InvalidGraphId();
+  }
+}
+
+void Mutex::ForgetDeadlockInfo() {
+  if (kDebugMode && synch_deadlock_detection.load(std::memory_order_acquire) !=
+                        OnDeadlockCycle::kIgnore) {
+    deadlock_graph_mu.Lock();
+    if (deadlock_graph != nullptr) {
+      deadlock_graph->RemoveNode(this);
+    }
+    deadlock_graph_mu.Unlock();
+  }
+}
+
+void Mutex::AssertNotHeld() const {
+  // We have the data to allow this check only if in debug mode and deadlock
+  // detection is enabled.
+  if (kDebugMode &&
+      (mu_.load(std::memory_order_relaxed) & (kMuWriter | kMuReader)) != 0 &&
+      synch_deadlock_detection.load(std::memory_order_acquire) !=
+          OnDeadlockCycle::kIgnore) {
+    GraphId id = GetGraphId(const_cast<Mutex *>(this));
+    SynchLocksHeld *locks = Synch_GetAllLocks();
+    for (int i = 0; i != locks->n; i++) {
+      if (locks->locks[i].id == id) {
+        SynchEvent *mu_events = GetSynchEvent(this);
+        ABSL_RAW_LOG(FATAL, "thread should not hold mutex %p %s",
+                     static_cast<const void *>(this),
+                     (mu_events == nullptr ? "" : mu_events->name));
+      }
+    }
+  }
+}
+
+// Attempt to acquire *mu, and return whether successful.  The implementation
+// may spin for a short while if the lock cannot be acquired immediately.
+static bool TryAcquireWithSpinning(std::atomic<intptr_t>* mu) {
+  int c = GetMutexGlobals().spinloop_iterations;
+  do {  // do/while somewhat faster on AMD
+    intptr_t v = mu->load(std::memory_order_relaxed);
+    if ((v & (kMuReader|kMuEvent)) != 0) {
+      return false;  // a reader or tracing -> give up
+    } else if (((v & kMuWriter) == 0) &&  // no holder -> try to acquire
+               mu->compare_exchange_strong(v, kMuWriter | v,
+                                           std::memory_order_acquire,
+                                           std::memory_order_relaxed)) {
+      return true;
+    }
+  } while (--c > 0);
+  return false;
+}
+
+ABSL_XRAY_LOG_ARGS(1) void Mutex::Lock() {
+  ABSL_TSAN_MUTEX_PRE_LOCK(this, 0);
+  GraphId id = DebugOnlyDeadlockCheck(this);
+  intptr_t v = mu_.load(std::memory_order_relaxed);
+  // try fast acquire, then spin loop
+  if ((v & (kMuWriter | kMuReader | kMuEvent)) != 0 ||
+      !mu_.compare_exchange_strong(v, kMuWriter | v,
+                                   std::memory_order_acquire,
+                                   std::memory_order_relaxed)) {
+    // try spin acquire, then slow loop
+    if (!TryAcquireWithSpinning(&this->mu_)) {
+      this->LockSlow(kExclusive, nullptr, 0);
+    }
+  }
+  DebugOnlyLockEnter(this, id);
+  ABSL_TSAN_MUTEX_POST_LOCK(this, 0, 0);
+}
+
+ABSL_XRAY_LOG_ARGS(1) void Mutex::ReaderLock() {
+  ABSL_TSAN_MUTEX_PRE_LOCK(this, __tsan_mutex_read_lock);
+  GraphId id = DebugOnlyDeadlockCheck(this);
+  intptr_t v = mu_.load(std::memory_order_relaxed);
+  // try fast acquire, then slow loop
+  if ((v & (kMuWriter | kMuWait | kMuEvent)) != 0 ||
+      !mu_.compare_exchange_strong(v, (kMuReader | v) + kMuOne,
+                                   std::memory_order_acquire,
+                                   std::memory_order_relaxed)) {
+    this->LockSlow(kShared, nullptr, 0);
+  }
+  DebugOnlyLockEnter(this, id);
+  ABSL_TSAN_MUTEX_POST_LOCK(this, __tsan_mutex_read_lock, 0);
+}
+
+void Mutex::LockWhen(const Condition &cond) {
+  ABSL_TSAN_MUTEX_PRE_LOCK(this, 0);
+  GraphId id = DebugOnlyDeadlockCheck(this);
+  this->LockSlow(kExclusive, &cond, 0);
+  DebugOnlyLockEnter(this, id);
+  ABSL_TSAN_MUTEX_POST_LOCK(this, 0, 0);
+}
+
+bool Mutex::LockWhenWithTimeout(const Condition &cond, absl::Duration timeout) {
+  return LockWhenWithDeadline(cond, DeadlineFromTimeout(timeout));
+}
+
+bool Mutex::LockWhenWithDeadline(const Condition &cond, absl::Time deadline) {
+  ABSL_TSAN_MUTEX_PRE_LOCK(this, 0);
+  GraphId id = DebugOnlyDeadlockCheck(this);
+  bool res = LockSlowWithDeadline(kExclusive, &cond,
+                                  KernelTimeout(deadline), 0);
+  DebugOnlyLockEnter(this, id);
+  ABSL_TSAN_MUTEX_POST_LOCK(this, 0, 0);
+  return res;
+}
+
+void Mutex::ReaderLockWhen(const Condition &cond) {
+  ABSL_TSAN_MUTEX_PRE_LOCK(this, __tsan_mutex_read_lock);
+  GraphId id = DebugOnlyDeadlockCheck(this);
+  this->LockSlow(kShared, &cond, 0);
+  DebugOnlyLockEnter(this, id);
+  ABSL_TSAN_MUTEX_POST_LOCK(this, __tsan_mutex_read_lock, 0);
+}
+
+bool Mutex::ReaderLockWhenWithTimeout(const Condition &cond,
+                                      absl::Duration timeout) {
+  return ReaderLockWhenWithDeadline(cond, DeadlineFromTimeout(timeout));
+}
+
+bool Mutex::ReaderLockWhenWithDeadline(const Condition &cond,
+                                       absl::Time deadline) {
+  ABSL_TSAN_MUTEX_PRE_LOCK(this, __tsan_mutex_read_lock);
+  GraphId id = DebugOnlyDeadlockCheck(this);
+  bool res = LockSlowWithDeadline(kShared, &cond, KernelTimeout(deadline), 0);
+  DebugOnlyLockEnter(this, id);
+  ABSL_TSAN_MUTEX_POST_LOCK(this, __tsan_mutex_read_lock, 0);
+  return res;
+}
+
+void Mutex::Await(const Condition &cond) {
+  if (cond.Eval()) {    // condition already true; nothing to do
+    if (kDebugMode) {
+      this->AssertReaderHeld();
+    }
+  } else {              // normal case
+    ABSL_RAW_CHECK(this->AwaitCommon(cond, KernelTimeout::Never()),
+                   "condition untrue on return from Await");
+  }
+}
+
+bool Mutex::AwaitWithTimeout(const Condition &cond, absl::Duration timeout) {
+  return AwaitWithDeadline(cond, DeadlineFromTimeout(timeout));
+}
+
+bool Mutex::AwaitWithDeadline(const Condition &cond, absl::Time deadline) {
+  if (cond.Eval()) {      // condition already true; nothing to do
+    if (kDebugMode) {
+      this->AssertReaderHeld();
+    }
+    return true;
+  }
+
+  KernelTimeout t{deadline};
+  bool res = this->AwaitCommon(cond, t);
+  ABSL_RAW_CHECK(res || t.has_timeout(),
+                 "condition untrue on return from Await");
+  return res;
+}
+
+bool Mutex::AwaitCommon(const Condition &cond, KernelTimeout t) {
+  this->AssertReaderHeld();
+  MuHow how =
+      (mu_.load(std::memory_order_relaxed) & kMuWriter) ? kExclusive : kShared;
+  ABSL_TSAN_MUTEX_PRE_UNLOCK(this, TsanFlags(how));
+  SynchWaitParams waitp(
+      how, &cond, t, nullptr /*no cvmu*/, Synch_GetPerThreadAnnotated(this),
+      nullptr /*no cv_word*/);
+  int flags = kMuHasBlocked;
+  if (!Condition::GuaranteedEqual(&cond, nullptr)) {
+    flags |= kMuIsCond;
+  }
+  this->UnlockSlow(&waitp);
+  this->Block(waitp.thread);
+  ABSL_TSAN_MUTEX_POST_UNLOCK(this, TsanFlags(how));
+  ABSL_TSAN_MUTEX_PRE_LOCK(this, TsanFlags(how));
+  this->LockSlowLoop(&waitp, flags);
+  bool res = waitp.cond != nullptr ||  // => cond known true from LockSlowLoop
+             EvalConditionAnnotated(&cond, this, true, false, how == kShared);
+  ABSL_TSAN_MUTEX_POST_LOCK(this, TsanFlags(how), 0);
+  return res;
+}
+
+ABSL_XRAY_LOG_ARGS(1) bool Mutex::TryLock() {
+  ABSL_TSAN_MUTEX_PRE_LOCK(this, __tsan_mutex_try_lock);
+  intptr_t v = mu_.load(std::memory_order_relaxed);
+  if ((v & (kMuWriter | kMuReader | kMuEvent)) == 0 &&  // try fast acquire
+      mu_.compare_exchange_strong(v, kMuWriter | v,
+                                  std::memory_order_acquire,
+                                  std::memory_order_relaxed)) {
+    DebugOnlyLockEnter(this);
+    ABSL_TSAN_MUTEX_POST_LOCK(this, __tsan_mutex_try_lock, 0);
+    return true;
+  }
+  if ((v & kMuEvent) != 0) {              // we're recording events
+    if ((v & kExclusive->slow_need_zero) == 0 &&  // try fast acquire
+        mu_.compare_exchange_strong(
+            v, (kExclusive->fast_or | v) + kExclusive->fast_add,
+            std::memory_order_acquire, std::memory_order_relaxed)) {
+      DebugOnlyLockEnter(this);
+      PostSynchEvent(this, SYNCH_EV_TRYLOCK_SUCCESS);
+      ABSL_TSAN_MUTEX_POST_LOCK(this, __tsan_mutex_try_lock, 0);
+      return true;
+    } else {
+      PostSynchEvent(this, SYNCH_EV_TRYLOCK_FAILED);
+    }
+  }
+  ABSL_TSAN_MUTEX_POST_LOCK(
+      this, __tsan_mutex_try_lock | __tsan_mutex_try_lock_failed, 0);
+  return false;
+}
+
+ABSL_XRAY_LOG_ARGS(1) bool Mutex::ReaderTryLock() {
+  ABSL_TSAN_MUTEX_PRE_LOCK(this,
+                           __tsan_mutex_read_lock | __tsan_mutex_try_lock);
+  intptr_t v = mu_.load(std::memory_order_relaxed);
+  // The while-loops (here and below) iterate only if the mutex word keeps
+  // changing (typically because the reader count changes) under the CAS.  We
+  // limit the number of attempts to avoid having to think about livelock.
+  int loop_limit = 5;
+  while ((v & (kMuWriter|kMuWait|kMuEvent)) == 0 && loop_limit != 0) {
+    if (mu_.compare_exchange_strong(v, (kMuReader | v) + kMuOne,
+                                    std::memory_order_acquire,
+                                    std::memory_order_relaxed)) {
+      DebugOnlyLockEnter(this);
+      ABSL_TSAN_MUTEX_POST_LOCK(
+          this, __tsan_mutex_read_lock | __tsan_mutex_try_lock, 0);
+      return true;
+    }
+    loop_limit--;
+    v = mu_.load(std::memory_order_relaxed);
+  }
+  if ((v & kMuEvent) != 0) {   // we're recording events
+    loop_limit = 5;
+    while ((v & kShared->slow_need_zero) == 0 && loop_limit != 0) {
+      if (mu_.compare_exchange_strong(v, (kMuReader | v) + kMuOne,
+                                      std::memory_order_acquire,
+                                      std::memory_order_relaxed)) {
+        DebugOnlyLockEnter(this);
+        PostSynchEvent(this, SYNCH_EV_READERTRYLOCK_SUCCESS);
+        ABSL_TSAN_MUTEX_POST_LOCK(
+            this, __tsan_mutex_read_lock | __tsan_mutex_try_lock, 0);
+        return true;
+      }
+      loop_limit--;
+      v = mu_.load(std::memory_order_relaxed);
+    }
+    if ((v & kMuEvent) != 0) {
+      PostSynchEvent(this, SYNCH_EV_READERTRYLOCK_FAILED);
+    }
+  }
+  ABSL_TSAN_MUTEX_POST_LOCK(this,
+                            __tsan_mutex_read_lock | __tsan_mutex_try_lock |
+                                __tsan_mutex_try_lock_failed,
+                            0);
+  return false;
+}
+
+ABSL_XRAY_LOG_ARGS(1) void Mutex::Unlock() {
+  ABSL_TSAN_MUTEX_PRE_UNLOCK(this, 0);
+  DebugOnlyLockLeave(this);
+  intptr_t v = mu_.load(std::memory_order_relaxed);
+
+  if (kDebugMode && ((v & (kMuWriter | kMuReader)) != kMuWriter)) {
+    ABSL_RAW_LOG(FATAL, "Mutex unlocked when destroyed or not locked: v=0x%x",
+                 static_cast<unsigned>(v));
+  }
+
+  // should_try_cas is whether we'll try a compare-and-swap immediately.
+  // NOTE: optimized out when kDebugMode is false.
+  bool should_try_cas = ((v & (kMuEvent | kMuWriter)) == kMuWriter &&
+                          (v & (kMuWait | kMuDesig)) != kMuWait);
+  // But, we can use an alternate computation of it, that compilers
+  // currently don't find on their own.  When that changes, this function
+  // can be simplified.
+  intptr_t x = (v ^ (kMuWriter | kMuWait)) & (kMuWriter | kMuEvent);
+  intptr_t y = (v ^ (kMuWriter | kMuWait)) & (kMuWait | kMuDesig);
+  // Claim: "x == 0 && y > 0" is equal to should_try_cas.
+  // Also, because kMuWriter and kMuEvent exceed kMuDesig and kMuWait,
+  // all possible non-zero values for x exceed all possible values for y.
+  // Therefore, (x == 0 && y > 0) == (x < y).
+  if (kDebugMode && should_try_cas != (x < y)) {
+    // We would usually use PRIdPTR here, but is not correctly implemented
+    // within the android toolchain.
+    ABSL_RAW_LOG(FATAL, "internal logic error %llx %llx %llx\n",
+                 static_cast<long long>(v), static_cast<long long>(x),
+                 static_cast<long long>(y));
+  }
+  if (x < y &&
+      mu_.compare_exchange_strong(v, v & ~(kMuWrWait | kMuWriter),
+                                  std::memory_order_release,
+                                  std::memory_order_relaxed)) {
+    // fast writer release (writer with no waiters or with designated waker)
+  } else {
+    this->UnlockSlow(nullptr /*no waitp*/);  // take slow path
+  }
+  ABSL_TSAN_MUTEX_POST_UNLOCK(this, 0);
+}
+
+// Requires v to represent a reader-locked state.
+static bool ExactlyOneReader(intptr_t v) {
+  assert((v & (kMuWriter|kMuReader)) == kMuReader);
+  assert((v & kMuHigh) != 0);
+  // The more straightforward "(v & kMuHigh) == kMuOne" also works, but
+  // on some architectures the following generates slightly smaller code.
+  // It may be faster too.
+  constexpr intptr_t kMuMultipleWaitersMask = kMuHigh ^ kMuOne;
+  return (v & kMuMultipleWaitersMask) == 0;
+}
+
+ABSL_XRAY_LOG_ARGS(1) void Mutex::ReaderUnlock() {
+  ABSL_TSAN_MUTEX_PRE_UNLOCK(this, __tsan_mutex_read_lock);
+  DebugOnlyLockLeave(this);
+  intptr_t v = mu_.load(std::memory_order_relaxed);
+  assert((v & (kMuWriter|kMuReader)) == kMuReader);
+  if ((v & (kMuReader|kMuWait|kMuEvent)) == kMuReader) {
+    // fast reader release (reader with no waiters)
+    intptr_t clear = ExactlyOneReader(v) ? kMuReader|kMuOne : kMuOne;
+    if (mu_.compare_exchange_strong(v, v - clear,
+                                    std::memory_order_release,
+                                    std::memory_order_relaxed)) {
+      ABSL_TSAN_MUTEX_POST_UNLOCK(this, __tsan_mutex_read_lock);
+      return;
+    }
+  }
+  this->UnlockSlow(nullptr /*no waitp*/);  // take slow path
+  ABSL_TSAN_MUTEX_POST_UNLOCK(this, __tsan_mutex_read_lock);
+}
+
+// The zap_desig_waker bitmask is used to clear the designated waker flag in
+// the mutex if this thread has blocked, and therefore may be the designated
+// waker.
+static const intptr_t zap_desig_waker[] = {
+    ~static_cast<intptr_t>(0),  // not blocked
+    ~static_cast<intptr_t>(
+        kMuDesig)  // blocked; turn off the designated waker bit
+};
+
+// The ignore_waiting_writers bitmask is used to ignore the existence
+// of waiting writers if a reader that has already blocked once
+// wakes up.
+static const intptr_t ignore_waiting_writers[] = {
+    ~static_cast<intptr_t>(0),  // not blocked
+    ~static_cast<intptr_t>(
+        kMuWrWait)  // blocked; pretend there are no waiting writers
+};
+
+// Internal version of LockWhen().  See LockSlowWithDeadline()
+ABSL_ATTRIBUTE_NOINLINE void Mutex::LockSlow(MuHow how, const Condition *cond,
+                                             int flags) {
+  ABSL_RAW_CHECK(
+      this->LockSlowWithDeadline(how, cond, KernelTimeout::Never(), flags),
+      "condition untrue on return from LockSlow");
+}
+
+// Compute cond->Eval() and tell race detectors that we do it under mutex mu.
+static inline bool EvalConditionAnnotated(const Condition *cond, Mutex *mu,
+                                          bool locking, bool trylock,
+                                          bool read_lock) {
+  // Delicate annotation dance.
+  // We are currently inside of read/write lock/unlock operation.
+  // All memory accesses are ignored inside of mutex operations + for unlock
+  // operation tsan considers that we've already released the mutex.
+  bool res = false;
+#ifdef ABSL_INTERNAL_HAVE_TSAN_INTERFACE
+  const int flags = read_lock ? __tsan_mutex_read_lock : 0;
+  const int tryflags = flags | (trylock ? __tsan_mutex_try_lock : 0);
+#endif
+  if (locking) {
+    // For lock we pretend that we have finished the operation,
+    // evaluate the predicate, then unlock the mutex and start locking it again
+    // to match the annotation at the end of outer lock operation.
+    // Note: we can't simply do POST_LOCK, Eval, PRE_LOCK, because then tsan
+    // will think the lock acquisition is recursive which will trigger
+    // deadlock detector.
+    ABSL_TSAN_MUTEX_POST_LOCK(mu, tryflags, 0);
+    res = cond->Eval();
+    // There is no "try" version of Unlock, so use flags instead of tryflags.
+    ABSL_TSAN_MUTEX_PRE_UNLOCK(mu, flags);
+    ABSL_TSAN_MUTEX_POST_UNLOCK(mu, flags);
+    ABSL_TSAN_MUTEX_PRE_LOCK(mu, tryflags);
+  } else {
+    // Similarly, for unlock we pretend that we have unlocked the mutex,
+    // lock the mutex, evaluate the predicate, and start unlocking it again
+    // to match the annotation at the end of outer unlock operation.
+    ABSL_TSAN_MUTEX_POST_UNLOCK(mu, flags);
+    ABSL_TSAN_MUTEX_PRE_LOCK(mu, flags);
+    ABSL_TSAN_MUTEX_POST_LOCK(mu, flags, 0);
+    res = cond->Eval();
+    ABSL_TSAN_MUTEX_PRE_UNLOCK(mu, flags);
+  }
+  // Prevent unused param warnings in non-TSAN builds.
+  static_cast<void>(mu);
+  static_cast<void>(trylock);
+  static_cast<void>(read_lock);
+  return res;
+}
+
+// Compute cond->Eval() hiding it from race detectors.
+// We are hiding it because inside of UnlockSlow we can evaluate a predicate
+// that was just added by a concurrent Lock operation; Lock adds the predicate
+// to the internal Mutex list without actually acquiring the Mutex
+// (it only acquires the internal spinlock, which is rightfully invisible for
+// tsan). As the result there is no tsan-visible synchronization between the
+// addition and this thread. So if we would enable race detection here,
+// it would race with the predicate initialization.
+static inline bool EvalConditionIgnored(Mutex *mu, const Condition *cond) {
+  // Memory accesses are already ignored inside of lock/unlock operations,
+  // but synchronization operations are also ignored. When we evaluate the
+  // predicate we must ignore only memory accesses but not synchronization,
+  // because missed synchronization can lead to false reports later.
+  // So we "divert" (which un-ignores both memory accesses and synchronization)
+  // and then separately turn on ignores of memory accesses.
+  ABSL_TSAN_MUTEX_PRE_DIVERT(mu, 0);
+  ABSL_ANNOTATE_IGNORE_READS_AND_WRITES_BEGIN();
+  bool res = cond->Eval();
+  ABSL_ANNOTATE_IGNORE_READS_AND_WRITES_END();
+  ABSL_TSAN_MUTEX_POST_DIVERT(mu, 0);
+  static_cast<void>(mu);  // Prevent unused param warning in non-TSAN builds.
+  return res;
+}
+
+// Internal equivalent of *LockWhenWithDeadline(), where
+//   "t" represents the absolute timeout; !t.has_timeout() means "forever".
+//   "how" is "kShared" (for ReaderLockWhen) or "kExclusive" (for LockWhen)
+// In flags, bits are ored together:
+// - kMuHasBlocked indicates that the client has already blocked on the call so
+//   the designated waker bit must be cleared and waiting writers should not
+//   obstruct this call
+// - kMuIsCond indicates that this is a conditional acquire (condition variable,
+//   Await,  LockWhen) so contention profiling should be suppressed.
+bool Mutex::LockSlowWithDeadline(MuHow how, const Condition *cond,
+                                 KernelTimeout t, int flags) {
+  intptr_t v = mu_.load(std::memory_order_relaxed);
+  bool unlock = false;
+  if ((v & how->fast_need_zero) == 0 &&  // try fast acquire
+      mu_.compare_exchange_strong(
+          v, (how->fast_or | (v & zap_desig_waker[flags & kMuHasBlocked])) +
+                 how->fast_add,
+          std::memory_order_acquire, std::memory_order_relaxed)) {
+    if (cond == nullptr ||
+        EvalConditionAnnotated(cond, this, true, false, how == kShared)) {
+      return true;
+    }
+    unlock = true;
+  }
+  SynchWaitParams waitp(
+      how, cond, t, nullptr /*no cvmu*/, Synch_GetPerThreadAnnotated(this),
+      nullptr /*no cv_word*/);
+  if (!Condition::GuaranteedEqual(cond, nullptr)) {
+    flags |= kMuIsCond;
+  }
+  if (unlock) {
+    this->UnlockSlow(&waitp);
+    this->Block(waitp.thread);
+    flags |= kMuHasBlocked;
+  }
+  this->LockSlowLoop(&waitp, flags);
+  return waitp.cond != nullptr ||  // => cond known true from LockSlowLoop
+         cond == nullptr ||
+         EvalConditionAnnotated(cond, this, true, false, how == kShared);
+}
+
+// RAW_CHECK_FMT() takes a condition, a printf-style format string, and
+// the printf-style argument list.   The format string must be a literal.
+// Arguments after the first are not evaluated unless the condition is true.
+#define RAW_CHECK_FMT(cond, ...)                                   \
+  do {                                                             \
+    if (ABSL_PREDICT_FALSE(!(cond))) {                             \
+      ABSL_RAW_LOG(FATAL, "Check " #cond " failed: " __VA_ARGS__); \
+    }                                                              \
+  } while (0)
+
+static void CheckForMutexCorruption(intptr_t v, const char* label) {
+  // Test for either of two situations that should not occur in v:
+  //   kMuWriter and kMuReader
+  //   kMuWrWait and !kMuWait
+  const uintptr_t w = v ^ kMuWait;
+  // By flipping that bit, we can now test for:
+  //   kMuWriter and kMuReader in w
+  //   kMuWrWait and kMuWait in w
+  // We've chosen these two pairs of values to be so that they will overlap,
+  // respectively, when the word is left shifted by three.  This allows us to
+  // save a branch in the common (correct) case of them not being coincident.
+  static_assert(kMuReader << 3 == kMuWriter, "must match");
+  static_assert(kMuWait << 3 == kMuWrWait, "must match");
+  if (ABSL_PREDICT_TRUE((w & (w << 3) & (kMuWriter | kMuWrWait)) == 0)) return;
+  RAW_CHECK_FMT((v & (kMuWriter | kMuReader)) != (kMuWriter | kMuReader),
+                "%s: Mutex corrupt: both reader and writer lock held: %p",
+                label, reinterpret_cast<void *>(v));
+  RAW_CHECK_FMT((v & (kMuWait | kMuWrWait)) != kMuWrWait,
+                "%s: Mutex corrupt: waiting writer with no waiters: %p",
+                label, reinterpret_cast<void *>(v));
+  assert(false);
+}
+
+void Mutex::LockSlowLoop(SynchWaitParams *waitp, int flags) {
+  SchedulingGuard::ScopedDisable disable_rescheduling;
+  int c = 0;
+  intptr_t v = mu_.load(std::memory_order_relaxed);
+  if ((v & kMuEvent) != 0) {
+    PostSynchEvent(this,
+         waitp->how == kExclusive?  SYNCH_EV_LOCK: SYNCH_EV_READERLOCK);
+  }
+  ABSL_RAW_CHECK(
+      waitp->thread->waitp == nullptr || waitp->thread->suppress_fatal_errors,
+      "detected illegal recursion into Mutex code");
+  for (;;) {
+    v = mu_.load(std::memory_order_relaxed);
+    CheckForMutexCorruption(v, "Lock");
+    if ((v & waitp->how->slow_need_zero) == 0) {
+      if (mu_.compare_exchange_strong(
+              v, (waitp->how->fast_or |
+                  (v & zap_desig_waker[flags & kMuHasBlocked])) +
+                     waitp->how->fast_add,
+              std::memory_order_acquire, std::memory_order_relaxed)) {
+        if (waitp->cond == nullptr ||
+            EvalConditionAnnotated(waitp->cond, this, true, false,
+                                   waitp->how == kShared)) {
+          break;  // we timed out, or condition true, so return
+        }
+        this->UnlockSlow(waitp);  // got lock but condition false
+        this->Block(waitp->thread);
+        flags |= kMuHasBlocked;
+        c = 0;
+      }
+    } else {                      // need to access waiter list
+      bool dowait = false;
+      if ((v & (kMuSpin|kMuWait)) == 0) {   // no waiters
+        // This thread tries to become the one and only waiter.
+        PerThreadSynch *new_h = Enqueue(nullptr, waitp, v, flags);
+        intptr_t nv = (v & zap_desig_waker[flags & kMuHasBlocked] & kMuLow) |
+                      kMuWait;
+        ABSL_RAW_CHECK(new_h != nullptr, "Enqueue to empty list failed");
+        if (waitp->how == kExclusive && (v & kMuReader) != 0) {
+          nv |= kMuWrWait;
+        }
+        if (mu_.compare_exchange_strong(
+                v, reinterpret_cast<intptr_t>(new_h) | nv,
+                std::memory_order_release, std::memory_order_relaxed)) {
+          dowait = true;
+        } else {            // attempted Enqueue() failed
+          // zero out the waitp field set by Enqueue()
+          waitp->thread->waitp = nullptr;
+        }
+      } else if ((v & waitp->how->slow_inc_need_zero &
+                  ignore_waiting_writers[flags & kMuHasBlocked]) == 0) {
+        // This is a reader that needs to increment the reader count,
+        // but the count is currently held in the last waiter.
+        if (mu_.compare_exchange_strong(
+                v, (v & zap_desig_waker[flags & kMuHasBlocked]) | kMuSpin |
+                       kMuReader,
+                std::memory_order_acquire, std::memory_order_relaxed)) {
+          PerThreadSynch *h = GetPerThreadSynch(v);
+          h->readers += kMuOne;       // inc reader count in waiter
+          do {                        // release spinlock
+            v = mu_.load(std::memory_order_relaxed);
+          } while (!mu_.compare_exchange_weak(v, (v & ~kMuSpin) | kMuReader,
+                                              std::memory_order_release,
+                                              std::memory_order_relaxed));
+          if (waitp->cond == nullptr ||
+              EvalConditionAnnotated(waitp->cond, this, true, false,
+                                     waitp->how == kShared)) {
+            break;  // we timed out, or condition true, so return
+          }
+          this->UnlockSlow(waitp);           // got lock but condition false
+          this->Block(waitp->thread);
+          flags |= kMuHasBlocked;
+          c = 0;
+        }
+      } else if ((v & kMuSpin) == 0 &&  // attempt to queue ourselves
+                 mu_.compare_exchange_strong(
+                     v, (v & zap_desig_waker[flags & kMuHasBlocked]) | kMuSpin |
+                            kMuWait,
+                     std::memory_order_acquire, std::memory_order_relaxed)) {
+        PerThreadSynch *h = GetPerThreadSynch(v);
+        PerThreadSynch *new_h = Enqueue(h, waitp, v, flags);
+        intptr_t wr_wait = 0;
+        ABSL_RAW_CHECK(new_h != nullptr, "Enqueue to list failed");
+        if (waitp->how == kExclusive && (v & kMuReader) != 0) {
+          wr_wait = kMuWrWait;      // give priority to a waiting writer
+        }
+        do {                        // release spinlock
+          v = mu_.load(std::memory_order_relaxed);
+        } while (!mu_.compare_exchange_weak(
+            v, (v & (kMuLow & ~kMuSpin)) | kMuWait | wr_wait |
+            reinterpret_cast<intptr_t>(new_h),
+            std::memory_order_release, std::memory_order_relaxed));
+        dowait = true;
+      }
+      if (dowait) {
+        this->Block(waitp->thread);  // wait until removed from list or timeout
+        flags |= kMuHasBlocked;
+        c = 0;
+      }
+    }
+    ABSL_RAW_CHECK(
+        waitp->thread->waitp == nullptr || waitp->thread->suppress_fatal_errors,
+        "detected illegal recursion into Mutex code");
+    // delay, then try again
+    c = synchronization_internal::MutexDelay(c, GENTLE);
+  }
+  ABSL_RAW_CHECK(
+      waitp->thread->waitp == nullptr || waitp->thread->suppress_fatal_errors,
+      "detected illegal recursion into Mutex code");
+  if ((v & kMuEvent) != 0) {
+    PostSynchEvent(this,
+                   waitp->how == kExclusive? SYNCH_EV_LOCK_RETURNING :
+                                      SYNCH_EV_READERLOCK_RETURNING);
+  }
+}
+
+// Unlock this mutex, which is held by the current thread.
+// If waitp is non-zero, it must be the wait parameters for the current thread
+// which holds the lock but is not runnable because its condition is false
+// or it is in the process of blocking on a condition variable; it must requeue
+// itself on the mutex/condvar to wait for its condition to become true.
+ABSL_ATTRIBUTE_NOINLINE void Mutex::UnlockSlow(SynchWaitParams *waitp) {
+  SchedulingGuard::ScopedDisable disable_rescheduling;
+  intptr_t v = mu_.load(std::memory_order_relaxed);
+  this->AssertReaderHeld();
+  CheckForMutexCorruption(v, "Unlock");
+  if ((v & kMuEvent) != 0) {
+    PostSynchEvent(this,
+                (v & kMuWriter) != 0? SYNCH_EV_UNLOCK: SYNCH_EV_READERUNLOCK);
+  }
+  int c = 0;
+  // the waiter under consideration to wake, or zero
+  PerThreadSynch *w = nullptr;
+  // the predecessor to w or zero
+  PerThreadSynch *pw = nullptr;
+  // head of the list searched previously, or zero
+  PerThreadSynch *old_h = nullptr;
+  // a condition that's known to be false.
+  const Condition *known_false = nullptr;
+  PerThreadSynch *wake_list = kPerThreadSynchNull;   // list of threads to wake
+  intptr_t wr_wait = 0;        // set to kMuWrWait if we wake a reader and a
+                               // later writer could have acquired the lock
+                               // (starvation avoidance)
+  ABSL_RAW_CHECK(waitp == nullptr || waitp->thread->waitp == nullptr ||
+                     waitp->thread->suppress_fatal_errors,
+                 "detected illegal recursion into Mutex code");
+  // This loop finds threads wake_list to wakeup if any, and removes them from
+  // the list of waiters.  In addition, it places waitp.thread on the queue of
+  // waiters if waitp is non-zero.
+  for (;;) {
+    v = mu_.load(std::memory_order_relaxed);
+    if ((v & kMuWriter) != 0 && (v & (kMuWait | kMuDesig)) != kMuWait &&
+        waitp == nullptr) {
+      // fast writer release (writer with no waiters or with designated waker)
+      if (mu_.compare_exchange_strong(v, v & ~(kMuWrWait | kMuWriter),
+                                      std::memory_order_release,
+                                      std::memory_order_relaxed)) {
+        return;
+      }
+    } else if ((v & (kMuReader | kMuWait)) == kMuReader && waitp == nullptr) {
+      // fast reader release (reader with no waiters)
+      intptr_t clear = ExactlyOneReader(v) ? kMuReader | kMuOne : kMuOne;
+      if (mu_.compare_exchange_strong(v, v - clear,
+                                      std::memory_order_release,
+                                      std::memory_order_relaxed)) {
+        return;
+      }
+    } else if ((v & kMuSpin) == 0 &&  // attempt to get spinlock
+               mu_.compare_exchange_strong(v, v | kMuSpin,
+                                           std::memory_order_acquire,
+                                           std::memory_order_relaxed)) {
+      if ((v & kMuWait) == 0) {       // no one to wake
+        intptr_t nv;
+        bool do_enqueue = true;  // always Enqueue() the first time
+        ABSL_RAW_CHECK(waitp != nullptr,
+                       "UnlockSlow is confused");  // about to sleep
+        do {    // must loop to release spinlock as reader count may change
+          v = mu_.load(std::memory_order_relaxed);
+          // decrement reader count if there are readers
+          intptr_t new_readers = (v >= kMuOne)?  v - kMuOne : v;
+          PerThreadSynch *new_h = nullptr;
+          if (do_enqueue) {
+            // If we are enqueuing on a CondVar (waitp->cv_word != nullptr) then
+            // we must not retry here.  The initial attempt will always have
+            // succeeded, further attempts would enqueue us against *this due to
+            // Fer() handling.
+            do_enqueue = (waitp->cv_word == nullptr);
+            new_h = Enqueue(nullptr, waitp, new_readers, kMuIsCond);
+          }
+          intptr_t clear = kMuWrWait | kMuWriter;  // by default clear write bit
+          if ((v & kMuWriter) == 0 && ExactlyOneReader(v)) {  // last reader
+            clear = kMuWrWait | kMuReader;                    // clear read bit
+          }
+          nv = (v & kMuLow & ~clear & ~kMuSpin);
+          if (new_h != nullptr) {
+            nv |= kMuWait | reinterpret_cast<intptr_t>(new_h);
+          } else {  // new_h could be nullptr if we queued ourselves on a
+                    // CondVar
+            // In that case, we must place the reader count back in the mutex
+            // word, as Enqueue() did not store it in the new waiter.
+            nv |= new_readers & kMuHigh;
+          }
+          // release spinlock & our lock; retry if reader-count changed
+          // (writer count cannot change since we hold lock)
+        } while (!mu_.compare_exchange_weak(v, nv,
+                                            std::memory_order_release,
+                                            std::memory_order_relaxed));
+        break;
+      }
+
+      // There are waiters.
+      // Set h to the head of the circular waiter list.
+      PerThreadSynch *h = GetPerThreadSynch(v);
+      if ((v & kMuReader) != 0 && (h->readers & kMuHigh) > kMuOne) {
+        // a reader but not the last
+        h->readers -= kMuOne;  // release our lock
+        intptr_t nv = v;       // normally just release spinlock
+        if (waitp != nullptr) {  // but waitp!=nullptr => must queue ourselves
+          PerThreadSynch *new_h = Enqueue(h, waitp, v, kMuIsCond);
+          ABSL_RAW_CHECK(new_h != nullptr,
+                         "waiters disappeared during Enqueue()!");
+          nv &= kMuLow;
+          nv |= kMuWait | reinterpret_cast<intptr_t>(new_h);
+        }
+        mu_.store(nv, std::memory_order_release);  // release spinlock
+        // can release with a store because there were waiters
+        break;
+      }
+
+      // Either we didn't search before, or we marked the queue
+      // as "maybe_unlocking" and no one else should have changed it.
+      ABSL_RAW_CHECK(old_h == nullptr || h->maybe_unlocking,
+                     "Mutex queue changed beneath us");
+
+      // The lock is becoming free, and there's a waiter
+      if (old_h != nullptr &&
+          !old_h->may_skip) {                  // we used old_h as a terminator
+        old_h->may_skip = true;                // allow old_h to skip once more
+        ABSL_RAW_CHECK(old_h->skip == nullptr, "illegal skip from head");
+        if (h != old_h && MuEquivalentWaiter(old_h, old_h->next)) {
+          old_h->skip = old_h->next;  // old_h not head & can skip to successor
+        }
+      }
+      if (h->next->waitp->how == kExclusive &&
+          Condition::GuaranteedEqual(h->next->waitp->cond, nullptr)) {
+        // easy case: writer with no condition; no need to search
+        pw = h;                       // wake w, the successor of h (=pw)
+        w = h->next;
+        w->wake = true;
+        // We are waking up a writer.  This writer may be racing against
+        // an already awake reader for the lock.  We want the
+        // writer to usually win this race,
+        // because if it doesn't, we can potentially keep taking a reader
+        // perpetually and writers will starve.  Worse than
+        // that, this can also starve other readers if kMuWrWait gets set
+        // later.
+        wr_wait = kMuWrWait;
+      } else if (w != nullptr && (w->waitp->how == kExclusive || h == old_h)) {
+        // we found a waiter w to wake on a previous iteration and either it's
+        // a writer, or we've searched the entire list so we have all the
+        // readers.
+        if (pw == nullptr) {  // if w's predecessor is unknown, it must be h
+          pw = h;
+        }
+      } else {
+        // At this point we don't know all the waiters to wake, and the first
+        // waiter has a condition or is a reader.  We avoid searching over
+        // waiters we've searched on previous iterations by starting at
+        // old_h if it's set.  If old_h==h, there's no one to wakeup at all.
+        if (old_h == h) {      // we've searched before, and nothing's new
+                               // so there's no one to wake.
+          intptr_t nv = (v & ~(kMuReader|kMuWriter|kMuWrWait));
+          h->readers = 0;
+          h->maybe_unlocking = false;   // finished unlocking
+          if (waitp != nullptr) {       // we must queue ourselves and sleep
+            PerThreadSynch *new_h = Enqueue(h, waitp, v, kMuIsCond);
+            nv &= kMuLow;
+            if (new_h != nullptr) {
+              nv |= kMuWait | reinterpret_cast<intptr_t>(new_h);
+            }  // else new_h could be nullptr if we queued ourselves on a
+               // CondVar
+          }
+          // release spinlock & lock
+          // can release with a store because there were waiters
+          mu_.store(nv, std::memory_order_release);
+          break;
+        }
+
+        // set up to walk the list
+        PerThreadSynch *w_walk;   // current waiter during list walk
+        PerThreadSynch *pw_walk;  // previous waiter during list walk
+        if (old_h != nullptr) {  // we've searched up to old_h before
+          pw_walk = old_h;
+          w_walk = old_h->next;
+        } else {            // no prior search, start at beginning
+          pw_walk =
+              nullptr;  // h->next's predecessor may change; don't record it
+          w_walk = h->next;
+        }
+
+        h->may_skip = false;  // ensure we never skip past h in future searches
+                              // even if other waiters are queued after it.
+        ABSL_RAW_CHECK(h->skip == nullptr, "illegal skip from head");
+
+        h->maybe_unlocking = true;  // we're about to scan the waiter list
+                                    // without the spinlock held.
+                                    // Enqueue must be conservative about
+                                    // priority queuing.
+
+        // We must release the spinlock to evaluate the conditions.
+        mu_.store(v, std::memory_order_release);  // release just spinlock
+        // can release with a store because there were waiters
+
+        // h is the last waiter queued, and w_walk the first unsearched waiter.
+        // Without the spinlock, the locations mu_ and h->next may now change
+        // underneath us, but since we hold the lock itself, the only legal
+        // change is to add waiters between h and w_walk.  Therefore, it's safe
+        // to walk the path from w_walk to h inclusive. (TryRemove() can remove
+        // a waiter anywhere, but it acquires both the spinlock and the Mutex)
+
+        old_h = h;        // remember we searched to here
+
+        // Walk the path upto and including h looking for waiters we can wake.
+        while (pw_walk != h) {
+          w_walk->wake = false;
+          if (w_walk->waitp->cond ==
+                  nullptr ||  // no condition => vacuously true OR
+              (w_walk->waitp->cond != known_false &&
+               // this thread's condition is not known false, AND
+               //  is in fact true
+               EvalConditionIgnored(this, w_walk->waitp->cond))) {
+            if (w == nullptr) {
+              w_walk->wake = true;    // can wake this waiter
+              w = w_walk;
+              pw = pw_walk;
+              if (w_walk->waitp->how == kExclusive) {
+                wr_wait = kMuWrWait;
+                break;                // bail if waking this writer
+              }
+            } else if (w_walk->waitp->how == kShared) {  // wake if a reader
+              w_walk->wake = true;
+            } else {   // writer with true condition
+              wr_wait = kMuWrWait;
+            }
+          } else {                  // can't wake; condition false
+            known_false = w_walk->waitp->cond;  // remember last false condition
+          }
+          if (w_walk->wake) {   // we're waking reader w_walk
+            pw_walk = w_walk;   // don't skip similar waiters
+          } else {              // not waking; skip as much as possible
+            pw_walk = Skip(w_walk);
+          }
+          // If pw_walk == h, then load of pw_walk->next can race with
+          // concurrent write in Enqueue(). However, at the same time
+          // we do not need to do the load, because we will bail out
+          // from the loop anyway.
+          if (pw_walk != h) {
+            w_walk = pw_walk->next;
+          }
+        }
+
+        continue;  // restart for(;;)-loop to wakeup w or to find more waiters
+      }
+      ABSL_RAW_CHECK(pw->next == w, "pw not w's predecessor");
+      // The first (and perhaps only) waiter we've chosen to wake is w, whose
+      // predecessor is pw.  If w is a reader, we must wake all the other
+      // waiters with wake==true as well.  We may also need to queue
+      // ourselves if waitp != null.  The spinlock and the lock are still
+      // held.
+
+      // This traverses the list in [ pw->next, h ], where h is the head,
+      // removing all elements with wake==true and placing them in the
+      // singly-linked list wake_list.  Returns the new head.
+      h = DequeueAllWakeable(h, pw, &wake_list);
+
+      intptr_t nv = (v & kMuEvent) | kMuDesig;
+                                             // assume no waiters left,
+                                             // set kMuDesig for INV1a
+
+      if (waitp != nullptr) {  // we must queue ourselves and sleep
+        h = Enqueue(h, waitp, v, kMuIsCond);
+        // h is new last waiter; could be null if we queued ourselves on a
+        // CondVar
+      }
+
+      ABSL_RAW_CHECK(wake_list != kPerThreadSynchNull,
+                     "unexpected empty wake list");
+
+      if (h != nullptr) {  // there are waiters left
+        h->readers = 0;
+        h->maybe_unlocking = false;     // finished unlocking
+        nv |= wr_wait | kMuWait | reinterpret_cast<intptr_t>(h);
+      }
+
+      // release both spinlock & lock
+      // can release with a store because there were waiters
+      mu_.store(nv, std::memory_order_release);
+      break;  // out of for(;;)-loop
+    }
+    // aggressive here; no one can proceed till we do
+    c = synchronization_internal::MutexDelay(c, AGGRESSIVE);
+  }                            // end of for(;;)-loop
+
+  if (wake_list != kPerThreadSynchNull) {
+    int64_t enqueue_timestamp = wake_list->waitp->contention_start_cycles;
+    bool cond_waiter = wake_list->cond_waiter;
+    do {
+      wake_list = Wakeup(wake_list);              // wake waiters
+    } while (wake_list != kPerThreadSynchNull);
+    if (!cond_waiter) {
+      // Sample lock contention events only if the (first) waiter was trying to
+      // acquire the lock, not waiting on a condition variable or Condition.
+      int64_t wait_cycles =
+          base_internal::CycleClock::Now() - enqueue_timestamp;
+      mutex_tracer("slow release", this, wait_cycles);
+      ABSL_TSAN_MUTEX_PRE_DIVERT(this, 0);
+      submit_profile_data(enqueue_timestamp);
+      ABSL_TSAN_MUTEX_POST_DIVERT(this, 0);
+    }
+  }
+}
+
+// Used by CondVar implementation to reacquire mutex after waking from
+// condition variable.  This routine is used instead of Lock() because the
+// waiting thread may have been moved from the condition variable queue to the
+// mutex queue without a wakeup, by Trans().  In that case, when the thread is
+// finally woken, the woken thread will believe it has been woken from the
+// condition variable (i.e. its PC will be in when in the CondVar code), when
+// in fact it has just been woken from the mutex.  Thus, it must enter the slow
+// path of the mutex in the same state as if it had just woken from the mutex.
+// That is, it must ensure to clear kMuDesig (INV1b).
+void Mutex::Trans(MuHow how) {
+  this->LockSlow(how, nullptr, kMuHasBlocked | kMuIsCond);
+}
+
+// Used by CondVar implementation to effectively wake thread w from the
+// condition variable.  If this mutex is free, we simply wake the thread.
+// It will later acquire the mutex with high probability.  Otherwise, we
+// enqueue thread w on this mutex.
+void Mutex::Fer(PerThreadSynch *w) {
+  SchedulingGuard::ScopedDisable disable_rescheduling;
+  int c = 0;
+  ABSL_RAW_CHECK(w->waitp->cond == nullptr,
+                 "Mutex::Fer while waiting on Condition");
+  ABSL_RAW_CHECK(!w->waitp->timeout.has_timeout(),
+                 "Mutex::Fer while in timed wait");
+  ABSL_RAW_CHECK(w->waitp->cv_word == nullptr,
+                 "Mutex::Fer with pending CondVar queueing");
+  for (;;) {
+    intptr_t v = mu_.load(std::memory_order_relaxed);
+    // Note: must not queue if the mutex is unlocked (nobody will wake it).
+    // For example, we can have only kMuWait (conditional) or maybe
+    // kMuWait|kMuWrWait.
+    // conflicting != 0 implies that the waking thread cannot currently take
+    // the mutex, which in turn implies that someone else has it and can wake
+    // us if we queue.
+    const intptr_t conflicting =
+        kMuWriter | (w->waitp->how == kShared ? 0 : kMuReader);
+    if ((v & conflicting) == 0) {
+      w->next = nullptr;
+      w->state.store(PerThreadSynch::kAvailable, std::memory_order_release);
+      IncrementSynchSem(this, w);
+      return;
+    } else {
+      if ((v & (kMuSpin|kMuWait)) == 0) {       // no waiters
+        // This thread tries to become the one and only waiter.
+        PerThreadSynch *new_h = Enqueue(nullptr, w->waitp, v, kMuIsCond);
+        ABSL_RAW_CHECK(new_h != nullptr,
+                       "Enqueue failed");  // we must queue ourselves
+        if (mu_.compare_exchange_strong(
+                v, reinterpret_cast<intptr_t>(new_h) | (v & kMuLow) | kMuWait,
+                std::memory_order_release, std::memory_order_relaxed)) {
+          return;
+        }
+      } else if ((v & kMuSpin) == 0 &&
+                 mu_.compare_exchange_strong(v, v | kMuSpin | kMuWait)) {
+        PerThreadSynch *h = GetPerThreadSynch(v);
+        PerThreadSynch *new_h = Enqueue(h, w->waitp, v, kMuIsCond);
+        ABSL_RAW_CHECK(new_h != nullptr,
+                       "Enqueue failed");  // we must queue ourselves
+        do {
+          v = mu_.load(std::memory_order_relaxed);
+        } while (!mu_.compare_exchange_weak(
+            v,
+            (v & kMuLow & ~kMuSpin) | kMuWait |
+                reinterpret_cast<intptr_t>(new_h),
+            std::memory_order_release, std::memory_order_relaxed));
+        return;
+      }
+    }
+    c = synchronization_internal::MutexDelay(c, GENTLE);
+  }
+}
+
+void Mutex::AssertHeld() const {
+  if ((mu_.load(std::memory_order_relaxed) & kMuWriter) == 0) {
+    SynchEvent *e = GetSynchEvent(this);
+    ABSL_RAW_LOG(FATAL, "thread should hold write lock on Mutex %p %s",
+                 static_cast<const void *>(this),
+                 (e == nullptr ? "" : e->name));
+  }
+}
+
+void Mutex::AssertReaderHeld() const {
+  if ((mu_.load(std::memory_order_relaxed) & (kMuReader | kMuWriter)) == 0) {
+    SynchEvent *e = GetSynchEvent(this);
+    ABSL_RAW_LOG(
+        FATAL, "thread should hold at least a read lock on Mutex %p %s",
+        static_cast<const void *>(this), (e == nullptr ? "" : e->name));
+  }
+}
+
+// -------------------------------- condition variables
+static const intptr_t kCvSpin = 0x0001L;   // spinlock protects waiter list
+static const intptr_t kCvEvent = 0x0002L;  // record events
+
+static const intptr_t kCvLow = 0x0003L;  // low order bits of CV
+
+// Hack to make constant values available to gdb pretty printer
+enum { kGdbCvSpin = kCvSpin, kGdbCvEvent = kCvEvent, kGdbCvLow = kCvLow, };
+
+static_assert(PerThreadSynch::kAlignment > kCvLow,
+              "PerThreadSynch::kAlignment must be greater than kCvLow");
+
+void CondVar::EnableDebugLog(const char *name) {
+  SynchEvent *e = EnsureSynchEvent(&this->cv_, name, kCvEvent, kCvSpin);
+  e->log = true;
+  UnrefSynchEvent(e);
+}
+
+CondVar::~CondVar() {
+  if ((cv_.load(std::memory_order_relaxed) & kCvEvent) != 0) {
+    ForgetSynchEvent(&this->cv_, kCvEvent, kCvSpin);
+  }
+}
+
+
+// Remove thread s from the list of waiters on this condition variable.
+void CondVar::Remove(PerThreadSynch *s) {
+  SchedulingGuard::ScopedDisable disable_rescheduling;
+  intptr_t v;
+  int c = 0;
+  for (v = cv_.load(std::memory_order_relaxed);;
+       v = cv_.load(std::memory_order_relaxed)) {
+    if ((v & kCvSpin) == 0 &&  // attempt to acquire spinlock
+        cv_.compare_exchange_strong(v, v | kCvSpin,
+                                    std::memory_order_acquire,
+                                    std::memory_order_relaxed)) {
+      PerThreadSynch *h = reinterpret_cast<PerThreadSynch *>(v & ~kCvLow);
+      if (h != nullptr) {
+        PerThreadSynch *w = h;
+        while (w->next != s && w->next != h) {  // search for thread
+          w = w->next;
+        }
+        if (w->next == s) {           // found thread; remove it
+          w->next = s->next;
+          if (h == s) {
+            h = (w == s) ? nullptr : w;
+          }
+          s->next = nullptr;
+          s->state.store(PerThreadSynch::kAvailable, std::memory_order_release);
+        }
+      }
+                                      // release spinlock
+      cv_.store((v & kCvEvent) | reinterpret_cast<intptr_t>(h),
+                std::memory_order_release);
+      return;
+    } else {
+      // try again after a delay
+      c = synchronization_internal::MutexDelay(c, GENTLE);
+    }
+  }
+}
+
+// Queue thread waitp->thread on condition variable word cv_word using
+// wait parameters waitp.
+// We split this into a separate routine, rather than simply doing it as part
+// of WaitCommon().  If we were to queue ourselves on the condition variable
+// before calling Mutex::UnlockSlow(), the Mutex code might be re-entered (via
+// the logging code, or via a Condition function) and might potentially attempt
+// to block this thread.  That would be a problem if the thread were already on
+// a the condition variable waiter queue.  Thus, we use the waitp->cv_word
+// to tell the unlock code to call CondVarEnqueue() to queue the thread on the
+// condition variable queue just before the mutex is to be unlocked, and (most
+// importantly) after any call to an external routine that might re-enter the
+// mutex code.
+static void CondVarEnqueue(SynchWaitParams *waitp) {
+  // This thread might be transferred to the Mutex queue by Fer() when
+  // we are woken.  To make sure that is what happens, Enqueue() doesn't
+  // call CondVarEnqueue() again but instead uses its normal code.  We
+  // must do this before we queue ourselves so that cv_word will be null
+  // when seen by the dequeuer, who may wish immediately to requeue
+  // this thread on another queue.
+  std::atomic<intptr_t> *cv_word = waitp->cv_word;
+  waitp->cv_word = nullptr;
+
+  intptr_t v = cv_word->load(std::memory_order_relaxed);
+  int c = 0;
+  while ((v & kCvSpin) != 0 ||  // acquire spinlock
+         !cv_word->compare_exchange_weak(v, v | kCvSpin,
+                                         std::memory_order_acquire,
+                                         std::memory_order_relaxed)) {
+    c = synchronization_internal::MutexDelay(c, GENTLE);
+    v = cv_word->load(std::memory_order_relaxed);
+  }
+  ABSL_RAW_CHECK(waitp->thread->waitp == nullptr, "waiting when shouldn't be");
+  waitp->thread->waitp = waitp;      // prepare ourselves for waiting
+  PerThreadSynch *h = reinterpret_cast<PerThreadSynch *>(v & ~kCvLow);
+  if (h == nullptr) {  // add this thread to waiter list
+    waitp->thread->next = waitp->thread;
+  } else {
+    waitp->thread->next = h->next;
+    h->next = waitp->thread;
+  }
+  waitp->thread->state.store(PerThreadSynch::kQueued,
+                             std::memory_order_relaxed);
+  cv_word->store((v & kCvEvent) | reinterpret_cast<intptr_t>(waitp->thread),
+                 std::memory_order_release);
+}
+
+bool CondVar::WaitCommon(Mutex *mutex, KernelTimeout t) {
+  bool rc = false;          // return value; true iff we timed-out
+
+  intptr_t mutex_v = mutex->mu_.load(std::memory_order_relaxed);
+  Mutex::MuHow mutex_how = ((mutex_v & kMuWriter) != 0) ? kExclusive : kShared;
+  ABSL_TSAN_MUTEX_PRE_UNLOCK(mutex, TsanFlags(mutex_how));
+
+  // maybe trace this call
+  intptr_t v = cv_.load(std::memory_order_relaxed);
+  cond_var_tracer("Wait", this);
+  if ((v & kCvEvent) != 0) {
+    PostSynchEvent(this, SYNCH_EV_WAIT);
+  }
+
+  // Release mu and wait on condition variable.
+  SynchWaitParams waitp(mutex_how, nullptr, t, mutex,
+                        Synch_GetPerThreadAnnotated(mutex), &cv_);
+  // UnlockSlow() will call CondVarEnqueue() just before releasing the
+  // Mutex, thus queuing this thread on the condition variable.  See
+  // CondVarEnqueue() for the reasons.
+  mutex->UnlockSlow(&waitp);
+
+  // wait for signal
+  while (waitp.thread->state.load(std::memory_order_acquire) ==
+         PerThreadSynch::kQueued) {
+    if (!Mutex::DecrementSynchSem(mutex, waitp.thread, t)) {
+      this->Remove(waitp.thread);
+      rc = true;
+    }
+  }
+
+  ABSL_RAW_CHECK(waitp.thread->waitp != nullptr, "not waiting when should be");
+  waitp.thread->waitp = nullptr;  // cleanup
+
+  // maybe trace this call
+  cond_var_tracer("Unwait", this);
+  if ((v & kCvEvent) != 0) {
+    PostSynchEvent(this, SYNCH_EV_WAIT_RETURNING);
+  }
+
+  // From synchronization point of view Wait is unlock of the mutex followed
+  // by lock of the mutex. We've annotated start of unlock in the beginning
+  // of the function. Now, finish unlock and annotate lock of the mutex.
+  // (Trans is effectively lock).
+  ABSL_TSAN_MUTEX_POST_UNLOCK(mutex, TsanFlags(mutex_how));
+  ABSL_TSAN_MUTEX_PRE_LOCK(mutex, TsanFlags(mutex_how));
+  mutex->Trans(mutex_how);  // Reacquire mutex
+  ABSL_TSAN_MUTEX_POST_LOCK(mutex, TsanFlags(mutex_how), 0);
+  return rc;
+}
+
+bool CondVar::WaitWithTimeout(Mutex *mu, absl::Duration timeout) {
+  return WaitWithDeadline(mu, DeadlineFromTimeout(timeout));
+}
+
+bool CondVar::WaitWithDeadline(Mutex *mu, absl::Time deadline) {
+  return WaitCommon(mu, KernelTimeout(deadline));
+}
+
+void CondVar::Wait(Mutex *mu) {
+  WaitCommon(mu, KernelTimeout::Never());
+}
+
+// Wake thread w
+// If it was a timed wait, w will be waiting on w->cv
+// Otherwise, if it was not a Mutex mutex, w will be waiting on w->sem
+// Otherwise, w is transferred to the Mutex mutex via Mutex::Fer().
+void CondVar::Wakeup(PerThreadSynch *w) {
+  if (w->waitp->timeout.has_timeout() || w->waitp->cvmu == nullptr) {
+    // The waiting thread only needs to observe "w->state == kAvailable" to be
+    // released, we must cache "cvmu" before clearing "next".
+    Mutex *mu = w->waitp->cvmu;
+    w->next = nullptr;
+    w->state.store(PerThreadSynch::kAvailable, std::memory_order_release);
+    Mutex::IncrementSynchSem(mu, w);
+  } else {
+    w->waitp->cvmu->Fer(w);
+  }
+}
+
+void CondVar::Signal() {
+  SchedulingGuard::ScopedDisable disable_rescheduling;
+  ABSL_TSAN_MUTEX_PRE_SIGNAL(nullptr, 0);
+  intptr_t v;
+  int c = 0;
+  for (v = cv_.load(std::memory_order_relaxed); v != 0;
+       v = cv_.load(std::memory_order_relaxed)) {
+    if ((v & kCvSpin) == 0 &&  // attempt to acquire spinlock
+        cv_.compare_exchange_strong(v, v | kCvSpin,
+                                    std::memory_order_acquire,
+                                    std::memory_order_relaxed)) {
+      PerThreadSynch *h = reinterpret_cast<PerThreadSynch *>(v & ~kCvLow);
+      PerThreadSynch *w = nullptr;
+      if (h != nullptr) {  // remove first waiter
+        w = h->next;
+        if (w == h) {
+          h = nullptr;
+        } else {
+          h->next = w->next;
+        }
+      }
+                                      // release spinlock
+      cv_.store((v & kCvEvent) | reinterpret_cast<intptr_t>(h),
+                std::memory_order_release);
+      if (w != nullptr) {
+        CondVar::Wakeup(w);                // wake waiter, if there was one
+        cond_var_tracer("Signal wakeup", this);
+      }
+      if ((v & kCvEvent) != 0) {
+        PostSynchEvent(this, SYNCH_EV_SIGNAL);
+      }
+      ABSL_TSAN_MUTEX_POST_SIGNAL(nullptr, 0);
+      return;
+    } else {
+      c = synchronization_internal::MutexDelay(c, GENTLE);
+    }
+  }
+  ABSL_TSAN_MUTEX_POST_SIGNAL(nullptr, 0);
+}
+
+void CondVar::SignalAll () {
+  ABSL_TSAN_MUTEX_PRE_SIGNAL(nullptr, 0);
+  intptr_t v;
+  int c = 0;
+  for (v = cv_.load(std::memory_order_relaxed); v != 0;
+       v = cv_.load(std::memory_order_relaxed)) {
+    // empty the list if spinlock free
+    // We do this by simply setting the list to empty using
+    // compare and swap.   We then have the entire list in our hands,
+    // which cannot be changing since we grabbed it while no one
+    // held the lock.
+    if ((v & kCvSpin) == 0 &&
+        cv_.compare_exchange_strong(v, v & kCvEvent, std::memory_order_acquire,
+                                    std::memory_order_relaxed)) {
+      PerThreadSynch *h = reinterpret_cast<PerThreadSynch *>(v & ~kCvLow);
+      if (h != nullptr) {
+        PerThreadSynch *w;
+        PerThreadSynch *n = h->next;
+        do {                          // for every thread, wake it up
+          w = n;
+          n = n->next;
+          CondVar::Wakeup(w);
+        } while (w != h);
+        cond_var_tracer("SignalAll wakeup", this);
+      }
+      if ((v & kCvEvent) != 0) {
+        PostSynchEvent(this, SYNCH_EV_SIGNALALL);
+      }
+      ABSL_TSAN_MUTEX_POST_SIGNAL(nullptr, 0);
+      return;
+    } else {
+      // try again after a delay
+      c = synchronization_internal::MutexDelay(c, GENTLE);
+    }
+  }
+  ABSL_TSAN_MUTEX_POST_SIGNAL(nullptr, 0);
+}
+
+void ReleasableMutexLock::Release() {
+  ABSL_RAW_CHECK(this->mu_ != nullptr,
+                 "ReleasableMutexLock::Release may only be called once");
+  this->mu_->Unlock();
+  this->mu_ = nullptr;
+}
+
+#ifdef ABSL_HAVE_THREAD_SANITIZER
+extern "C" void __tsan_read1(void *addr);
+#else
+#define __tsan_read1(addr)  // do nothing if TSan not enabled
+#endif
+
+// A function that just returns its argument, dereferenced
+static bool Dereference(void *arg) {
+  // ThreadSanitizer does not instrument this file for memory accesses.
+  // This function dereferences a user variable that can participate
+  // in a data race, so we need to manually tell TSan about this memory access.
+  __tsan_read1(arg);
+  return *(static_cast<bool *>(arg));
+}
+
+Condition::Condition() {}   // null constructor, used for kTrue only
+const Condition Condition::kTrue;
+
+Condition::Condition(bool (*func)(void *), void *arg)
+    : eval_(&CallVoidPtrFunction),
+      function_(func),
+      method_(nullptr),
+      arg_(arg) {}
+
+bool Condition::CallVoidPtrFunction(const Condition *c) {
+  return (*c->function_)(c->arg_);
+}
+
+Condition::Condition(const bool *cond)
+    : eval_(CallVoidPtrFunction),
+      function_(Dereference),
+      method_(nullptr),
+      // const_cast is safe since Dereference does not modify arg
+      arg_(const_cast<bool *>(cond)) {}
+
+bool Condition::Eval() const {
+  // eval_ == null for kTrue
+  return (this->eval_ == nullptr) || (*this->eval_)(this);
+}
+
+bool Condition::GuaranteedEqual(const Condition *a, const Condition *b) {
+  if (a == nullptr) {
+    return b == nullptr || b->eval_ == nullptr;
+  }
+  if (b == nullptr || b->eval_ == nullptr) {
+    return a->eval_ == nullptr;
+  }
+  return a->eval_ == b->eval_ && a->function_ == b->function_ &&
+         a->arg_ == b->arg_ && a->method_ == b->method_;
+}
+
+ABSL_NAMESPACE_END
+}  // namespace absl
diff --git a/src/absl/synchronization/mutex.h b/src/absl/synchronization/mutex.h
new file mode 100644 (file)
index 0000000..f49e0c8
--- /dev/null
@@ -0,0 +1,1082 @@
+// Copyright 2017 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// -----------------------------------------------------------------------------
+// mutex.h
+// -----------------------------------------------------------------------------
+//
+// This header file defines a `Mutex` -- a mutually exclusive lock -- and the
+// most common type of synchronization primitive for facilitating locks on
+// shared resources. A mutex is used to prevent multiple threads from accessing
+// and/or writing to a shared resource concurrently.
+//
+// Unlike a `std::mutex`, the Abseil `Mutex` provides the following additional
+// features:
+//   * Conditional predicates intrinsic to the `Mutex` object
+//   * Shared/reader locks, in addition to standard exclusive/writer locks
+//   * Deadlock detection and debug support.
+//
+// The following helper classes are also defined within this file:
+//
+//  MutexLock - An RAII wrapper to acquire and release a `Mutex` for exclusive/
+//              write access within the current scope.
+//
+//  ReaderMutexLock
+//            - An RAII wrapper to acquire and release a `Mutex` for shared/read
+//              access within the current scope.
+//
+//  WriterMutexLock
+//            - Effectively an alias for `MutexLock` above, designed for use in
+//              distinguishing reader and writer locks within code.
+//
+// In addition to simple mutex locks, this file also defines ways to perform
+// locking under certain conditions.
+//
+//  Condition - (Preferred) Used to wait for a particular predicate that
+//              depends on state protected by the `Mutex` to become true.
+//  CondVar   - A lower-level variant of `Condition` that relies on
+//              application code to explicitly signal the `CondVar` when
+//              a condition has been met.
+//
+// See below for more information on using `Condition` or `CondVar`.
+//
+// Mutexes and mutex behavior can be quite complicated. The information within
+// this header file is limited, as a result. Please consult the Mutex guide for
+// more complete information and examples.
+
+#ifndef ABSL_SYNCHRONIZATION_MUTEX_H_
+#define ABSL_SYNCHRONIZATION_MUTEX_H_
+
+#include <atomic>
+#include <cstdint>
+#include <string>
+
+#include "absl/base/const_init.h"
+#include "absl/base/internal/identity.h"
+#include "absl/base/internal/low_level_alloc.h"
+#include "absl/base/internal/thread_identity.h"
+#include "absl/base/internal/tsan_mutex_interface.h"
+#include "absl/base/port.h"
+#include "absl/base/thread_annotations.h"
+#include "absl/synchronization/internal/kernel_timeout.h"
+#include "absl/synchronization/internal/per_thread_sem.h"
+#include "absl/time/time.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+
+class Condition;
+struct SynchWaitParams;
+
+// -----------------------------------------------------------------------------
+// Mutex
+// -----------------------------------------------------------------------------
+//
+// A `Mutex` is a non-reentrant (aka non-recursive) Mutually Exclusive lock
+// on some resource, typically a variable or data structure with associated
+// invariants. Proper usage of mutexes prevents concurrent access by different
+// threads to the same resource.
+//
+// A `Mutex` has two basic operations: `Mutex::Lock()` and `Mutex::Unlock()`.
+// The `Lock()` operation *acquires* a `Mutex` (in a state known as an
+// *exclusive* -- or write -- lock), while the `Unlock()` operation *releases* a
+// Mutex. During the span of time between the Lock() and Unlock() operations,
+// a mutex is said to be *held*. By design all mutexes support exclusive/write
+// locks, as this is the most common way to use a mutex.
+//
+// The `Mutex` state machine for basic lock/unlock operations is quite simple:
+//
+// |                | Lock()     | Unlock() |
+// |----------------+------------+----------|
+// | Free           | Exclusive  | invalid  |
+// | Exclusive      | blocks     | Free     |
+//
+// Attempts to `Unlock()` must originate from the thread that performed the
+// corresponding `Lock()` operation.
+//
+// An "invalid" operation is disallowed by the API. The `Mutex` implementation
+// is allowed to do anything on an invalid call, including but not limited to
+// crashing with a useful error message, silently succeeding, or corrupting
+// data structures. In debug mode, the implementation attempts to crash with a
+// useful error message.
+//
+// `Mutex` is not guaranteed to be "fair" in prioritizing waiting threads; it
+// is, however, approximately fair over long periods, and starvation-free for
+// threads at the same priority.
+//
+// The lock/unlock primitives are now annotated with lock annotations
+// defined in (base/thread_annotations.h). When writing multi-threaded code,
+// you should use lock annotations whenever possible to document your lock
+// synchronization policy. Besides acting as documentation, these annotations
+// also help compilers or static analysis tools to identify and warn about
+// issues that could potentially result in race conditions and deadlocks.
+//
+// For more information about the lock annotations, please see
+// [Thread Safety Analysis](http://clang.llvm.org/docs/ThreadSafetyAnalysis.html)
+// in the Clang documentation.
+//
+// See also `MutexLock`, below, for scoped `Mutex` acquisition.
+
+class ABSL_LOCKABLE Mutex {
+ public:
+  // Creates a `Mutex` that is not held by anyone. This constructor is
+  // typically used for Mutexes allocated on the heap or the stack.
+  //
+  // To create `Mutex` instances with static storage duration
+  // (e.g. a namespace-scoped or global variable), see
+  // `Mutex::Mutex(absl::kConstInit)` below instead.
+  Mutex();
+
+  // Creates a mutex with static storage duration.  A global variable
+  // constructed this way avoids the lifetime issues that can occur on program
+  // startup and shutdown.  (See absl/base/const_init.h.)
+  //
+  // For Mutexes allocated on the heap and stack, instead use the default
+  // constructor, which can interact more fully with the thread sanitizer.
+  //
+  // Example usage:
+  //   namespace foo {
+  //   ABSL_CONST_INIT absl::Mutex mu(absl::kConstInit);
+  //   }
+  explicit constexpr Mutex(absl::ConstInitType);
+
+  ~Mutex();
+
+  // Mutex::Lock()
+  //
+  // Blocks the calling thread, if necessary, until this `Mutex` is free, and
+  // then acquires it exclusively. (This lock is also known as a "write lock.")
+  void Lock() ABSL_EXCLUSIVE_LOCK_FUNCTION();
+
+  // Mutex::Unlock()
+  //
+  // Releases this `Mutex` and returns it from the exclusive/write state to the
+  // free state. Calling thread must hold the `Mutex` exclusively.
+  void Unlock() ABSL_UNLOCK_FUNCTION();
+
+  // Mutex::TryLock()
+  //
+  // If the mutex can be acquired without blocking, does so exclusively and
+  // returns `true`. Otherwise, returns `false`. Returns `true` with high
+  // probability if the `Mutex` was free.
+  bool TryLock() ABSL_EXCLUSIVE_TRYLOCK_FUNCTION(true);
+
+  // Mutex::AssertHeld()
+  //
+  // Return immediately if this thread holds the `Mutex` exclusively (in write
+  // mode). Otherwise, may report an error (typically by crashing with a
+  // diagnostic), or may return immediately.
+  void AssertHeld() const ABSL_ASSERT_EXCLUSIVE_LOCK();
+
+  // ---------------------------------------------------------------------------
+  // Reader-Writer Locking
+  // ---------------------------------------------------------------------------
+
+  // A Mutex can also be used as a starvation-free reader-writer lock.
+  // Neither read-locks nor write-locks are reentrant/recursive to avoid
+  // potential client programming errors.
+  //
+  // The Mutex API provides `Writer*()` aliases for the existing `Lock()`,
+  // `Unlock()` and `TryLock()` methods for use within applications mixing
+  // reader/writer locks. Using `Reader*()` and `Writer*()` operations in this
+  // manner can make locking behavior clearer when mixing read and write modes.
+  //
+  // Introducing reader locks necessarily complicates the `Mutex` state
+  // machine somewhat. The table below illustrates the allowed state transitions
+  // of a mutex in such cases. Note that ReaderLock() may block even if the lock
+  // is held in shared mode; this occurs when another thread is blocked on a
+  // call to WriterLock().
+  //
+  // ---------------------------------------------------------------------------
+  //     Operation: WriterLock() Unlock()  ReaderLock()           ReaderUnlock()
+  // ---------------------------------------------------------------------------
+  // State
+  // ---------------------------------------------------------------------------
+  // Free           Exclusive    invalid   Shared(1)              invalid
+  // Shared(1)      blocks       invalid   Shared(2) or blocks    Free
+  // Shared(n) n>1  blocks       invalid   Shared(n+1) or blocks  Shared(n-1)
+  // Exclusive      blocks       Free      blocks                 invalid
+  // ---------------------------------------------------------------------------
+  //
+  // In comments below, "shared" refers to a state of Shared(n) for any n > 0.
+
+  // Mutex::ReaderLock()
+  //
+  // Blocks the calling thread, if necessary, until this `Mutex` is either free,
+  // or in shared mode, and then acquires a share of it. Note that
+  // `ReaderLock()` will block if some other thread has an exclusive/writer lock
+  // on the mutex.
+
+  void ReaderLock() ABSL_SHARED_LOCK_FUNCTION();
+
+  // Mutex::ReaderUnlock()
+  //
+  // Releases a read share of this `Mutex`. `ReaderUnlock` may return a mutex to
+  // the free state if this thread holds the last reader lock on the mutex. Note
+  // that you cannot call `ReaderUnlock()` on a mutex held in write mode.
+  void ReaderUnlock() ABSL_UNLOCK_FUNCTION();
+
+  // Mutex::ReaderTryLock()
+  //
+  // If the mutex can be acquired without blocking, acquires this mutex for
+  // shared access and returns `true`. Otherwise, returns `false`. Returns
+  // `true` with high probability if the `Mutex` was free or shared.
+  bool ReaderTryLock() ABSL_SHARED_TRYLOCK_FUNCTION(true);
+
+  // Mutex::AssertReaderHeld()
+  //
+  // Returns immediately if this thread holds the `Mutex` in at least shared
+  // mode (read mode). Otherwise, may report an error (typically by
+  // crashing with a diagnostic), or may return immediately.
+  void AssertReaderHeld() const ABSL_ASSERT_SHARED_LOCK();
+
+  // Mutex::WriterLock()
+  // Mutex::WriterUnlock()
+  // Mutex::WriterTryLock()
+  //
+  // Aliases for `Mutex::Lock()`, `Mutex::Unlock()`, and `Mutex::TryLock()`.
+  //
+  // These methods may be used (along with the complementary `Reader*()`
+  // methods) to distingish simple exclusive `Mutex` usage (`Lock()`,
+  // etc.) from reader/writer lock usage.
+  void WriterLock() ABSL_EXCLUSIVE_LOCK_FUNCTION() { this->Lock(); }
+
+  void WriterUnlock() ABSL_UNLOCK_FUNCTION() { this->Unlock(); }
+
+  bool WriterTryLock() ABSL_EXCLUSIVE_TRYLOCK_FUNCTION(true) {
+    return this->TryLock();
+  }
+
+  // ---------------------------------------------------------------------------
+  // Conditional Critical Regions
+  // ---------------------------------------------------------------------------
+
+  // Conditional usage of a `Mutex` can occur using two distinct paradigms:
+  //
+  //   * Use of `Mutex` member functions with `Condition` objects.
+  //   * Use of the separate `CondVar` abstraction.
+  //
+  // In general, prefer use of `Condition` and the `Mutex` member functions
+  // listed below over `CondVar`. When there are multiple threads waiting on
+  // distinctly different conditions, however, a battery of `CondVar`s may be
+  // more efficient. This section discusses use of `Condition` objects.
+  //
+  // `Mutex` contains member functions for performing lock operations only under
+  // certain conditions, of class `Condition`. For correctness, the `Condition`
+  // must return a boolean that is a pure function, only of state protected by
+  // the `Mutex`. The condition must be invariant w.r.t. environmental state
+  // such as thread, cpu id, or time, and must be `noexcept`. The condition will
+  // always be invoked with the mutex held in at least read mode, so you should
+  // not block it for long periods or sleep it on a timer.
+  //
+  // Since a condition must not depend directly on the current time, use
+  // `*WithTimeout()` member function variants to make your condition
+  // effectively true after a given duration, or `*WithDeadline()` variants to
+  // make your condition effectively true after a given time.
+  //
+  // The condition function should have no side-effects aside from debug
+  // logging; as a special exception, the function may acquire other mutexes
+  // provided it releases all those that it acquires.  (This exception was
+  // required to allow logging.)
+
+  // Mutex::Await()
+  //
+  // Unlocks this `Mutex` and blocks until simultaneously both `cond` is `true`
+  // and this `Mutex` can be reacquired, then reacquires this `Mutex` in the
+  // same mode in which it was previously held. If the condition is initially
+  // `true`, `Await()` *may* skip the release/re-acquire step.
+  //
+  // `Await()` requires that this thread holds this `Mutex` in some mode.
+  void Await(const Condition &cond);
+
+  // Mutex::LockWhen()
+  // Mutex::ReaderLockWhen()
+  // Mutex::WriterLockWhen()
+  //
+  // Blocks until simultaneously both `cond` is `true` and this `Mutex` can
+  // be acquired, then atomically acquires this `Mutex`. `LockWhen()` is
+  // logically equivalent to `*Lock(); Await();` though they may have different
+  // performance characteristics.
+  void LockWhen(const Condition &cond) ABSL_EXCLUSIVE_LOCK_FUNCTION();
+
+  void ReaderLockWhen(const Condition &cond) ABSL_SHARED_LOCK_FUNCTION();
+
+  void WriterLockWhen(const Condition &cond) ABSL_EXCLUSIVE_LOCK_FUNCTION() {
+    this->LockWhen(cond);
+  }
+
+  // ---------------------------------------------------------------------------
+  // Mutex Variants with Timeouts/Deadlines
+  // ---------------------------------------------------------------------------
+
+  // Mutex::AwaitWithTimeout()
+  // Mutex::AwaitWithDeadline()
+  //
+  // Unlocks this `Mutex` and blocks until simultaneously:
+  //   - either `cond` is true or the {timeout has expired, deadline has passed}
+  //     and
+  //   - this `Mutex` can be reacquired,
+  // then reacquire this `Mutex` in the same mode in which it was previously
+  // held, returning `true` iff `cond` is `true` on return.
+  //
+  // If the condition is initially `true`, the implementation *may* skip the
+  // release/re-acquire step and return immediately.
+  //
+  // Deadlines in the past are equivalent to an immediate deadline.
+  // Negative timeouts are equivalent to a zero timeout.
+  //
+  // This method requires that this thread holds this `Mutex` in some mode.
+  bool AwaitWithTimeout(const Condition &cond, absl::Duration timeout);
+
+  bool AwaitWithDeadline(const Condition &cond, absl::Time deadline);
+
+  // Mutex::LockWhenWithTimeout()
+  // Mutex::ReaderLockWhenWithTimeout()
+  // Mutex::WriterLockWhenWithTimeout()
+  //
+  // Blocks until simultaneously both:
+  //   - either `cond` is `true` or the timeout has expired, and
+  //   - this `Mutex` can be acquired,
+  // then atomically acquires this `Mutex`, returning `true` iff `cond` is
+  // `true` on return.
+  //
+  // Negative timeouts are equivalent to a zero timeout.
+  bool LockWhenWithTimeout(const Condition &cond, absl::Duration timeout)
+      ABSL_EXCLUSIVE_LOCK_FUNCTION();
+  bool ReaderLockWhenWithTimeout(const Condition &cond, absl::Duration timeout)
+      ABSL_SHARED_LOCK_FUNCTION();
+  bool WriterLockWhenWithTimeout(const Condition &cond, absl::Duration timeout)
+      ABSL_EXCLUSIVE_LOCK_FUNCTION() {
+    return this->LockWhenWithTimeout(cond, timeout);
+  }
+
+  // Mutex::LockWhenWithDeadline()
+  // Mutex::ReaderLockWhenWithDeadline()
+  // Mutex::WriterLockWhenWithDeadline()
+  //
+  // Blocks until simultaneously both:
+  //   - either `cond` is `true` or the deadline has been passed, and
+  //   - this `Mutex` can be acquired,
+  // then atomically acquires this Mutex, returning `true` iff `cond` is `true`
+  // on return.
+  //
+  // Deadlines in the past are equivalent to an immediate deadline.
+  bool LockWhenWithDeadline(const Condition &cond, absl::Time deadline)
+      ABSL_EXCLUSIVE_LOCK_FUNCTION();
+  bool ReaderLockWhenWithDeadline(const Condition &cond, absl::Time deadline)
+      ABSL_SHARED_LOCK_FUNCTION();
+  bool WriterLockWhenWithDeadline(const Condition &cond, absl::Time deadline)
+      ABSL_EXCLUSIVE_LOCK_FUNCTION() {
+    return this->LockWhenWithDeadline(cond, deadline);
+  }
+
+  // ---------------------------------------------------------------------------
+  // Debug Support: Invariant Checking, Deadlock Detection, Logging.
+  // ---------------------------------------------------------------------------
+
+  // Mutex::EnableInvariantDebugging()
+  //
+  // If `invariant`!=null and if invariant debugging has been enabled globally,
+  // cause `(*invariant)(arg)` to be called at moments when the invariant for
+  // this `Mutex` should hold (for example: just after acquire, just before
+  // release).
+  //
+  // The routine `invariant` should have no side-effects since it is not
+  // guaranteed how many times it will be called; it should check the invariant
+  // and crash if it does not hold. Enabling global invariant debugging may
+  // substantially reduce `Mutex` performance; it should be set only for
+  // non-production runs.  Optimization options may also disable invariant
+  // checks.
+  void EnableInvariantDebugging(void (*invariant)(void *), void *arg);
+
+  // Mutex::EnableDebugLog()
+  //
+  // Cause all subsequent uses of this `Mutex` to be logged via
+  // `ABSL_RAW_LOG(INFO)`. Log entries are tagged with `name` if no previous
+  // call to `EnableInvariantDebugging()` or `EnableDebugLog()` has been made.
+  //
+  // Note: This method substantially reduces `Mutex` performance.
+  void EnableDebugLog(const char *name);
+
+  // Deadlock detection
+
+  // Mutex::ForgetDeadlockInfo()
+  //
+  // Forget any deadlock-detection information previously gathered
+  // about this `Mutex`. Call this method in debug mode when the lock ordering
+  // of a `Mutex` changes.
+  void ForgetDeadlockInfo();
+
+  // Mutex::AssertNotHeld()
+  //
+  // Return immediately if this thread does not hold this `Mutex` in any
+  // mode; otherwise, may report an error (typically by crashing with a
+  // diagnostic), or may return immediately.
+  //
+  // Currently this check is performed only if all of:
+  //    - in debug mode
+  //    - SetMutexDeadlockDetectionMode() has been set to kReport or kAbort
+  //    - number of locks concurrently held by this thread is not large.
+  // are true.
+  void AssertNotHeld() const;
+
+  // Special cases.
+
+  // A `MuHow` is a constant that indicates how a lock should be acquired.
+  // Internal implementation detail.  Clients should ignore.
+  typedef const struct MuHowS *MuHow;
+
+  // Mutex::InternalAttemptToUseMutexInFatalSignalHandler()
+  //
+  // Causes the `Mutex` implementation to prepare itself for re-entry caused by
+  // future use of `Mutex` within a fatal signal handler. This method is
+  // intended for use only for last-ditch attempts to log crash information.
+  // It does not guarantee that attempts to use Mutexes within the handler will
+  // not deadlock; it merely makes other faults less likely.
+  //
+  // WARNING:  This routine must be invoked from a signal handler, and the
+  // signal handler must either loop forever or terminate the process.
+  // Attempts to return from (or `longjmp` out of) the signal handler once this
+  // call has been made may cause arbitrary program behaviour including
+  // crashes and deadlocks.
+  static void InternalAttemptToUseMutexInFatalSignalHandler();
+
+ private:
+  std::atomic<intptr_t> mu_;  // The Mutex state.
+
+  // Post()/Wait() versus associated PerThreadSem; in class for required
+  // friendship with PerThreadSem.
+  static void IncrementSynchSem(Mutex *mu, base_internal::PerThreadSynch *w);
+  static bool DecrementSynchSem(Mutex *mu, base_internal::PerThreadSynch *w,
+                                synchronization_internal::KernelTimeout t);
+
+  // slow path acquire
+  void LockSlowLoop(SynchWaitParams *waitp, int flags);
+  // wrappers around LockSlowLoop()
+  bool LockSlowWithDeadline(MuHow how, const Condition *cond,
+                            synchronization_internal::KernelTimeout t,
+                            int flags);
+  void LockSlow(MuHow how, const Condition *cond,
+                int flags) ABSL_ATTRIBUTE_COLD;
+  // slow path release
+  void UnlockSlow(SynchWaitParams *waitp) ABSL_ATTRIBUTE_COLD;
+  // Common code between Await() and AwaitWithTimeout/Deadline()
+  bool AwaitCommon(const Condition &cond,
+                   synchronization_internal::KernelTimeout t);
+  // Attempt to remove thread s from queue.
+  void TryRemove(base_internal::PerThreadSynch *s);
+  // Block a thread on mutex.
+  void Block(base_internal::PerThreadSynch *s);
+  // Wake a thread; return successor.
+  base_internal::PerThreadSynch *Wakeup(base_internal::PerThreadSynch *w);
+
+  friend class CondVar;   // for access to Trans()/Fer().
+  void Trans(MuHow how);  // used for CondVar->Mutex transfer
+  void Fer(
+      base_internal::PerThreadSynch *w);  // used for CondVar->Mutex transfer
+
+  // Catch the error of writing Mutex when intending MutexLock.
+  Mutex(const volatile Mutex * /*ignored*/) {}  // NOLINT(runtime/explicit)
+
+  Mutex(const Mutex&) = delete;
+  Mutex& operator=(const Mutex&) = delete;
+};
+
+// -----------------------------------------------------------------------------
+// Mutex RAII Wrappers
+// -----------------------------------------------------------------------------
+
+// MutexLock
+//
+// `MutexLock` is a helper class, which acquires and releases a `Mutex` via
+// RAII.
+//
+// Example:
+//
+// Class Foo {
+//  public:
+//   Foo::Bar* Baz() {
+//     MutexLock lock(&mu_);
+//     ...
+//     return bar;
+//   }
+//
+// private:
+//   Mutex mu_;
+// };
+class ABSL_SCOPED_LOCKABLE MutexLock {
+ public:
+  // Constructors
+
+  // Calls `mu->Lock()` and returns when that call returns. That is, `*mu` is
+  // guaranteed to be locked when this object is constructed. Requires that
+  // `mu` be dereferenceable.
+  explicit MutexLock(Mutex *mu) ABSL_EXCLUSIVE_LOCK_FUNCTION(mu) : mu_(mu) {
+    this->mu_->Lock();
+  }
+
+  // Like above, but calls `mu->LockWhen(cond)` instead. That is, in addition to
+  // the above, the condition given by `cond` is also guaranteed to hold when
+  // this object is constructed.
+  explicit MutexLock(Mutex *mu, const Condition &cond)
+      ABSL_EXCLUSIVE_LOCK_FUNCTION(mu)
+      : mu_(mu) {
+    this->mu_->LockWhen(cond);
+  }
+
+  MutexLock(const MutexLock &) = delete;  // NOLINT(runtime/mutex)
+  MutexLock(MutexLock&&) = delete;  // NOLINT(runtime/mutex)
+  MutexLock& operator=(const MutexLock&) = delete;
+  MutexLock& operator=(MutexLock&&) = delete;
+
+  ~MutexLock() ABSL_UNLOCK_FUNCTION() { this->mu_->Unlock(); }
+
+ private:
+  Mutex *const mu_;
+};
+
+// ReaderMutexLock
+//
+// The `ReaderMutexLock` is a helper class, like `MutexLock`, which acquires and
+// releases a shared lock on a `Mutex` via RAII.
+class ABSL_SCOPED_LOCKABLE ReaderMutexLock {
+ public:
+  explicit ReaderMutexLock(Mutex *mu) ABSL_SHARED_LOCK_FUNCTION(mu) : mu_(mu) {
+    mu->ReaderLock();
+  }
+
+  explicit ReaderMutexLock(Mutex *mu, const Condition &cond)
+      ABSL_SHARED_LOCK_FUNCTION(mu)
+      : mu_(mu) {
+    mu->ReaderLockWhen(cond);
+  }
+
+  ReaderMutexLock(const ReaderMutexLock&) = delete;
+  ReaderMutexLock(ReaderMutexLock&&) = delete;
+  ReaderMutexLock& operator=(const ReaderMutexLock&) = delete;
+  ReaderMutexLock& operator=(ReaderMutexLock&&) = delete;
+
+  ~ReaderMutexLock() ABSL_UNLOCK_FUNCTION() { this->mu_->ReaderUnlock(); }
+
+ private:
+  Mutex *const mu_;
+};
+
+// WriterMutexLock
+//
+// The `WriterMutexLock` is a helper class, like `MutexLock`, which acquires and
+// releases a write (exclusive) lock on a `Mutex` via RAII.
+class ABSL_SCOPED_LOCKABLE WriterMutexLock {
+ public:
+  explicit WriterMutexLock(Mutex *mu) ABSL_EXCLUSIVE_LOCK_FUNCTION(mu)
+      : mu_(mu) {
+    mu->WriterLock();
+  }
+
+  explicit WriterMutexLock(Mutex *mu, const Condition &cond)
+      ABSL_EXCLUSIVE_LOCK_FUNCTION(mu)
+      : mu_(mu) {
+    mu->WriterLockWhen(cond);
+  }
+
+  WriterMutexLock(const WriterMutexLock&) = delete;
+  WriterMutexLock(WriterMutexLock&&) = delete;
+  WriterMutexLock& operator=(const WriterMutexLock&) = delete;
+  WriterMutexLock& operator=(WriterMutexLock&&) = delete;
+
+  ~WriterMutexLock() ABSL_UNLOCK_FUNCTION() { this->mu_->WriterUnlock(); }
+
+ private:
+  Mutex *const mu_;
+};
+
+// -----------------------------------------------------------------------------
+// Condition
+// -----------------------------------------------------------------------------
+//
+// As noted above, `Mutex` contains a number of member functions which take a
+// `Condition` as an argument; clients can wait for conditions to become `true`
+// before attempting to acquire the mutex. These sections are known as
+// "condition critical" sections. To use a `Condition`, you simply need to
+// construct it, and use within an appropriate `Mutex` member function;
+// everything else in the `Condition` class is an implementation detail.
+//
+// A `Condition` is specified as a function pointer which returns a boolean.
+// `Condition` functions should be pure functions -- their results should depend
+// only on passed arguments, should not consult any external state (such as
+// clocks), and should have no side-effects, aside from debug logging. Any
+// objects that the function may access should be limited to those which are
+// constant while the mutex is blocked on the condition (e.g. a stack variable),
+// or objects of state protected explicitly by the mutex.
+//
+// No matter which construction is used for `Condition`, the underlying
+// function pointer / functor / callable must not throw any
+// exceptions. Correctness of `Mutex` / `Condition` is not guaranteed in
+// the face of a throwing `Condition`. (When Abseil is allowed to depend
+// on C++17, these function pointers will be explicitly marked
+// `noexcept`; until then this requirement cannot be enforced in the
+// type system.)
+//
+// Note: to use a `Condition`, you need only construct it and pass it to a
+// suitable `Mutex' member function, such as `Mutex::Await()`, or to the
+// constructor of one of the scope guard classes.
+//
+// Example using LockWhen/Unlock:
+//
+//   // assume count_ is not internal reference count
+//   int count_ ABSL_GUARDED_BY(mu_);
+//   Condition count_is_zero(+[](int *count) { return *count == 0; }, &count_);
+//
+//   mu_.LockWhen(count_is_zero);
+//   // ...
+//   mu_.Unlock();
+//
+// Example using a scope guard:
+//
+//   {
+//     MutexLock lock(&mu_, count_is_zero);
+//     // ...
+//   }
+//
+// When multiple threads are waiting on exactly the same condition, make sure
+// that they are constructed with the same parameters (same pointer to function
+// + arg, or same pointer to object + method), so that the mutex implementation
+// can avoid redundantly evaluating the same condition for each thread.
+class Condition {
+ public:
+  // A Condition that returns the result of "(*func)(arg)"
+  Condition(bool (*func)(void *), void *arg);
+
+  // Templated version for people who are averse to casts.
+  //
+  // To use a lambda, prepend it with unary plus, which converts the lambda
+  // into a function pointer:
+  //     Condition(+[](T* t) { return ...; }, arg).
+  //
+  // Note: lambdas in this case must contain no bound variables.
+  //
+  // See class comment for performance advice.
+  template<typename T>
+  Condition(bool (*func)(T *), T *arg);
+
+  // Templated version for invoking a method that returns a `bool`.
+  //
+  // `Condition(object, &Class::Method)` constructs a `Condition` that evaluates
+  // `object->Method()`.
+  //
+  // Implementation Note: `absl::internal::identity` is used to allow methods to
+  // come from base classes. A simpler signature like
+  // `Condition(T*, bool (T::*)())` does not suffice.
+  template<typename T>
+  Condition(T *object, bool (absl::internal::identity<T>::type::* method)());
+
+  // Same as above, for const members
+  template<typename T>
+  Condition(const T *object,
+            bool (absl::internal::identity<T>::type::* method)() const);
+
+  // A Condition that returns the value of `*cond`
+  explicit Condition(const bool *cond);
+
+  // Templated version for invoking a functor that returns a `bool`.
+  // This approach accepts pointers to non-mutable lambdas, `std::function`,
+  // the result of` std::bind` and user-defined functors that define
+  // `bool F::operator()() const`.
+  //
+  // Example:
+  //
+  //   auto reached = [this, current]() {
+  //     mu_.AssertReaderHeld();                // For annotalysis.
+  //     return processed_ >= current;
+  //   };
+  //   mu_.Await(Condition(&reached));
+  //
+  // NOTE: never use "mu_.AssertHeld()" instead of "mu_.AssertReaderHeld()" in
+  // the lambda as it may be called when the mutex is being unlocked from a
+  // scope holding only a reader lock, which will make the assertion not
+  // fulfilled and crash the binary.
+
+  // See class comment for performance advice. In particular, if there
+  // might be more than one waiter for the same condition, make sure
+  // that all waiters construct the condition with the same pointers.
+
+  // Implementation note: The second template parameter ensures that this
+  // constructor doesn't participate in overload resolution if T doesn't have
+  // `bool operator() const`.
+  template <typename T, typename E = decltype(
+      static_cast<bool (T::*)() const>(&T::operator()))>
+  explicit Condition(const T *obj)
+      : Condition(obj, static_cast<bool (T::*)() const>(&T::operator())) {}
+
+  // A Condition that always returns `true`.
+  static const Condition kTrue;
+
+  // Evaluates the condition.
+  bool Eval() const;
+
+  // Returns `true` if the two conditions are guaranteed to return the same
+  // value if evaluated at the same time, `false` if the evaluation *may* return
+  // different results.
+  //
+  // Two `Condition` values are guaranteed equal if both their `func` and `arg`
+  // components are the same. A null pointer is equivalent to a `true`
+  // condition.
+  static bool GuaranteedEqual(const Condition *a, const Condition *b);
+
+ private:
+  typedef bool (*InternalFunctionType)(void * arg);
+  typedef bool (Condition::*InternalMethodType)();
+  typedef bool (*InternalMethodCallerType)(void * arg,
+                                           InternalMethodType internal_method);
+
+  bool (*eval_)(const Condition*);  // Actual evaluator
+  InternalFunctionType function_;   // function taking pointer returning bool
+  InternalMethodType method_;       // method returning bool
+  void *arg_;                       // arg of function_ or object of method_
+
+  Condition();        // null constructor used only to create kTrue
+
+  // Various functions eval_ can point to:
+  static bool CallVoidPtrFunction(const Condition*);
+  template <typename T> static bool CastAndCallFunction(const Condition* c);
+  template <typename T> static bool CastAndCallMethod(const Condition* c);
+};
+
+// -----------------------------------------------------------------------------
+// CondVar
+// -----------------------------------------------------------------------------
+//
+// A condition variable, reflecting state evaluated separately outside of the
+// `Mutex` object, which can be signaled to wake callers.
+// This class is not normally needed; use `Mutex` member functions such as
+// `Mutex::Await()` and intrinsic `Condition` abstractions. In rare cases
+// with many threads and many conditions, `CondVar` may be faster.
+//
+// The implementation may deliver signals to any condition variable at
+// any time, even when no call to `Signal()` or `SignalAll()` is made; as a
+// result, upon being awoken, you must check the logical condition you have
+// been waiting upon.
+//
+// Examples:
+//
+// Usage for a thread waiting for some condition C protected by mutex mu:
+//       mu.Lock();
+//       while (!C) { cv->Wait(&mu); }        // releases and reacquires mu
+//       //  C holds; process data
+//       mu.Unlock();
+//
+// Usage to wake T is:
+//       mu.Lock();
+//      // process data, possibly establishing C
+//      if (C) { cv->Signal(); }
+//      mu.Unlock();
+//
+// If C may be useful to more than one waiter, use `SignalAll()` instead of
+// `Signal()`.
+//
+// With this implementation it is efficient to use `Signal()/SignalAll()` inside
+// the locked region; this usage can make reasoning about your program easier.
+//
+class CondVar {
+ public:
+  // A `CondVar` allocated on the heap or on the stack can use the this
+  // constructor.
+  CondVar();
+  ~CondVar();
+
+  // CondVar::Wait()
+  //
+  // Atomically releases a `Mutex` and blocks on this condition variable.
+  // Waits until awakened by a call to `Signal()` or `SignalAll()` (or a
+  // spurious wakeup), then reacquires the `Mutex` and returns.
+  //
+  // Requires and ensures that the current thread holds the `Mutex`.
+  void Wait(Mutex *mu);
+
+  // CondVar::WaitWithTimeout()
+  //
+  // Atomically releases a `Mutex` and blocks on this condition variable.
+  // Waits until awakened by a call to `Signal()` or `SignalAll()` (or a
+  // spurious wakeup), or until the timeout has expired, then reacquires
+  // the `Mutex` and returns.
+  //
+  // Returns true if the timeout has expired without this `CondVar`
+  // being signalled in any manner. If both the timeout has expired
+  // and this `CondVar` has been signalled, the implementation is free
+  // to return `true` or `false`.
+  //
+  // Requires and ensures that the current thread holds the `Mutex`.
+  bool WaitWithTimeout(Mutex *mu, absl::Duration timeout);
+
+  // CondVar::WaitWithDeadline()
+  //
+  // Atomically releases a `Mutex` and blocks on this condition variable.
+  // Waits until awakened by a call to `Signal()` or `SignalAll()` (or a
+  // spurious wakeup), or until the deadline has passed, then reacquires
+  // the `Mutex` and returns.
+  //
+  // Deadlines in the past are equivalent to an immediate deadline.
+  //
+  // Returns true if the deadline has passed without this `CondVar`
+  // being signalled in any manner. If both the deadline has passed
+  // and this `CondVar` has been signalled, the implementation is free
+  // to return `true` or `false`.
+  //
+  // Requires and ensures that the current thread holds the `Mutex`.
+  bool WaitWithDeadline(Mutex *mu, absl::Time deadline);
+
+  // CondVar::Signal()
+  //
+  // Signal this `CondVar`; wake at least one waiter if one exists.
+  void Signal();
+
+  // CondVar::SignalAll()
+  //
+  // Signal this `CondVar`; wake all waiters.
+  void SignalAll();
+
+  // CondVar::EnableDebugLog()
+  //
+  // Causes all subsequent uses of this `CondVar` to be logged via
+  // `ABSL_RAW_LOG(INFO)`. Log entries are tagged with `name` if `name != 0`.
+  // Note: this method substantially reduces `CondVar` performance.
+  void EnableDebugLog(const char *name);
+
+ private:
+  bool WaitCommon(Mutex *mutex, synchronization_internal::KernelTimeout t);
+  void Remove(base_internal::PerThreadSynch *s);
+  void Wakeup(base_internal::PerThreadSynch *w);
+  std::atomic<intptr_t> cv_;  // Condition variable state.
+  CondVar(const CondVar&) = delete;
+  CondVar& operator=(const CondVar&) = delete;
+};
+
+
+// Variants of MutexLock.
+//
+// If you find yourself using one of these, consider instead using
+// Mutex::Unlock() and/or if-statements for clarity.
+
+// MutexLockMaybe
+//
+// MutexLockMaybe is like MutexLock, but is a no-op when mu is null.
+class ABSL_SCOPED_LOCKABLE MutexLockMaybe {
+ public:
+  explicit MutexLockMaybe(Mutex *mu) ABSL_EXCLUSIVE_LOCK_FUNCTION(mu)
+      : mu_(mu) {
+    if (this->mu_ != nullptr) {
+      this->mu_->Lock();
+    }
+  }
+
+  explicit MutexLockMaybe(Mutex *mu, const Condition &cond)
+      ABSL_EXCLUSIVE_LOCK_FUNCTION(mu)
+      : mu_(mu) {
+    if (this->mu_ != nullptr) {
+      this->mu_->LockWhen(cond);
+    }
+  }
+
+  ~MutexLockMaybe() ABSL_UNLOCK_FUNCTION() {
+    if (this->mu_ != nullptr) { this->mu_->Unlock(); }
+  }
+
+ private:
+  Mutex *const mu_;
+  MutexLockMaybe(const MutexLockMaybe&) = delete;
+  MutexLockMaybe(MutexLockMaybe&&) = delete;
+  MutexLockMaybe& operator=(const MutexLockMaybe&) = delete;
+  MutexLockMaybe& operator=(MutexLockMaybe&&) = delete;
+};
+
+// ReleasableMutexLock
+//
+// ReleasableMutexLock is like MutexLock, but permits `Release()` of its
+// mutex before destruction. `Release()` may be called at most once.
+class ABSL_SCOPED_LOCKABLE ReleasableMutexLock {
+ public:
+  explicit ReleasableMutexLock(Mutex *mu) ABSL_EXCLUSIVE_LOCK_FUNCTION(mu)
+      : mu_(mu) {
+    this->mu_->Lock();
+  }
+
+  explicit ReleasableMutexLock(Mutex *mu, const Condition &cond)
+      ABSL_EXCLUSIVE_LOCK_FUNCTION(mu)
+      : mu_(mu) {
+    this->mu_->LockWhen(cond);
+  }
+
+  ~ReleasableMutexLock() ABSL_UNLOCK_FUNCTION() {
+    if (this->mu_ != nullptr) { this->mu_->Unlock(); }
+  }
+
+  void Release() ABSL_UNLOCK_FUNCTION();
+
+ private:
+  Mutex *mu_;
+  ReleasableMutexLock(const ReleasableMutexLock&) = delete;
+  ReleasableMutexLock(ReleasableMutexLock&&) = delete;
+  ReleasableMutexLock& operator=(const ReleasableMutexLock&) = delete;
+  ReleasableMutexLock& operator=(ReleasableMutexLock&&) = delete;
+};
+
+inline Mutex::Mutex() : mu_(0) {
+  ABSL_TSAN_MUTEX_CREATE(this, __tsan_mutex_not_static);
+}
+
+inline constexpr Mutex::Mutex(absl::ConstInitType) : mu_(0) {}
+
+inline CondVar::CondVar() : cv_(0) {}
+
+// static
+template <typename T>
+bool Condition::CastAndCallMethod(const Condition *c) {
+  typedef bool (T::*MemberType)();
+  MemberType rm = reinterpret_cast<MemberType>(c->method_);
+  T *x = static_cast<T *>(c->arg_);
+  return (x->*rm)();
+}
+
+// static
+template <typename T>
+bool Condition::CastAndCallFunction(const Condition *c) {
+  typedef bool (*FuncType)(T *);
+  FuncType fn = reinterpret_cast<FuncType>(c->function_);
+  T *x = static_cast<T *>(c->arg_);
+  return (*fn)(x);
+}
+
+template <typename T>
+inline Condition::Condition(bool (*func)(T *), T *arg)
+    : eval_(&CastAndCallFunction<T>),
+      function_(reinterpret_cast<InternalFunctionType>(func)),
+      method_(nullptr),
+      arg_(const_cast<void *>(static_cast<const void *>(arg))) {}
+
+template <typename T>
+inline Condition::Condition(T *object,
+                            bool (absl::internal::identity<T>::type::*method)())
+    : eval_(&CastAndCallMethod<T>),
+      function_(nullptr),
+      method_(reinterpret_cast<InternalMethodType>(method)),
+      arg_(object) {}
+
+template <typename T>
+inline Condition::Condition(const T *object,
+                            bool (absl::internal::identity<T>::type::*method)()
+                                const)
+    : eval_(&CastAndCallMethod<T>),
+      function_(nullptr),
+      method_(reinterpret_cast<InternalMethodType>(method)),
+      arg_(reinterpret_cast<void *>(const_cast<T *>(object))) {}
+
+// Register a hook for profiling support.
+//
+// The function pointer registered here will be called whenever a mutex is
+// contended.  The callback is given the absl/base/cycleclock.h timestamp when
+// waiting began.
+//
+// Calls to this function do not race or block, but there is no ordering
+// guaranteed between calls to this function and call to the provided hook.
+// In particular, the previously registered hook may still be called for some
+// time after this function returns.
+void RegisterMutexProfiler(void (*fn)(int64_t wait_timestamp));
+
+// Register a hook for Mutex tracing.
+//
+// The function pointer registered here will be called whenever a mutex is
+// contended.  The callback is given an opaque handle to the contended mutex,
+// an event name, and the number of wait cycles (as measured by
+// //absl/base/internal/cycleclock.h, and which may not be real
+// "cycle" counts.)
+//
+// The only event name currently sent is "slow release".
+//
+// This has the same memory ordering concerns as RegisterMutexProfiler() above.
+void RegisterMutexTracer(void (*fn)(const char *msg, const void *obj,
+                                    int64_t wait_cycles));
+
+// TODO(gfalcon): Combine RegisterMutexProfiler() and RegisterMutexTracer()
+// into a single interface, since they are only ever called in pairs.
+
+// Register a hook for CondVar tracing.
+//
+// The function pointer registered here will be called here on various CondVar
+// events.  The callback is given an opaque handle to the CondVar object and
+// a string identifying the event.  This is thread-safe, but only a single
+// tracer can be registered.
+//
+// Events that can be sent are "Wait", "Unwait", "Signal wakeup", and
+// "SignalAll wakeup".
+//
+// This has the same memory ordering concerns as RegisterMutexProfiler() above.
+void RegisterCondVarTracer(void (*fn)(const char *msg, const void *cv));
+
+// Register a hook for symbolizing stack traces in deadlock detector reports.
+//
+// 'pc' is the program counter being symbolized, 'out' is the buffer to write
+// into, and 'out_size' is the size of the buffer.  This function can return
+// false if symbolizing failed, or true if a NUL-terminated symbol was written
+// to 'out.'
+//
+// This has the same memory ordering concerns as RegisterMutexProfiler() above.
+//
+// DEPRECATED: The default symbolizer function is absl::Symbolize() and the
+// ability to register a different hook for symbolizing stack traces will be
+// removed on or after 2023-05-01.
+ABSL_DEPRECATED("absl::RegisterSymbolizer() is deprecated and will be removed "
+                "on or after 2023-05-01")
+void RegisterSymbolizer(bool (*fn)(const void *pc, char *out, int out_size));
+
+// EnableMutexInvariantDebugging()
+//
+// Enable or disable global support for Mutex invariant debugging.  If enabled,
+// then invariant predicates can be registered per-Mutex for debug checking.
+// See Mutex::EnableInvariantDebugging().
+void EnableMutexInvariantDebugging(bool enabled);
+
+// When in debug mode, and when the feature has been enabled globally, the
+// implementation will keep track of lock ordering and complain (or optionally
+// crash) if a cycle is detected in the acquired-before graph.
+
+// Possible modes of operation for the deadlock detector in debug mode.
+enum class OnDeadlockCycle {
+  kIgnore,  // Neither report on nor attempt to track cycles in lock ordering
+  kReport,  // Report lock cycles to stderr when detected
+  kAbort,  // Report lock cycles to stderr when detected, then abort
+};
+
+// SetMutexDeadlockDetectionMode()
+//
+// Enable or disable global support for detection of potential deadlocks
+// due to Mutex lock ordering inversions.  When set to 'kIgnore', tracking of
+// lock ordering is disabled.  Otherwise, in debug builds, a lock ordering graph
+// will be maintained internally, and detected cycles will be reported in
+// the manner chosen here.
+void SetMutexDeadlockDetectionMode(OnDeadlockCycle mode);
+
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+// In some build configurations we pass --detect-odr-violations to the
+// gold linker.  This causes it to flag weak symbol overrides as ODR
+// violations.  Because ODR only applies to C++ and not C,
+// --detect-odr-violations ignores symbols not mangled with C++ names.
+// By changing our extension points to be extern "C", we dodge this
+// check.
+extern "C" {
+void ABSL_INTERNAL_C_SYMBOL(AbslInternalMutexYield)();
+}  // extern "C"
+
+#endif  // ABSL_SYNCHRONIZATION_MUTEX_H_
diff --git a/src/absl/synchronization/notification.cc b/src/absl/synchronization/notification.cc
new file mode 100644 (file)
index 0000000..e91b903
--- /dev/null
@@ -0,0 +1,78 @@
+// Copyright 2017 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "absl/synchronization/notification.h"
+
+#include <atomic>
+
+#include "absl/base/attributes.h"
+#include "absl/base/internal/raw_logging.h"
+#include "absl/synchronization/mutex.h"
+#include "absl/time/time.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+
+void Notification::Notify() {
+  MutexLock l(&this->mutex_);
+
+#ifndef NDEBUG
+  if (ABSL_PREDICT_FALSE(notified_yet_.load(std::memory_order_relaxed))) {
+    ABSL_RAW_LOG(
+        FATAL,
+        "Notify() method called more than once for Notification object %p",
+        static_cast<void *>(this));
+  }
+#endif
+
+  notified_yet_.store(true, std::memory_order_release);
+}
+
+Notification::~Notification() {
+  // Make sure that the thread running Notify() exits before the object is
+  // destructed.
+  MutexLock l(&this->mutex_);
+}
+
+void Notification::WaitForNotification() const {
+  if (!HasBeenNotifiedInternal(&this->notified_yet_)) {
+    this->mutex_.LockWhen(Condition(&HasBeenNotifiedInternal,
+                                    &this->notified_yet_));
+    this->mutex_.Unlock();
+  }
+}
+
+bool Notification::WaitForNotificationWithTimeout(
+    absl::Duration timeout) const {
+  bool notified = HasBeenNotifiedInternal(&this->notified_yet_);
+  if (!notified) {
+    notified = this->mutex_.LockWhenWithTimeout(
+        Condition(&HasBeenNotifiedInternal, &this->notified_yet_), timeout);
+    this->mutex_.Unlock();
+  }
+  return notified;
+}
+
+bool Notification::WaitForNotificationWithDeadline(absl::Time deadline) const {
+  bool notified = HasBeenNotifiedInternal(&this->notified_yet_);
+  if (!notified) {
+    notified = this->mutex_.LockWhenWithDeadline(
+        Condition(&HasBeenNotifiedInternal, &this->notified_yet_), deadline);
+    this->mutex_.Unlock();
+  }
+  return notified;
+}
+
+ABSL_NAMESPACE_END
+}  // namespace absl
diff --git a/src/absl/synchronization/notification.h b/src/absl/synchronization/notification.h
new file mode 100644 (file)
index 0000000..9a354ca
--- /dev/null
@@ -0,0 +1,123 @@
+// Copyright 2017 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// -----------------------------------------------------------------------------
+// notification.h
+// -----------------------------------------------------------------------------
+//
+// This header file defines a `Notification` abstraction, which allows threads
+// to receive notification of a single occurrence of a single event.
+//
+// The `Notification` object maintains a private boolean "notified" state that
+// transitions to `true` at most once. The `Notification` class provides the
+// following primary member functions:
+//   * `HasBeenNotified() `to query its state
+//   * `WaitForNotification*()` to have threads wait until the "notified" state
+//      is `true`.
+//   * `Notify()` to set the notification's "notified" state to `true` and
+//     notify all waiting threads that the event has occurred.
+//     This method may only be called once.
+//
+// Note that while `Notify()` may only be called once, it is perfectly valid to
+// call any of the `WaitForNotification*()` methods multiple times, from
+// multiple threads -- even after the notification's "notified" state has been
+// set -- in which case those methods will immediately return.
+//
+// Note that the lifetime of a `Notification` requires careful consideration;
+// it might not be safe to destroy a notification after calling `Notify()` since
+// it is still legal for other threads to call `WaitForNotification*()` methods
+// on the notification. However, observers responding to a "notified" state of
+// `true` can safely delete the notification without interfering with the call
+// to `Notify()` in the other thread.
+//
+// Memory ordering: For any threads X and Y, if X calls `Notify()`, then any
+// action taken by X before it calls `Notify()` is visible to thread Y after:
+//  * Y returns from `WaitForNotification()`, or
+//  * Y receives a `true` return value from either `HasBeenNotified()` or
+//    `WaitForNotificationWithTimeout()`.
+
+#ifndef ABSL_SYNCHRONIZATION_NOTIFICATION_H_
+#define ABSL_SYNCHRONIZATION_NOTIFICATION_H_
+
+#include <atomic>
+
+#include "absl/base/macros.h"
+#include "absl/synchronization/mutex.h"
+#include "absl/time/time.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+
+// -----------------------------------------------------------------------------
+// Notification
+// -----------------------------------------------------------------------------
+class Notification {
+ public:
+  // Initializes the "notified" state to unnotified.
+  Notification() : notified_yet_(false) {}
+  explicit Notification(bool prenotify) : notified_yet_(prenotify) {}
+  Notification(const Notification&) = delete;
+  Notification& operator=(const Notification&) = delete;
+  ~Notification();
+
+  // Notification::HasBeenNotified()
+  //
+  // Returns the value of the notification's internal "notified" state.
+  bool HasBeenNotified() const {
+    return HasBeenNotifiedInternal(&this->notified_yet_);
+  }
+
+  // Notification::WaitForNotification()
+  //
+  // Blocks the calling thread until the notification's "notified" state is
+  // `true`. Note that if `Notify()` has been previously called on this
+  // notification, this function will immediately return.
+  void WaitForNotification() const;
+
+  // Notification::WaitForNotificationWithTimeout()
+  //
+  // Blocks until either the notification's "notified" state is `true` (which
+  // may occur immediately) or the timeout has elapsed, returning the value of
+  // its "notified" state in either case.
+  bool WaitForNotificationWithTimeout(absl::Duration timeout) const;
+
+  // Notification::WaitForNotificationWithDeadline()
+  //
+  // Blocks until either the notification's "notified" state is `true` (which
+  // may occur immediately) or the deadline has expired, returning the value of
+  // its "notified" state in either case.
+  bool WaitForNotificationWithDeadline(absl::Time deadline) const;
+
+  // Notification::Notify()
+  //
+  // Sets the "notified" state of this notification to `true` and wakes waiting
+  // threads. Note: do not call `Notify()` multiple times on the same
+  // `Notification`; calling `Notify()` more than once on the same notification
+  // results in undefined behavior.
+  void Notify();
+
+ private:
+  static inline bool HasBeenNotifiedInternal(
+      const std::atomic<bool>* notified_yet) {
+    return notified_yet->load(std::memory_order_acquire);
+  }
+
+  mutable Mutex mutex_;
+  std::atomic<bool> notified_yet_;  // written under mutex_
+};
+
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#endif  // ABSL_SYNCHRONIZATION_NOTIFICATION_H_
diff --git a/src/absl/time/civil_time.cc b/src/absl/time/civil_time.cc
new file mode 100644 (file)
index 0000000..bdfe9ce
--- /dev/null
@@ -0,0 +1,175 @@
+// Copyright 2018 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "absl/time/civil_time.h"
+
+#include <cstdlib>
+#include <string>
+
+#include "absl/strings/str_cat.h"
+#include "absl/time/time.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+
+namespace {
+
+// Since a civil time has a larger year range than absl::Time (64-bit years vs
+// 64-bit seconds, respectively) we normalize years to roughly +/- 400 years
+// around the year 2400, which will produce an equivalent year in a range that
+// absl::Time can handle.
+inline civil_year_t NormalizeYear(civil_year_t year) {
+  return 2400 + year % 400;
+}
+
+// Formats the given CivilSecond according to the given format.
+std::string FormatYearAnd(string_view fmt, CivilSecond cs) {
+  const CivilSecond ncs(NormalizeYear(cs.year()), cs.month(), cs.day(),
+                        cs.hour(), cs.minute(), cs.second());
+  const TimeZone utc = UTCTimeZone();
+  // TODO(absl-team): Avoid conversion of fmt string.
+  return StrCat(cs.year(),
+                FormatTime(std::string(fmt), FromCivil(ncs, utc), utc));
+}
+
+template <typename CivilT>
+bool ParseYearAnd(string_view fmt, string_view s, CivilT* c) {
+  // Civil times support a larger year range than absl::Time, so we need to
+  // parse the year separately, normalize it, then use absl::ParseTime on the
+  // normalized string.
+  const std::string ss = std::string(s);  // TODO(absl-team): Avoid conversion.
+  const char* const np = ss.c_str();
+  char* endp;
+  errno = 0;
+  const civil_year_t y =
+      std::strtoll(np, &endp, 10);  // NOLINT(runtime/deprecated_fn)
+  if (endp == np || errno == ERANGE) return false;
+  const std::string norm = StrCat(NormalizeYear(y), endp);
+
+  const TimeZone utc = UTCTimeZone();
+  Time t;
+  if (ParseTime(StrCat("%Y", fmt), norm, utc, &t, nullptr)) {
+    const auto cs = ToCivilSecond(t, utc);
+    *c = CivilT(y, cs.month(), cs.day(), cs.hour(), cs.minute(), cs.second());
+    return true;
+  }
+
+  return false;
+}
+
+// Tries to parse the type as a CivilT1, but then assigns the result to the
+// argument of type CivilT2.
+template <typename CivilT1, typename CivilT2>
+bool ParseAs(string_view s, CivilT2* c) {
+  CivilT1 t1;
+  if (ParseCivilTime(s, &t1)) {
+    *c = CivilT2(t1);
+    return true;
+  }
+  return false;
+}
+
+template <typename CivilT>
+bool ParseLenient(string_view s, CivilT* c) {
+  // A fastpath for when the given string data parses exactly into the given
+  // type T (e.g., s="YYYY-MM-DD" and CivilT=CivilDay).
+  if (ParseCivilTime(s, c)) return true;
+  // Try parsing as each of the 6 types, trying the most common types first
+  // (based on csearch results).
+  if (ParseAs<CivilDay>(s, c)) return true;
+  if (ParseAs<CivilSecond>(s, c)) return true;
+  if (ParseAs<CivilHour>(s, c)) return true;
+  if (ParseAs<CivilMonth>(s, c)) return true;
+  if (ParseAs<CivilMinute>(s, c)) return true;
+  if (ParseAs<CivilYear>(s, c)) return true;
+  return false;
+}
+}  // namespace
+
+std::string FormatCivilTime(CivilSecond c) {
+  return FormatYearAnd("-%m-%d%ET%H:%M:%S", c);
+}
+std::string FormatCivilTime(CivilMinute c) {
+  return FormatYearAnd("-%m-%d%ET%H:%M", c);
+}
+std::string FormatCivilTime(CivilHour c) {
+  return FormatYearAnd("-%m-%d%ET%H", c);
+}
+std::string FormatCivilTime(CivilDay c) { return FormatYearAnd("-%m-%d", c); }
+std::string FormatCivilTime(CivilMonth c) { return FormatYearAnd("-%m", c); }
+std::string FormatCivilTime(CivilYear c) { return FormatYearAnd("", c); }
+
+bool ParseCivilTime(string_view s, CivilSecond* c) {
+  return ParseYearAnd("-%m-%d%ET%H:%M:%S", s, c);
+}
+bool ParseCivilTime(string_view s, CivilMinute* c) {
+  return ParseYearAnd("-%m-%d%ET%H:%M", s, c);
+}
+bool ParseCivilTime(string_view s, CivilHour* c) {
+  return ParseYearAnd("-%m-%d%ET%H", s, c);
+}
+bool ParseCivilTime(string_view s, CivilDay* c) {
+  return ParseYearAnd("-%m-%d", s, c);
+}
+bool ParseCivilTime(string_view s, CivilMonth* c) {
+  return ParseYearAnd("-%m", s, c);
+}
+bool ParseCivilTime(string_view s, CivilYear* c) {
+  return ParseYearAnd("", s, c);
+}
+
+bool ParseLenientCivilTime(string_view s, CivilSecond* c) {
+  return ParseLenient(s, c);
+}
+bool ParseLenientCivilTime(string_view s, CivilMinute* c) {
+  return ParseLenient(s, c);
+}
+bool ParseLenientCivilTime(string_view s, CivilHour* c) {
+  return ParseLenient(s, c);
+}
+bool ParseLenientCivilTime(string_view s, CivilDay* c) {
+  return ParseLenient(s, c);
+}
+bool ParseLenientCivilTime(string_view s, CivilMonth* c) {
+  return ParseLenient(s, c);
+}
+bool ParseLenientCivilTime(string_view s, CivilYear* c) {
+  return ParseLenient(s, c);
+}
+
+namespace time_internal {
+
+std::ostream& operator<<(std::ostream& os, CivilYear y) {
+  return os << FormatCivilTime(y);
+}
+std::ostream& operator<<(std::ostream& os, CivilMonth m) {
+  return os << FormatCivilTime(m);
+}
+std::ostream& operator<<(std::ostream& os, CivilDay d) {
+  return os << FormatCivilTime(d);
+}
+std::ostream& operator<<(std::ostream& os, CivilHour h) {
+  return os << FormatCivilTime(h);
+}
+std::ostream& operator<<(std::ostream& os, CivilMinute m) {
+  return os << FormatCivilTime(m);
+}
+std::ostream& operator<<(std::ostream& os, CivilSecond s) {
+  return os << FormatCivilTime(s);
+}
+
+}  // namespace time_internal
+
+ABSL_NAMESPACE_END
+}  // namespace absl
diff --git a/src/absl/time/civil_time.h b/src/absl/time/civil_time.h
new file mode 100644 (file)
index 0000000..bb46004
--- /dev/null
@@ -0,0 +1,538 @@
+// Copyright 2018 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// -----------------------------------------------------------------------------
+// File: civil_time.h
+// -----------------------------------------------------------------------------
+//
+// This header file defines abstractions for computing with "civil time".
+// The term "civil time" refers to the legally recognized human-scale time
+// that is represented by the six fields `YYYY-MM-DD hh:mm:ss`. A "date"
+// is perhaps the most common example of a civil time (represented here as
+// an `absl::CivilDay`).
+//
+// Modern-day civil time follows the Gregorian Calendar and is a
+// time-zone-independent concept: a civil time of "2015-06-01 12:00:00", for
+// example, is not tied to a time zone. Put another way, a civil time does not
+// map to a unique point in time; a civil time must be mapped to an absolute
+// time *through* a time zone.
+//
+// Because a civil time is what most people think of as "time," it is common to
+// map absolute times to civil times to present to users.
+//
+// Time zones define the relationship between absolute and civil times. Given an
+// absolute or civil time and a time zone, you can compute the other time:
+//
+//   Civil Time = F(Absolute Time, Time Zone)
+//   Absolute Time = G(Civil Time, Time Zone)
+//
+// The Abseil time library allows you to construct such civil times from
+// absolute times; consult time.h for such functionality.
+//
+// This library provides six classes for constructing civil-time objects, and
+// provides several helper functions for rounding, iterating, and performing
+// arithmetic on civil-time objects, while avoiding complications like
+// daylight-saving time (DST):
+//
+//   * `absl::CivilSecond`
+//   * `absl::CivilMinute`
+//   * `absl::CivilHour`
+//   * `absl::CivilDay`
+//   * `absl::CivilMonth`
+//   * `absl::CivilYear`
+//
+// Example:
+//
+//   // Construct a civil-time object for a specific day
+//   const absl::CivilDay cd(1969, 07, 20);
+//
+//   // Construct a civil-time object for a specific second
+//   const absl::CivilSecond cd(2018, 8, 1, 12, 0, 1);
+//
+// Note: In C++14 and later, this library is usable in a constexpr context.
+//
+// Example:
+//
+//   // Valid in C++14
+//   constexpr absl::CivilDay cd(1969, 07, 20);
+
+#ifndef ABSL_TIME_CIVIL_TIME_H_
+#define ABSL_TIME_CIVIL_TIME_H_
+
+#include <string>
+
+#include "absl/strings/string_view.h"
+#include "absl/time/internal/cctz/include/cctz/civil_time.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+
+namespace time_internal {
+struct second_tag : cctz::detail::second_tag {};
+struct minute_tag : second_tag, cctz::detail::minute_tag {};
+struct hour_tag : minute_tag, cctz::detail::hour_tag {};
+struct day_tag : hour_tag, cctz::detail::day_tag {};
+struct month_tag : day_tag, cctz::detail::month_tag {};
+struct year_tag : month_tag, cctz::detail::year_tag {};
+}  // namespace time_internal
+
+// -----------------------------------------------------------------------------
+// CivilSecond, CivilMinute, CivilHour, CivilDay, CivilMonth, CivilYear
+// -----------------------------------------------------------------------------
+//
+// Each of these civil-time types is a simple value type with the same
+// interface for construction and the same six accessors for each of the civil
+// time fields (year, month, day, hour, minute, and second, aka YMDHMS). These
+// classes differ only in their alignment, which is indicated by the type name
+// and specifies the field on which arithmetic operates.
+//
+// CONSTRUCTION
+//
+// Each of the civil-time types can be constructed in two ways: by directly
+// passing to the constructor up to six integers representing the YMDHMS fields,
+// or by copying the YMDHMS fields from a differently aligned civil-time type.
+// Omitted fields are assigned their minimum valid value. Hours, minutes, and
+// seconds will be set to 0, month and day will be set to 1. Since there is no
+// minimum year, the default is 1970.
+//
+// Examples:
+//
+//   absl::CivilDay default_value;               // 1970-01-01 00:00:00
+//
+//   absl::CivilDay a(2015, 2, 3);               // 2015-02-03 00:00:00
+//   absl::CivilDay b(2015, 2, 3, 4, 5, 6);      // 2015-02-03 00:00:00
+//   absl::CivilDay c(2015);                     // 2015-01-01 00:00:00
+//
+//   absl::CivilSecond ss(2015, 2, 3, 4, 5, 6);  // 2015-02-03 04:05:06
+//   absl::CivilMinute mm(ss);                   // 2015-02-03 04:05:00
+//   absl::CivilHour hh(mm);                     // 2015-02-03 04:00:00
+//   absl::CivilDay d(hh);                       // 2015-02-03 00:00:00
+//   absl::CivilMonth m(d);                      // 2015-02-01 00:00:00
+//   absl::CivilYear y(m);                       // 2015-01-01 00:00:00
+//
+//   m = absl::CivilMonth(y);                    // 2015-01-01 00:00:00
+//   d = absl::CivilDay(m);                      // 2015-01-01 00:00:00
+//   hh = absl::CivilHour(d);                    // 2015-01-01 00:00:00
+//   mm = absl::CivilMinute(hh);                 // 2015-01-01 00:00:00
+//   ss = absl::CivilSecond(mm);                 // 2015-01-01 00:00:00
+//
+// Each civil-time class is aligned to the civil-time field indicated in the
+// class's name after normalization. Alignment is performed by setting all the
+// inferior fields to their minimum valid value (as described above). The
+// following are examples of how each of the six types would align the fields
+// representing November 22, 2015 at 12:34:56 in the afternoon. (Note: the
+// string format used here is not important; it's just a shorthand way of
+// showing the six YMDHMS fields.)
+//
+//   absl::CivilSecond   : 2015-11-22 12:34:56
+//   absl::CivilMinute   : 2015-11-22 12:34:00
+//   absl::CivilHour     : 2015-11-22 12:00:00
+//   absl::CivilDay      : 2015-11-22 00:00:00
+//   absl::CivilMonth    : 2015-11-01 00:00:00
+//   absl::CivilYear     : 2015-01-01 00:00:00
+//
+// Each civil-time type performs arithmetic on the field to which it is
+// aligned. This means that adding 1 to an absl::CivilDay increments the day
+// field (normalizing as necessary), and subtracting 7 from an absl::CivilMonth
+// operates on the month field (normalizing as necessary). All arithmetic
+// produces a valid civil time. Difference requires two similarly aligned
+// civil-time objects and returns the scalar answer in units of the objects'
+// alignment. For example, the difference between two absl::CivilHour objects
+// will give an answer in units of civil hours.
+//
+// ALIGNMENT CONVERSION
+//
+// The alignment of a civil-time object cannot change, but the object may be
+// used to construct a new object with a different alignment. This is referred
+// to as "realigning". When realigning to a type with the same or more
+// precision (e.g., absl::CivilDay -> absl::CivilSecond), the conversion may be
+// performed implicitly since no information is lost. However, if information
+// could be discarded (e.g., CivilSecond -> CivilDay), the conversion must
+// be explicit at the call site.
+//
+// Examples:
+//
+//   void UseDay(absl::CivilDay day);
+//
+//   absl::CivilSecond cs;
+//   UseDay(cs);                  // Won't compile because data may be discarded
+//   UseDay(absl::CivilDay(cs));  // OK: explicit conversion
+//
+//   absl::CivilDay cd;
+//   UseDay(cd);                  // OK: no conversion needed
+//
+//   absl::CivilMonth cm;
+//   UseDay(cm);                  // OK: implicit conversion to absl::CivilDay
+//
+// NORMALIZATION
+//
+// Normalization takes invalid values and adjusts them to produce valid values.
+// Within the civil-time library, integer arguments passed to the Civil*
+// constructors may be out-of-range, in which case they are normalized by
+// carrying overflow into a field of courser granularity to produce valid
+// civil-time objects. This normalization enables natural arithmetic on
+// constructor arguments without worrying about the field's range.
+//
+// Examples:
+//
+//   // Out-of-range; normalized to 2016-11-01
+//   absl::CivilDay d(2016, 10, 32);
+//   // Out-of-range, negative: normalized to 2016-10-30T23
+//   absl::CivilHour h1(2016, 10, 31, -1);
+//   // Normalization is cumulative: normalized to 2016-10-30T23
+//   absl::CivilHour h2(2016, 10, 32, -25);
+//
+// Note: If normalization is undesired, you can signal an error by comparing
+// the constructor arguments to the normalized values returned by the YMDHMS
+// properties.
+//
+// COMPARISON
+//
+// Comparison between civil-time objects considers all six YMDHMS fields,
+// regardless of the type's alignment. Comparison between differently aligned
+// civil-time types is allowed.
+//
+// Examples:
+//
+//   absl::CivilDay feb_3(2015, 2, 3);  // 2015-02-03 00:00:00
+//   absl::CivilDay mar_4(2015, 3, 4);  // 2015-03-04 00:00:00
+//   // feb_3 < mar_4
+//   // absl::CivilYear(feb_3) == absl::CivilYear(mar_4)
+//
+//   absl::CivilSecond feb_3_noon(2015, 2, 3, 12, 0, 0);  // 2015-02-03 12:00:00
+//   // feb_3 < feb_3_noon
+//   // feb_3 == absl::CivilDay(feb_3_noon)
+//
+//   // Iterates all the days of February 2015.
+//   for (absl::CivilDay d(2015, 2, 1); d < absl::CivilMonth(2015, 3); ++d) {
+//     // ...
+//   }
+//
+// ARITHMETIC
+//
+// Civil-time types support natural arithmetic operators such as addition,
+// subtraction, and difference. Arithmetic operates on the civil-time field
+// indicated in the type's name. Difference operators require arguments with
+// the same alignment and return the answer in units of the alignment.
+//
+// Example:
+//
+//   absl::CivilDay a(2015, 2, 3);
+//   ++a;                              // 2015-02-04 00:00:00
+//   --a;                              // 2015-02-03 00:00:00
+//   absl::CivilDay b = a + 1;         // 2015-02-04 00:00:00
+//   absl::CivilDay c = 1 + b;         // 2015-02-05 00:00:00
+//   int n = c - a;                    // n = 2 (civil days)
+//   int m = c - absl::CivilMonth(c);  // Won't compile: different types.
+//
+// ACCESSORS
+//
+// Each civil-time type has accessors for all six of the civil-time fields:
+// year, month, day, hour, minute, and second.
+//
+// civil_year_t year()
+// int          month()
+// int          day()
+// int          hour()
+// int          minute()
+// int          second()
+//
+// Recall that fields inferior to the type's alignment will be set to their
+// minimum valid value.
+//
+// Example:
+//
+//   absl::CivilDay d(2015, 6, 28);
+//   // d.year() == 2015
+//   // d.month() == 6
+//   // d.day() == 28
+//   // d.hour() == 0
+//   // d.minute() == 0
+//   // d.second() == 0
+//
+// CASE STUDY: Adding a month to January 31.
+//
+// One of the classic questions that arises when considering a civil time
+// library (or a date library or a date/time library) is this:
+//   "What is the result of adding a month to January 31?"
+// This is an interesting question because it is unclear what is meant by a
+// "month", and several different answers are possible, depending on context:
+//
+//   1. March 3 (or 2 if a leap year), if "add a month" means to add a month to
+//      the current month, and adjust the date to overflow the extra days into
+//      March. In this case the result of "February 31" would be normalized as
+//      within the civil-time library.
+//   2. February 28 (or 29 if a leap year), if "add a month" means to add a
+//      month, and adjust the date while holding the resulting month constant.
+//      In this case, the result of "February 31" would be truncated to the last
+//      day in February.
+//   3. An error. The caller may get some error, an exception, an invalid date
+//      object, or perhaps return `false`. This may make sense because there is
+//      no single unambiguously correct answer to the question.
+//
+// Practically speaking, any answer that is not what the programmer intended
+// is the wrong answer.
+//
+// The Abseil time library avoids this problem by making it impossible to
+// ask ambiguous questions. All civil-time objects are aligned to a particular
+// civil-field boundary (such as aligned to a year, month, day, hour, minute,
+// or second), and arithmetic operates on the field to which the object is
+// aligned. This means that in order to "add a month" the object must first be
+// aligned to a month boundary, which is equivalent to the first day of that
+// month.
+//
+// Of course, there are ways to compute an answer the question at hand using
+// this Abseil time library, but they require the programmer to be explicit
+// about the answer they expect. To illustrate, let's see how to compute all
+// three of the above possible answers to the question of "Jan 31 plus 1
+// month":
+//
+// Example:
+//
+//   const absl::CivilDay d(2015, 1, 31);
+//
+//   // Answer 1:
+//   // Add 1 to the month field in the constructor, and rely on normalization.
+//   const auto normalized = absl::CivilDay(d.year(), d.month() + 1, d.day());
+//   // normalized == 2015-03-03 (aka Feb 31)
+//
+//   // Answer 2:
+//   // Add 1 to month field, capping to the end of next month.
+//   const auto next_month = absl::CivilMonth(d) + 1;
+//   const auto last_day_of_next_month = absl::CivilDay(next_month + 1) - 1;
+//   const auto capped = std::min(normalized, last_day_of_next_month);
+//   // capped == 2015-02-28
+//
+//   // Answer 3:
+//   // Signal an error if the normalized answer is not in next month.
+//   if (absl::CivilMonth(normalized) != next_month) {
+//     // error, month overflow
+//   }
+//
+using CivilSecond =
+    time_internal::cctz::detail::civil_time<time_internal::second_tag>;
+using CivilMinute =
+    time_internal::cctz::detail::civil_time<time_internal::minute_tag>;
+using CivilHour =
+    time_internal::cctz::detail::civil_time<time_internal::hour_tag>;
+using CivilDay =
+    time_internal::cctz::detail::civil_time<time_internal::day_tag>;
+using CivilMonth =
+    time_internal::cctz::detail::civil_time<time_internal::month_tag>;
+using CivilYear =
+    time_internal::cctz::detail::civil_time<time_internal::year_tag>;
+
+// civil_year_t
+//
+// Type alias of a civil-time year value. This type is guaranteed to (at least)
+// support any year value supported by `time_t`.
+//
+// Example:
+//
+//   absl::CivilSecond cs = ...;
+//   absl::civil_year_t y = cs.year();
+//   cs = absl::CivilSecond(y, 1, 1, 0, 0, 0);  // CivilSecond(CivilYear(cs))
+//
+using civil_year_t = time_internal::cctz::year_t;
+
+// civil_diff_t
+//
+// Type alias of the difference between two civil-time values.
+// This type is used to indicate arguments that are not
+// normalized (such as parameters to the civil-time constructors), the results
+// of civil-time subtraction, or the operand to civil-time addition.
+//
+// Example:
+//
+//   absl::civil_diff_t n_sec = cs1 - cs2;             // cs1 == cs2 + n_sec;
+//
+using civil_diff_t = time_internal::cctz::diff_t;
+
+// Weekday::monday, Weekday::tuesday, Weekday::wednesday, Weekday::thursday,
+// Weekday::friday, Weekday::saturday, Weekday::sunday
+//
+// The Weekday enum class represents the civil-time concept of a "weekday" with
+// members for all days of the week.
+//
+//   absl::Weekday wd = absl::Weekday::thursday;
+//
+using Weekday = time_internal::cctz::weekday;
+
+// GetWeekday()
+//
+// Returns the absl::Weekday for the given (realigned) civil-time value.
+//
+// Example:
+//
+//   absl::CivilDay a(2015, 8, 13);
+//   absl::Weekday wd = absl::GetWeekday(a);  // wd == absl::Weekday::thursday
+//
+inline Weekday GetWeekday(CivilSecond cs) {
+  return time_internal::cctz::get_weekday(cs);
+}
+
+// NextWeekday()
+// PrevWeekday()
+//
+// Returns the absl::CivilDay that strictly follows or precedes a given
+// absl::CivilDay, and that falls on the given absl::Weekday.
+//
+// Example, given the following month:
+//
+//       August 2015
+//   Su Mo Tu We Th Fr Sa
+//                      1
+//    2  3  4  5  6  7  8
+//    9 10 11 12 13 14 15
+//   16 17 18 19 20 21 22
+//   23 24 25 26 27 28 29
+//   30 31
+//
+//   absl::CivilDay a(2015, 8, 13);
+//   // absl::GetWeekday(a) == absl::Weekday::thursday
+//   absl::CivilDay b = absl::NextWeekday(a, absl::Weekday::thursday);
+//   // b = 2015-08-20
+//   absl::CivilDay c = absl::PrevWeekday(a, absl::Weekday::thursday);
+//   // c = 2015-08-06
+//
+//   absl::CivilDay d = ...
+//   // Gets the following Thursday if d is not already Thursday
+//   absl::CivilDay thurs1 = absl::NextWeekday(d - 1, absl::Weekday::thursday);
+//   // Gets the previous Thursday if d is not already Thursday
+//   absl::CivilDay thurs2 = absl::PrevWeekday(d + 1, absl::Weekday::thursday);
+//
+inline CivilDay NextWeekday(CivilDay cd, Weekday wd) {
+  return CivilDay(time_internal::cctz::next_weekday(cd, wd));
+}
+inline CivilDay PrevWeekday(CivilDay cd, Weekday wd) {
+  return CivilDay(time_internal::cctz::prev_weekday(cd, wd));
+}
+
+// GetYearDay()
+//
+// Returns the day-of-year for the given (realigned) civil-time value.
+//
+// Example:
+//
+//   absl::CivilDay a(2015, 1, 1);
+//   int yd_jan_1 = absl::GetYearDay(a);   // yd_jan_1 = 1
+//   absl::CivilDay b(2015, 12, 31);
+//   int yd_dec_31 = absl::GetYearDay(b);  // yd_dec_31 = 365
+//
+inline int GetYearDay(CivilSecond cs) {
+  return time_internal::cctz::get_yearday(cs);
+}
+
+// FormatCivilTime()
+//
+// Formats the given civil-time value into a string value of the following
+// format:
+//
+//  Type        | Format
+//  ---------------------------------
+//  CivilSecond | YYYY-MM-DDTHH:MM:SS
+//  CivilMinute | YYYY-MM-DDTHH:MM
+//  CivilHour   | YYYY-MM-DDTHH
+//  CivilDay    | YYYY-MM-DD
+//  CivilMonth  | YYYY-MM
+//  CivilYear   | YYYY
+//
+// Example:
+//
+//   absl::CivilDay d = absl::CivilDay(1969, 7, 20);
+//   std::string day_string = absl::FormatCivilTime(d);  // "1969-07-20"
+//
+std::string FormatCivilTime(CivilSecond c);
+std::string FormatCivilTime(CivilMinute c);
+std::string FormatCivilTime(CivilHour c);
+std::string FormatCivilTime(CivilDay c);
+std::string FormatCivilTime(CivilMonth c);
+std::string FormatCivilTime(CivilYear c);
+
+// absl::ParseCivilTime()
+//
+// Parses a civil-time value from the specified `absl::string_view` into the
+// passed output parameter. Returns `true` upon successful parsing.
+//
+// The expected form of the input string is as follows:
+//
+//  Type        | Format
+//  ---------------------------------
+//  CivilSecond | YYYY-MM-DDTHH:MM:SS
+//  CivilMinute | YYYY-MM-DDTHH:MM
+//  CivilHour   | YYYY-MM-DDTHH
+//  CivilDay    | YYYY-MM-DD
+//  CivilMonth  | YYYY-MM
+//  CivilYear   | YYYY
+//
+// Example:
+//
+//   absl::CivilDay d;
+//   bool ok = absl::ParseCivilTime("2018-01-02", &d); // OK
+//
+// Note that parsing will fail if the string's format does not match the
+// expected type exactly. `ParseLenientCivilTime()` below is more lenient.
+//
+bool ParseCivilTime(absl::string_view s, CivilSecond* c);
+bool ParseCivilTime(absl::string_view s, CivilMinute* c);
+bool ParseCivilTime(absl::string_view s, CivilHour* c);
+bool ParseCivilTime(absl::string_view s, CivilDay* c);
+bool ParseCivilTime(absl::string_view s, CivilMonth* c);
+bool ParseCivilTime(absl::string_view s, CivilYear* c);
+
+// ParseLenientCivilTime()
+//
+// Parses any of the formats accepted by `absl::ParseCivilTime()`, but is more
+// lenient if the format of the string does not exactly match the associated
+// type.
+//
+// Example:
+//
+//   absl::CivilDay d;
+//   bool ok = absl::ParseLenientCivilTime("1969-07-20", &d); // OK
+//   ok = absl::ParseLenientCivilTime("1969-07-20T10", &d);   // OK: T10 floored
+//   ok = absl::ParseLenientCivilTime("1969-07", &d);   // OK: day defaults to 1
+//
+bool ParseLenientCivilTime(absl::string_view s, CivilSecond* c);
+bool ParseLenientCivilTime(absl::string_view s, CivilMinute* c);
+bool ParseLenientCivilTime(absl::string_view s, CivilHour* c);
+bool ParseLenientCivilTime(absl::string_view s, CivilDay* c);
+bool ParseLenientCivilTime(absl::string_view s, CivilMonth* c);
+bool ParseLenientCivilTime(absl::string_view s, CivilYear* c);
+
+namespace time_internal {  // For functions found via ADL on civil-time tags.
+
+// Streaming Operators
+//
+// Each civil-time type may be sent to an output stream using operator<<().
+// The result matches the string produced by `FormatCivilTime()`.
+//
+// Example:
+//
+//   absl::CivilDay d = absl::CivilDay(1969, 7, 20);
+//   std::cout << "Date is: " << d << "\n";
+//
+std::ostream& operator<<(std::ostream& os, CivilYear y);
+std::ostream& operator<<(std::ostream& os, CivilMonth m);
+std::ostream& operator<<(std::ostream& os, CivilDay d);
+std::ostream& operator<<(std::ostream& os, CivilHour h);
+std::ostream& operator<<(std::ostream& os, CivilMinute m);
+std::ostream& operator<<(std::ostream& os, CivilSecond s);
+
+}  // namespace time_internal
+
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#endif  // ABSL_TIME_CIVIL_TIME_H_
diff --git a/src/absl/time/clock.cc b/src/absl/time/clock.cc
new file mode 100644 (file)
index 0000000..7b204c4
--- /dev/null
@@ -0,0 +1,585 @@
+// Copyright 2017 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "absl/time/clock.h"
+
+#include "absl/base/attributes.h"
+#include "absl/base/optimization.h"
+
+#ifdef _WIN32
+#include <windows.h>
+#endif
+
+#include <algorithm>
+#include <atomic>
+#include <cerrno>
+#include <cstdint>
+#include <ctime>
+#include <limits>
+
+#include "absl/base/internal/spinlock.h"
+#include "absl/base/internal/unscaledcycleclock.h"
+#include "absl/base/macros.h"
+#include "absl/base/port.h"
+#include "absl/base/thread_annotations.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+Time Now() {
+  // TODO(bww): Get a timespec instead so we don't have to divide.
+  int64_t n = absl::GetCurrentTimeNanos();
+  if (n >= 0) {
+    return time_internal::FromUnixDuration(
+        time_internal::MakeDuration(n / 1000000000, n % 1000000000 * 4));
+  }
+  return time_internal::FromUnixDuration(absl::Nanoseconds(n));
+}
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+// Decide if we should use the fast GetCurrentTimeNanos() algorithm
+// based on the cyclecounter, otherwise just get the time directly
+// from the OS on every call. This can be chosen at compile-time via
+// -DABSL_USE_CYCLECLOCK_FOR_GET_CURRENT_TIME_NANOS=[0|1]
+#ifndef ABSL_USE_CYCLECLOCK_FOR_GET_CURRENT_TIME_NANOS
+#if ABSL_USE_UNSCALED_CYCLECLOCK
+#define ABSL_USE_CYCLECLOCK_FOR_GET_CURRENT_TIME_NANOS 1
+#else
+#define ABSL_USE_CYCLECLOCK_FOR_GET_CURRENT_TIME_NANOS 0
+#endif
+#endif
+
+#if defined(__APPLE__) || defined(_WIN32)
+#include "absl/time/internal/get_current_time_chrono.inc"
+#else
+#include "absl/time/internal/get_current_time_posix.inc"
+#endif
+
+// Allows override by test.
+#ifndef GET_CURRENT_TIME_NANOS_FROM_SYSTEM
+#define GET_CURRENT_TIME_NANOS_FROM_SYSTEM() \
+  ::absl::time_internal::GetCurrentTimeNanosFromSystem()
+#endif
+
+#if !ABSL_USE_CYCLECLOCK_FOR_GET_CURRENT_TIME_NANOS
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+int64_t GetCurrentTimeNanos() { return GET_CURRENT_TIME_NANOS_FROM_SYSTEM(); }
+ABSL_NAMESPACE_END
+}  // namespace absl
+#else  // Use the cyclecounter-based implementation below.
+
+// Allows override by test.
+#ifndef GET_CURRENT_TIME_NANOS_CYCLECLOCK_NOW
+#define GET_CURRENT_TIME_NANOS_CYCLECLOCK_NOW() \
+  ::absl::time_internal::UnscaledCycleClockWrapperForGetCurrentTime::Now()
+#endif
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace time_internal {
+// This is a friend wrapper around UnscaledCycleClock::Now()
+// (needed to access UnscaledCycleClock).
+class UnscaledCycleClockWrapperForGetCurrentTime {
+ public:
+  static int64_t Now() { return base_internal::UnscaledCycleClock::Now(); }
+};
+}  // namespace time_internal
+
+// uint64_t is used in this module to provide an extra bit in multiplications
+
+// ---------------------------------------------------------------------
+// An implementation of reader-write locks that use no atomic ops in the read
+// case.  This is a generalization of Lamport's method for reading a multiword
+// clock.  Increment a word on each write acquisition, using the low-order bit
+// as a spinlock; the word is the high word of the "clock".  Readers read the
+// high word, then all other data, then the high word again, and repeat the
+// read if the reads of the high words yields different answers, or an odd
+// value (either case suggests possible interference from a writer).
+// Here we use a spinlock to ensure only one writer at a time, rather than
+// spinning on the bottom bit of the word to benefit from SpinLock
+// spin-delay tuning.
+
+// Acquire seqlock (*seq) and return the value to be written to unlock.
+static inline uint64_t SeqAcquire(std::atomic<uint64_t> *seq) {
+  uint64_t x = seq->fetch_add(1, std::memory_order_relaxed);
+
+  // We put a release fence between update to *seq and writes to shared data.
+  // Thus all stores to shared data are effectively release operations and
+  // update to *seq above cannot be re-ordered past any of them.  Note that
+  // this barrier is not for the fetch_add above.  A release barrier for the
+  // fetch_add would be before it, not after.
+  std::atomic_thread_fence(std::memory_order_release);
+
+  return x + 2;   // original word plus 2
+}
+
+// Release seqlock (*seq) by writing x to it---a value previously returned by
+// SeqAcquire.
+static inline void SeqRelease(std::atomic<uint64_t> *seq, uint64_t x) {
+  // The unlock store to *seq must have release ordering so that all
+  // updates to shared data must finish before this store.
+  seq->store(x, std::memory_order_release);  // release lock for readers
+}
+
+// ---------------------------------------------------------------------
+
+// "nsscaled" is unit of time equal to a (2**kScale)th of a nanosecond.
+enum { kScale = 30 };
+
+// The minimum interval between samples of the time base.
+// We pick enough time to amortize the cost of the sample,
+// to get a reasonably accurate cycle counter rate reading,
+// and not so much that calculations will overflow 64-bits.
+static const uint64_t kMinNSBetweenSamples = 2000 << 20;
+
+// We require that kMinNSBetweenSamples shifted by kScale
+// have at least a bit left over for 64-bit calculations.
+static_assert(((kMinNSBetweenSamples << (kScale + 1)) >> (kScale + 1)) ==
+               kMinNSBetweenSamples,
+               "cannot represent kMaxBetweenSamplesNSScaled");
+
+// data from a sample of the kernel's time value
+struct TimeSampleAtomic {
+  std::atomic<uint64_t> raw_ns{0};              // raw kernel time
+  std::atomic<uint64_t> base_ns{0};             // our estimate of time
+  std::atomic<uint64_t> base_cycles{0};         // cycle counter reading
+  std::atomic<uint64_t> nsscaled_per_cycle{0};  // cycle period
+  // cycles before we'll sample again (a scaled reciprocal of the period,
+  // to avoid a division on the fast path).
+  std::atomic<uint64_t> min_cycles_per_sample{0};
+};
+// Same again, but with non-atomic types
+struct TimeSample {
+  uint64_t raw_ns = 0;                 // raw kernel time
+  uint64_t base_ns = 0;                // our estimate of time
+  uint64_t base_cycles = 0;            // cycle counter reading
+  uint64_t nsscaled_per_cycle = 0;     // cycle period
+  uint64_t min_cycles_per_sample = 0;  // approx cycles before next sample
+};
+
+struct ABSL_CACHELINE_ALIGNED TimeState {
+  std::atomic<uint64_t> seq{0};
+  TimeSampleAtomic last_sample;  // the last sample; under seq
+
+  // The following counters are used only by the test code.
+  int64_t stats_initializations{0};
+  int64_t stats_reinitializations{0};
+  int64_t stats_calibrations{0};
+  int64_t stats_slow_paths{0};
+  int64_t stats_fast_slow_paths{0};
+
+  uint64_t last_now_cycles ABSL_GUARDED_BY(lock){0};
+
+  // Used by GetCurrentTimeNanosFromKernel().
+  // We try to read clock values at about the same time as the kernel clock.
+  // This value gets adjusted up or down as estimate of how long that should
+  // take, so we can reject attempts that take unusually long.
+  std::atomic<uint64_t> approx_syscall_time_in_cycles{10 * 1000};
+  // Number of times in a row we've seen a kernel time call take substantially
+  // less than approx_syscall_time_in_cycles.
+  std::atomic<uint32_t> kernel_time_seen_smaller{0};
+
+  // A reader-writer lock protecting the static locations below.
+  // See SeqAcquire() and SeqRelease() above.
+  absl::base_internal::SpinLock lock{absl::kConstInit,
+                                     base_internal::SCHEDULE_KERNEL_ONLY};
+};
+ABSL_CONST_INIT static TimeState time_state{};
+
+// Return the time in ns as told by the kernel interface.  Place in *cycleclock
+// the value of the cycleclock at about the time of the syscall.
+// This call represents the time base that this module synchronizes to.
+// Ensures that *cycleclock does not step back by up to (1 << 16) from
+// last_cycleclock, to discard small backward counter steps.  (Larger steps are
+// assumed to be complete resyncs, which shouldn't happen.  If they do, a full
+// reinitialization of the outer algorithm should occur.)
+static int64_t GetCurrentTimeNanosFromKernel(uint64_t last_cycleclock,
+                                             uint64_t *cycleclock)
+    ABSL_EXCLUSIVE_LOCKS_REQUIRED(time_state.lock) {
+  uint64_t local_approx_syscall_time_in_cycles =  // local copy
+      time_state.approx_syscall_time_in_cycles.load(std::memory_order_relaxed);
+
+  int64_t current_time_nanos_from_system;
+  uint64_t before_cycles;
+  uint64_t after_cycles;
+  uint64_t elapsed_cycles;
+  int loops = 0;
+  do {
+    before_cycles = GET_CURRENT_TIME_NANOS_CYCLECLOCK_NOW();
+    current_time_nanos_from_system = GET_CURRENT_TIME_NANOS_FROM_SYSTEM();
+    after_cycles = GET_CURRENT_TIME_NANOS_CYCLECLOCK_NOW();
+    // elapsed_cycles is unsigned, so is large on overflow
+    elapsed_cycles = after_cycles - before_cycles;
+    if (elapsed_cycles >= local_approx_syscall_time_in_cycles &&
+        ++loops == 20) {  // clock changed frequencies?  Back off.
+      loops = 0;
+      if (local_approx_syscall_time_in_cycles < 1000 * 1000) {
+        local_approx_syscall_time_in_cycles =
+            (local_approx_syscall_time_in_cycles + 1) << 1;
+      }
+      time_state.approx_syscall_time_in_cycles.store(
+          local_approx_syscall_time_in_cycles, std::memory_order_relaxed);
+    }
+  } while (elapsed_cycles >= local_approx_syscall_time_in_cycles ||
+           last_cycleclock - after_cycles < (static_cast<uint64_t>(1) << 16));
+
+  // Adjust approx_syscall_time_in_cycles to be within a factor of 2
+  // of the typical time to execute one iteration of the loop above.
+  if ((local_approx_syscall_time_in_cycles >> 1) < elapsed_cycles) {
+    // measured time is no smaller than half current approximation
+    time_state.kernel_time_seen_smaller.store(0, std::memory_order_relaxed);
+  } else if (time_state.kernel_time_seen_smaller.fetch_add(
+                 1, std::memory_order_relaxed) >= 3) {
+    // smaller delays several times in a row; reduce approximation by 12.5%
+    const uint64_t new_approximation =
+        local_approx_syscall_time_in_cycles -
+        (local_approx_syscall_time_in_cycles >> 3);
+    time_state.approx_syscall_time_in_cycles.store(new_approximation,
+                                                   std::memory_order_relaxed);
+    time_state.kernel_time_seen_smaller.store(0, std::memory_order_relaxed);
+  }
+
+  *cycleclock = after_cycles;
+  return current_time_nanos_from_system;
+}
+
+static int64_t GetCurrentTimeNanosSlowPath() ABSL_ATTRIBUTE_COLD;
+
+// Read the contents of *atomic into *sample.
+// Each field is read atomically, but to maintain atomicity between fields,
+// the access must be done under a lock.
+static void ReadTimeSampleAtomic(const struct TimeSampleAtomic *atomic,
+                                 struct TimeSample *sample) {
+  sample->base_ns = atomic->base_ns.load(std::memory_order_relaxed);
+  sample->base_cycles = atomic->base_cycles.load(std::memory_order_relaxed);
+  sample->nsscaled_per_cycle =
+      atomic->nsscaled_per_cycle.load(std::memory_order_relaxed);
+  sample->min_cycles_per_sample =
+      atomic->min_cycles_per_sample.load(std::memory_order_relaxed);
+  sample->raw_ns = atomic->raw_ns.load(std::memory_order_relaxed);
+}
+
+// Public routine.
+// Algorithm:  We wish to compute real time from a cycle counter.  In normal
+// operation, we construct a piecewise linear approximation to the kernel time
+// source, using the cycle counter value.  The start of each line segment is at
+// the same point as the end of the last, but may have a different slope (that
+// is, a different idea of the cycle counter frequency).  Every couple of
+// seconds, the kernel time source is sampled and compared with the current
+// approximation.  A new slope is chosen that, if followed for another couple
+// of seconds, will correct the error at the current position.  The information
+// for a sample is in the "last_sample" struct.  The linear approximation is
+//   estimated_time = last_sample.base_ns +
+//     last_sample.ns_per_cycle * (counter_reading - last_sample.base_cycles)
+// (ns_per_cycle is actually stored in different units and scaled, to avoid
+// overflow).  The base_ns of the next linear approximation is the
+// estimated_time using the last approximation; the base_cycles is the cycle
+// counter value at that time; the ns_per_cycle is the number of ns per cycle
+// measured since the last sample, but adjusted so that most of the difference
+// between the estimated_time and the kernel time will be corrected by the
+// estimated time to the next sample.  In normal operation, this algorithm
+// relies on:
+// - the cycle counter and kernel time rates not changing a lot in a few
+//   seconds.
+// - the client calling into the code often compared to a couple of seconds, so
+//   the time to the next correction can be estimated.
+// Any time ns_per_cycle is not known, a major error is detected, or the
+// assumption about frequent calls is violated, the implementation returns the
+// kernel time.  It records sufficient data that a linear approximation can
+// resume a little later.
+
+int64_t GetCurrentTimeNanos() {
+  // read the data from the "last_sample" struct (but don't need raw_ns yet)
+  // The reads of "seq" and test of the values emulate a reader lock.
+  uint64_t base_ns;
+  uint64_t base_cycles;
+  uint64_t nsscaled_per_cycle;
+  uint64_t min_cycles_per_sample;
+  uint64_t seq_read0;
+  uint64_t seq_read1;
+
+  // If we have enough information to interpolate, the value returned will be
+  // derived from this cycleclock-derived time estimate.  On some platforms
+  // (POWER) the function to retrieve this value has enough complexity to
+  // contribute to register pressure - reading it early before initializing
+  // the other pieces of the calculation minimizes spill/restore instructions,
+  // minimizing icache cost.
+  uint64_t now_cycles = GET_CURRENT_TIME_NANOS_CYCLECLOCK_NOW();
+
+  // Acquire pairs with the barrier in SeqRelease - if this load sees that
+  // store, the shared-data reads necessarily see that SeqRelease's updates
+  // to the same shared data.
+  seq_read0 = time_state.seq.load(std::memory_order_acquire);
+
+  base_ns = time_state.last_sample.base_ns.load(std::memory_order_relaxed);
+  base_cycles =
+      time_state.last_sample.base_cycles.load(std::memory_order_relaxed);
+  nsscaled_per_cycle =
+      time_state.last_sample.nsscaled_per_cycle.load(std::memory_order_relaxed);
+  min_cycles_per_sample = time_state.last_sample.min_cycles_per_sample.load(
+      std::memory_order_relaxed);
+
+  // This acquire fence pairs with the release fence in SeqAcquire.  Since it
+  // is sequenced between reads of shared data and seq_read1, the reads of
+  // shared data are effectively acquiring.
+  std::atomic_thread_fence(std::memory_order_acquire);
+
+  // The shared-data reads are effectively acquire ordered, and the
+  // shared-data writes are effectively release ordered. Therefore if our
+  // shared-data reads see any of a particular update's shared-data writes,
+  // seq_read1 is guaranteed to see that update's SeqAcquire.
+  seq_read1 = time_state.seq.load(std::memory_order_relaxed);
+
+  // Fast path.  Return if min_cycles_per_sample has not yet elapsed since the
+  // last sample, and we read a consistent sample.  The fast path activates
+  // only when min_cycles_per_sample is non-zero, which happens when we get an
+  // estimate for the cycle time.  The predicate will fail if now_cycles <
+  // base_cycles, or if some other thread is in the slow path.
+  //
+  // Since we now read now_cycles before base_ns, it is possible for now_cycles
+  // to be less than base_cycles (if we were interrupted between those loads and
+  // last_sample was updated). This is harmless, because delta_cycles will wrap
+  // and report a time much much bigger than min_cycles_per_sample. In that case
+  // we will take the slow path.
+  uint64_t delta_cycles;
+  if (seq_read0 == seq_read1 && (seq_read0 & 1) == 0 &&
+      (delta_cycles = now_cycles - base_cycles) < min_cycles_per_sample) {
+    return base_ns + ((delta_cycles * nsscaled_per_cycle) >> kScale);
+  }
+  return GetCurrentTimeNanosSlowPath();
+}
+
+// Return (a << kScale)/b.
+// Zero is returned if b==0.   Scaling is performed internally to
+// preserve precision without overflow.
+static uint64_t SafeDivideAndScale(uint64_t a, uint64_t b) {
+  // Find maximum safe_shift so that
+  //  0 <= safe_shift <= kScale  and  (a << safe_shift) does not overflow.
+  int safe_shift = kScale;
+  while (((a << safe_shift) >> safe_shift) != a) {
+    safe_shift--;
+  }
+  uint64_t scaled_b = b >> (kScale - safe_shift);
+  uint64_t quotient = 0;
+  if (scaled_b != 0) {
+    quotient = (a << safe_shift) / scaled_b;
+  }
+  return quotient;
+}
+
+static uint64_t UpdateLastSample(
+    uint64_t now_cycles, uint64_t now_ns, uint64_t delta_cycles,
+    const struct TimeSample *sample) ABSL_ATTRIBUTE_COLD;
+
+// The slow path of GetCurrentTimeNanos().  This is taken while gathering
+// initial samples, when enough time has elapsed since the last sample, and if
+// any other thread is writing to last_sample.
+//
+// Manually mark this 'noinline' to minimize stack frame size of the fast
+// path.  Without this, sometimes a compiler may inline this big block of code
+// into the fast path.  That causes lots of register spills and reloads that
+// are unnecessary unless the slow path is taken.
+//
+// TODO(absl-team): Remove this attribute when our compiler is smart enough
+// to do the right thing.
+ABSL_ATTRIBUTE_NOINLINE
+static int64_t GetCurrentTimeNanosSlowPath()
+    ABSL_LOCKS_EXCLUDED(time_state.lock) {
+  // Serialize access to slow-path.  Fast-path readers are not blocked yet, and
+  // code below must not modify last_sample until the seqlock is acquired.
+  time_state.lock.Lock();
+
+  // Sample the kernel time base.  This is the definition of
+  // "now" if we take the slow path.
+  uint64_t now_cycles;
+  uint64_t now_ns =
+      GetCurrentTimeNanosFromKernel(time_state.last_now_cycles, &now_cycles);
+  time_state.last_now_cycles = now_cycles;
+
+  uint64_t estimated_base_ns;
+
+  // ----------
+  // Read the "last_sample" values again; this time holding the write lock.
+  struct TimeSample sample;
+  ReadTimeSampleAtomic(&time_state.last_sample, &sample);
+
+  // ----------
+  // Try running the fast path again; another thread may have updated the
+  // sample between our run of the fast path and the sample we just read.
+  uint64_t delta_cycles = now_cycles - sample.base_cycles;
+  if (delta_cycles < sample.min_cycles_per_sample) {
+    // Another thread updated the sample.  This path does not take the seqlock
+    // so that blocked readers can make progress without blocking new readers.
+    estimated_base_ns = sample.base_ns +
+        ((delta_cycles * sample.nsscaled_per_cycle) >> kScale);
+    time_state.stats_fast_slow_paths++;
+  } else {
+    estimated_base_ns =
+        UpdateLastSample(now_cycles, now_ns, delta_cycles, &sample);
+  }
+
+  time_state.lock.Unlock();
+
+  return estimated_base_ns;
+}
+
+// Main part of the algorithm.  Locks out readers, updates the approximation
+// using the new sample from the kernel, and stores the result in last_sample
+// for readers.  Returns the new estimated time.
+static uint64_t UpdateLastSample(uint64_t now_cycles, uint64_t now_ns,
+                                 uint64_t delta_cycles,
+                                 const struct TimeSample *sample)
+    ABSL_EXCLUSIVE_LOCKS_REQUIRED(time_state.lock) {
+  uint64_t estimated_base_ns = now_ns;
+  uint64_t lock_value =
+      SeqAcquire(&time_state.seq);  // acquire seqlock to block readers
+
+  // The 5s in the next if-statement limits the time for which we will trust
+  // the cycle counter and our last sample to give a reasonable result.
+  // Errors in the rate of the source clock can be multiplied by the ratio
+  // between this limit and kMinNSBetweenSamples.
+  if (sample->raw_ns == 0 ||  // no recent sample, or clock went backwards
+      sample->raw_ns + static_cast<uint64_t>(5) * 1000 * 1000 * 1000 < now_ns ||
+      now_ns < sample->raw_ns || now_cycles < sample->base_cycles) {
+    // record this sample, and forget any previously known slope.
+    time_state.last_sample.raw_ns.store(now_ns, std::memory_order_relaxed);
+    time_state.last_sample.base_ns.store(estimated_base_ns,
+                                         std::memory_order_relaxed);
+    time_state.last_sample.base_cycles.store(now_cycles,
+                                             std::memory_order_relaxed);
+    time_state.last_sample.nsscaled_per_cycle.store(0,
+                                                    std::memory_order_relaxed);
+    time_state.last_sample.min_cycles_per_sample.store(
+        0, std::memory_order_relaxed);
+    time_state.stats_initializations++;
+  } else if (sample->raw_ns + 500 * 1000 * 1000 < now_ns &&
+             sample->base_cycles + 50 < now_cycles) {
+    // Enough time has passed to compute the cycle time.
+    if (sample->nsscaled_per_cycle != 0) {  // Have a cycle time estimate.
+      // Compute time from counter reading, but avoiding overflow
+      // delta_cycles may be larger than on the fast path.
+      uint64_t estimated_scaled_ns;
+      int s = -1;
+      do {
+        s++;
+        estimated_scaled_ns = (delta_cycles >> s) * sample->nsscaled_per_cycle;
+      } while (estimated_scaled_ns / sample->nsscaled_per_cycle !=
+               (delta_cycles >> s));
+      estimated_base_ns = sample->base_ns +
+                          (estimated_scaled_ns >> (kScale - s));
+    }
+
+    // Compute the assumed cycle time kMinNSBetweenSamples ns into the future
+    // assuming the cycle counter rate stays the same as the last interval.
+    uint64_t ns = now_ns - sample->raw_ns;
+    uint64_t measured_nsscaled_per_cycle = SafeDivideAndScale(ns, delta_cycles);
+
+    uint64_t assumed_next_sample_delta_cycles =
+        SafeDivideAndScale(kMinNSBetweenSamples, measured_nsscaled_per_cycle);
+
+    int64_t diff_ns = now_ns - estimated_base_ns;  // estimate low by this much
+
+    // We want to set nsscaled_per_cycle so that our estimate of the ns time
+    // at the assumed cycle time is the assumed ns time.
+    // That is, we want to set nsscaled_per_cycle so:
+    //  kMinNSBetweenSamples + diff_ns  ==
+    //  (assumed_next_sample_delta_cycles * nsscaled_per_cycle) >> kScale
+    // But we wish to damp oscillations, so instead correct only most
+    // of our current error, by solving:
+    //  kMinNSBetweenSamples + diff_ns - (diff_ns / 16) ==
+    //  (assumed_next_sample_delta_cycles * nsscaled_per_cycle) >> kScale
+    ns = kMinNSBetweenSamples + diff_ns - (diff_ns / 16);
+    uint64_t new_nsscaled_per_cycle =
+        SafeDivideAndScale(ns, assumed_next_sample_delta_cycles);
+    if (new_nsscaled_per_cycle != 0 &&
+        diff_ns < 100 * 1000 * 1000 && -diff_ns < 100 * 1000 * 1000) {
+      // record the cycle time measurement
+      time_state.last_sample.nsscaled_per_cycle.store(
+          new_nsscaled_per_cycle, std::memory_order_relaxed);
+      uint64_t new_min_cycles_per_sample =
+          SafeDivideAndScale(kMinNSBetweenSamples, new_nsscaled_per_cycle);
+      time_state.last_sample.min_cycles_per_sample.store(
+          new_min_cycles_per_sample, std::memory_order_relaxed);
+      time_state.stats_calibrations++;
+    } else {  // something went wrong; forget the slope
+      time_state.last_sample.nsscaled_per_cycle.store(
+          0, std::memory_order_relaxed);
+      time_state.last_sample.min_cycles_per_sample.store(
+          0, std::memory_order_relaxed);
+      estimated_base_ns = now_ns;
+      time_state.stats_reinitializations++;
+    }
+    time_state.last_sample.raw_ns.store(now_ns, std::memory_order_relaxed);
+    time_state.last_sample.base_ns.store(estimated_base_ns,
+                                         std::memory_order_relaxed);
+    time_state.last_sample.base_cycles.store(now_cycles,
+                                             std::memory_order_relaxed);
+  } else {
+    // have a sample, but no slope; waiting for enough time for a calibration
+    time_state.stats_slow_paths++;
+  }
+
+  SeqRelease(&time_state.seq, lock_value);  // release the readers
+
+  return estimated_base_ns;
+}
+ABSL_NAMESPACE_END
+}  // namespace absl
+#endif  // ABSL_USE_CYCLECLOCK_FOR_GET_CURRENT_TIME_NANOS
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace {
+
+// Returns the maximum duration that SleepOnce() can sleep for.
+constexpr absl::Duration MaxSleep() {
+#ifdef _WIN32
+  // Windows Sleep() takes unsigned long argument in milliseconds.
+  return absl::Milliseconds(
+      std::numeric_limits<unsigned long>::max());  // NOLINT(runtime/int)
+#else
+  return absl::Seconds(std::numeric_limits<time_t>::max());
+#endif
+}
+
+// Sleeps for the given duration.
+// REQUIRES: to_sleep <= MaxSleep().
+void SleepOnce(absl::Duration to_sleep) {
+#ifdef _WIN32
+  Sleep(to_sleep / absl::Milliseconds(1));
+#else
+  struct timespec sleep_time = absl::ToTimespec(to_sleep);
+  while (nanosleep(&sleep_time, &sleep_time) != 0 && errno == EINTR) {
+    // Ignore signals and wait for the full interval to elapse.
+  }
+#endif
+}
+
+}  // namespace
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+extern "C" {
+
+ABSL_ATTRIBUTE_WEAK void ABSL_INTERNAL_C_SYMBOL(AbslInternalSleepFor)(
+    absl::Duration duration) {
+  while (duration > absl::ZeroDuration()) {
+    absl::Duration to_sleep = std::min(duration, absl::MaxSleep());
+    absl::SleepOnce(to_sleep);
+    duration -= to_sleep;
+  }
+}
+
+}  // extern "C"
diff --git a/src/absl/time/clock.h b/src/absl/time/clock.h
new file mode 100644 (file)
index 0000000..5fe244d
--- /dev/null
@@ -0,0 +1,74 @@
+// Copyright 2017 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// -----------------------------------------------------------------------------
+// File: clock.h
+// -----------------------------------------------------------------------------
+//
+// This header file contains utility functions for working with the system-wide
+// realtime clock. For descriptions of the main time abstractions used within
+// this header file, consult the time.h header file.
+#ifndef ABSL_TIME_CLOCK_H_
+#define ABSL_TIME_CLOCK_H_
+
+#include "absl/base/macros.h"
+#include "absl/time/time.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+
+// Now()
+//
+// Returns the current time, expressed as an `absl::Time` absolute time value.
+absl::Time Now();
+
+// GetCurrentTimeNanos()
+//
+// Returns the current time, expressed as a count of nanoseconds since the Unix
+// Epoch (https://en.wikipedia.org/wiki/Unix_time). Prefer `absl::Now()` instead
+// for all but the most performance-sensitive cases (i.e. when you are calling
+// this function hundreds of thousands of times per second).
+int64_t GetCurrentTimeNanos();
+
+// SleepFor()
+//
+// Sleeps for the specified duration, expressed as an `absl::Duration`.
+//
+// Notes:
+// * Signal interruptions will not reduce the sleep duration.
+// * Returns immediately when passed a nonpositive duration.
+void SleepFor(absl::Duration duration);
+
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+// -----------------------------------------------------------------------------
+// Implementation Details
+// -----------------------------------------------------------------------------
+
+// In some build configurations we pass --detect-odr-violations to the
+// gold linker.  This causes it to flag weak symbol overrides as ODR
+// violations.  Because ODR only applies to C++ and not C,
+// --detect-odr-violations ignores symbols not mangled with C++ names.
+// By changing our extension points to be extern "C", we dodge this
+// check.
+extern "C" {
+void ABSL_INTERNAL_C_SYMBOL(AbslInternalSleepFor)(absl::Duration duration);
+}  // extern "C"
+
+inline void absl::SleepFor(absl::Duration duration) {
+  ABSL_INTERNAL_C_SYMBOL(AbslInternalSleepFor)(duration);
+}
+
+#endif  // ABSL_TIME_CLOCK_H_
diff --git a/src/absl/time/duration.cc b/src/absl/time/duration.cc
new file mode 100644 (file)
index 0000000..4443109
--- /dev/null
@@ -0,0 +1,954 @@
+// Copyright 2017 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// The implementation of the absl::Duration class, which is declared in
+// //absl/time.h.  This class behaves like a numeric type; it has no public
+// methods and is used only through the operators defined here.
+//
+// Implementation notes:
+//
+// An absl::Duration is represented as
+//
+//   rep_hi_ : (int64_t)  Whole seconds
+//   rep_lo_ : (uint32_t) Fractions of a second
+//
+// The seconds value (rep_hi_) may be positive or negative as appropriate.
+// The fractional seconds (rep_lo_) is always a positive offset from rep_hi_.
+// The API for Duration guarantees at least nanosecond resolution, which
+// means rep_lo_ could have a max value of 1B - 1 if it stored nanoseconds.
+// However, to utilize more of the available 32 bits of space in rep_lo_,
+// we instead store quarters of a nanosecond in rep_lo_ resulting in a max
+// value of 4B - 1.  This allows us to correctly handle calculations like
+// 0.5 nanos + 0.5 nanos = 1 nano.  The following example shows the actual
+// Duration rep using quarters of a nanosecond.
+//
+//    2.5 sec = {rep_hi_=2,  rep_lo_=2000000000}  // lo = 4 * 500000000
+//   -2.5 sec = {rep_hi_=-3, rep_lo_=2000000000}
+//
+// Infinite durations are represented as Durations with the rep_lo_ field set
+// to all 1s.
+//
+//   +InfiniteDuration:
+//     rep_hi_ : kint64max
+//     rep_lo_ : ~0U
+//
+//   -InfiniteDuration:
+//     rep_hi_ : kint64min
+//     rep_lo_ : ~0U
+//
+// Arithmetic overflows/underflows to +/- infinity and saturates.
+
+#if defined(_MSC_VER)
+#include <winsock2.h>  // for timeval
+#endif
+
+#include <algorithm>
+#include <cassert>
+#include <cctype>
+#include <cerrno>
+#include <cmath>
+#include <cstdint>
+#include <cstdlib>
+#include <cstring>
+#include <ctime>
+#include <functional>
+#include <limits>
+#include <string>
+
+#include "absl/base/casts.h"
+#include "absl/base/macros.h"
+#include "absl/numeric/int128.h"
+#include "absl/strings/string_view.h"
+#include "absl/strings/strip.h"
+#include "absl/time/time.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+
+namespace {
+
+using time_internal::kTicksPerNanosecond;
+using time_internal::kTicksPerSecond;
+
+constexpr int64_t kint64max = std::numeric_limits<int64_t>::max();
+constexpr int64_t kint64min = std::numeric_limits<int64_t>::min();
+
+// Can't use std::isinfinite() because it doesn't exist on windows.
+inline bool IsFinite(double d) {
+  if (std::isnan(d)) return false;
+  return d != std::numeric_limits<double>::infinity() &&
+         d != -std::numeric_limits<double>::infinity();
+}
+
+inline bool IsValidDivisor(double d) {
+  if (std::isnan(d)) return false;
+  return d != 0.0;
+}
+
+// Can't use std::round() because it is only available in C++11.
+// Note that we ignore the possibility of floating-point over/underflow.
+template <typename Double>
+inline double Round(Double d) {
+  return d < 0 ? std::ceil(d - 0.5) : std::floor(d + 0.5);
+}
+
+// *sec may be positive or negative.  *ticks must be in the range
+// -kTicksPerSecond < *ticks < kTicksPerSecond.  If *ticks is negative it
+// will be normalized to a positive value by adjusting *sec accordingly.
+inline void NormalizeTicks(int64_t* sec, int64_t* ticks) {
+  if (*ticks < 0) {
+    --*sec;
+    *ticks += kTicksPerSecond;
+  }
+}
+
+// Makes a uint128 from the absolute value of the given scalar.
+inline uint128 MakeU128(int64_t a) {
+  uint128 u128 = 0;
+  if (a < 0) {
+    ++u128;
+    ++a;  // Makes it safe to negate 'a'
+    a = -a;
+  }
+  u128 += static_cast<uint64_t>(a);
+  return u128;
+}
+
+// Makes a uint128 count of ticks out of the absolute value of the Duration.
+inline uint128 MakeU128Ticks(Duration d) {
+  int64_t rep_hi = time_internal::GetRepHi(d);
+  uint32_t rep_lo = time_internal::GetRepLo(d);
+  if (rep_hi < 0) {
+    ++rep_hi;
+    rep_hi = -rep_hi;
+    rep_lo = kTicksPerSecond - rep_lo;
+  }
+  uint128 u128 = static_cast<uint64_t>(rep_hi);
+  u128 *= static_cast<uint64_t>(kTicksPerSecond);
+  u128 += rep_lo;
+  return u128;
+}
+
+// Breaks a uint128 of ticks into a Duration.
+inline Duration MakeDurationFromU128(uint128 u128, bool is_neg) {
+  int64_t rep_hi;
+  uint32_t rep_lo;
+  const uint64_t h64 = Uint128High64(u128);
+  const uint64_t l64 = Uint128Low64(u128);
+  if (h64 == 0) {  // fastpath
+    const uint64_t hi = l64 / kTicksPerSecond;
+    rep_hi = static_cast<int64_t>(hi);
+    rep_lo = static_cast<uint32_t>(l64 - hi * kTicksPerSecond);
+  } else {
+    // kMaxRepHi64 is the high 64 bits of (2^63 * kTicksPerSecond).
+    // Any positive tick count whose high 64 bits are >= kMaxRepHi64
+    // is not representable as a Duration.  A negative tick count can
+    // have its high 64 bits == kMaxRepHi64 but only when the low 64
+    // bits are all zero, otherwise it is not representable either.
+    const uint64_t kMaxRepHi64 = 0x77359400UL;
+    if (h64 >= kMaxRepHi64) {
+      if (is_neg && h64 == kMaxRepHi64 && l64 == 0) {
+        // Avoid trying to represent -kint64min below.
+        return time_internal::MakeDuration(kint64min);
+      }
+      return is_neg ? -InfiniteDuration() : InfiniteDuration();
+    }
+    const uint128 kTicksPerSecond128 = static_cast<uint64_t>(kTicksPerSecond);
+    const uint128 hi = u128 / kTicksPerSecond128;
+    rep_hi = static_cast<int64_t>(Uint128Low64(hi));
+    rep_lo =
+        static_cast<uint32_t>(Uint128Low64(u128 - hi * kTicksPerSecond128));
+  }
+  if (is_neg) {
+    rep_hi = -rep_hi;
+    if (rep_lo != 0) {
+      --rep_hi;
+      rep_lo = kTicksPerSecond - rep_lo;
+    }
+  }
+  return time_internal::MakeDuration(rep_hi, rep_lo);
+}
+
+// Convert between int64_t and uint64_t, preserving representation. This
+// allows us to do arithmetic in the unsigned domain, where overflow has
+// well-defined behavior. See operator+=() and operator-=().
+//
+// C99 7.20.1.1.1, as referenced by C++11 18.4.1.2, says, "The typedef
+// name intN_t designates a signed integer type with width N, no padding
+// bits, and a two's complement representation." So, we can convert to
+// and from the corresponding uint64_t value using a bit cast.
+inline uint64_t EncodeTwosComp(int64_t v) {
+  return absl::bit_cast<uint64_t>(v);
+}
+inline int64_t DecodeTwosComp(uint64_t v) { return absl::bit_cast<int64_t>(v); }
+
+// Note: The overflow detection in this function is done using greater/less *or
+// equal* because kint64max/min is too large to be represented exactly in a
+// double (which only has 53 bits of precision). In order to avoid assigning to
+// rep->hi a double value that is too large for an int64_t (and therefore is
+// undefined), we must consider computations that equal kint64max/min as a
+// double as overflow cases.
+inline bool SafeAddRepHi(double a_hi, double b_hi, Duration* d) {
+  double c = a_hi + b_hi;
+  if (c >= static_cast<double>(kint64max)) {
+    *d = InfiniteDuration();
+    return false;
+  }
+  if (c <= static_cast<double>(kint64min)) {
+    *d = -InfiniteDuration();
+    return false;
+  }
+  *d = time_internal::MakeDuration(c, time_internal::GetRepLo(*d));
+  return true;
+}
+
+// A functor that's similar to std::multiplies<T>, except this returns the max
+// T value instead of overflowing. This is only defined for uint128.
+template <typename Ignored>
+struct SafeMultiply {
+  uint128 operator()(uint128 a, uint128 b) const {
+    // b hi is always zero because it originated as an int64_t.
+    assert(Uint128High64(b) == 0);
+    // Fastpath to avoid the expensive overflow check with division.
+    if (Uint128High64(a) == 0) {
+      return (((Uint128Low64(a) | Uint128Low64(b)) >> 32) == 0)
+                 ? static_cast<uint128>(Uint128Low64(a) * Uint128Low64(b))
+                 : a * b;
+    }
+    return b == 0 ? b : (a > kuint128max / b) ? kuint128max : a * b;
+  }
+};
+
+// Scales (i.e., multiplies or divides, depending on the Operation template)
+// the Duration d by the int64_t r.
+template <template <typename> class Operation>
+inline Duration ScaleFixed(Duration d, int64_t r) {
+  const uint128 a = MakeU128Ticks(d);
+  const uint128 b = MakeU128(r);
+  const uint128 q = Operation<uint128>()(a, b);
+  const bool is_neg = (time_internal::GetRepHi(d) < 0) != (r < 0);
+  return MakeDurationFromU128(q, is_neg);
+}
+
+// Scales (i.e., multiplies or divides, depending on the Operation template)
+// the Duration d by the double r.
+template <template <typename> class Operation>
+inline Duration ScaleDouble(Duration d, double r) {
+  Operation<double> op;
+  double hi_doub = op(time_internal::GetRepHi(d), r);
+  double lo_doub = op(time_internal::GetRepLo(d), r);
+
+  double hi_int = 0;
+  double hi_frac = std::modf(hi_doub, &hi_int);
+
+  // Moves hi's fractional bits to lo.
+  lo_doub /= kTicksPerSecond;
+  lo_doub += hi_frac;
+
+  double lo_int = 0;
+  double lo_frac = std::modf(lo_doub, &lo_int);
+
+  // Rolls lo into hi if necessary.
+  int64_t lo64 = Round(lo_frac * kTicksPerSecond);
+
+  Duration ans;
+  if (!SafeAddRepHi(hi_int, lo_int, &ans)) return ans;
+  int64_t hi64 = time_internal::GetRepHi(ans);
+  if (!SafeAddRepHi(hi64, lo64 / kTicksPerSecond, &ans)) return ans;
+  hi64 = time_internal::GetRepHi(ans);
+  lo64 %= kTicksPerSecond;
+  NormalizeTicks(&hi64, &lo64);
+  return time_internal::MakeDuration(hi64, lo64);
+}
+
+// Tries to divide num by den as fast as possible by looking for common, easy
+// cases. If the division was done, the quotient is in *q and the remainder is
+// in *rem and true will be returned.
+inline bool IDivFastPath(const Duration num, const Duration den, int64_t* q,
+                         Duration* rem) {
+  // Bail if num or den is an infinity.
+  if (time_internal::IsInfiniteDuration(num) ||
+      time_internal::IsInfiniteDuration(den))
+    return false;
+
+  int64_t num_hi = time_internal::GetRepHi(num);
+  uint32_t num_lo = time_internal::GetRepLo(num);
+  int64_t den_hi = time_internal::GetRepHi(den);
+  uint32_t den_lo = time_internal::GetRepLo(den);
+
+  if (den_hi == 0 && den_lo == kTicksPerNanosecond) {
+    // Dividing by 1ns
+    if (num_hi >= 0 && num_hi < (kint64max - kTicksPerSecond) / 1000000000) {
+      *q = num_hi * 1000000000 + num_lo / kTicksPerNanosecond;
+      *rem = time_internal::MakeDuration(0, num_lo % den_lo);
+      return true;
+    }
+  } else if (den_hi == 0 && den_lo == 100 * kTicksPerNanosecond) {
+    // Dividing by 100ns (common when converting to Universal time)
+    if (num_hi >= 0 && num_hi < (kint64max - kTicksPerSecond) / 10000000) {
+      *q = num_hi * 10000000 + num_lo / (100 * kTicksPerNanosecond);
+      *rem = time_internal::MakeDuration(0, num_lo % den_lo);
+      return true;
+    }
+  } else if (den_hi == 0 && den_lo == 1000 * kTicksPerNanosecond) {
+    // Dividing by 1us
+    if (num_hi >= 0 && num_hi < (kint64max - kTicksPerSecond) / 1000000) {
+      *q = num_hi * 1000000 + num_lo / (1000 * kTicksPerNanosecond);
+      *rem = time_internal::MakeDuration(0, num_lo % den_lo);
+      return true;
+    }
+  } else if (den_hi == 0 && den_lo == 1000000 * kTicksPerNanosecond) {
+    // Dividing by 1ms
+    if (num_hi >= 0 && num_hi < (kint64max - kTicksPerSecond) / 1000) {
+      *q = num_hi * 1000 + num_lo / (1000000 * kTicksPerNanosecond);
+      *rem = time_internal::MakeDuration(0, num_lo % den_lo);
+      return true;
+    }
+  } else if (den_hi > 0 && den_lo == 0) {
+    // Dividing by positive multiple of 1s
+    if (num_hi >= 0) {
+      if (den_hi == 1) {
+        *q = num_hi;
+        *rem = time_internal::MakeDuration(0, num_lo);
+        return true;
+      }
+      *q = num_hi / den_hi;
+      *rem = time_internal::MakeDuration(num_hi % den_hi, num_lo);
+      return true;
+    }
+    if (num_lo != 0) {
+      num_hi += 1;
+    }
+    int64_t quotient = num_hi / den_hi;
+    int64_t rem_sec = num_hi % den_hi;
+    if (rem_sec > 0) {
+      rem_sec -= den_hi;
+      quotient += 1;
+    }
+    if (num_lo != 0) {
+      rem_sec -= 1;
+    }
+    *q = quotient;
+    *rem = time_internal::MakeDuration(rem_sec, num_lo);
+    return true;
+  }
+
+  return false;
+}
+
+}  // namespace
+
+namespace time_internal {
+
+// The 'satq' argument indicates whether the quotient should saturate at the
+// bounds of int64_t.  If it does saturate, the difference will spill over to
+// the remainder.  If it does not saturate, the remainder remain accurate,
+// but the returned quotient will over/underflow int64_t and should not be used.
+int64_t IDivDuration(bool satq, const Duration num, const Duration den,
+                     Duration* rem) {
+  int64_t q = 0;
+  if (IDivFastPath(num, den, &q, rem)) {
+    return q;
+  }
+
+  const bool num_neg = num < ZeroDuration();
+  const bool den_neg = den < ZeroDuration();
+  const bool quotient_neg = num_neg != den_neg;
+
+  if (time_internal::IsInfiniteDuration(num) || den == ZeroDuration()) {
+    *rem = num_neg ? -InfiniteDuration() : InfiniteDuration();
+    return quotient_neg ? kint64min : kint64max;
+  }
+  if (time_internal::IsInfiniteDuration(den)) {
+    *rem = num;
+    return 0;
+  }
+
+  const uint128 a = MakeU128Ticks(num);
+  const uint128 b = MakeU128Ticks(den);
+  uint128 quotient128 = a / b;
+
+  if (satq) {
+    // Limits the quotient to the range of int64_t.
+    if (quotient128 > uint128(static_cast<uint64_t>(kint64max))) {
+      quotient128 = quotient_neg ? uint128(static_cast<uint64_t>(kint64min))
+                                 : uint128(static_cast<uint64_t>(kint64max));
+    }
+  }
+
+  const uint128 remainder128 = a - quotient128 * b;
+  *rem = MakeDurationFromU128(remainder128, num_neg);
+
+  if (!quotient_neg || quotient128 == 0) {
+    return Uint128Low64(quotient128) & kint64max;
+  }
+  // The quotient needs to be negated, but we need to carefully handle
+  // quotient128s with the top bit on.
+  return -static_cast<int64_t>(Uint128Low64(quotient128 - 1) & kint64max) - 1;
+}
+
+}  // namespace time_internal
+
+//
+// Additive operators.
+//
+
+Duration& Duration::operator+=(Duration rhs) {
+  if (time_internal::IsInfiniteDuration(*this)) return *this;
+  if (time_internal::IsInfiniteDuration(rhs)) return *this = rhs;
+  const int64_t orig_rep_hi = rep_hi_;
+  rep_hi_ =
+      DecodeTwosComp(EncodeTwosComp(rep_hi_) + EncodeTwosComp(rhs.rep_hi_));
+  if (rep_lo_ >= kTicksPerSecond - rhs.rep_lo_) {
+    rep_hi_ = DecodeTwosComp(EncodeTwosComp(rep_hi_) + 1);
+    rep_lo_ -= kTicksPerSecond;
+  }
+  rep_lo_ += rhs.rep_lo_;
+  if (rhs.rep_hi_ < 0 ? rep_hi_ > orig_rep_hi : rep_hi_ < orig_rep_hi) {
+    return *this = rhs.rep_hi_ < 0 ? -InfiniteDuration() : InfiniteDuration();
+  }
+  return *this;
+}
+
+Duration& Duration::operator-=(Duration rhs) {
+  if (time_internal::IsInfiniteDuration(*this)) return *this;
+  if (time_internal::IsInfiniteDuration(rhs)) {
+    return *this = rhs.rep_hi_ >= 0 ? -InfiniteDuration() : InfiniteDuration();
+  }
+  const int64_t orig_rep_hi = rep_hi_;
+  rep_hi_ =
+      DecodeTwosComp(EncodeTwosComp(rep_hi_) - EncodeTwosComp(rhs.rep_hi_));
+  if (rep_lo_ < rhs.rep_lo_) {
+    rep_hi_ = DecodeTwosComp(EncodeTwosComp(rep_hi_) - 1);
+    rep_lo_ += kTicksPerSecond;
+  }
+  rep_lo_ -= rhs.rep_lo_;
+  if (rhs.rep_hi_ < 0 ? rep_hi_ < orig_rep_hi : rep_hi_ > orig_rep_hi) {
+    return *this = rhs.rep_hi_ >= 0 ? -InfiniteDuration() : InfiniteDuration();
+  }
+  return *this;
+}
+
+//
+// Multiplicative operators.
+//
+
+Duration& Duration::operator*=(int64_t r) {
+  if (time_internal::IsInfiniteDuration(*this)) {
+    const bool is_neg = (r < 0) != (rep_hi_ < 0);
+    return *this = is_neg ? -InfiniteDuration() : InfiniteDuration();
+  }
+  return *this = ScaleFixed<SafeMultiply>(*this, r);
+}
+
+Duration& Duration::operator*=(double r) {
+  if (time_internal::IsInfiniteDuration(*this) || !IsFinite(r)) {
+    const bool is_neg = (std::signbit(r) != 0) != (rep_hi_ < 0);
+    return *this = is_neg ? -InfiniteDuration() : InfiniteDuration();
+  }
+  return *this = ScaleDouble<std::multiplies>(*this, r);
+}
+
+Duration& Duration::operator/=(int64_t r) {
+  if (time_internal::IsInfiniteDuration(*this) || r == 0) {
+    const bool is_neg = (r < 0) != (rep_hi_ < 0);
+    return *this = is_neg ? -InfiniteDuration() : InfiniteDuration();
+  }
+  return *this = ScaleFixed<std::divides>(*this, r);
+}
+
+Duration& Duration::operator/=(double r) {
+  if (time_internal::IsInfiniteDuration(*this) || !IsValidDivisor(r)) {
+    const bool is_neg = (std::signbit(r) != 0) != (rep_hi_ < 0);
+    return *this = is_neg ? -InfiniteDuration() : InfiniteDuration();
+  }
+  return *this = ScaleDouble<std::divides>(*this, r);
+}
+
+Duration& Duration::operator%=(Duration rhs) {
+  time_internal::IDivDuration(false, *this, rhs, this);
+  return *this;
+}
+
+double FDivDuration(Duration num, Duration den) {
+  // Arithmetic with infinity is sticky.
+  if (time_internal::IsInfiniteDuration(num) || den == ZeroDuration()) {
+    return (num < ZeroDuration()) == (den < ZeroDuration())
+               ? std::numeric_limits<double>::infinity()
+               : -std::numeric_limits<double>::infinity();
+  }
+  if (time_internal::IsInfiniteDuration(den)) return 0.0;
+
+  double a =
+      static_cast<double>(time_internal::GetRepHi(num)) * kTicksPerSecond +
+      time_internal::GetRepLo(num);
+  double b =
+      static_cast<double>(time_internal::GetRepHi(den)) * kTicksPerSecond +
+      time_internal::GetRepLo(den);
+  return a / b;
+}
+
+//
+// Trunc/Floor/Ceil.
+//
+
+Duration Trunc(Duration d, Duration unit) {
+  return d - (d % unit);
+}
+
+Duration Floor(const Duration d, const Duration unit) {
+  const absl::Duration td = Trunc(d, unit);
+  return td <= d ? td : td - AbsDuration(unit);
+}
+
+Duration Ceil(const Duration d, const Duration unit) {
+  const absl::Duration td = Trunc(d, unit);
+  return td >= d ? td : td + AbsDuration(unit);
+}
+
+//
+// Factory functions.
+//
+
+Duration DurationFromTimespec(timespec ts) {
+  if (static_cast<uint64_t>(ts.tv_nsec) < 1000 * 1000 * 1000) {
+    int64_t ticks = ts.tv_nsec * kTicksPerNanosecond;
+    return time_internal::MakeDuration(ts.tv_sec, ticks);
+  }
+  return Seconds(ts.tv_sec) + Nanoseconds(ts.tv_nsec);
+}
+
+Duration DurationFromTimeval(timeval tv) {
+  if (static_cast<uint64_t>(tv.tv_usec) < 1000 * 1000) {
+    int64_t ticks = tv.tv_usec * 1000 * kTicksPerNanosecond;
+    return time_internal::MakeDuration(tv.tv_sec, ticks);
+  }
+  return Seconds(tv.tv_sec) + Microseconds(tv.tv_usec);
+}
+
+//
+// Conversion to other duration types.
+//
+
+int64_t ToInt64Nanoseconds(Duration d) {
+  if (time_internal::GetRepHi(d) >= 0 &&
+      time_internal::GetRepHi(d) >> 33 == 0) {
+    return (time_internal::GetRepHi(d) * 1000 * 1000 * 1000) +
+           (time_internal::GetRepLo(d) / kTicksPerNanosecond);
+  }
+  return d / Nanoseconds(1);
+}
+int64_t ToInt64Microseconds(Duration d) {
+  if (time_internal::GetRepHi(d) >= 0 &&
+      time_internal::GetRepHi(d) >> 43 == 0) {
+    return (time_internal::GetRepHi(d) * 1000 * 1000) +
+           (time_internal::GetRepLo(d) / (kTicksPerNanosecond * 1000));
+  }
+  return d / Microseconds(1);
+}
+int64_t ToInt64Milliseconds(Duration d) {
+  if (time_internal::GetRepHi(d) >= 0 &&
+      time_internal::GetRepHi(d) >> 53 == 0) {
+    return (time_internal::GetRepHi(d) * 1000) +
+           (time_internal::GetRepLo(d) / (kTicksPerNanosecond * 1000 * 1000));
+  }
+  return d / Milliseconds(1);
+}
+int64_t ToInt64Seconds(Duration d) {
+  int64_t hi = time_internal::GetRepHi(d);
+  if (time_internal::IsInfiniteDuration(d)) return hi;
+  if (hi < 0 && time_internal::GetRepLo(d) != 0) ++hi;
+  return hi;
+}
+int64_t ToInt64Minutes(Duration d) {
+  int64_t hi = time_internal::GetRepHi(d);
+  if (time_internal::IsInfiniteDuration(d)) return hi;
+  if (hi < 0 && time_internal::GetRepLo(d) != 0) ++hi;
+  return hi / 60;
+}
+int64_t ToInt64Hours(Duration d) {
+  int64_t hi = time_internal::GetRepHi(d);
+  if (time_internal::IsInfiniteDuration(d)) return hi;
+  if (hi < 0 && time_internal::GetRepLo(d) != 0) ++hi;
+  return hi / (60 * 60);
+}
+
+double ToDoubleNanoseconds(Duration d) {
+  return FDivDuration(d, Nanoseconds(1));
+}
+double ToDoubleMicroseconds(Duration d) {
+  return FDivDuration(d, Microseconds(1));
+}
+double ToDoubleMilliseconds(Duration d) {
+  return FDivDuration(d, Milliseconds(1));
+}
+double ToDoubleSeconds(Duration d) {
+  return FDivDuration(d, Seconds(1));
+}
+double ToDoubleMinutes(Duration d) {
+  return FDivDuration(d, Minutes(1));
+}
+double ToDoubleHours(Duration d) {
+  return FDivDuration(d, Hours(1));
+}
+
+timespec ToTimespec(Duration d) {
+  timespec ts;
+  if (!time_internal::IsInfiniteDuration(d)) {
+    int64_t rep_hi = time_internal::GetRepHi(d);
+    uint32_t rep_lo = time_internal::GetRepLo(d);
+    if (rep_hi < 0) {
+      // Tweak the fields so that unsigned division of rep_lo
+      // maps to truncation (towards zero) for the timespec.
+      rep_lo += kTicksPerNanosecond - 1;
+      if (rep_lo >= kTicksPerSecond) {
+        rep_hi += 1;
+        rep_lo -= kTicksPerSecond;
+      }
+    }
+    ts.tv_sec = rep_hi;
+    if (ts.tv_sec == rep_hi) {  // no time_t narrowing
+      ts.tv_nsec = rep_lo / kTicksPerNanosecond;
+      return ts;
+    }
+  }
+  if (d >= ZeroDuration()) {
+    ts.tv_sec = std::numeric_limits<time_t>::max();
+    ts.tv_nsec = 1000 * 1000 * 1000 - 1;
+  } else {
+    ts.tv_sec = std::numeric_limits<time_t>::min();
+    ts.tv_nsec = 0;
+  }
+  return ts;
+}
+
+timeval ToTimeval(Duration d) {
+  timeval tv;
+  timespec ts = ToTimespec(d);
+  if (ts.tv_sec < 0) {
+    // Tweak the fields so that positive division of tv_nsec
+    // maps to truncation (towards zero) for the timeval.
+    ts.tv_nsec += 1000 - 1;
+    if (ts.tv_nsec >= 1000 * 1000 * 1000) {
+      ts.tv_sec += 1;
+      ts.tv_nsec -= 1000 * 1000 * 1000;
+    }
+  }
+  tv.tv_sec = ts.tv_sec;
+  if (tv.tv_sec != ts.tv_sec) {  // narrowing
+    if (ts.tv_sec < 0) {
+      tv.tv_sec = std::numeric_limits<decltype(tv.tv_sec)>::min();
+      tv.tv_usec = 0;
+    } else {
+      tv.tv_sec = std::numeric_limits<decltype(tv.tv_sec)>::max();
+      tv.tv_usec = 1000 * 1000 - 1;
+    }
+    return tv;
+  }
+  tv.tv_usec = static_cast<int>(ts.tv_nsec / 1000);  // suseconds_t
+  return tv;
+}
+
+std::chrono::nanoseconds ToChronoNanoseconds(Duration d) {
+  return time_internal::ToChronoDuration<std::chrono::nanoseconds>(d);
+}
+std::chrono::microseconds ToChronoMicroseconds(Duration d) {
+  return time_internal::ToChronoDuration<std::chrono::microseconds>(d);
+}
+std::chrono::milliseconds ToChronoMilliseconds(Duration d) {
+  return time_internal::ToChronoDuration<std::chrono::milliseconds>(d);
+}
+std::chrono::seconds ToChronoSeconds(Duration d) {
+  return time_internal::ToChronoDuration<std::chrono::seconds>(d);
+}
+std::chrono::minutes ToChronoMinutes(Duration d) {
+  return time_internal::ToChronoDuration<std::chrono::minutes>(d);
+}
+std::chrono::hours ToChronoHours(Duration d) {
+  return time_internal::ToChronoDuration<std::chrono::hours>(d);
+}
+
+//
+// To/From string formatting.
+//
+
+namespace {
+
+// Formats a positive 64-bit integer in the given field width.  Note that
+// it is up to the caller of Format64() to ensure that there is sufficient
+// space before ep to hold the conversion.
+char* Format64(char* ep, int width, int64_t v) {
+  do {
+    --width;
+    *--ep = '0' + (v % 10);  // contiguous digits
+  } while (v /= 10);
+  while (--width >= 0) *--ep = '0';  // zero pad
+  return ep;
+}
+
+// Helpers for FormatDuration() that format 'n' and append it to 'out'
+// followed by the given 'unit'.  If 'n' formats to "0", nothing is
+// appended (not even the unit).
+
+// A type that encapsulates how to display a value of a particular unit. For
+// values that are displayed with fractional parts, the precision indicates
+// where to round the value. The precision varies with the display unit because
+// a Duration can hold only quarters of a nanosecond, so displaying information
+// beyond that is just noise.
+//
+// For example, a microsecond value of 42.00025xxxxx should not display beyond 5
+// fractional digits, because it is in the noise of what a Duration can
+// represent.
+struct DisplayUnit {
+  absl::string_view abbr;
+  int prec;
+  double pow10;
+};
+ABSL_CONST_INIT const DisplayUnit kDisplayNano = {"ns", 2, 1e2};
+ABSL_CONST_INIT const DisplayUnit kDisplayMicro = {"us", 5, 1e5};
+ABSL_CONST_INIT const DisplayUnit kDisplayMilli = {"ms", 8, 1e8};
+ABSL_CONST_INIT const DisplayUnit kDisplaySec = {"s", 11, 1e11};
+ABSL_CONST_INIT const DisplayUnit kDisplayMin = {"m", -1, 0.0};  // prec ignored
+ABSL_CONST_INIT const DisplayUnit kDisplayHour = {"h", -1,
+                                                  0.0};  // prec ignored
+
+void AppendNumberUnit(std::string* out, int64_t n, DisplayUnit unit) {
+  char buf[sizeof("2562047788015216")];  // hours in max duration
+  char* const ep = buf + sizeof(buf);
+  char* bp = Format64(ep, 0, n);
+  if (*bp != '0' || bp + 1 != ep) {
+    out->append(bp, ep - bp);
+    out->append(unit.abbr.data(), unit.abbr.size());
+  }
+}
+
+// Note: unit.prec is limited to double's digits10 value (typically 15) so it
+// always fits in buf[].
+void AppendNumberUnit(std::string* out, double n, DisplayUnit unit) {
+  constexpr int kBufferSize = std::numeric_limits<double>::digits10;
+  const int prec = std::min(kBufferSize, unit.prec);
+  char buf[kBufferSize];  // also large enough to hold integer part
+  char* ep = buf + sizeof(buf);
+  double d = 0;
+  int64_t frac_part = Round(std::modf(n, &d) * unit.pow10);
+  int64_t int_part = d;
+  if (int_part != 0 || frac_part != 0) {
+    char* bp = Format64(ep, 0, int_part);  // always < 1000
+    out->append(bp, ep - bp);
+    if (frac_part != 0) {
+      out->push_back('.');
+      bp = Format64(ep, prec, frac_part);
+      while (ep[-1] == '0') --ep;
+      out->append(bp, ep - bp);
+    }
+    out->append(unit.abbr.data(), unit.abbr.size());
+  }
+}
+
+}  // namespace
+
+// From Go's doc at https://golang.org/pkg/time/#Duration.String
+//   [FormatDuration] returns a string representing the duration in the
+//   form "72h3m0.5s". Leading zero units are omitted.  As a special
+//   case, durations less than one second format use a smaller unit
+//   (milli-, micro-, or nanoseconds) to ensure that the leading digit
+//   is non-zero.
+// Unlike Go, we format the zero duration as 0, with no unit.
+std::string FormatDuration(Duration d) {
+  const Duration min_duration = Seconds(kint64min);
+  if (d == min_duration) {
+    // Avoid needing to negate kint64min by directly returning what the
+    // following code should produce in that case.
+    return "-2562047788015215h30m8s";
+  }
+  std::string s;
+  if (d < ZeroDuration()) {
+    s.append("-");
+    d = -d;
+  }
+  if (d == InfiniteDuration()) {
+    s.append("inf");
+  } else if (d < Seconds(1)) {
+    // Special case for durations with a magnitude < 1 second.  The duration
+    // is printed as a fraction of a single unit, e.g., "1.2ms".
+    if (d < Microseconds(1)) {
+      AppendNumberUnit(&s, FDivDuration(d, Nanoseconds(1)), kDisplayNano);
+    } else if (d < Milliseconds(1)) {
+      AppendNumberUnit(&s, FDivDuration(d, Microseconds(1)), kDisplayMicro);
+    } else {
+      AppendNumberUnit(&s, FDivDuration(d, Milliseconds(1)), kDisplayMilli);
+    }
+  } else {
+    AppendNumberUnit(&s, IDivDuration(d, Hours(1), &d), kDisplayHour);
+    AppendNumberUnit(&s, IDivDuration(d, Minutes(1), &d), kDisplayMin);
+    AppendNumberUnit(&s, FDivDuration(d, Seconds(1)), kDisplaySec);
+  }
+  if (s.empty() || s == "-") {
+    s = "0";
+  }
+  return s;
+}
+
+namespace {
+
+// A helper for ParseDuration() that parses a leading number from the given
+// string and stores the result in *int_part/*frac_part/*frac_scale.  The
+// given string pointer is modified to point to the first unconsumed char.
+bool ConsumeDurationNumber(const char** dpp, const char* ep, int64_t* int_part,
+                           int64_t* frac_part, int64_t* frac_scale) {
+  *int_part = 0;
+  *frac_part = 0;
+  *frac_scale = 1;  // invariant: *frac_part < *frac_scale
+  const char* start = *dpp;
+  for (; *dpp != ep; *dpp += 1) {
+    const int d = **dpp - '0';  // contiguous digits
+    if (d < 0 || 10 <= d) break;
+
+    if (*int_part > kint64max / 10) return false;
+    *int_part *= 10;
+    if (*int_part > kint64max - d) return false;
+    *int_part += d;
+  }
+  const bool int_part_empty = (*dpp == start);
+  if (*dpp == ep || **dpp != '.') return !int_part_empty;
+
+  for (*dpp += 1; *dpp != ep; *dpp += 1) {
+    const int d = **dpp - '0';  // contiguous digits
+    if (d < 0 || 10 <= d) break;
+    if (*frac_scale <= kint64max / 10) {
+      *frac_part *= 10;
+      *frac_part += d;
+      *frac_scale *= 10;
+    }
+  }
+  return !int_part_empty || *frac_scale != 1;
+}
+
+// A helper for ParseDuration() that parses a leading unit designator (e.g.,
+// ns, us, ms, s, m, h) from the given string and stores the resulting unit
+// in "*unit".  The given string pointer is modified to point to the first
+// unconsumed char.
+bool ConsumeDurationUnit(const char** start, const char* end, Duration* unit) {
+  size_t size = end - *start;
+  switch (size) {
+    case 0:
+      return false;
+    default:
+      switch (**start) {
+        case 'n':
+          if (*(*start + 1) == 's') {
+            *start += 2;
+            *unit = Nanoseconds(1);
+            return true;
+          }
+          break;
+        case 'u':
+          if (*(*start + 1) == 's') {
+            *start += 2;
+            *unit = Microseconds(1);
+            return true;
+          }
+          break;
+        case 'm':
+          if (*(*start + 1) == 's') {
+            *start += 2;
+            *unit = Milliseconds(1);
+            return true;
+          }
+          break;
+        default:
+          break;
+      }
+      ABSL_FALLTHROUGH_INTENDED;
+    case 1:
+      switch (**start) {
+        case 's':
+          *unit = Seconds(1);
+          *start += 1;
+          return true;
+        case 'm':
+          *unit = Minutes(1);
+          *start += 1;
+          return true;
+        case 'h':
+          *unit = Hours(1);
+          *start += 1;
+          return true;
+        default:
+          return false;
+      }
+  }
+}
+
+}  // namespace
+
+// From Go's doc at https://golang.org/pkg/time/#ParseDuration
+//   [ParseDuration] parses a duration string. A duration string is
+//   a possibly signed sequence of decimal numbers, each with optional
+//   fraction and a unit suffix, such as "300ms", "-1.5h" or "2h45m".
+//   Valid time units are "ns", "us" "ms", "s", "m", "h".
+bool ParseDuration(absl::string_view dur_sv, Duration* d) {
+  int sign = 1;
+  if (absl::ConsumePrefix(&dur_sv, "-")) {
+    sign = -1;
+  } else {
+    absl::ConsumePrefix(&dur_sv, "+");
+  }
+  if (dur_sv.empty()) return false;
+
+  // Special case for a string of "0".
+  if (dur_sv == "0") {
+    *d = ZeroDuration();
+    return true;
+  }
+
+  if (dur_sv == "inf") {
+    *d = sign * InfiniteDuration();
+    return true;
+  }
+
+  const char* start = dur_sv.data();
+  const char* end = start + dur_sv.size();
+
+  Duration dur;
+  while (start != end) {
+    int64_t int_part;
+    int64_t frac_part;
+    int64_t frac_scale;
+    Duration unit;
+    if (!ConsumeDurationNumber(&start, end, &int_part, &frac_part,
+                               &frac_scale) ||
+        !ConsumeDurationUnit(&start, end, &unit)) {
+      return false;
+    }
+    if (int_part != 0) dur += sign * int_part * unit;
+    if (frac_part != 0) dur += sign * frac_part * unit / frac_scale;
+  }
+  *d = dur;
+  return true;
+}
+
+bool AbslParseFlag(absl::string_view text, Duration* dst, std::string*) {
+  return ParseDuration(text, dst);
+}
+
+std::string AbslUnparseFlag(Duration d) { return FormatDuration(d); }
+bool ParseFlag(const std::string& text, Duration* dst, std::string* ) {
+  return ParseDuration(text, dst);
+}
+
+std::string UnparseFlag(Duration d) { return FormatDuration(d); }
+
+ABSL_NAMESPACE_END
+}  // namespace absl
diff --git a/src/absl/time/format.cc b/src/absl/time/format.cc
new file mode 100644 (file)
index 0000000..4005fb7
--- /dev/null
@@ -0,0 +1,160 @@
+// Copyright 2017 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <string.h>
+
+#include <cctype>
+#include <cstdint>
+
+#include "absl/strings/match.h"
+#include "absl/strings/string_view.h"
+#include "absl/time/internal/cctz/include/cctz/time_zone.h"
+#include "absl/time/time.h"
+
+namespace cctz = absl::time_internal::cctz;
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+
+ABSL_DLL extern const char RFC3339_full[] = "%Y-%m-%d%ET%H:%M:%E*S%Ez";
+ABSL_DLL extern const char RFC3339_sec[] = "%Y-%m-%d%ET%H:%M:%S%Ez";
+
+ABSL_DLL extern const char RFC1123_full[] = "%a, %d %b %E4Y %H:%M:%S %z";
+ABSL_DLL extern const char RFC1123_no_wday[] = "%d %b %E4Y %H:%M:%S %z";
+
+namespace {
+
+const char kInfiniteFutureStr[] = "infinite-future";
+const char kInfinitePastStr[] = "infinite-past";
+
+struct cctz_parts {
+  cctz::time_point<cctz::seconds> sec;
+  cctz::detail::femtoseconds fem;
+};
+
+inline cctz::time_point<cctz::seconds> unix_epoch() {
+  return std::chrono::time_point_cast<cctz::seconds>(
+      std::chrono::system_clock::from_time_t(0));
+}
+
+// Splits a Time into seconds and femtoseconds, which can be used with CCTZ.
+// Requires that 't' is finite. See duration.cc for details about rep_hi and
+// rep_lo.
+cctz_parts Split(absl::Time t) {
+  const auto d = time_internal::ToUnixDuration(t);
+  const int64_t rep_hi = time_internal::GetRepHi(d);
+  const int64_t rep_lo = time_internal::GetRepLo(d);
+  const auto sec = unix_epoch() + cctz::seconds(rep_hi);
+  const auto fem = cctz::detail::femtoseconds(rep_lo * (1000 * 1000 / 4));
+  return {sec, fem};
+}
+
+// Joins the given seconds and femtoseconds into a Time. See duration.cc for
+// details about rep_hi and rep_lo.
+absl::Time Join(const cctz_parts& parts) {
+  const int64_t rep_hi = (parts.sec - unix_epoch()).count();
+  const uint32_t rep_lo = parts.fem.count() / (1000 * 1000 / 4);
+  const auto d = time_internal::MakeDuration(rep_hi, rep_lo);
+  return time_internal::FromUnixDuration(d);
+}
+
+}  // namespace
+
+std::string FormatTime(absl::string_view format, absl::Time t,
+                       absl::TimeZone tz) {
+  if (t == absl::InfiniteFuture()) return std::string(kInfiniteFutureStr);
+  if (t == absl::InfinitePast()) return std::string(kInfinitePastStr);
+  const auto parts = Split(t);
+  return cctz::detail::format(std::string(format), parts.sec, parts.fem,
+                              cctz::time_zone(tz));
+}
+
+std::string FormatTime(absl::Time t, absl::TimeZone tz) {
+  return FormatTime(RFC3339_full, t, tz);
+}
+
+std::string FormatTime(absl::Time t) {
+  return absl::FormatTime(RFC3339_full, t, absl::LocalTimeZone());
+}
+
+bool ParseTime(absl::string_view format, absl::string_view input,
+               absl::Time* time, std::string* err) {
+  return absl::ParseTime(format, input, absl::UTCTimeZone(), time, err);
+}
+
+// If the input string does not contain an explicit UTC offset, interpret
+// the fields with respect to the given TimeZone.
+bool ParseTime(absl::string_view format, absl::string_view input,
+               absl::TimeZone tz, absl::Time* time, std::string* err) {
+  auto strip_leading_space = [](absl::string_view* sv) {
+    while (!sv->empty()) {
+      if (!std::isspace(sv->front())) return;
+      sv->remove_prefix(1);
+    }
+  };
+
+  // Portable toolchains means we don't get nice constexpr here.
+  struct Literal {
+    const char* name;
+    size_t size;
+    absl::Time value;
+  };
+  static Literal literals[] = {
+      {kInfiniteFutureStr, strlen(kInfiniteFutureStr), InfiniteFuture()},
+      {kInfinitePastStr, strlen(kInfinitePastStr), InfinitePast()},
+  };
+  strip_leading_space(&input);
+  for (const auto& lit : literals) {
+    if (absl::StartsWith(input, absl::string_view(lit.name, lit.size))) {
+      absl::string_view tail = input;
+      tail.remove_prefix(lit.size);
+      strip_leading_space(&tail);
+      if (tail.empty()) {
+        *time = lit.value;
+        return true;
+      }
+    }
+  }
+
+  std::string error;
+  cctz_parts parts;
+  const bool b =
+      cctz::detail::parse(std::string(format), std::string(input),
+                          cctz::time_zone(tz), &parts.sec, &parts.fem, &error);
+  if (b) {
+    *time = Join(parts);
+  } else if (err != nullptr) {
+    *err = error;
+  }
+  return b;
+}
+
+// Functions required to support absl::Time flags.
+bool AbslParseFlag(absl::string_view text, absl::Time* t, std::string* error) {
+  return absl::ParseTime(RFC3339_full, text, absl::UTCTimeZone(), t, error);
+}
+
+std::string AbslUnparseFlag(absl::Time t) {
+  return absl::FormatTime(RFC3339_full, t, absl::UTCTimeZone());
+}
+bool ParseFlag(const std::string& text, absl::Time* t, std::string* error) {
+  return absl::ParseTime(RFC3339_full, text, absl::UTCTimeZone(), t, error);
+}
+
+std::string UnparseFlag(absl::Time t) {
+  return absl::FormatTime(RFC3339_full, t, absl::UTCTimeZone());
+}
+
+ABSL_NAMESPACE_END
+}  // namespace absl
diff --git a/src/absl/time/internal/cctz/include/cctz/civil_time.h b/src/absl/time/internal/cctz/include/cctz/civil_time.h
new file mode 100644 (file)
index 0000000..d47ff86
--- /dev/null
@@ -0,0 +1,332 @@
+// Copyright 2016 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//   https://www.apache.org/licenses/LICENSE-2.0
+//
+//   Unless required by applicable law or agreed to in writing, software
+//   distributed under the License is distributed on an "AS IS" BASIS,
+//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//   See the License for the specific language governing permissions and
+//   limitations under the License.
+
+#ifndef ABSL_TIME_INTERNAL_CCTZ_CIVIL_TIME_H_
+#define ABSL_TIME_INTERNAL_CCTZ_CIVIL_TIME_H_
+
+#include "absl/base/config.h"
+#include "absl/time/internal/cctz/include/cctz/civil_time_detail.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace time_internal {
+namespace cctz {
+
+// The term "civil time" refers to the legally recognized human-scale time
+// that is represented by the six fields YYYY-MM-DD hh:mm:ss. Modern-day civil
+// time follows the Gregorian Calendar and is a time-zone-independent concept.
+// A "date" is perhaps the most common example of a civil time (represented in
+// this library as cctz::civil_day). This library provides six classes and a
+// handful of functions that help with rounding, iterating, and arithmetic on
+// civil times while avoiding complications like daylight-saving time (DST).
+//
+// The following six classes form the core of this civil-time library:
+//
+//   * civil_second
+//   * civil_minute
+//   * civil_hour
+//   * civil_day
+//   * civil_month
+//   * civil_year
+//
+// Each class is a simple value type with the same interface for construction
+// and the same six accessors for each of the civil fields (year, month, day,
+// hour, minute, and second, aka YMDHMS). These classes differ only in their
+// alignment, which is indicated by the type name and specifies the field on
+// which arithmetic operates.
+//
+// Each class can be constructed by passing up to six optional integer
+// arguments representing the YMDHMS fields (in that order) to the
+// constructor. Omitted fields are assigned their minimum valid value. Hours,
+// minutes, and seconds will be set to 0, month and day will be set to 1, and
+// since there is no minimum valid year, it will be set to 1970. So, a
+// default-constructed civil-time object will have YMDHMS fields representing
+// "1970-01-01 00:00:00". Fields that are out-of-range are normalized (e.g.,
+// October 32 -> November 1) so that all civil-time objects represent valid
+// values.
+//
+// Each civil-time class is aligned to the civil-time field indicated in the
+// class's name after normalization. Alignment is performed by setting all the
+// inferior fields to their minimum valid value (as described above). The
+// following are examples of how each of the six types would align the fields
+// representing November 22, 2015 at 12:34:56 in the afternoon. (Note: the
+// string format used here is not important; it's just a shorthand way of
+// showing the six YMDHMS fields.)
+//
+//   civil_second  2015-11-22 12:34:56
+//   civil_minute  2015-11-22 12:34:00
+//   civil_hour    2015-11-22 12:00:00
+//   civil_day     2015-11-22 00:00:00
+//   civil_month   2015-11-01 00:00:00
+//   civil_year    2015-01-01 00:00:00
+//
+// Each civil-time type performs arithmetic on the field to which it is
+// aligned. This means that adding 1 to a civil_day increments the day field
+// (normalizing as necessary), and subtracting 7 from a civil_month operates
+// on the month field (normalizing as necessary). All arithmetic produces a
+// valid civil time. Difference requires two similarly aligned civil-time
+// objects and returns the scalar answer in units of the objects' alignment.
+// For example, the difference between two civil_hour objects will give an
+// answer in units of civil hours.
+//
+// In addition to the six civil-time types just described, there are
+// a handful of helper functions and algorithms for performing common
+// calculations. These are described below.
+//
+// Note: In C++14 and later, this library is usable in a constexpr context.
+//
+// CONSTRUCTION:
+//
+// Each of the civil-time types can be constructed in two ways: by directly
+// passing to the constructor up to six (optional) integers representing the
+// YMDHMS fields, or by copying the YMDHMS fields from a differently aligned
+// civil-time type.
+//
+//   civil_day default_value;  // 1970-01-01 00:00:00
+//
+//   civil_day a(2015, 2, 3);           // 2015-02-03 00:00:00
+//   civil_day b(2015, 2, 3, 4, 5, 6);  // 2015-02-03 00:00:00
+//   civil_day c(2015);                 // 2015-01-01 00:00:00
+//
+//   civil_second ss(2015, 2, 3, 4, 5, 6);  // 2015-02-03 04:05:06
+//   civil_minute mm(ss);                   // 2015-02-03 04:05:00
+//   civil_hour hh(mm);                     // 2015-02-03 04:00:00
+//   civil_day d(hh);                       // 2015-02-03 00:00:00
+//   civil_month m(d);                      // 2015-02-01 00:00:00
+//   civil_year y(m);                       // 2015-01-01 00:00:00
+//
+//   m = civil_month(y);     // 2015-01-01 00:00:00
+//   d = civil_day(m);       // 2015-01-01 00:00:00
+//   hh = civil_hour(d);     // 2015-01-01 00:00:00
+//   mm = civil_minute(hh);  // 2015-01-01 00:00:00
+//   ss = civil_second(mm);  // 2015-01-01 00:00:00
+//
+// ALIGNMENT CONVERSION:
+//
+// The alignment of a civil-time object cannot change, but the object may be
+// used to construct a new object with a different alignment. This is referred
+// to as "realigning". When realigning to a type with the same or more
+// precision (e.g., civil_day -> civil_second), the conversion may be
+// performed implicitly since no information is lost. However, if information
+// could be discarded (e.g., civil_second -> civil_day), the conversion must
+// be explicit at the call site.
+//
+//   void fun(const civil_day& day);
+//
+//   civil_second cs;
+//   fun(cs);  // Won't compile because data may be discarded
+//   fun(civil_day(cs));  // OK: explicit conversion
+//
+//   civil_day cd;
+//   fun(cd);  // OK: no conversion needed
+//
+//   civil_month cm;
+//   fun(cm);  // OK: implicit conversion to civil_day
+//
+// NORMALIZATION:
+//
+// Integer arguments passed to the constructor may be out-of-range, in which
+// case they are normalized to produce a valid civil-time object. This enables
+// natural arithmetic on constructor arguments without worrying about the
+// field's range. Normalization guarantees that there are no invalid
+// civil-time objects.
+//
+//   civil_day d(2016, 10, 32);  // Out-of-range day; normalized to 2016-11-01
+//
+// Note: If normalization is undesired, you can signal an error by comparing
+// the constructor arguments to the normalized values returned by the YMDHMS
+// properties.
+//
+// PROPERTIES:
+//
+// All civil-time types have accessors for all six of the civil-time fields:
+// year, month, day, hour, minute, and second. Recall that fields inferior to
+// the type's alignment will be set to their minimum valid value.
+//
+//   civil_day d(2015, 6, 28);
+//   // d.year() == 2015
+//   // d.month() == 6
+//   // d.day() == 28
+//   // d.hour() == 0
+//   // d.minute() == 0
+//   // d.second() == 0
+//
+// COMPARISON:
+//
+// Comparison always considers all six YMDHMS fields, regardless of the type's
+// alignment. Comparison between differently aligned civil-time types is
+// allowed.
+//
+//   civil_day feb_3(2015, 2, 3);  // 2015-02-03 00:00:00
+//   civil_day mar_4(2015, 3, 4);  // 2015-03-04 00:00:00
+//   // feb_3 < mar_4
+//   // civil_year(feb_3) == civil_year(mar_4)
+//
+//   civil_second feb_3_noon(2015, 2, 3, 12, 0, 0);  // 2015-02-03 12:00:00
+//   // feb_3 < feb_3_noon
+//   // feb_3 == civil_day(feb_3_noon)
+//
+//   // Iterates all the days of February 2015.
+//   for (civil_day d(2015, 2, 1); d < civil_month(2015, 3); ++d) {
+//     // ...
+//   }
+//
+// STREAMING:
+//
+// Each civil-time type may be sent to an output stream using operator<<().
+// The output format follows the pattern "YYYY-MM-DDThh:mm:ss" where fields
+// inferior to the type's alignment are omitted.
+//
+//   civil_second cs(2015, 2, 3, 4, 5, 6);
+//   std::cout << cs << "\n";  // Outputs: 2015-02-03T04:05:06
+//
+//   civil_day cd(cs);
+//   std::cout << cd << "\n";  // Outputs: 2015-02-03
+//
+//   civil_year cy(cs);
+//   std::cout << cy << "\n";  // Outputs: 2015
+//
+// ARITHMETIC:
+//
+// Civil-time types support natural arithmetic operators such as addition,
+// subtraction, and difference. Arithmetic operates on the civil-time field
+// indicated in the type's name. Difference requires arguments with the same
+// alignment and returns the answer in units of the alignment.
+//
+//   civil_day a(2015, 2, 3);
+//   ++a;                         // 2015-02-04 00:00:00
+//   --a;                         // 2015-02-03 00:00:00
+//   civil_day b = a + 1;         // 2015-02-04 00:00:00
+//   civil_day c = 1 + b;         // 2015-02-05 00:00:00
+//   int n = c - a;               // n = 2 (civil days)
+//   int m = c - civil_month(c);  // Won't compile: different types.
+//
+// EXAMPLE: Adding a month to January 31.
+//
+// One of the classic questions that arises when considering a civil-time
+// library (or a date library or a date/time library) is this: "What happens
+// when you add a month to January 31?" This is an interesting question
+// because there could be a number of possible answers:
+//
+//   1. March 3 (or 2 if a leap year). This may make sense if the operation
+//      wants the equivalent of February 31.
+//   2. February 28 (or 29 if a leap year). This may make sense if the operation
+//      wants the last day of January to go to the last day of February.
+//   3. Error. The caller may get some error, an exception, an invalid date
+//      object, or maybe false is returned. This may make sense because there is
+//      no single unambiguously correct answer to the question.
+//
+// Practically speaking, any answer that is not what the programmer intended
+// is the wrong answer.
+//
+// This civil-time library avoids the problem by making it impossible to ask
+// ambiguous questions. All civil-time objects are aligned to a particular
+// civil-field boundary (such as aligned to a year, month, day, hour, minute,
+// or second), and arithmetic operates on the field to which the object is
+// aligned. This means that in order to "add a month" the object must first be
+// aligned to a month boundary, which is equivalent to the first day of that
+// month.
+//
+// Of course, there are ways to compute an answer the question at hand using
+// this civil-time library, but they require the programmer to be explicit
+// about the answer they expect. To illustrate, let's see how to compute all
+// three of the above possible answers to the question of "Jan 31 plus 1
+// month":
+//
+//   const civil_day d(2015, 1, 31);
+//
+//   // Answer 1:
+//   // Add 1 to the month field in the constructor, and rely on normalization.
+//   const auto ans_normalized = civil_day(d.year(), d.month() + 1, d.day());
+//   // ans_normalized == 2015-03-03 (aka Feb 31)
+//
+//   // Answer 2:
+//   // Add 1 to month field, capping to the end of next month.
+//   const auto next_month = civil_month(d) + 1;
+//   const auto last_day_of_next_month = civil_day(next_month + 1) - 1;
+//   const auto ans_capped = std::min(ans_normalized, last_day_of_next_month);
+//   // ans_capped == 2015-02-28
+//
+//   // Answer 3:
+//   // Signal an error if the normalized answer is not in next month.
+//   if (civil_month(ans_normalized) != next_month) {
+//     // error, month overflow
+//   }
+//
+using civil_year = detail::civil_year;
+using civil_month = detail::civil_month;
+using civil_day = detail::civil_day;
+using civil_hour = detail::civil_hour;
+using civil_minute = detail::civil_minute;
+using civil_second = detail::civil_second;
+
+// An enum class with members monday, tuesday, wednesday, thursday, friday,
+// saturday, and sunday. These enum values may be sent to an output stream
+// using operator<<(). The result is the full weekday name in English with a
+// leading capital letter.
+//
+//   weekday wd = weekday::thursday;
+//   std::cout << wd << "\n";  // Outputs: Thursday
+//
+using detail::weekday;
+
+// Returns the weekday for the given civil-time value.
+//
+//   civil_day a(2015, 8, 13);
+//   weekday wd = get_weekday(a);  // wd == weekday::thursday
+//
+using detail::get_weekday;
+
+// Returns the civil_day that strictly follows or precedes the given
+// civil_day, and that falls on the given weekday.
+//
+// For example, given:
+//
+//     August 2015
+// Su Mo Tu We Th Fr Sa
+//                    1
+//  2  3  4  5  6  7  8
+//  9 10 11 12 13 14 15
+// 16 17 18 19 20 21 22
+// 23 24 25 26 27 28 29
+// 30 31
+//
+//   civil_day a(2015, 8, 13);  // get_weekday(a) == weekday::thursday
+//   civil_day b = next_weekday(a, weekday::thursday);  // b = 2015-08-20
+//   civil_day c = prev_weekday(a, weekday::thursday);  // c = 2015-08-06
+//
+//   civil_day d = ...
+//   // Gets the following Thursday if d is not already Thursday
+//   civil_day thurs1 = next_weekday(d - 1, weekday::thursday);
+//   // Gets the previous Thursday if d is not already Thursday
+//   civil_day thurs2 = prev_weekday(d + 1, weekday::thursday);
+//
+using detail::next_weekday;
+using detail::prev_weekday;
+
+// Returns the day-of-year for the given civil-time value.
+//
+//   civil_day a(2015, 1, 1);
+//   int yd_jan_1 = get_yearday(a);   // yd_jan_1 = 1
+//   civil_day b(2015, 12, 31);
+//   int yd_dec_31 = get_yearday(b);  // yd_dec_31 = 365
+//
+using detail::get_yearday;
+
+}  // namespace cctz
+}  // namespace time_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#endif  // ABSL_TIME_INTERNAL_CCTZ_CIVIL_TIME_H_
diff --git a/src/absl/time/internal/cctz/include/cctz/civil_time_detail.h b/src/absl/time/internal/cctz/include/cctz/civil_time_detail.h
new file mode 100644 (file)
index 0000000..8aadde5
--- /dev/null
@@ -0,0 +1,628 @@
+// Copyright 2016 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//   https://www.apache.org/licenses/LICENSE-2.0
+//
+//   Unless required by applicable law or agreed to in writing, software
+//   distributed under the License is distributed on an "AS IS" BASIS,
+//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//   See the License for the specific language governing permissions and
+//   limitations under the License.
+
+#ifndef ABSL_TIME_INTERNAL_CCTZ_CIVIL_TIME_DETAIL_H_
+#define ABSL_TIME_INTERNAL_CCTZ_CIVIL_TIME_DETAIL_H_
+
+#include <cstdint>
+#include <limits>
+#include <ostream>
+#include <type_traits>
+
+#include "absl/base/config.h"
+
+// Disable constexpr support unless we are in C++14 mode.
+#if __cpp_constexpr >= 201304 || (defined(_MSC_VER) && _MSC_VER >= 1910)
+#define CONSTEXPR_D constexpr  // data
+#define CONSTEXPR_F constexpr  // function
+#define CONSTEXPR_M constexpr  // member
+#else
+#define CONSTEXPR_D const
+#define CONSTEXPR_F inline
+#define CONSTEXPR_M
+#endif
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace time_internal {
+namespace cctz {
+
+// Support years that at least span the range of 64-bit time_t values.
+using year_t = std::int_fast64_t;
+
+// Type alias that indicates an argument is not normalized (e.g., the
+// constructor parameters and operands/results of addition/subtraction).
+using diff_t = std::int_fast64_t;
+
+namespace detail {
+
+// Type aliases that indicate normalized argument values.
+using month_t = std::int_fast8_t;   // [1:12]
+using day_t = std::int_fast8_t;     // [1:31]
+using hour_t = std::int_fast8_t;    // [0:23]
+using minute_t = std::int_fast8_t;  // [0:59]
+using second_t = std::int_fast8_t;  // [0:59]
+
+// Normalized civil-time fields: Y-M-D HH:MM:SS.
+struct fields {
+  CONSTEXPR_M fields(year_t year, month_t month, day_t day, hour_t hour,
+                     minute_t minute, second_t second)
+      : y(year), m(month), d(day), hh(hour), mm(minute), ss(second) {}
+  std::int_least64_t y;
+  std::int_least8_t m;
+  std::int_least8_t d;
+  std::int_least8_t hh;
+  std::int_least8_t mm;
+  std::int_least8_t ss;
+};
+
+struct second_tag {};
+struct minute_tag : second_tag {};
+struct hour_tag : minute_tag {};
+struct day_tag : hour_tag {};
+struct month_tag : day_tag {};
+struct year_tag : month_tag {};
+
+////////////////////////////////////////////////////////////////////////
+
+// Field normalization (without avoidable overflow).
+
+namespace impl {
+
+CONSTEXPR_F bool is_leap_year(year_t y) noexcept {
+  return y % 4 == 0 && (y % 100 != 0 || y % 400 == 0);
+}
+CONSTEXPR_F int year_index(year_t y, month_t m) noexcept {
+  return (static_cast<int>((y + (m > 2)) % 400) + 400) % 400;
+}
+CONSTEXPR_F int days_per_century(year_t y, month_t m) noexcept {
+  const int yi = year_index(y, m);
+  return 36524 + (yi == 0 || yi > 300);
+}
+CONSTEXPR_F int days_per_4years(year_t y, month_t m) noexcept {
+  const int yi = year_index(y, m);
+  return 1460 + (yi == 0 || yi > 300 || (yi - 1) % 100 < 96);
+}
+CONSTEXPR_F int days_per_year(year_t y, month_t m) noexcept {
+  return is_leap_year(y + (m > 2)) ? 366 : 365;
+}
+CONSTEXPR_F int days_per_month(year_t y, month_t m) noexcept {
+  CONSTEXPR_D int k_days_per_month[1 + 12] = {
+      -1, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31  // non leap year
+  };
+  return k_days_per_month[m] + (m == 2 && is_leap_year(y));
+}
+
+CONSTEXPR_F fields n_day(year_t y, month_t m, diff_t d, diff_t cd, hour_t hh,
+                         minute_t mm, second_t ss) noexcept {
+  year_t ey = y % 400;
+  const year_t oey = ey;
+  ey += (cd / 146097) * 400;
+  cd %= 146097;
+  if (cd < 0) {
+    ey -= 400;
+    cd += 146097;
+  }
+  ey += (d / 146097) * 400;
+  d = d % 146097 + cd;
+  if (d > 0) {
+    if (d > 146097) {
+      ey += 400;
+      d -= 146097;
+    }
+  } else {
+    if (d > -365) {
+      // We often hit the previous year when stepping a civil time backwards,
+      // so special case it to avoid counting up by 100/4/1-year chunks.
+      ey -= 1;
+      d += days_per_year(ey, m);
+    } else {
+      ey -= 400;
+      d += 146097;
+    }
+  }
+  if (d > 365) {
+    for (;;) {
+      int n = days_per_century(ey, m);
+      if (d <= n) break;
+      d -= n;
+      ey += 100;
+    }
+    for (;;) {
+      int n = days_per_4years(ey, m);
+      if (d <= n) break;
+      d -= n;
+      ey += 4;
+    }
+    for (;;) {
+      int n = days_per_year(ey, m);
+      if (d <= n) break;
+      d -= n;
+      ++ey;
+    }
+  }
+  if (d > 28) {
+    for (;;) {
+      int n = days_per_month(ey, m);
+      if (d <= n) break;
+      d -= n;
+      if (++m > 12) {
+        ++ey;
+        m = 1;
+      }
+    }
+  }
+  return fields(y + (ey - oey), m, static_cast<day_t>(d), hh, mm, ss);
+}
+CONSTEXPR_F fields n_mon(year_t y, diff_t m, diff_t d, diff_t cd, hour_t hh,
+                         minute_t mm, second_t ss) noexcept {
+  if (m != 12) {
+    y += m / 12;
+    m %= 12;
+    if (m <= 0) {
+      y -= 1;
+      m += 12;
+    }
+  }
+  return n_day(y, static_cast<month_t>(m), d, cd, hh, mm, ss);
+}
+CONSTEXPR_F fields n_hour(year_t y, diff_t m, diff_t d, diff_t cd, diff_t hh,
+                          minute_t mm, second_t ss) noexcept {
+  cd += hh / 24;
+  hh %= 24;
+  if (hh < 0) {
+    cd -= 1;
+    hh += 24;
+  }
+  return n_mon(y, m, d, cd, static_cast<hour_t>(hh), mm, ss);
+}
+CONSTEXPR_F fields n_min(year_t y, diff_t m, diff_t d, diff_t hh, diff_t ch,
+                         diff_t mm, second_t ss) noexcept {
+  ch += mm / 60;
+  mm %= 60;
+  if (mm < 0) {
+    ch -= 1;
+    mm += 60;
+  }
+  return n_hour(y, m, d, hh / 24 + ch / 24, hh % 24 + ch % 24,
+                static_cast<minute_t>(mm), ss);
+}
+CONSTEXPR_F fields n_sec(year_t y, diff_t m, diff_t d, diff_t hh, diff_t mm,
+                         diff_t ss) noexcept {
+  // Optimization for when (non-constexpr) fields are already normalized.
+  if (0 <= ss && ss < 60) {
+    const second_t nss = static_cast<second_t>(ss);
+    if (0 <= mm && mm < 60) {
+      const minute_t nmm = static_cast<minute_t>(mm);
+      if (0 <= hh && hh < 24) {
+        const hour_t nhh = static_cast<hour_t>(hh);
+        if (1 <= d && d <= 28 && 1 <= m && m <= 12) {
+          const day_t nd = static_cast<day_t>(d);
+          const month_t nm = static_cast<month_t>(m);
+          return fields(y, nm, nd, nhh, nmm, nss);
+        }
+        return n_mon(y, m, d, 0, nhh, nmm, nss);
+      }
+      return n_hour(y, m, d, hh / 24, hh % 24, nmm, nss);
+    }
+    return n_min(y, m, d, hh, mm / 60, mm % 60, nss);
+  }
+  diff_t cm = ss / 60;
+  ss %= 60;
+  if (ss < 0) {
+    cm -= 1;
+    ss += 60;
+  }
+  return n_min(y, m, d, hh, mm / 60 + cm / 60, mm % 60 + cm % 60,
+               static_cast<second_t>(ss));
+}
+
+}  // namespace impl
+
+////////////////////////////////////////////////////////////////////////
+
+// Increments the indicated (normalized) field by "n".
+CONSTEXPR_F fields step(second_tag, fields f, diff_t n) noexcept {
+  return impl::n_sec(f.y, f.m, f.d, f.hh, f.mm + n / 60, f.ss + n % 60);
+}
+CONSTEXPR_F fields step(minute_tag, fields f, diff_t n) noexcept {
+  return impl::n_min(f.y, f.m, f.d, f.hh + n / 60, 0, f.mm + n % 60, f.ss);
+}
+CONSTEXPR_F fields step(hour_tag, fields f, diff_t n) noexcept {
+  return impl::n_hour(f.y, f.m, f.d + n / 24, 0, f.hh + n % 24, f.mm, f.ss);
+}
+CONSTEXPR_F fields step(day_tag, fields f, diff_t n) noexcept {
+  return impl::n_day(f.y, f.m, f.d, n, f.hh, f.mm, f.ss);
+}
+CONSTEXPR_F fields step(month_tag, fields f, diff_t n) noexcept {
+  return impl::n_mon(f.y + n / 12, f.m + n % 12, f.d, 0, f.hh, f.mm, f.ss);
+}
+CONSTEXPR_F fields step(year_tag, fields f, diff_t n) noexcept {
+  return fields(f.y + n, f.m, f.d, f.hh, f.mm, f.ss);
+}
+
+////////////////////////////////////////////////////////////////////////
+
+namespace impl {
+
+// Returns (v * f + a) but avoiding intermediate overflow when possible.
+CONSTEXPR_F diff_t scale_add(diff_t v, diff_t f, diff_t a) noexcept {
+  return (v < 0) ? ((v + 1) * f + a) - f : ((v - 1) * f + a) + f;
+}
+
+// Map a (normalized) Y/M/D to the number of days before/after 1970-01-01.
+// Probably overflows for years outside [-292277022656:292277026595].
+CONSTEXPR_F diff_t ymd_ord(year_t y, month_t m, day_t d) noexcept {
+  const diff_t eyear = (m <= 2) ? y - 1 : y;
+  const diff_t era = (eyear >= 0 ? eyear : eyear - 399) / 400;
+  const diff_t yoe = eyear - era * 400;
+  const diff_t doy = (153 * (m + (m > 2 ? -3 : 9)) + 2) / 5 + d - 1;
+  const diff_t doe = yoe * 365 + yoe / 4 - yoe / 100 + doy;
+  return era * 146097 + doe - 719468;
+}
+
+// Returns the difference in days between two normalized Y-M-D tuples.
+// ymd_ord() will encounter integer overflow given extreme year values,
+// yet the difference between two such extreme values may actually be
+// small, so we take a little care to avoid overflow when possible by
+// exploiting the 146097-day cycle.
+CONSTEXPR_F diff_t day_difference(year_t y1, month_t m1, day_t d1, year_t y2,
+                                  month_t m2, day_t d2) noexcept {
+  const diff_t a_c4_off = y1 % 400;
+  const diff_t b_c4_off = y2 % 400;
+  diff_t c4_diff = (y1 - a_c4_off) - (y2 - b_c4_off);
+  diff_t delta = ymd_ord(a_c4_off, m1, d1) - ymd_ord(b_c4_off, m2, d2);
+  if (c4_diff > 0 && delta < 0) {
+    delta += 2 * 146097;
+    c4_diff -= 2 * 400;
+  } else if (c4_diff < 0 && delta > 0) {
+    delta -= 2 * 146097;
+    c4_diff += 2 * 400;
+  }
+  return (c4_diff / 400 * 146097) + delta;
+}
+
+}  // namespace impl
+
+// Returns the difference between fields structs using the indicated unit.
+CONSTEXPR_F diff_t difference(year_tag, fields f1, fields f2) noexcept {
+  return f1.y - f2.y;
+}
+CONSTEXPR_F diff_t difference(month_tag, fields f1, fields f2) noexcept {
+  return impl::scale_add(difference(year_tag{}, f1, f2), 12, (f1.m - f2.m));
+}
+CONSTEXPR_F diff_t difference(day_tag, fields f1, fields f2) noexcept {
+  return impl::day_difference(f1.y, f1.m, f1.d, f2.y, f2.m, f2.d);
+}
+CONSTEXPR_F diff_t difference(hour_tag, fields f1, fields f2) noexcept {
+  return impl::scale_add(difference(day_tag{}, f1, f2), 24, (f1.hh - f2.hh));
+}
+CONSTEXPR_F diff_t difference(minute_tag, fields f1, fields f2) noexcept {
+  return impl::scale_add(difference(hour_tag{}, f1, f2), 60, (f1.mm - f2.mm));
+}
+CONSTEXPR_F diff_t difference(second_tag, fields f1, fields f2) noexcept {
+  return impl::scale_add(difference(minute_tag{}, f1, f2), 60, f1.ss - f2.ss);
+}
+
+////////////////////////////////////////////////////////////////////////
+
+// Aligns the (normalized) fields struct to the indicated field.
+CONSTEXPR_F fields align(second_tag, fields f) noexcept { return f; }
+CONSTEXPR_F fields align(minute_tag, fields f) noexcept {
+  return fields{f.y, f.m, f.d, f.hh, f.mm, 0};
+}
+CONSTEXPR_F fields align(hour_tag, fields f) noexcept {
+  return fields{f.y, f.m, f.d, f.hh, 0, 0};
+}
+CONSTEXPR_F fields align(day_tag, fields f) noexcept {
+  return fields{f.y, f.m, f.d, 0, 0, 0};
+}
+CONSTEXPR_F fields align(month_tag, fields f) noexcept {
+  return fields{f.y, f.m, 1, 0, 0, 0};
+}
+CONSTEXPR_F fields align(year_tag, fields f) noexcept {
+  return fields{f.y, 1, 1, 0, 0, 0};
+}
+
+////////////////////////////////////////////////////////////////////////
+
+namespace impl {
+
+template <typename H>
+H AbslHashValueImpl(second_tag, H h, fields f) {
+  return H::combine(std::move(h), f.y, f.m, f.d, f.hh, f.mm, f.ss);
+}
+template <typename H>
+H AbslHashValueImpl(minute_tag, H h, fields f) {
+  return H::combine(std::move(h), f.y, f.m, f.d, f.hh, f.mm);
+}
+template <typename H>
+H AbslHashValueImpl(hour_tag, H h, fields f) {
+  return H::combine(std::move(h), f.y, f.m, f.d, f.hh);
+}
+template <typename H>
+H AbslHashValueImpl(day_tag, H h, fields f) {
+  return H::combine(std::move(h), f.y, f.m, f.d);
+}
+template <typename H>
+H AbslHashValueImpl(month_tag, H h, fields f) {
+  return H::combine(std::move(h), f.y, f.m);
+}
+template <typename H>
+H AbslHashValueImpl(year_tag, H h, fields f) {
+  return H::combine(std::move(h), f.y);
+}
+
+}  // namespace impl
+
+////////////////////////////////////////////////////////////////////////
+
+template <typename T>
+class civil_time {
+ public:
+  explicit CONSTEXPR_M civil_time(year_t y, diff_t m = 1, diff_t d = 1,
+                                  diff_t hh = 0, diff_t mm = 0,
+                                  diff_t ss = 0) noexcept
+      : civil_time(impl::n_sec(y, m, d, hh, mm, ss)) {}
+
+  CONSTEXPR_M civil_time() noexcept : f_{1970, 1, 1, 0, 0, 0} {}
+  civil_time(const civil_time&) = default;
+  civil_time& operator=(const civil_time&) = default;
+
+  // Conversion between civil times of different alignment. Conversion to
+  // a more precise alignment is allowed implicitly (e.g., day -> hour),
+  // but conversion where information is discarded must be explicit
+  // (e.g., second -> minute).
+  template <typename U, typename S>
+  using preserves_data =
+      typename std::enable_if<std::is_base_of<U, S>::value>::type;
+  template <typename U>
+  CONSTEXPR_M civil_time(const civil_time<U>& ct,
+                         preserves_data<T, U>* = nullptr) noexcept
+      : civil_time(ct.f_) {}
+  template <typename U>
+  explicit CONSTEXPR_M civil_time(const civil_time<U>& ct,
+                                  preserves_data<U, T>* = nullptr) noexcept
+      : civil_time(ct.f_) {}
+
+  // Factories for the maximum/minimum representable civil_time.
+  static CONSTEXPR_F civil_time(max)() {
+    const auto max_year = (std::numeric_limits<std::int_least64_t>::max)();
+    return civil_time(max_year, 12, 31, 23, 59, 59);
+  }
+  static CONSTEXPR_F civil_time(min)() {
+    const auto min_year = (std::numeric_limits<std::int_least64_t>::min)();
+    return civil_time(min_year, 1, 1, 0, 0, 0);
+  }
+
+  // Field accessors.  Note: All but year() return an int.
+  CONSTEXPR_M year_t year() const noexcept { return f_.y; }
+  CONSTEXPR_M int month() const noexcept { return f_.m; }
+  CONSTEXPR_M int day() const noexcept { return f_.d; }
+  CONSTEXPR_M int hour() const noexcept { return f_.hh; }
+  CONSTEXPR_M int minute() const noexcept { return f_.mm; }
+  CONSTEXPR_M int second() const noexcept { return f_.ss; }
+
+  // Assigning arithmetic.
+  CONSTEXPR_M civil_time& operator+=(diff_t n) noexcept {
+    return *this = *this + n;
+  }
+  CONSTEXPR_M civil_time& operator-=(diff_t n) noexcept {
+    return *this = *this - n;
+  }
+  CONSTEXPR_M civil_time& operator++() noexcept { return *this += 1; }
+  CONSTEXPR_M civil_time operator++(int) noexcept {
+    const civil_time a = *this;
+    ++*this;
+    return a;
+  }
+  CONSTEXPR_M civil_time& operator--() noexcept { return *this -= 1; }
+  CONSTEXPR_M civil_time operator--(int) noexcept {
+    const civil_time a = *this;
+    --*this;
+    return a;
+  }
+
+  // Binary arithmetic operators.
+  friend CONSTEXPR_F civil_time operator+(civil_time a, diff_t n) noexcept {
+    return civil_time(step(T{}, a.f_, n));
+  }
+  friend CONSTEXPR_F civil_time operator+(diff_t n, civil_time a) noexcept {
+    return a + n;
+  }
+  friend CONSTEXPR_F civil_time operator-(civil_time a, diff_t n) noexcept {
+    return n != (std::numeric_limits<diff_t>::min)()
+               ? civil_time(step(T{}, a.f_, -n))
+               : civil_time(step(T{}, step(T{}, a.f_, -(n + 1)), 1));
+  }
+  friend CONSTEXPR_F diff_t operator-(civil_time lhs, civil_time rhs) noexcept {
+    return difference(T{}, lhs.f_, rhs.f_);
+  }
+
+  template <typename H>
+  friend H AbslHashValue(H h, civil_time a) {
+    return impl::AbslHashValueImpl(T{}, std::move(h), a.f_);
+  }
+
+ private:
+  // All instantiations of this template are allowed to call the following
+  // private constructor and access the private fields member.
+  template <typename U>
+  friend class civil_time;
+
+  // The designated constructor that all others eventually call.
+  explicit CONSTEXPR_M civil_time(fields f) noexcept : f_(align(T{}, f)) {}
+
+  fields f_;
+};
+
+// Disallows difference between differently aligned types.
+// auto n = civil_day(...) - civil_hour(...);  // would be confusing.
+template <typename T, typename U>
+CONSTEXPR_F diff_t operator-(civil_time<T>, civil_time<U>) = delete;
+
+using civil_year = civil_time<year_tag>;
+using civil_month = civil_time<month_tag>;
+using civil_day = civil_time<day_tag>;
+using civil_hour = civil_time<hour_tag>;
+using civil_minute = civil_time<minute_tag>;
+using civil_second = civil_time<second_tag>;
+
+////////////////////////////////////////////////////////////////////////
+
+// Relational operators that work with differently aligned objects.
+// Always compares all six fields.
+template <typename T1, typename T2>
+CONSTEXPR_F bool operator<(const civil_time<T1>& lhs,
+                           const civil_time<T2>& rhs) noexcept {
+  return (
+      lhs.year() < rhs.year() ||
+      (lhs.year() == rhs.year() &&
+       (lhs.month() < rhs.month() ||
+        (lhs.month() == rhs.month() &&
+         (lhs.day() < rhs.day() || (lhs.day() == rhs.day() &&
+                                    (lhs.hour() < rhs.hour() ||
+                                     (lhs.hour() == rhs.hour() &&
+                                      (lhs.minute() < rhs.minute() ||
+                                       (lhs.minute() == rhs.minute() &&
+                                        (lhs.second() < rhs.second())))))))))));
+}
+template <typename T1, typename T2>
+CONSTEXPR_F bool operator<=(const civil_time<T1>& lhs,
+                            const civil_time<T2>& rhs) noexcept {
+  return !(rhs < lhs);
+}
+template <typename T1, typename T2>
+CONSTEXPR_F bool operator>=(const civil_time<T1>& lhs,
+                            const civil_time<T2>& rhs) noexcept {
+  return !(lhs < rhs);
+}
+template <typename T1, typename T2>
+CONSTEXPR_F bool operator>(const civil_time<T1>& lhs,
+                           const civil_time<T2>& rhs) noexcept {
+  return rhs < lhs;
+}
+template <typename T1, typename T2>
+CONSTEXPR_F bool operator==(const civil_time<T1>& lhs,
+                            const civil_time<T2>& rhs) noexcept {
+  return lhs.year() == rhs.year() && lhs.month() == rhs.month() &&
+         lhs.day() == rhs.day() && lhs.hour() == rhs.hour() &&
+         lhs.minute() == rhs.minute() && lhs.second() == rhs.second();
+}
+template <typename T1, typename T2>
+CONSTEXPR_F bool operator!=(const civil_time<T1>& lhs,
+                            const civil_time<T2>& rhs) noexcept {
+  return !(lhs == rhs);
+}
+
+////////////////////////////////////////////////////////////////////////
+
+enum class weekday {
+  monday,
+  tuesday,
+  wednesday,
+  thursday,
+  friday,
+  saturday,
+  sunday,
+};
+
+CONSTEXPR_F weekday get_weekday(const civil_second& cs) noexcept {
+  CONSTEXPR_D weekday k_weekday_by_mon_off[13] = {
+      weekday::monday,    weekday::tuesday,  weekday::wednesday,
+      weekday::thursday,  weekday::friday,   weekday::saturday,
+      weekday::sunday,    weekday::monday,   weekday::tuesday,
+      weekday::wednesday, weekday::thursday, weekday::friday,
+      weekday::saturday,
+  };
+  CONSTEXPR_D int k_weekday_offsets[1 + 12] = {
+      -1, 0, 3, 2, 5, 0, 3, 5, 1, 4, 6, 2, 4,
+  };
+  year_t wd = 2400 + (cs.year() % 400) - (cs.month() < 3);
+  wd += wd / 4 - wd / 100 + wd / 400;
+  wd += k_weekday_offsets[cs.month()] + cs.day();
+  return k_weekday_by_mon_off[wd % 7 + 6];
+}
+
+////////////////////////////////////////////////////////////////////////
+
+CONSTEXPR_F civil_day next_weekday(civil_day cd, weekday wd) noexcept {
+  CONSTEXPR_D weekday k_weekdays_forw[14] = {
+      weekday::monday,    weekday::tuesday,  weekday::wednesday,
+      weekday::thursday,  weekday::friday,   weekday::saturday,
+      weekday::sunday,    weekday::monday,   weekday::tuesday,
+      weekday::wednesday, weekday::thursday, weekday::friday,
+      weekday::saturday,  weekday::sunday,
+  };
+  weekday base = get_weekday(cd);
+  for (int i = 0;; ++i) {
+    if (base == k_weekdays_forw[i]) {
+      for (int j = i + 1;; ++j) {
+        if (wd == k_weekdays_forw[j]) {
+          return cd + (j - i);
+        }
+      }
+    }
+  }
+}
+
+CONSTEXPR_F civil_day prev_weekday(civil_day cd, weekday wd) noexcept {
+  CONSTEXPR_D weekday k_weekdays_back[14] = {
+      weekday::sunday,   weekday::saturday,  weekday::friday,
+      weekday::thursday, weekday::wednesday, weekday::tuesday,
+      weekday::monday,   weekday::sunday,    weekday::saturday,
+      weekday::friday,   weekday::thursday,  weekday::wednesday,
+      weekday::tuesday,  weekday::monday,
+  };
+  weekday base = get_weekday(cd);
+  for (int i = 0;; ++i) {
+    if (base == k_weekdays_back[i]) {
+      for (int j = i + 1;; ++j) {
+        if (wd == k_weekdays_back[j]) {
+          return cd - (j - i);
+        }
+      }
+    }
+  }
+}
+
+CONSTEXPR_F int get_yearday(const civil_second& cs) noexcept {
+  CONSTEXPR_D int k_month_offsets[1 + 12] = {
+      -1, 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334,
+  };
+  const int feb29 = (cs.month() > 2 && impl::is_leap_year(cs.year()));
+  return k_month_offsets[cs.month()] + feb29 + cs.day();
+}
+
+////////////////////////////////////////////////////////////////////////
+
+std::ostream& operator<<(std::ostream& os, const civil_year& y);
+std::ostream& operator<<(std::ostream& os, const civil_month& m);
+std::ostream& operator<<(std::ostream& os, const civil_day& d);
+std::ostream& operator<<(std::ostream& os, const civil_hour& h);
+std::ostream& operator<<(std::ostream& os, const civil_minute& m);
+std::ostream& operator<<(std::ostream& os, const civil_second& s);
+std::ostream& operator<<(std::ostream& os, weekday wd);
+
+}  // namespace detail
+}  // namespace cctz
+}  // namespace time_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#undef CONSTEXPR_M
+#undef CONSTEXPR_F
+#undef CONSTEXPR_D
+
+#endif  // ABSL_TIME_INTERNAL_CCTZ_CIVIL_TIME_DETAIL_H_
diff --git a/src/absl/time/internal/cctz/include/cctz/time_zone.h b/src/absl/time/internal/cctz/include/cctz/time_zone.h
new file mode 100644 (file)
index 0000000..5562a37
--- /dev/null
@@ -0,0 +1,386 @@
+// Copyright 2016 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//   https://www.apache.org/licenses/LICENSE-2.0
+//
+//   Unless required by applicable law or agreed to in writing, software
+//   distributed under the License is distributed on an "AS IS" BASIS,
+//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//   See the License for the specific language governing permissions and
+//   limitations under the License.
+
+// A library for translating between absolute times (represented by
+// std::chrono::time_points of the std::chrono::system_clock) and civil
+// times (represented by cctz::civil_second) using the rules defined by
+// a time zone (cctz::time_zone).
+
+#ifndef ABSL_TIME_INTERNAL_CCTZ_TIME_ZONE_H_
+#define ABSL_TIME_INTERNAL_CCTZ_TIME_ZONE_H_
+
+#include <chrono>
+#include <cstdint>
+#include <string>
+#include <utility>
+
+#include "absl/base/config.h"
+#include "absl/time/internal/cctz/include/cctz/civil_time.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace time_internal {
+namespace cctz {
+
+// Convenience aliases. Not intended as public API points.
+template <typename D>
+using time_point = std::chrono::time_point<std::chrono::system_clock, D>;
+using seconds = std::chrono::duration<std::int_fast64_t>;
+using sys_seconds = seconds;  // Deprecated.  Use cctz::seconds instead.
+
+namespace detail {
+template <typename D>
+inline std::pair<time_point<seconds>, D> split_seconds(
+    const time_point<D>& tp) {
+  auto sec = std::chrono::time_point_cast<seconds>(tp);
+  auto sub = tp - sec;
+  if (sub.count() < 0) {
+    sec -= seconds(1);
+    sub += seconds(1);
+  }
+  return {sec, std::chrono::duration_cast<D>(sub)};
+}
+inline std::pair<time_point<seconds>, seconds> split_seconds(
+    const time_point<seconds>& tp) {
+  return {tp, seconds::zero()};
+}
+}  // namespace detail
+
+// cctz::time_zone is an opaque, small, value-type class representing a
+// geo-political region within which particular rules are used for mapping
+// between absolute and civil times. Time zones are named using the TZ
+// identifiers from the IANA Time Zone Database, such as "America/Los_Angeles"
+// or "Australia/Sydney". Time zones are created from factory functions such
+// as load_time_zone(). Note: strings like "PST" and "EDT" are not valid TZ
+// identifiers.
+//
+// Example:
+//   cctz::time_zone utc = cctz::utc_time_zone();
+//   cctz::time_zone pst = cctz::fixed_time_zone(std::chrono::hours(-8));
+//   cctz::time_zone loc = cctz::local_time_zone();
+//   cctz::time_zone lax;
+//   if (!cctz::load_time_zone("America/Los_Angeles", &lax)) { ... }
+//
+// See also:
+// - http://www.iana.org/time-zones
+// - https://en.wikipedia.org/wiki/Zoneinfo
+class time_zone {
+ public:
+  time_zone() : time_zone(nullptr) {}  // Equivalent to UTC
+  time_zone(const time_zone&) = default;
+  time_zone& operator=(const time_zone&) = default;
+
+  std::string name() const;
+
+  // An absolute_lookup represents the civil time (cctz::civil_second) within
+  // this time_zone at the given absolute time (time_point). There are
+  // additionally a few other fields that may be useful when working with
+  // older APIs, such as std::tm.
+  //
+  // Example:
+  //   const cctz::time_zone tz = ...
+  //   const auto tp = std::chrono::system_clock::now();
+  //   const cctz::time_zone::absolute_lookup al = tz.lookup(tp);
+  struct absolute_lookup {
+    civil_second cs;
+    // Note: The following fields exist for backward compatibility with older
+    // APIs. Accessing these fields directly is a sign of imprudent logic in
+    // the calling code. Modern time-related code should only access this data
+    // indirectly by way of cctz::format().
+    int offset;        // civil seconds east of UTC
+    bool is_dst;       // is offset non-standard?
+    const char* abbr;  // time-zone abbreviation (e.g., "PST")
+  };
+  absolute_lookup lookup(const time_point<seconds>& tp) const;
+  template <typename D>
+  absolute_lookup lookup(const time_point<D>& tp) const {
+    return lookup(detail::split_seconds(tp).first);
+  }
+
+  // A civil_lookup represents the absolute time(s) (time_point) that
+  // correspond to the given civil time (cctz::civil_second) within this
+  // time_zone. Usually the given civil time represents a unique instant
+  // in time, in which case the conversion is unambiguous. However,
+  // within this time zone, the given civil time may be skipped (e.g.,
+  // during a positive UTC offset shift), or repeated (e.g., during a
+  // negative UTC offset shift). To account for these possibilities,
+  // civil_lookup is richer than just a single time_point.
+  //
+  // In all cases the civil_lookup::kind enum will indicate the nature
+  // of the given civil-time argument, and the pre, trans, and post
+  // members will give the absolute time answers using the pre-transition
+  // offset, the transition point itself, and the post-transition offset,
+  // respectively (all three times are equal if kind == UNIQUE). If any
+  // of these three absolute times is outside the representable range of a
+  // time_point<seconds> the field is set to its maximum/minimum value.
+  //
+  // Example:
+  //   cctz::time_zone lax;
+  //   if (!cctz::load_time_zone("America/Los_Angeles", &lax)) { ... }
+  //
+  //   // A unique civil time.
+  //   auto jan01 = lax.lookup(cctz::civil_second(2011, 1, 1, 0, 0, 0));
+  //   // jan01.kind == cctz::time_zone::civil_lookup::UNIQUE
+  //   // jan01.pre    is 2011/01/01 00:00:00 -0800
+  //   // jan01.trans  is 2011/01/01 00:00:00 -0800
+  //   // jan01.post   is 2011/01/01 00:00:00 -0800
+  //
+  //   // A Spring DST transition, when there is a gap in civil time.
+  //   auto mar13 = lax.lookup(cctz::civil_second(2011, 3, 13, 2, 15, 0));
+  //   // mar13.kind == cctz::time_zone::civil_lookup::SKIPPED
+  //   // mar13.pre   is 2011/03/13 03:15:00 -0700
+  //   // mar13.trans is 2011/03/13 03:00:00 -0700
+  //   // mar13.post  is 2011/03/13 01:15:00 -0800
+  //
+  //   // A Fall DST transition, when civil times are repeated.
+  //   auto nov06 = lax.lookup(cctz::civil_second(2011, 11, 6, 1, 15, 0));
+  //   // nov06.kind == cctz::time_zone::civil_lookup::REPEATED
+  //   // nov06.pre   is 2011/11/06 01:15:00 -0700
+  //   // nov06.trans is 2011/11/06 01:00:00 -0800
+  //   // nov06.post  is 2011/11/06 01:15:00 -0800
+  struct civil_lookup {
+    enum civil_kind {
+      UNIQUE,    // the civil time was singular (pre == trans == post)
+      SKIPPED,   // the civil time did not exist (pre >= trans > post)
+      REPEATED,  // the civil time was ambiguous (pre < trans <= post)
+    } kind;
+    time_point<seconds> pre;    // uses the pre-transition offset
+    time_point<seconds> trans;  // instant of civil-offset change
+    time_point<seconds> post;   // uses the post-transition offset
+  };
+  civil_lookup lookup(const civil_second& cs) const;
+
+  // Finds the time of the next/previous offset change in this time zone.
+  //
+  // By definition, next_transition(tp, &trans) returns false when tp has
+  // its maximum value, and prev_transition(tp, &trans) returns false
+  // when tp has its minimum value. If the zone has no transitions, the
+  // result will also be false no matter what the argument.
+  //
+  // Otherwise, when tp has its minimum value, next_transition(tp, &trans)
+  // returns true and sets trans to the first recorded transition. Chains
+  // of calls to next_transition()/prev_transition() will eventually return
+  // false, but it is unspecified exactly when next_transition(tp, &trans)
+  // jumps to false, or what time is set by prev_transition(tp, &trans) for
+  // a very distant tp.
+  //
+  // Note: Enumeration of time-zone transitions is for informational purposes
+  // only. Modern time-related code should not care about when offset changes
+  // occur.
+  //
+  // Example:
+  //   cctz::time_zone nyc;
+  //   if (!cctz::load_time_zone("America/New_York", &nyc)) { ... }
+  //   const auto now = std::chrono::system_clock::now();
+  //   auto tp = cctz::time_point<cctz::seconds>::min();
+  //   cctz::time_zone::civil_transition trans;
+  //   while (tp <= now && nyc.next_transition(tp, &trans)) {
+  //     // transition: trans.from -> trans.to
+  //     tp = nyc.lookup(trans.to).trans;
+  //   }
+  struct civil_transition {
+    civil_second from;  // the civil time we jump from
+    civil_second to;    // the civil time we jump to
+  };
+  bool next_transition(const time_point<seconds>& tp,
+                       civil_transition* trans) const;
+  template <typename D>
+  bool next_transition(const time_point<D>& tp, civil_transition* trans) const {
+    return next_transition(detail::split_seconds(tp).first, trans);
+  }
+  bool prev_transition(const time_point<seconds>& tp,
+                       civil_transition* trans) const;
+  template <typename D>
+  bool prev_transition(const time_point<D>& tp, civil_transition* trans) const {
+    return prev_transition(detail::split_seconds(tp).first, trans);
+  }
+
+  // version() and description() provide additional information about the
+  // time zone. The content of each of the returned strings is unspecified,
+  // however, when the IANA Time Zone Database is the underlying data source
+  // the version() string will be in the familar form (e.g, "2018e") or
+  // empty when unavailable.
+  //
+  // Note: These functions are for informational or testing purposes only.
+  std::string version() const;  // empty when unknown
+  std::string description() const;
+
+  // Relational operators.
+  friend bool operator==(time_zone lhs, time_zone rhs) {
+    return &lhs.effective_impl() == &rhs.effective_impl();
+  }
+  friend bool operator!=(time_zone lhs, time_zone rhs) { return !(lhs == rhs); }
+
+  template <typename H>
+  friend H AbslHashValue(H h, time_zone tz) {
+    return H::combine(std::move(h), &tz.effective_impl());
+  }
+
+  class Impl;
+
+ private:
+  explicit time_zone(const Impl* impl) : impl_(impl) {}
+  const Impl& effective_impl() const;  // handles implicit UTC
+  const Impl* impl_;
+};
+
+// Loads the named time zone. May perform I/O on the initial load.
+// If the name is invalid, or some other kind of error occurs, returns
+// false and "*tz" is set to the UTC time zone.
+bool load_time_zone(const std::string& name, time_zone* tz);
+
+// Returns a time_zone representing UTC. Cannot fail.
+time_zone utc_time_zone();
+
+// Returns a time zone that is a fixed offset (seconds east) from UTC.
+// Note: If the absolute value of the offset is greater than 24 hours
+// you'll get UTC (i.e., zero offset) instead.
+time_zone fixed_time_zone(const seconds& offset);
+
+// Returns a time zone representing the local time zone. Falls back to UTC.
+// Note: local_time_zone.name() may only be something like "localtime".
+time_zone local_time_zone();
+
+// Returns the civil time (cctz::civil_second) within the given time zone at
+// the given absolute time (time_point). Since the additional fields provided
+// by the time_zone::absolute_lookup struct should rarely be needed in modern
+// code, this convert() function is simpler and should be preferred.
+template <typename D>
+inline civil_second convert(const time_point<D>& tp, const time_zone& tz) {
+  return tz.lookup(tp).cs;
+}
+
+// Returns the absolute time (time_point) that corresponds to the given civil
+// time within the given time zone. If the civil time is not unique (i.e., if
+// it was either repeated or non-existent), then the returned time_point is
+// the best estimate that preserves relative order. That is, this function
+// guarantees that if cs1 < cs2, then convert(cs1, tz) <= convert(cs2, tz).
+inline time_point<seconds> convert(const civil_second& cs,
+                                   const time_zone& tz) {
+  const time_zone::civil_lookup cl = tz.lookup(cs);
+  if (cl.kind == time_zone::civil_lookup::SKIPPED) return cl.trans;
+  return cl.pre;
+}
+
+namespace detail {
+using femtoseconds = std::chrono::duration<std::int_fast64_t, std::femto>;
+std::string format(const std::string&, const time_point<seconds>&,
+                   const femtoseconds&, const time_zone&);
+bool parse(const std::string&, const std::string&, const time_zone&,
+           time_point<seconds>*, femtoseconds*, std::string* err = nullptr);
+}  // namespace detail
+
+// Formats the given time_point in the given cctz::time_zone according to
+// the provided format string. Uses strftime()-like formatting options,
+// with the following extensions:
+//
+//   - %Ez  - RFC3339-compatible numeric UTC offset (+hh:mm or -hh:mm)
+//   - %E*z - Full-resolution numeric UTC offset (+hh:mm:ss or -hh:mm:ss)
+//   - %E#S - Seconds with # digits of fractional precision
+//   - %E*S - Seconds with full fractional precision (a literal '*')
+//   - %E#f - Fractional seconds with # digits of precision
+//   - %E*f - Fractional seconds with full precision (a literal '*')
+//   - %E4Y - Four-character years (-999 ... -001, 0000, 0001 ... 9999)
+//   - %ET  - The RFC3339 "date-time" separator "T"
+//
+// Note that %E0S behaves like %S, and %E0f produces no characters. In
+// contrast %E*f always produces at least one digit, which may be '0'.
+//
+// Note that %Y produces as many characters as it takes to fully render the
+// year. A year outside of [-999:9999] when formatted with %E4Y will produce
+// more than four characters, just like %Y.
+//
+// Tip: Format strings should include the UTC offset (e.g., %z, %Ez, or %E*z)
+// so that the resulting string uniquely identifies an absolute time.
+//
+// Example:
+//   cctz::time_zone lax;
+//   if (!cctz::load_time_zone("America/Los_Angeles", &lax)) { ... }
+//   auto tp = cctz::convert(cctz::civil_second(2013, 1, 2, 3, 4, 5), lax);
+//   std::string f = cctz::format("%H:%M:%S", tp, lax);  // "03:04:05"
+//   f = cctz::format("%H:%M:%E3S", tp, lax);            // "03:04:05.000"
+template <typename D>
+inline std::string format(const std::string& fmt, const time_point<D>& tp,
+                          const time_zone& tz) {
+  const auto p = detail::split_seconds(tp);
+  const auto n = std::chrono::duration_cast<detail::femtoseconds>(p.second);
+  return detail::format(fmt, p.first, n, tz);
+}
+
+// Parses an input string according to the provided format string and
+// returns the corresponding time_point. Uses strftime()-like formatting
+// options, with the same extensions as cctz::format(), but with the
+// exceptions that %E#S is interpreted as %E*S, and %E#f as %E*f. %Ez
+// and %E*z also accept the same inputs, which (along with %z) includes
+// 'z' and 'Z' as synonyms for +00:00.  %ET accepts either 'T' or 't'.
+//
+// %Y consumes as many numeric characters as it can, so the matching data
+// should always be terminated with a non-numeric. %E4Y always consumes
+// exactly four characters, including any sign.
+//
+// Unspecified fields are taken from the default date and time of ...
+//
+//   "1970-01-01 00:00:00.0 +0000"
+//
+// For example, parsing a string of "15:45" (%H:%M) will return a time_point
+// that represents "1970-01-01 15:45:00.0 +0000".
+//
+// Note that parse() returns time instants, so it makes most sense to parse
+// fully-specified date/time strings that include a UTC offset (%z, %Ez, or
+// %E*z).
+//
+// Note also that parse() only heeds the fields year, month, day, hour,
+// minute, (fractional) second, and UTC offset. Other fields, like weekday (%a
+// or %A), while parsed for syntactic validity, are ignored in the conversion.
+//
+// Date and time fields that are out-of-range will be treated as errors rather
+// than normalizing them like cctz::civil_second() would do. For example, it
+// is an error to parse the date "Oct 32, 2013" because 32 is out of range.
+//
+// A second of ":60" is normalized to ":00" of the following minute with
+// fractional seconds discarded. The following table shows how the given
+// seconds and subseconds will be parsed:
+//
+//   "59.x" -> 59.x  // exact
+//   "60.x" -> 00.0  // normalized
+//   "00.x" -> 00.x  // exact
+//
+// Errors are indicated by returning false.
+//
+// Example:
+//   const cctz::time_zone tz = ...
+//   std::chrono::system_clock::time_point tp;
+//   if (cctz::parse("%Y-%m-%d", "2015-10-09", tz, &tp)) {
+//     ...
+//   }
+template <typename D>
+inline bool parse(const std::string& fmt, const std::string& input,
+                  const time_zone& tz, time_point<D>* tpp) {
+  time_point<seconds> sec;
+  detail::femtoseconds fs;
+  const bool b = detail::parse(fmt, input, tz, &sec, &fs);
+  if (b) {
+    // TODO: Return false if unrepresentable as a time_point<D>.
+    *tpp = std::chrono::time_point_cast<D>(sec);
+    *tpp += std::chrono::duration_cast<D>(fs);
+  }
+  return b;
+}
+
+}  // namespace cctz
+}  // namespace time_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#endif  // ABSL_TIME_INTERNAL_CCTZ_TIME_ZONE_H_
diff --git a/src/absl/time/internal/cctz/include/cctz/zone_info_source.h b/src/absl/time/internal/cctz/include/cctz/zone_info_source.h
new file mode 100644 (file)
index 0000000..012eb4e
--- /dev/null
@@ -0,0 +1,102 @@
+// Copyright 2016 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//   https://www.apache.org/licenses/LICENSE-2.0
+//
+//   Unless required by applicable law or agreed to in writing, software
+//   distributed under the License is distributed on an "AS IS" BASIS,
+//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//   See the License for the specific language governing permissions and
+//   limitations under the License.
+
+#ifndef ABSL_TIME_INTERNAL_CCTZ_ZONE_INFO_SOURCE_H_
+#define ABSL_TIME_INTERNAL_CCTZ_ZONE_INFO_SOURCE_H_
+
+#include <cstddef>
+#include <functional>
+#include <memory>
+#include <string>
+
+#include "absl/base/config.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace time_internal {
+namespace cctz {
+
+// A stdio-like interface for providing zoneinfo data for a particular zone.
+class ZoneInfoSource {
+ public:
+  virtual ~ZoneInfoSource();
+
+  virtual std::size_t Read(void* ptr, std::size_t size) = 0;  // like fread()
+  virtual int Skip(std::size_t offset) = 0;                   // like fseek()
+
+  // Until the zoneinfo data supports versioning information, we provide
+  // a way for a ZoneInfoSource to indicate it out-of-band.  The default
+  // implementation returns an empty string.
+  virtual std::string Version() const;
+};
+
+}  // namespace cctz
+}  // namespace time_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace time_internal {
+namespace cctz_extension {
+
+// A function-pointer type for a factory that returns a ZoneInfoSource
+// given the name of a time zone and a fallback factory.  Returns null
+// when the data for the named zone cannot be found.
+using ZoneInfoSourceFactory =
+    std::unique_ptr<absl::time_internal::cctz::ZoneInfoSource> (*)(
+        const std::string&,
+        const std::function<std::unique_ptr<
+            absl::time_internal::cctz::ZoneInfoSource>(const std::string&)>&);
+
+// The user can control the mapping of zone names to zoneinfo data by
+// providing a definition for cctz_extension::zone_info_source_factory.
+// For example, given functions my_factory() and my_other_factory() that
+// can return a ZoneInfoSource for a named zone, we could inject them into
+// cctz::load_time_zone() with:
+//
+//   namespace cctz_extension {
+//   namespace {
+//   std::unique_ptr<cctz::ZoneInfoSource> CustomFactory(
+//       const std::string& name,
+//       const std::function<std::unique_ptr<cctz::ZoneInfoSource>(
+//           const std::string& name)>& fallback_factory) {
+//     if (auto zip = my_factory(name)) return zip;
+//     if (auto zip = fallback_factory(name)) return zip;
+//     if (auto zip = my_other_factory(name)) return zip;
+//     return nullptr;
+//   }
+//   }  // namespace
+//   ZoneInfoSourceFactory zone_info_source_factory = CustomFactory;
+//   }  // namespace cctz_extension
+//
+// This might be used, say, to use zoneinfo data embedded in the program,
+// or read from a (possibly compressed) file archive, or both.
+//
+// cctz_extension::zone_info_source_factory() will be called:
+//   (1) from the same thread as the cctz::load_time_zone() call,
+//   (2) only once for any zone name, and
+//   (3) serially (i.e., no concurrent execution).
+//
+// The fallback factory obtains zoneinfo data by reading files in ${TZDIR},
+// and it is used automatically when no zone_info_source_factory definition
+// is linked into the program.
+extern ZoneInfoSourceFactory zone_info_source_factory;
+
+}  // namespace cctz_extension
+}  // namespace time_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#endif  // ABSL_TIME_INTERNAL_CCTZ_ZONE_INFO_SOURCE_H_
diff --git a/src/absl/time/internal/cctz/src/civil_time_detail.cc b/src/absl/time/internal/cctz/src/civil_time_detail.cc
new file mode 100644 (file)
index 0000000..0b07e39
--- /dev/null
@@ -0,0 +1,94 @@
+// Copyright 2016 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//   https://www.apache.org/licenses/LICENSE-2.0
+//
+//   Unless required by applicable law or agreed to in writing, software
+//   distributed under the License is distributed on an "AS IS" BASIS,
+//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//   See the License for the specific language governing permissions and
+//   limitations under the License.
+
+#include "absl/time/internal/cctz/include/cctz/civil_time_detail.h"
+
+#include <iomanip>
+#include <ostream>
+#include <sstream>
+
+#include "absl/base/config.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace time_internal {
+namespace cctz {
+namespace detail {
+
+// Output stream operators output a format matching YYYY-MM-DDThh:mm:ss,
+// while omitting fields inferior to the type's alignment. For example,
+// civil_day is formatted only as YYYY-MM-DD.
+std::ostream& operator<<(std::ostream& os, const civil_year& y) {
+  std::stringstream ss;
+  ss << y.year();  // No padding.
+  return os << ss.str();
+}
+std::ostream& operator<<(std::ostream& os, const civil_month& m) {
+  std::stringstream ss;
+  ss << civil_year(m) << '-';
+  ss << std::setfill('0') << std::setw(2) << m.month();
+  return os << ss.str();
+}
+std::ostream& operator<<(std::ostream& os, const civil_day& d) {
+  std::stringstream ss;
+  ss << civil_month(d) << '-';
+  ss << std::setfill('0') << std::setw(2) << d.day();
+  return os << ss.str();
+}
+std::ostream& operator<<(std::ostream& os, const civil_hour& h) {
+  std::stringstream ss;
+  ss << civil_day(h) << 'T';
+  ss << std::setfill('0') << std::setw(2) << h.hour();
+  return os << ss.str();
+}
+std::ostream& operator<<(std::ostream& os, const civil_minute& m) {
+  std::stringstream ss;
+  ss << civil_hour(m) << ':';
+  ss << std::setfill('0') << std::setw(2) << m.minute();
+  return os << ss.str();
+}
+std::ostream& operator<<(std::ostream& os, const civil_second& s) {
+  std::stringstream ss;
+  ss << civil_minute(s) << ':';
+  ss << std::setfill('0') << std::setw(2) << s.second();
+  return os << ss.str();
+}
+
+////////////////////////////////////////////////////////////////////////
+
+std::ostream& operator<<(std::ostream& os, weekday wd) {
+  switch (wd) {
+    case weekday::monday:
+      return os << "Monday";
+    case weekday::tuesday:
+      return os << "Tuesday";
+    case weekday::wednesday:
+      return os << "Wednesday";
+    case weekday::thursday:
+      return os << "Thursday";
+    case weekday::friday:
+      return os << "Friday";
+    case weekday::saturday:
+      return os << "Saturday";
+    case weekday::sunday:
+      return os << "Sunday";
+  }
+  return os;  // Should never get here, but -Wreturn-type may warn without this.
+}
+
+}  // namespace detail
+}  // namespace cctz
+}  // namespace time_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
diff --git a/src/absl/time/internal/cctz/src/time_zone_fixed.cc b/src/absl/time/internal/cctz/src/time_zone_fixed.cc
new file mode 100644 (file)
index 0000000..303c024
--- /dev/null
@@ -0,0 +1,140 @@
+// Copyright 2016 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//   https://www.apache.org/licenses/LICENSE-2.0
+//
+//   Unless required by applicable law or agreed to in writing, software
+//   distributed under the License is distributed on an "AS IS" BASIS,
+//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//   See the License for the specific language governing permissions and
+//   limitations under the License.
+
+#include "time_zone_fixed.h"
+
+#include <algorithm>
+#include <cassert>
+#include <chrono>
+#include <cstring>
+#include <string>
+
+#include "absl/base/config.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace time_internal {
+namespace cctz {
+
+namespace {
+
+// The prefix used for the internal names of fixed-offset zones.
+const char kFixedZonePrefix[] = "Fixed/UTC";
+
+const char kDigits[] = "0123456789";
+
+char* Format02d(char* p, int v) {
+  *p++ = kDigits[(v / 10) % 10];
+  *p++ = kDigits[v % 10];
+  return p;
+}
+
+int Parse02d(const char* p) {
+  if (const char* ap = std::strchr(kDigits, *p)) {
+    int v = static_cast<int>(ap - kDigits);
+    if (const char* bp = std::strchr(kDigits, *++p)) {
+      return (v * 10) + static_cast<int>(bp - kDigits);
+    }
+  }
+  return -1;
+}
+
+}  // namespace
+
+bool FixedOffsetFromName(const std::string& name, seconds* offset) {
+  if (name.compare(0, std::string::npos, "UTC", 3) == 0) {
+    *offset = seconds::zero();
+    return true;
+  }
+
+  const std::size_t prefix_len = sizeof(kFixedZonePrefix) - 1;
+  const char* const ep = kFixedZonePrefix + prefix_len;
+  if (name.size() != prefix_len + 9)  // <prefix>+99:99:99
+    return false;
+  if (!std::equal(kFixedZonePrefix, ep, name.begin())) return false;
+  const char* np = name.data() + prefix_len;
+  if (np[0] != '+' && np[0] != '-') return false;
+  if (np[3] != ':' || np[6] != ':')  // see note below about large offsets
+    return false;
+
+  int hours = Parse02d(np + 1);
+  if (hours == -1) return false;
+  int mins = Parse02d(np + 4);
+  if (mins == -1) return false;
+  int secs = Parse02d(np + 7);
+  if (secs == -1) return false;
+
+  secs += ((hours * 60) + mins) * 60;
+  if (secs > 24 * 60 * 60) return false;  // outside supported offset range
+  *offset = seconds(secs * (np[0] == '-' ? -1 : 1));  // "-" means west
+  return true;
+}
+
+std::string FixedOffsetToName(const seconds& offset) {
+  if (offset == seconds::zero()) return "UTC";
+  if (offset < std::chrono::hours(-24) || offset > std::chrono::hours(24)) {
+    // We don't support fixed-offset zones more than 24 hours
+    // away from UTC to avoid complications in rendering such
+    // offsets and to (somewhat) limit the total number of zones.
+    return "UTC";
+  }
+  int offset_seconds = static_cast<int>(offset.count());
+  const char sign = (offset_seconds < 0 ? '-' : '+');
+  int offset_minutes = offset_seconds / 60;
+  offset_seconds %= 60;
+  if (sign == '-') {
+    if (offset_seconds > 0) {
+      offset_seconds -= 60;
+      offset_minutes += 1;
+    }
+    offset_seconds = -offset_seconds;
+    offset_minutes = -offset_minutes;
+  }
+  int offset_hours = offset_minutes / 60;
+  offset_minutes %= 60;
+  const std::size_t prefix_len = sizeof(kFixedZonePrefix) - 1;
+  char buf[prefix_len + sizeof("-24:00:00")];
+  char* ep = std::copy(kFixedZonePrefix, kFixedZonePrefix + prefix_len, buf);
+  *ep++ = sign;
+  ep = Format02d(ep, offset_hours);
+  *ep++ = ':';
+  ep = Format02d(ep, offset_minutes);
+  *ep++ = ':';
+  ep = Format02d(ep, offset_seconds);
+  *ep++ = '\0';
+  assert(ep == buf + sizeof(buf));
+  return buf;
+}
+
+std::string FixedOffsetToAbbr(const seconds& offset) {
+  std::string abbr = FixedOffsetToName(offset);
+  const std::size_t prefix_len = sizeof(kFixedZonePrefix) - 1;
+  if (abbr.size() == prefix_len + 9) {         // <prefix>+99:99:99
+    abbr.erase(0, prefix_len);                 // +99:99:99
+    abbr.erase(6, 1);                          // +99:9999
+    abbr.erase(3, 1);                          // +999999
+    if (abbr[5] == '0' && abbr[6] == '0') {    // +999900
+      abbr.erase(5, 2);                        // +9999
+      if (abbr[3] == '0' && abbr[4] == '0') {  // +9900
+        abbr.erase(3, 2);                      // +99
+      }
+    }
+  }
+  return abbr;
+}
+
+}  // namespace cctz
+}  // namespace time_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
diff --git a/src/absl/time/internal/cctz/src/time_zone_fixed.h b/src/absl/time/internal/cctz/src/time_zone_fixed.h
new file mode 100644 (file)
index 0000000..e74a0bb
--- /dev/null
@@ -0,0 +1,52 @@
+// Copyright 2016 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//   https://www.apache.org/licenses/LICENSE-2.0
+//
+//   Unless required by applicable law or agreed to in writing, software
+//   distributed under the License is distributed on an "AS IS" BASIS,
+//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//   See the License for the specific language governing permissions and
+//   limitations under the License.
+
+#ifndef ABSL_TIME_INTERNAL_CCTZ_TIME_ZONE_FIXED_H_
+#define ABSL_TIME_INTERNAL_CCTZ_TIME_ZONE_FIXED_H_
+
+#include <string>
+
+#include "absl/base/config.h"
+#include "absl/time/internal/cctz/include/cctz/time_zone.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace time_internal {
+namespace cctz {
+
+// Helper functions for dealing with the names and abbreviations
+// of time zones that are a fixed offset (seconds east) from UTC.
+// FixedOffsetFromName() extracts the offset from a valid fixed-offset
+// name, while FixedOffsetToName() and FixedOffsetToAbbr() generate
+// the canonical zone name and abbreviation respectively for the given
+// offset.
+//
+// A fixed-offset name looks like "Fixed/UTC<+-><hours>:<mins>:<secs>".
+// Its abbreviation is of the form "UTC(<+->H?H(MM(SS)?)?)?" where the
+// optional pieces are omitted when their values are zero.  (Note that
+// the sign is the opposite of that used in a POSIX TZ specification.)
+//
+// Note: FixedOffsetFromName() fails on syntax errors or when the parsed
+// offset exceeds 24 hours.  FixedOffsetToName() and FixedOffsetToAbbr()
+// both produce "UTC" when the argument offset exceeds 24 hours.
+bool FixedOffsetFromName(const std::string& name, seconds* offset);
+std::string FixedOffsetToName(const seconds& offset);
+std::string FixedOffsetToAbbr(const seconds& offset);
+
+}  // namespace cctz
+}  // namespace time_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#endif  // ABSL_TIME_INTERNAL_CCTZ_TIME_ZONE_FIXED_H_
diff --git a/src/absl/time/internal/cctz/src/time_zone_format.cc b/src/absl/time/internal/cctz/src/time_zone_format.cc
new file mode 100644 (file)
index 0000000..d8cb047
--- /dev/null
@@ -0,0 +1,1029 @@
+// Copyright 2016 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//   https://www.apache.org/licenses/LICENSE-2.0
+//
+//   Unless required by applicable law or agreed to in writing, software
+//   distributed under the License is distributed on an "AS IS" BASIS,
+//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//   See the License for the specific language governing permissions and
+//   limitations under the License.
+
+#if !defined(HAS_STRPTIME)
+#if !defined(_MSC_VER) && !defined(__MINGW32__)
+#define HAS_STRPTIME 1  // assume everyone has strptime() except windows
+#endif
+#endif
+
+#if defined(HAS_STRPTIME) && HAS_STRPTIME
+#if !defined(_XOPEN_SOURCE)
+#define _XOPEN_SOURCE  // Definedness suffices for strptime.
+#endif
+#endif
+
+#include "absl/base/config.h"
+#include "absl/time/internal/cctz/include/cctz/time_zone.h"
+
+// Include time.h directly since, by C++ standards, ctime doesn't have to
+// declare strptime.
+#include <time.h>
+
+#include <cctype>
+#include <chrono>
+#include <cstddef>
+#include <cstdint>
+#include <cstring>
+#include <ctime>
+#include <limits>
+#include <string>
+#include <vector>
+#if !HAS_STRPTIME
+#include <iomanip>
+#include <sstream>
+#endif
+
+#include "absl/time/internal/cctz/include/cctz/civil_time.h"
+#include "time_zone_if.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace time_internal {
+namespace cctz {
+namespace detail {
+
+namespace {
+
+#if !HAS_STRPTIME
+// Build a strptime() using C++11's std::get_time().
+char* strptime(const char* s, const char* fmt, std::tm* tm) {
+  std::istringstream input(s);
+  input >> std::get_time(tm, fmt);
+  if (input.fail()) return nullptr;
+  return const_cast<char*>(s) +
+         (input.eof() ? strlen(s) : static_cast<std::size_t>(input.tellg()));
+}
+#endif
+
+// Convert a cctz::weekday to a tm_wday value (0-6, Sunday = 0).
+int ToTmWday(weekday wd) {
+  switch (wd) {
+    case weekday::sunday:
+      return 0;
+    case weekday::monday:
+      return 1;
+    case weekday::tuesday:
+      return 2;
+    case weekday::wednesday:
+      return 3;
+    case weekday::thursday:
+      return 4;
+    case weekday::friday:
+      return 5;
+    case weekday::saturday:
+      return 6;
+  }
+  return 0; /*NOTREACHED*/
+}
+
+// Convert a tm_wday value (0-6, Sunday = 0) to a cctz::weekday.
+weekday FromTmWday(int tm_wday) {
+  switch (tm_wday) {
+    case 0:
+      return weekday::sunday;
+    case 1:
+      return weekday::monday;
+    case 2:
+      return weekday::tuesday;
+    case 3:
+      return weekday::wednesday;
+    case 4:
+      return weekday::thursday;
+    case 5:
+      return weekday::friday;
+    case 6:
+      return weekday::saturday;
+  }
+  return weekday::sunday; /*NOTREACHED*/
+}
+
+std::tm ToTM(const time_zone::absolute_lookup& al) {
+  std::tm tm{};
+  tm.tm_sec = al.cs.second();
+  tm.tm_min = al.cs.minute();
+  tm.tm_hour = al.cs.hour();
+  tm.tm_mday = al.cs.day();
+  tm.tm_mon = al.cs.month() - 1;
+
+  // Saturate tm.tm_year is cases of over/underflow.
+  if (al.cs.year() < std::numeric_limits<int>::min() + 1900) {
+    tm.tm_year = std::numeric_limits<int>::min();
+  } else if (al.cs.year() - 1900 > std::numeric_limits<int>::max()) {
+    tm.tm_year = std::numeric_limits<int>::max();
+  } else {
+    tm.tm_year = static_cast<int>(al.cs.year() - 1900);
+  }
+
+  tm.tm_wday = ToTmWday(get_weekday(al.cs));
+  tm.tm_yday = get_yearday(al.cs) - 1;
+  tm.tm_isdst = al.is_dst ? 1 : 0;
+  return tm;
+}
+
+// Returns the week of the year [0:53] given a civil day and the day on
+// which weeks are defined to start.
+int ToWeek(const civil_day& cd, weekday week_start) {
+  const civil_day d(cd.year() % 400, cd.month(), cd.day());
+  return static_cast<int>((d - prev_weekday(civil_year(d), week_start)) / 7);
+}
+
+const char kDigits[] = "0123456789";
+
+// Formats a 64-bit integer in the given field width.  Note that it is up
+// to the caller of Format64() [and Format02d()/FormatOffset()] to ensure
+// that there is sufficient space before ep to hold the conversion.
+char* Format64(char* ep, int width, std::int_fast64_t v) {
+  bool neg = false;
+  if (v < 0) {
+    --width;
+    neg = true;
+    if (v == std::numeric_limits<std::int_fast64_t>::min()) {
+      // Avoid negating minimum value.
+      std::int_fast64_t last_digit = -(v % 10);
+      v /= 10;
+      if (last_digit < 0) {
+        ++v;
+        last_digit += 10;
+      }
+      --width;
+      *--ep = kDigits[last_digit];
+    }
+    v = -v;
+  }
+  do {
+    --width;
+    *--ep = kDigits[v % 10];
+  } while (v /= 10);
+  while (--width >= 0) *--ep = '0';  // zero pad
+  if (neg) *--ep = '-';
+  return ep;
+}
+
+// Formats [0 .. 99] as %02d.
+char* Format02d(char* ep, int v) {
+  *--ep = kDigits[v % 10];
+  *--ep = kDigits[(v / 10) % 10];
+  return ep;
+}
+
+// Formats a UTC offset, like +00:00.
+char* FormatOffset(char* ep, int offset, const char* mode) {
+  // TODO: Follow the RFC3339 "Unknown Local Offset Convention" and
+  // generate a "negative zero" when we're formatting a zero offset
+  // as the result of a failed load_time_zone().
+  char sign = '+';
+  if (offset < 0) {
+    offset = -offset;  // bounded by 24h so no overflow
+    sign = '-';
+  }
+  const int seconds = offset % 60;
+  const int minutes = (offset /= 60) % 60;
+  const int hours = offset /= 60;
+  const char sep = mode[0];
+  const bool ext = (sep != '\0' && mode[1] == '*');
+  const bool ccc = (ext && mode[2] == ':');
+  if (ext && (!ccc || seconds != 0)) {
+    ep = Format02d(ep, seconds);
+    *--ep = sep;
+  } else {
+    // If we're not rendering seconds, sub-minute negative offsets
+    // should get a positive sign (e.g., offset=-10s => "+00:00").
+    if (hours == 0 && minutes == 0) sign = '+';
+  }
+  if (!ccc || minutes != 0 || seconds != 0) {
+    ep = Format02d(ep, minutes);
+    if (sep != '\0') *--ep = sep;
+  }
+  ep = Format02d(ep, hours);
+  *--ep = sign;
+  return ep;
+}
+
+// Formats a std::tm using strftime(3).
+void FormatTM(std::string* out, const std::string& fmt, const std::tm& tm) {
+  // strftime(3) returns the number of characters placed in the output
+  // array (which may be 0 characters).  It also returns 0 to indicate
+  // an error, like the array wasn't large enough.  To accommodate this,
+  // the following code grows the buffer size from 2x the format string
+  // length up to 32x.
+  for (std::size_t i = 2; i != 32; i *= 2) {
+    std::size_t buf_size = fmt.size() * i;
+    std::vector<char> buf(buf_size);
+    if (std::size_t len = strftime(&buf[0], buf_size, fmt.c_str(), &tm)) {
+      out->append(&buf[0], len);
+      return;
+    }
+  }
+}
+
+// Used for %E#S/%E#f specifiers and for data values in parse().
+template <typename T>
+const char* ParseInt(const char* dp, int width, T min, T max, T* vp) {
+  if (dp != nullptr) {
+    const T kmin = std::numeric_limits<T>::min();
+    bool erange = false;
+    bool neg = false;
+    T value = 0;
+    if (*dp == '-') {
+      neg = true;
+      if (width <= 0 || --width != 0) {
+        ++dp;
+      } else {
+        dp = nullptr;  // width was 1
+      }
+    }
+    if (const char* const bp = dp) {
+      while (const char* cp = strchr(kDigits, *dp)) {
+        int d = static_cast<int>(cp - kDigits);
+        if (d >= 10) break;
+        if (value < kmin / 10) {
+          erange = true;
+          break;
+        }
+        value *= 10;
+        if (value < kmin + d) {
+          erange = true;
+          break;
+        }
+        value -= d;
+        dp += 1;
+        if (width > 0 && --width == 0) break;
+      }
+      if (dp != bp && !erange && (neg || value != kmin)) {
+        if (!neg || value != 0) {
+          if (!neg) value = -value;  // make positive
+          if (min <= value && value <= max) {
+            *vp = value;
+          } else {
+            dp = nullptr;
+          }
+        } else {
+          dp = nullptr;
+        }
+      } else {
+        dp = nullptr;
+      }
+    }
+  }
+  return dp;
+}
+
+// The number of base-10 digits that can be represented by a signed 64-bit
+// integer.  That is, 10^kDigits10_64 <= 2^63 - 1 < 10^(kDigits10_64 + 1).
+const int kDigits10_64 = 18;
+
+// 10^n for everything that can be represented by a signed 64-bit integer.
+const std::int_fast64_t kExp10[kDigits10_64 + 1] = {
+    1,
+    10,
+    100,
+    1000,
+    10000,
+    100000,
+    1000000,
+    10000000,
+    100000000,
+    1000000000,
+    10000000000,
+    100000000000,
+    1000000000000,
+    10000000000000,
+    100000000000000,
+    1000000000000000,
+    10000000000000000,
+    100000000000000000,
+    1000000000000000000,
+};
+
+}  // namespace
+
+// Uses strftime(3) to format the given Time.  The following extended format
+// specifiers are also supported:
+//
+//   - %Ez  - RFC3339-compatible numeric UTC offset (+hh:mm or -hh:mm)
+//   - %E*z - Full-resolution numeric UTC offset (+hh:mm:ss or -hh:mm:ss)
+//   - %E#S - Seconds with # digits of fractional precision
+//   - %E*S - Seconds with full fractional precision (a literal '*')
+//   - %E4Y - Four-character years (-999 ... -001, 0000, 0001 ... 9999)
+//   - %ET  - The RFC3339 "date-time" separator "T"
+//
+// The standard specifiers from RFC3339_* (%Y, %m, %d, %H, %M, and %S) are
+// handled internally for performance reasons.  strftime(3) is slow due to
+// a POSIX requirement to respect changes to ${TZ}.
+//
+// The TZ/GNU %s extension is handled internally because strftime() has
+// to use mktime() to generate it, and that assumes the local time zone.
+//
+// We also handle the %z and %Z specifiers to accommodate platforms that do
+// not support the tm_gmtoff and tm_zone extensions to std::tm.
+//
+// Requires that zero() <= fs < seconds(1).
+std::string format(const std::string& format, const time_point<seconds>& tp,
+                   const detail::femtoseconds& fs, const time_zone& tz) {
+  std::string result;
+  result.reserve(format.size());  // A reasonable guess for the result size.
+  const time_zone::absolute_lookup al = tz.lookup(tp);
+  const std::tm tm = ToTM(al);
+
+  // Scratch buffer for internal conversions.
+  char buf[3 + kDigits10_64];  // enough for longest conversion
+  char* const ep = buf + sizeof(buf);
+  char* bp;  // works back from ep
+
+  // Maintain three, disjoint subsequences that span format.
+  //   [format.begin() ... pending) : already formatted into result
+  //   [pending ... cur) : formatting pending, but no special cases
+  //   [cur ... format.end()) : unexamined
+  // Initially, everything is in the unexamined part.
+  const char* pending = format.c_str();  // NUL terminated
+  const char* cur = pending;
+  const char* end = pending + format.length();
+
+  while (cur != end) {  // while something is unexamined
+    // Moves cur to the next percent sign.
+    const char* start = cur;
+    while (cur != end && *cur != '%') ++cur;
+
+    // If the new pending text is all ordinary, copy it out.
+    if (cur != start && pending == start) {
+      result.append(pending, static_cast<std::size_t>(cur - pending));
+      pending = start = cur;
+    }
+
+    // Span the sequential percent signs.
+    const char* percent = cur;
+    while (cur != end && *cur == '%') ++cur;
+
+    // If the new pending text is all percents, copy out one
+    // percent for every matched pair, then skip those pairs.
+    if (cur != start && pending == start) {
+      std::size_t escaped = static_cast<std::size_t>(cur - pending) / 2;
+      result.append(pending, escaped);
+      pending += escaped * 2;
+      // Also copy out a single trailing percent.
+      if (pending != cur && cur == end) {
+        result.push_back(*pending++);
+      }
+    }
+
+    // Loop unless we have an unescaped percent.
+    if (cur == end || (cur - percent) % 2 == 0) continue;
+
+    // Simple specifiers that we handle ourselves.
+    if (strchr("YmdeUuWwHMSzZs%", *cur)) {
+      if (cur - 1 != pending) {
+        FormatTM(&result, std::string(pending, cur - 1), tm);
+      }
+      switch (*cur) {
+        case 'Y':
+          // This avoids the tm.tm_year overflow problem for %Y, however
+          // tm.tm_year will still be used by other specifiers like %D.
+          bp = Format64(ep, 0, al.cs.year());
+          result.append(bp, static_cast<std::size_t>(ep - bp));
+          break;
+        case 'm':
+          bp = Format02d(ep, al.cs.month());
+          result.append(bp, static_cast<std::size_t>(ep - bp));
+          break;
+        case 'd':
+        case 'e':
+          bp = Format02d(ep, al.cs.day());
+          if (*cur == 'e' && *bp == '0') *bp = ' ';  // for Windows
+          result.append(bp, static_cast<std::size_t>(ep - bp));
+          break;
+        case 'U':
+          bp = Format02d(ep, ToWeek(civil_day(al.cs), weekday::sunday));
+          result.append(bp, static_cast<std::size_t>(ep - bp));
+          break;
+        case 'u':
+          bp = Format64(ep, 0, tm.tm_wday ? tm.tm_wday : 7);
+          result.append(bp, static_cast<std::size_t>(ep - bp));
+          break;
+        case 'W':
+          bp = Format02d(ep, ToWeek(civil_day(al.cs), weekday::monday));
+          result.append(bp, static_cast<std::size_t>(ep - bp));
+          break;
+        case 'w':
+          bp = Format64(ep, 0, tm.tm_wday);
+          result.append(bp, static_cast<std::size_t>(ep - bp));
+          break;
+        case 'H':
+          bp = Format02d(ep, al.cs.hour());
+          result.append(bp, static_cast<std::size_t>(ep - bp));
+          break;
+        case 'M':
+          bp = Format02d(ep, al.cs.minute());
+          result.append(bp, static_cast<std::size_t>(ep - bp));
+          break;
+        case 'S':
+          bp = Format02d(ep, al.cs.second());
+          result.append(bp, static_cast<std::size_t>(ep - bp));
+          break;
+        case 'z':
+          bp = FormatOffset(ep, al.offset, "");
+          result.append(bp, static_cast<std::size_t>(ep - bp));
+          break;
+        case 'Z':
+          result.append(al.abbr);
+          break;
+        case 's':
+          bp = Format64(ep, 0, ToUnixSeconds(tp));
+          result.append(bp, static_cast<std::size_t>(ep - bp));
+          break;
+        case '%':
+          result.push_back('%');
+          break;
+      }
+      pending = ++cur;
+      continue;
+    }
+
+    // More complex specifiers that we handle ourselves.
+    if (*cur == ':' && cur + 1 != end) {
+      if (*(cur + 1) == 'z') {
+        // Formats %:z.
+        if (cur - 1 != pending) {
+          FormatTM(&result, std::string(pending, cur - 1), tm);
+        }
+        bp = FormatOffset(ep, al.offset, ":");
+        result.append(bp, static_cast<std::size_t>(ep - bp));
+        pending = cur += 2;
+        continue;
+      }
+      if (*(cur + 1) == ':' && cur + 2 != end) {
+        if (*(cur + 2) == 'z') {
+          // Formats %::z.
+          if (cur - 1 != pending) {
+            FormatTM(&result, std::string(pending, cur - 1), tm);
+          }
+          bp = FormatOffset(ep, al.offset, ":*");
+          result.append(bp, static_cast<std::size_t>(ep - bp));
+          pending = cur += 3;
+          continue;
+        }
+        if (*(cur + 2) == ':' && cur + 3 != end) {
+          if (*(cur + 3) == 'z') {
+            // Formats %:::z.
+            if (cur - 1 != pending) {
+              FormatTM(&result, std::string(pending, cur - 1), tm);
+            }
+            bp = FormatOffset(ep, al.offset, ":*:");
+            result.append(bp, static_cast<std::size_t>(ep - bp));
+            pending = cur += 4;
+            continue;
+          }
+        }
+      }
+    }
+
+    // Loop if there is no E modifier.
+    if (*cur != 'E' || ++cur == end) continue;
+
+    // Format our extensions.
+    if (*cur == 'T') {
+      // Formats %ET.
+      if (cur - 2 != pending) {
+        FormatTM(&result, std::string(pending, cur - 2), tm);
+      }
+      result.append("T");
+      pending = ++cur;
+    } else if (*cur == 'z') {
+      // Formats %Ez.
+      if (cur - 2 != pending) {
+        FormatTM(&result, std::string(pending, cur - 2), tm);
+      }
+      bp = FormatOffset(ep, al.offset, ":");
+      result.append(bp, static_cast<std::size_t>(ep - bp));
+      pending = ++cur;
+    } else if (*cur == '*' && cur + 1 != end && *(cur + 1) == 'z') {
+      // Formats %E*z.
+      if (cur - 2 != pending) {
+        FormatTM(&result, std::string(pending, cur - 2), tm);
+      }
+      bp = FormatOffset(ep, al.offset, ":*");
+      result.append(bp, static_cast<std::size_t>(ep - bp));
+      pending = cur += 2;
+    } else if (*cur == '*' && cur + 1 != end &&
+               (*(cur + 1) == 'S' || *(cur + 1) == 'f')) {
+      // Formats %E*S or %E*F.
+      if (cur - 2 != pending) {
+        FormatTM(&result, std::string(pending, cur - 2), tm);
+      }
+      char* cp = ep;
+      bp = Format64(cp, 15, fs.count());
+      while (cp != bp && cp[-1] == '0') --cp;
+      switch (*(cur + 1)) {
+        case 'S':
+          if (cp != bp) *--bp = '.';
+          bp = Format02d(bp, al.cs.second());
+          break;
+        case 'f':
+          if (cp == bp) *--bp = '0';
+          break;
+      }
+      result.append(bp, static_cast<std::size_t>(cp - bp));
+      pending = cur += 2;
+    } else if (*cur == '4' && cur + 1 != end && *(cur + 1) == 'Y') {
+      // Formats %E4Y.
+      if (cur - 2 != pending) {
+        FormatTM(&result, std::string(pending, cur - 2), tm);
+      }
+      bp = Format64(ep, 4, al.cs.year());
+      result.append(bp, static_cast<std::size_t>(ep - bp));
+      pending = cur += 2;
+    } else if (std::isdigit(*cur)) {
+      // Possibly found %E#S or %E#f.
+      int n = 0;
+      if (const char* np = ParseInt(cur, 0, 0, 1024, &n)) {
+        if (*np == 'S' || *np == 'f') {
+          // Formats %E#S or %E#f.
+          if (cur - 2 != pending) {
+            FormatTM(&result, std::string(pending, cur - 2), tm);
+          }
+          bp = ep;
+          if (n > 0) {
+            if (n > kDigits10_64) n = kDigits10_64;
+            bp = Format64(bp, n,
+                          (n > 15) ? fs.count() * kExp10[n - 15]
+                                   : fs.count() / kExp10[15 - n]);
+            if (*np == 'S') *--bp = '.';
+          }
+          if (*np == 'S') bp = Format02d(bp, al.cs.second());
+          result.append(bp, static_cast<std::size_t>(ep - bp));
+          pending = cur = ++np;
+        }
+      }
+    }
+  }
+
+  // Formats any remaining data.
+  if (end != pending) {
+    FormatTM(&result, std::string(pending, end), tm);
+  }
+
+  return result;
+}
+
+namespace {
+
+const char* ParseOffset(const char* dp, const char* mode, int* offset) {
+  if (dp != nullptr) {
+    const char first = *dp++;
+    if (first == '+' || first == '-') {
+      char sep = mode[0];
+      int hours = 0;
+      int minutes = 0;
+      int seconds = 0;
+      const char* ap = ParseInt(dp, 2, 0, 23, &hours);
+      if (ap != nullptr && ap - dp == 2) {
+        dp = ap;
+        if (sep != '\0' && *ap == sep) ++ap;
+        const char* bp = ParseInt(ap, 2, 0, 59, &minutes);
+        if (bp != nullptr && bp - ap == 2) {
+          dp = bp;
+          if (sep != '\0' && *bp == sep) ++bp;
+          const char* cp = ParseInt(bp, 2, 0, 59, &seconds);
+          if (cp != nullptr && cp - bp == 2) dp = cp;
+        }
+        *offset = ((hours * 60 + minutes) * 60) + seconds;
+        if (first == '-') *offset = -*offset;
+      } else {
+        dp = nullptr;
+      }
+    } else if (first == 'Z' || first == 'z') {  // Zulu
+      *offset = 0;
+    } else {
+      dp = nullptr;
+    }
+  }
+  return dp;
+}
+
+const char* ParseZone(const char* dp, std::string* zone) {
+  zone->clear();
+  if (dp != nullptr) {
+    while (*dp != '\0' && !std::isspace(*dp)) zone->push_back(*dp++);
+    if (zone->empty()) dp = nullptr;
+  }
+  return dp;
+}
+
+const char* ParseSubSeconds(const char* dp, detail::femtoseconds* subseconds) {
+  if (dp != nullptr) {
+    std::int_fast64_t v = 0;
+    std::int_fast64_t exp = 0;
+    const char* const bp = dp;
+    while (const char* cp = strchr(kDigits, *dp)) {
+      int d = static_cast<int>(cp - kDigits);
+      if (d >= 10) break;
+      if (exp < 15) {
+        exp += 1;
+        v *= 10;
+        v += d;
+      }
+      ++dp;
+    }
+    if (dp != bp) {
+      v *= kExp10[15 - exp];
+      *subseconds = detail::femtoseconds(v);
+    } else {
+      dp = nullptr;
+    }
+  }
+  return dp;
+}
+
+// Parses a string into a std::tm using strptime(3).
+const char* ParseTM(const char* dp, const char* fmt, std::tm* tm) {
+  if (dp != nullptr) {
+    dp = strptime(dp, fmt, tm);
+  }
+  return dp;
+}
+
+// Sets year, tm_mon and tm_mday given the year, week_num, and tm_wday,
+// and the day on which weeks are defined to start.  Returns false if year
+// would need to move outside its bounds.
+bool FromWeek(int week_num, weekday week_start, year_t* year, std::tm* tm) {
+  const civil_year y(*year % 400);
+  civil_day cd = prev_weekday(y, week_start);  // week 0
+  cd = next_weekday(cd - 1, FromTmWday(tm->tm_wday)) + (week_num * 7);
+  if (const year_t shift = cd.year() - y.year()) {
+    if (shift > 0) {
+      if (*year > std::numeric_limits<year_t>::max() - shift) return false;
+    } else {
+      if (*year < std::numeric_limits<year_t>::min() - shift) return false;
+    }
+    *year += shift;
+  }
+  tm->tm_mon = cd.month() - 1;
+  tm->tm_mday = cd.day();
+  return true;
+}
+
+}  // namespace
+
+// Uses strptime(3) to parse the given input.  Supports the same extended
+// format specifiers as format(), although %E#S and %E*S are treated
+// identically (and similarly for %E#f and %E*f).  %Ez and %E*z also accept
+// the same inputs. %ET accepts either 'T' or 't'.
+//
+// The standard specifiers from RFC3339_* (%Y, %m, %d, %H, %M, and %S) are
+// handled internally so that we can normally avoid strptime() altogether
+// (which is particularly helpful when the native implementation is broken).
+//
+// The TZ/GNU %s extension is handled internally because strptime() has to
+// use localtime_r() to generate it, and that assumes the local time zone.
+//
+// We also handle the %z specifier to accommodate platforms that do not
+// support the tm_gmtoff extension to std::tm.  %Z is parsed but ignored.
+bool parse(const std::string& format, const std::string& input,
+           const time_zone& tz, time_point<seconds>* sec,
+           detail::femtoseconds* fs, std::string* err) {
+  // The unparsed input.
+  const char* data = input.c_str();  // NUL terminated
+
+  // Skips leading whitespace.
+  while (std::isspace(*data)) ++data;
+
+  const year_t kyearmax = std::numeric_limits<year_t>::max();
+  const year_t kyearmin = std::numeric_limits<year_t>::min();
+
+  // Sets default values for unspecified fields.
+  bool saw_year = false;
+  year_t year = 1970;
+  std::tm tm{};
+  tm.tm_year = 1970 - 1900;
+  tm.tm_mon = 1 - 1;  // Jan
+  tm.tm_mday = 1;
+  tm.tm_hour = 0;
+  tm.tm_min = 0;
+  tm.tm_sec = 0;
+  tm.tm_wday = 4;  // Thu
+  tm.tm_yday = 0;
+  tm.tm_isdst = 0;
+  auto subseconds = detail::femtoseconds::zero();
+  bool saw_offset = false;
+  int offset = 0;  // No offset from passed tz.
+  std::string zone = "UTC";
+
+  const char* fmt = format.c_str();  // NUL terminated
+  bool twelve_hour = false;
+  bool afternoon = false;
+  int week_num = -1;
+  weekday week_start = weekday::sunday;
+
+  bool saw_percent_s = false;
+  std::int_fast64_t percent_s = 0;
+
+  // Steps through format, one specifier at a time.
+  while (data != nullptr && *fmt != '\0') {
+    if (std::isspace(*fmt)) {
+      while (std::isspace(*data)) ++data;
+      while (std::isspace(*++fmt)) continue;
+      continue;
+    }
+
+    if (*fmt != '%') {
+      if (*data == *fmt) {
+        ++data;
+        ++fmt;
+      } else {
+        data = nullptr;
+      }
+      continue;
+    }
+
+    const char* percent = fmt;
+    if (*++fmt == '\0') {
+      data = nullptr;
+      continue;
+    }
+    switch (*fmt++) {
+      case 'Y':
+        // Symmetrically with FormatTime(), directly handing %Y avoids the
+        // tm.tm_year overflow problem.  However, tm.tm_year will still be
+        // used by other specifiers like %D.
+        data = ParseInt(data, 0, kyearmin, kyearmax, &year);
+        if (data != nullptr) saw_year = true;
+        continue;
+      case 'm':
+        data = ParseInt(data, 2, 1, 12, &tm.tm_mon);
+        if (data != nullptr) tm.tm_mon -= 1;
+        week_num = -1;
+        continue;
+      case 'd':
+      case 'e':
+        data = ParseInt(data, 2, 1, 31, &tm.tm_mday);
+        week_num = -1;
+        continue;
+      case 'U':
+        data = ParseInt(data, 0, 0, 53, &week_num);
+        week_start = weekday::sunday;
+        continue;
+      case 'W':
+        data = ParseInt(data, 0, 0, 53, &week_num);
+        week_start = weekday::monday;
+        continue;
+      case 'u':
+        data = ParseInt(data, 0, 1, 7, &tm.tm_wday);
+        if (data != nullptr) tm.tm_wday %= 7;
+        continue;
+      case 'w':
+        data = ParseInt(data, 0, 0, 6, &tm.tm_wday);
+        continue;
+      case 'H':
+        data = ParseInt(data, 2, 0, 23, &tm.tm_hour);
+        twelve_hour = false;
+        continue;
+      case 'M':
+        data = ParseInt(data, 2, 0, 59, &tm.tm_min);
+        continue;
+      case 'S':
+        data = ParseInt(data, 2, 0, 60, &tm.tm_sec);
+        continue;
+      case 'I':
+      case 'l':
+      case 'r':  // probably uses %I
+        twelve_hour = true;
+        break;
+      case 'R':  // uses %H
+      case 'T':  // uses %H
+      case 'c':  // probably uses %H
+      case 'X':  // probably uses %H
+        twelve_hour = false;
+        break;
+      case 'z':
+        data = ParseOffset(data, "", &offset);
+        if (data != nullptr) saw_offset = true;
+        continue;
+      case 'Z':  // ignored; zone abbreviations are ambiguous
+        data = ParseZone(data, &zone);
+        continue;
+      case 's':
+        data =
+            ParseInt(data, 0, std::numeric_limits<std::int_fast64_t>::min(),
+                     std::numeric_limits<std::int_fast64_t>::max(), &percent_s);
+        if (data != nullptr) saw_percent_s = true;
+        continue;
+      case ':':
+        if (fmt[0] == 'z' ||
+            (fmt[0] == ':' &&
+             (fmt[1] == 'z' || (fmt[1] == ':' && fmt[2] == 'z')))) {
+          data = ParseOffset(data, ":", &offset);
+          if (data != nullptr) saw_offset = true;
+          fmt += (fmt[0] == 'z') ? 1 : (fmt[1] == 'z') ? 2 : 3;
+          continue;
+        }
+        break;
+      case '%':
+        data = (*data == '%' ? data + 1 : nullptr);
+        continue;
+      case 'E':
+        if (fmt[0] == 'T') {
+          if (*data == 'T' || *data == 't') {
+            ++data;
+            ++fmt;
+          } else {
+            data = nullptr;
+          }
+          continue;
+        }
+        if (fmt[0] == 'z' || (fmt[0] == '*' && fmt[1] == 'z')) {
+          data = ParseOffset(data, ":", &offset);
+          if (data != nullptr) saw_offset = true;
+          fmt += (fmt[0] == 'z') ? 1 : 2;
+          continue;
+        }
+        if (fmt[0] == '*' && fmt[1] == 'S') {
+          data = ParseInt(data, 2, 0, 60, &tm.tm_sec);
+          if (data != nullptr && *data == '.') {
+            data = ParseSubSeconds(data + 1, &subseconds);
+          }
+          fmt += 2;
+          continue;
+        }
+        if (fmt[0] == '*' && fmt[1] == 'f') {
+          if (data != nullptr && std::isdigit(*data)) {
+            data = ParseSubSeconds(data, &subseconds);
+          }
+          fmt += 2;
+          continue;
+        }
+        if (fmt[0] == '4' && fmt[1] == 'Y') {
+          const char* bp = data;
+          data = ParseInt(data, 4, year_t{-999}, year_t{9999}, &year);
+          if (data != nullptr) {
+            if (data - bp == 4) {
+              saw_year = true;
+            } else {
+              data = nullptr;  // stopped too soon
+            }
+          }
+          fmt += 2;
+          continue;
+        }
+        if (std::isdigit(*fmt)) {
+          int n = 0;  // value ignored
+          if (const char* np = ParseInt(fmt, 0, 0, 1024, &n)) {
+            if (*np == 'S') {
+              data = ParseInt(data, 2, 0, 60, &tm.tm_sec);
+              if (data != nullptr && *data == '.') {
+                data = ParseSubSeconds(data + 1, &subseconds);
+              }
+              fmt = ++np;
+              continue;
+            }
+            if (*np == 'f') {
+              if (data != nullptr && std::isdigit(*data)) {
+                data = ParseSubSeconds(data, &subseconds);
+              }
+              fmt = ++np;
+              continue;
+            }
+          }
+        }
+        if (*fmt == 'c') twelve_hour = false;  // probably uses %H
+        if (*fmt == 'X') twelve_hour = false;  // probably uses %H
+        if (*fmt != '\0') ++fmt;
+        break;
+      case 'O':
+        if (*fmt == 'H') twelve_hour = false;
+        if (*fmt == 'I') twelve_hour = true;
+        if (*fmt != '\0') ++fmt;
+        break;
+    }
+
+    // Parses the current specifier.
+    const char* orig_data = data;
+    std::string spec(percent, static_cast<std::size_t>(fmt - percent));
+    data = ParseTM(data, spec.c_str(), &tm);
+
+    // If we successfully parsed %p we need to remember whether the result
+    // was AM or PM so that we can adjust tm_hour before time_zone::lookup().
+    // So reparse the input with a known AM hour, and check if it is shifted
+    // to a PM hour.
+    if (spec == "%p" && data != nullptr) {
+      std::string test_input = "1";
+      test_input.append(orig_data, static_cast<std::size_t>(data - orig_data));
+      const char* test_data = test_input.c_str();
+      std::tm tmp{};
+      ParseTM(test_data, "%I%p", &tmp);
+      afternoon = (tmp.tm_hour == 13);
+    }
+  }
+
+  // Adjust a 12-hour tm_hour value if it should be in the afternoon.
+  if (twelve_hour && afternoon && tm.tm_hour < 12) {
+    tm.tm_hour += 12;
+  }
+
+  if (data == nullptr) {
+    if (err != nullptr) *err = "Failed to parse input";
+    return false;
+  }
+
+  // Skip any remaining whitespace.
+  while (std::isspace(*data)) ++data;
+
+  // parse() must consume the entire input string.
+  if (*data != '\0') {
+    if (err != nullptr) *err = "Illegal trailing data in input string";
+    return false;
+  }
+
+  // If we saw %s then we ignore anything else and return that time.
+  if (saw_percent_s) {
+    *sec = FromUnixSeconds(percent_s);
+    *fs = detail::femtoseconds::zero();
+    return true;
+  }
+
+  // If we saw %z, %Ez, or %E*z then we want to interpret the parsed fields
+  // in UTC and then shift by that offset.  Otherwise we want to interpret
+  // the fields directly in the passed time_zone.
+  time_zone ptz = saw_offset ? utc_time_zone() : tz;
+
+  // Allows a leap second of 60 to normalize forward to the following ":00".
+  if (tm.tm_sec == 60) {
+    tm.tm_sec -= 1;
+    offset -= 1;
+    subseconds = detail::femtoseconds::zero();
+  }
+
+  if (!saw_year) {
+    year = year_t{tm.tm_year};
+    if (year > kyearmax - 1900) {
+      // Platform-dependent, maybe unreachable.
+      if (err != nullptr) *err = "Out-of-range year";
+      return false;
+    }
+    year += 1900;
+  }
+
+  // Compute year, tm.tm_mon and tm.tm_mday if we parsed a week number.
+  if (week_num != -1) {
+    if (!FromWeek(week_num, week_start, &year, &tm)) {
+      if (err != nullptr) *err = "Out-of-range field";
+      return false;
+    }
+  }
+
+  const int month = tm.tm_mon + 1;
+  civil_second cs(year, month, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec);
+
+  // parse() should not allow normalization. Due to the restricted field
+  // ranges above (see ParseInt()), the only possibility is for days to roll
+  // into months. That is, parsing "Sep 31" should not produce "Oct 1".
+  if (cs.month() != month || cs.day() != tm.tm_mday) {
+    if (err != nullptr) *err = "Out-of-range field";
+    return false;
+  }
+
+  // Accounts for the offset adjustment before converting to absolute time.
+  if ((offset < 0 && cs > civil_second::max() + offset) ||
+      (offset > 0 && cs < civil_second::min() + offset)) {
+    if (err != nullptr) *err = "Out-of-range field";
+    return false;
+  }
+  cs -= offset;
+
+  const auto tp = ptz.lookup(cs).pre;
+  // Checks for overflow/underflow and returns an error as necessary.
+  if (tp == time_point<seconds>::max()) {
+    const auto al = ptz.lookup(time_point<seconds>::max());
+    if (cs > al.cs) {
+      if (err != nullptr) *err = "Out-of-range field";
+      return false;
+    }
+  }
+  if (tp == time_point<seconds>::min()) {
+    const auto al = ptz.lookup(time_point<seconds>::min());
+    if (cs < al.cs) {
+      if (err != nullptr) *err = "Out-of-range field";
+      return false;
+    }
+  }
+
+  *sec = tp;
+  *fs = subseconds;
+  return true;
+}
+
+}  // namespace detail
+}  // namespace cctz
+}  // namespace time_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
diff --git a/src/absl/time/internal/cctz/src/time_zone_if.cc b/src/absl/time/internal/cctz/src/time_zone_if.cc
new file mode 100644 (file)
index 0000000..0319b2f
--- /dev/null
@@ -0,0 +1,45 @@
+// Copyright 2016 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//   https://www.apache.org/licenses/LICENSE-2.0
+//
+//   Unless required by applicable law or agreed to in writing, software
+//   distributed under the License is distributed on an "AS IS" BASIS,
+//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//   See the License for the specific language governing permissions and
+//   limitations under the License.
+
+#include "time_zone_if.h"
+
+#include "absl/base/config.h"
+#include "time_zone_info.h"
+#include "time_zone_libc.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace time_internal {
+namespace cctz {
+
+std::unique_ptr<TimeZoneIf> TimeZoneIf::Load(const std::string& name) {
+  // Support "libc:localtime" and "libc:*" to access the legacy
+  // localtime and UTC support respectively from the C library.
+  if (name.compare(0, 5, "libc:") == 0) {
+    return std::unique_ptr<TimeZoneIf>(new TimeZoneLibC(name.substr(5)));
+  }
+
+  // Otherwise use the "zoneinfo" implementation by default.
+  std::unique_ptr<TimeZoneInfo> tz(new TimeZoneInfo);
+  if (!tz->Load(name)) tz.reset();
+  return std::unique_ptr<TimeZoneIf>(tz.release());
+}
+
+// Defined out-of-line to avoid emitting a weak vtable in all TUs.
+TimeZoneIf::~TimeZoneIf() {}
+
+}  // namespace cctz
+}  // namespace time_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
diff --git a/src/absl/time/internal/cctz/src/time_zone_if.h b/src/absl/time/internal/cctz/src/time_zone_if.h
new file mode 100644 (file)
index 0000000..32c0891
--- /dev/null
@@ -0,0 +1,76 @@
+// Copyright 2016 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//   https://www.apache.org/licenses/LICENSE-2.0
+//
+//   Unless required by applicable law or agreed to in writing, software
+//   distributed under the License is distributed on an "AS IS" BASIS,
+//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//   See the License for the specific language governing permissions and
+//   limitations under the License.
+
+#ifndef ABSL_TIME_INTERNAL_CCTZ_TIME_ZONE_IF_H_
+#define ABSL_TIME_INTERNAL_CCTZ_TIME_ZONE_IF_H_
+
+#include <chrono>
+#include <cstdint>
+#include <memory>
+#include <string>
+
+#include "absl/base/config.h"
+#include "absl/time/internal/cctz/include/cctz/civil_time.h"
+#include "absl/time/internal/cctz/include/cctz/time_zone.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace time_internal {
+namespace cctz {
+
+// A simple interface used to hide time-zone complexities from time_zone::Impl.
+// Subclasses implement the functions for civil-time conversions in the zone.
+class TimeZoneIf {
+ public:
+  // A factory function for TimeZoneIf implementations.
+  static std::unique_ptr<TimeZoneIf> Load(const std::string& name);
+
+  virtual ~TimeZoneIf();
+
+  virtual time_zone::absolute_lookup BreakTime(
+      const time_point<seconds>& tp) const = 0;
+  virtual time_zone::civil_lookup MakeTime(const civil_second& cs) const = 0;
+
+  virtual bool NextTransition(const time_point<seconds>& tp,
+                              time_zone::civil_transition* trans) const = 0;
+  virtual bool PrevTransition(const time_point<seconds>& tp,
+                              time_zone::civil_transition* trans) const = 0;
+
+  virtual std::string Version() const = 0;
+  virtual std::string Description() const = 0;
+
+ protected:
+  TimeZoneIf() {}
+};
+
+// Convert between time_point<seconds> and a count of seconds since the
+// Unix epoch.  We assume that the std::chrono::system_clock and the
+// Unix clock are second aligned, but not that they share an epoch.
+inline std::int_fast64_t ToUnixSeconds(const time_point<seconds>& tp) {
+  return (tp - std::chrono::time_point_cast<seconds>(
+                   std::chrono::system_clock::from_time_t(0)))
+      .count();
+}
+inline time_point<seconds> FromUnixSeconds(std::int_fast64_t t) {
+  return std::chrono::time_point_cast<seconds>(
+             std::chrono::system_clock::from_time_t(0)) +
+         seconds(t);
+}
+
+}  // namespace cctz
+}  // namespace time_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#endif  // ABSL_TIME_INTERNAL_CCTZ_TIME_ZONE_IF_H_
diff --git a/src/absl/time/internal/cctz/src/time_zone_impl.cc b/src/absl/time/internal/cctz/src/time_zone_impl.cc
new file mode 100644 (file)
index 0000000..f34e3ae
--- /dev/null
@@ -0,0 +1,113 @@
+// Copyright 2016 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//   https://www.apache.org/licenses/LICENSE-2.0
+//
+//   Unless required by applicable law or agreed to in writing, software
+//   distributed under the License is distributed on an "AS IS" BASIS,
+//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//   See the License for the specific language governing permissions and
+//   limitations under the License.
+
+#include "time_zone_impl.h"
+
+#include <deque>
+#include <memory>
+#include <mutex>
+#include <string>
+#include <unordered_map>
+#include <utility>
+
+#include "absl/base/config.h"
+#include "time_zone_fixed.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace time_internal {
+namespace cctz {
+
+namespace {
+
+// time_zone::Impls are linked into a map to support fast lookup by name.
+using TimeZoneImplByName =
+    std::unordered_map<std::string, const time_zone::Impl*>;
+TimeZoneImplByName* time_zone_map = nullptr;
+
+// Mutual exclusion for time_zone_map.
+std::mutex& TimeZoneMutex() {
+  // This mutex is intentionally "leaked" to avoid the static deinitialization
+  // order fiasco (std::mutex's destructor is not trivial on many platforms).
+  static std::mutex* time_zone_mutex = new std::mutex;
+  return *time_zone_mutex;
+}
+
+}  // namespace
+
+time_zone time_zone::Impl::UTC() { return time_zone(UTCImpl()); }
+
+bool time_zone::Impl::LoadTimeZone(const std::string& name, time_zone* tz) {
+  const Impl* const utc_impl = UTCImpl();
+
+  // Check for UTC (which is never a key in time_zone_map).
+  auto offset = seconds::zero();
+  if (FixedOffsetFromName(name, &offset) && offset == seconds::zero()) {
+    *tz = time_zone(utc_impl);
+    return true;
+  }
+
+  // Check whether the time zone has already been loaded.
+  {
+    std::lock_guard<std::mutex> lock(TimeZoneMutex());
+    if (time_zone_map != nullptr) {
+      TimeZoneImplByName::const_iterator itr = time_zone_map->find(name);
+      if (itr != time_zone_map->end()) {
+        *tz = time_zone(itr->second);
+        return itr->second != utc_impl;
+      }
+    }
+  }
+
+  // Load the new time zone (outside the lock).
+  std::unique_ptr<const Impl> new_impl(new Impl(name));
+
+  // Add the new time zone to the map.
+  std::lock_guard<std::mutex> lock(TimeZoneMutex());
+  if (time_zone_map == nullptr) time_zone_map = new TimeZoneImplByName;
+  const Impl*& impl = (*time_zone_map)[name];
+  if (impl == nullptr) {  // this thread won any load race
+    impl = new_impl->zone_ ? new_impl.release() : utc_impl;
+  }
+  *tz = time_zone(impl);
+  return impl != utc_impl;
+}
+
+void time_zone::Impl::ClearTimeZoneMapTestOnly() {
+  std::lock_guard<std::mutex> lock(TimeZoneMutex());
+  if (time_zone_map != nullptr) {
+    // Existing time_zone::Impl* entries are in the wild, so we can't delete
+    // them. Instead, we move them to a private container, where they are
+    // logically unreachable but not "leaked".  Future requests will result
+    // in reloading the data.
+    static auto* cleared = new std::deque<const time_zone::Impl*>;
+    for (const auto& element : *time_zone_map) {
+      cleared->push_back(element.second);
+    }
+    time_zone_map->clear();
+  }
+}
+
+time_zone::Impl::Impl(const std::string& name)
+    : name_(name), zone_(TimeZoneIf::Load(name_)) {}
+
+const time_zone::Impl* time_zone::Impl::UTCImpl() {
+  static const Impl* utc_impl = new Impl("UTC");  // never fails
+  return utc_impl;
+}
+
+}  // namespace cctz
+}  // namespace time_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
diff --git a/src/absl/time/internal/cctz/src/time_zone_impl.h b/src/absl/time/internal/cctz/src/time_zone_impl.h
new file mode 100644 (file)
index 0000000..7d747ba
--- /dev/null
@@ -0,0 +1,93 @@
+// Copyright 2016 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//   https://www.apache.org/licenses/LICENSE-2.0
+//
+//   Unless required by applicable law or agreed to in writing, software
+//   distributed under the License is distributed on an "AS IS" BASIS,
+//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//   See the License for the specific language governing permissions and
+//   limitations under the License.
+
+#ifndef ABSL_TIME_INTERNAL_CCTZ_TIME_ZONE_IMPL_H_
+#define ABSL_TIME_INTERNAL_CCTZ_TIME_ZONE_IMPL_H_
+
+#include <memory>
+#include <string>
+
+#include "absl/base/config.h"
+#include "absl/time/internal/cctz/include/cctz/civil_time.h"
+#include "absl/time/internal/cctz/include/cctz/time_zone.h"
+#include "time_zone_if.h"
+#include "time_zone_info.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace time_internal {
+namespace cctz {
+
+// time_zone::Impl is the internal object referenced by a cctz::time_zone.
+class time_zone::Impl {
+ public:
+  // The UTC time zone. Also used for other time zones that fail to load.
+  static time_zone UTC();
+
+  // Load a named time zone. Returns false if the name is invalid, or if
+  // some other kind of error occurs. Note that loading "UTC" never fails.
+  static bool LoadTimeZone(const std::string& name, time_zone* tz);
+
+  // Clears the map of cached time zones.  Primarily for use in benchmarks
+  // that gauge the performance of loading/parsing the time-zone data.
+  static void ClearTimeZoneMapTestOnly();
+
+  // The primary key is the time-zone ID (e.g., "America/New_York").
+  const std::string& Name() const {
+    // TODO: It would nice if the zoneinfo data included the zone name.
+    return name_;
+  }
+
+  // Breaks a time_point down to civil-time components in this time zone.
+  time_zone::absolute_lookup BreakTime(const time_point<seconds>& tp) const {
+    return zone_->BreakTime(tp);
+  }
+
+  // Converts the civil-time components in this time zone into a time_point.
+  // That is, the opposite of BreakTime(). The requested civil time may be
+  // ambiguous or illegal due to a change of UTC offset.
+  time_zone::civil_lookup MakeTime(const civil_second& cs) const {
+    return zone_->MakeTime(cs);
+  }
+
+  // Finds the time of the next/previous offset change in this time zone.
+  bool NextTransition(const time_point<seconds>& tp,
+                      time_zone::civil_transition* trans) const {
+    return zone_->NextTransition(tp, trans);
+  }
+  bool PrevTransition(const time_point<seconds>& tp,
+                      time_zone::civil_transition* trans) const {
+    return zone_->PrevTransition(tp, trans);
+  }
+
+  // Returns an implementation-defined version string for this time zone.
+  std::string Version() const { return zone_->Version(); }
+
+  // Returns an implementation-defined description of this time zone.
+  std::string Description() const { return zone_->Description(); }
+
+ private:
+  explicit Impl(const std::string& name);
+  static const Impl* UTCImpl();
+
+  const std::string name_;
+  std::unique_ptr<TimeZoneIf> zone_;
+};
+
+}  // namespace cctz
+}  // namespace time_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#endif  // ABSL_TIME_INTERNAL_CCTZ_TIME_ZONE_IMPL_H_
diff --git a/src/absl/time/internal/cctz/src/time_zone_info.cc b/src/absl/time/internal/cctz/src/time_zone_info.cc
new file mode 100644 (file)
index 0000000..8039353
--- /dev/null
@@ -0,0 +1,965 @@
+// Copyright 2016 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//   https://www.apache.org/licenses/LICENSE-2.0
+//
+//   Unless required by applicable law or agreed to in writing, software
+//   distributed under the License is distributed on an "AS IS" BASIS,
+//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//   See the License for the specific language governing permissions and
+//   limitations under the License.
+
+// This file implements the TimeZoneIf interface using the "zoneinfo"
+// data provided by the IANA Time Zone Database (i.e., the only real game
+// in town).
+//
+// TimeZoneInfo represents the history of UTC-offset changes within a time
+// zone. Most changes are due to daylight-saving rules, but occasionally
+// shifts are made to the time-zone's base offset. The database only attempts
+// to be definitive for times since 1970, so be wary of local-time conversions
+// before that. Also, rule and zone-boundary changes are made at the whim
+// of governments, so the conversion of future times needs to be taken with
+// a grain of salt.
+//
+// For more information see tzfile(5), http://www.iana.org/time-zones, or
+// https://en.wikipedia.org/wiki/Zoneinfo.
+//
+// Note that we assume the proleptic Gregorian calendar and 60-second
+// minutes throughout.
+
+#include "time_zone_info.h"
+
+#include <algorithm>
+#include <cassert>
+#include <chrono>
+#include <cstdint>
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
+#include <functional>
+#include <memory>
+#include <sstream>
+#include <string>
+
+#include "absl/base/config.h"
+#include "absl/time/internal/cctz/include/cctz/civil_time.h"
+#include "time_zone_fixed.h"
+#include "time_zone_posix.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace time_internal {
+namespace cctz {
+
+namespace {
+
+inline bool IsLeap(year_t year) {
+  return (year % 4) == 0 && ((year % 100) != 0 || (year % 400) == 0);
+}
+
+// The number of days in non-leap and leap years respectively.
+const std::int_least32_t kDaysPerYear[2] = {365, 366};
+
+// The day offsets of the beginning of each (1-based) month in non-leap and
+// leap years respectively (e.g., 335 days before December in a leap year).
+const std::int_least16_t kMonthOffsets[2][1 + 12 + 1] = {
+    {-1, 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365},
+    {-1, 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366},
+};
+
+// We reject leap-second encoded zoneinfo and so assume 60-second minutes.
+const std::int_least32_t kSecsPerDay = 24 * 60 * 60;
+
+// 400-year chunks always have 146097 days (20871 weeks).
+const std::int_least64_t kSecsPer400Years = 146097LL * kSecsPerDay;
+
+// Like kDaysPerYear[] but scaled up by a factor of kSecsPerDay.
+const std::int_least32_t kSecsPerYear[2] = {
+    365 * kSecsPerDay,
+    366 * kSecsPerDay,
+};
+
+// Convert a cctz::weekday to a POSIX TZ weekday number (0==Sun, ..., 6=Sat).
+inline int ToPosixWeekday(weekday wd) {
+  switch (wd) {
+    case weekday::sunday:
+      return 0;
+    case weekday::monday:
+      return 1;
+    case weekday::tuesday:
+      return 2;
+    case weekday::wednesday:
+      return 3;
+    case weekday::thursday:
+      return 4;
+    case weekday::friday:
+      return 5;
+    case weekday::saturday:
+      return 6;
+  }
+  return 0; /*NOTREACHED*/
+}
+
+// Single-byte, unsigned numeric values are encoded directly.
+inline std::uint_fast8_t Decode8(const char* cp) {
+  return static_cast<std::uint_fast8_t>(*cp) & 0xff;
+}
+
+// Multi-byte, numeric values are encoded using a MSB first,
+// twos-complement representation. These helpers decode, from
+// the given address, 4-byte and 8-byte values respectively.
+// Note: If int_fastXX_t == intXX_t and this machine is not
+// twos complement, then there will be at least one input value
+// we cannot represent.
+std::int_fast32_t Decode32(const char* cp) {
+  std::uint_fast32_t v = 0;
+  for (int i = 0; i != (32 / 8); ++i) v = (v << 8) | Decode8(cp++);
+  const std::int_fast32_t s32max = 0x7fffffff;
+  const auto s32maxU = static_cast<std::uint_fast32_t>(s32max);
+  if (v <= s32maxU) return static_cast<std::int_fast32_t>(v);
+  return static_cast<std::int_fast32_t>(v - s32maxU - 1) - s32max - 1;
+}
+
+std::int_fast64_t Decode64(const char* cp) {
+  std::uint_fast64_t v = 0;
+  for (int i = 0; i != (64 / 8); ++i) v = (v << 8) | Decode8(cp++);
+  const std::int_fast64_t s64max = 0x7fffffffffffffff;
+  const auto s64maxU = static_cast<std::uint_fast64_t>(s64max);
+  if (v <= s64maxU) return static_cast<std::int_fast64_t>(v);
+  return static_cast<std::int_fast64_t>(v - s64maxU - 1) - s64max - 1;
+}
+
+// Generate a year-relative offset for a PosixTransition.
+std::int_fast64_t TransOffset(bool leap_year, int jan1_weekday,
+                              const PosixTransition& pt) {
+  std::int_fast64_t days = 0;
+  switch (pt.date.fmt) {
+    case PosixTransition::J: {
+      days = pt.date.j.day;
+      if (!leap_year || days < kMonthOffsets[1][3]) days -= 1;
+      break;
+    }
+    case PosixTransition::N: {
+      days = pt.date.n.day;
+      break;
+    }
+    case PosixTransition::M: {
+      const bool last_week = (pt.date.m.week == 5);
+      days = kMonthOffsets[leap_year][pt.date.m.month + last_week];
+      const std::int_fast64_t weekday = (jan1_weekday + days) % 7;
+      if (last_week) {
+        days -= (weekday + 7 - 1 - pt.date.m.weekday) % 7 + 1;
+      } else {
+        days += (pt.date.m.weekday + 7 - weekday) % 7;
+        days += (pt.date.m.week - 1) * 7;
+      }
+      break;
+    }
+  }
+  return (days * kSecsPerDay) + pt.time.offset;
+}
+
+inline time_zone::civil_lookup MakeUnique(const time_point<seconds>& tp) {
+  time_zone::civil_lookup cl;
+  cl.kind = time_zone::civil_lookup::UNIQUE;
+  cl.pre = cl.trans = cl.post = tp;
+  return cl;
+}
+
+inline time_zone::civil_lookup MakeUnique(std::int_fast64_t unix_time) {
+  return MakeUnique(FromUnixSeconds(unix_time));
+}
+
+inline time_zone::civil_lookup MakeSkipped(const Transition& tr,
+                                           const civil_second& cs) {
+  time_zone::civil_lookup cl;
+  cl.kind = time_zone::civil_lookup::SKIPPED;
+  cl.pre = FromUnixSeconds(tr.unix_time - 1 + (cs - tr.prev_civil_sec));
+  cl.trans = FromUnixSeconds(tr.unix_time);
+  cl.post = FromUnixSeconds(tr.unix_time - (tr.civil_sec - cs));
+  return cl;
+}
+
+inline time_zone::civil_lookup MakeRepeated(const Transition& tr,
+                                            const civil_second& cs) {
+  time_zone::civil_lookup cl;
+  cl.kind = time_zone::civil_lookup::REPEATED;
+  cl.pre = FromUnixSeconds(tr.unix_time - 1 - (tr.prev_civil_sec - cs));
+  cl.trans = FromUnixSeconds(tr.unix_time);
+  cl.post = FromUnixSeconds(tr.unix_time + (cs - tr.civil_sec));
+  return cl;
+}
+
+inline civil_second YearShift(const civil_second& cs, year_t shift) {
+  return civil_second(cs.year() + shift, cs.month(), cs.day(), cs.hour(),
+                      cs.minute(), cs.second());
+}
+
+}  // namespace
+
+// What (no leap-seconds) UTC+seconds zoneinfo would look like.
+bool TimeZoneInfo::ResetToBuiltinUTC(const seconds& offset) {
+  transition_types_.resize(1);
+  TransitionType& tt(transition_types_.back());
+  tt.utc_offset = static_cast<std::int_least32_t>(offset.count());
+  tt.is_dst = false;
+  tt.abbr_index = 0;
+
+  // We temporarily add some redundant, contemporary (2015 through 2025)
+  // transitions for performance reasons.  See TimeZoneInfo::LocalTime().
+  // TODO: Fix the performance issue and remove the extra transitions.
+  transitions_.clear();
+  transitions_.reserve(12);
+  for (const std::int_fast64_t unix_time : {
+           -(1LL << 59),  // a "first half" transition
+           1420070400LL,  // 2015-01-01T00:00:00+00:00
+           1451606400LL,  // 2016-01-01T00:00:00+00:00
+           1483228800LL,  // 2017-01-01T00:00:00+00:00
+           1514764800LL,  // 2018-01-01T00:00:00+00:00
+           1546300800LL,  // 2019-01-01T00:00:00+00:00
+           1577836800LL,  // 2020-01-01T00:00:00+00:00
+           1609459200LL,  // 2021-01-01T00:00:00+00:00
+           1640995200LL,  // 2022-01-01T00:00:00+00:00
+           1672531200LL,  // 2023-01-01T00:00:00+00:00
+           1704067200LL,  // 2024-01-01T00:00:00+00:00
+           1735689600LL,  // 2025-01-01T00:00:00+00:00
+       }) {
+    Transition& tr(*transitions_.emplace(transitions_.end()));
+    tr.unix_time = unix_time;
+    tr.type_index = 0;
+    tr.civil_sec = LocalTime(tr.unix_time, tt).cs;
+    tr.prev_civil_sec = tr.civil_sec - 1;
+  }
+
+  default_transition_type_ = 0;
+  abbreviations_ = FixedOffsetToAbbr(offset);
+  abbreviations_.append(1, '\0');
+  future_spec_.clear();  // never needed for a fixed-offset zone
+  extended_ = false;
+
+  tt.civil_max = LocalTime(seconds::max().count(), tt).cs;
+  tt.civil_min = LocalTime(seconds::min().count(), tt).cs;
+
+  transitions_.shrink_to_fit();
+  return true;
+}
+
+// Builds the in-memory header using the raw bytes from the file.
+bool TimeZoneInfo::Header::Build(const tzhead& tzh) {
+  std::int_fast32_t v;
+  if ((v = Decode32(tzh.tzh_timecnt)) < 0) return false;
+  timecnt = static_cast<std::size_t>(v);
+  if ((v = Decode32(tzh.tzh_typecnt)) < 0) return false;
+  typecnt = static_cast<std::size_t>(v);
+  if ((v = Decode32(tzh.tzh_charcnt)) < 0) return false;
+  charcnt = static_cast<std::size_t>(v);
+  if ((v = Decode32(tzh.tzh_leapcnt)) < 0) return false;
+  leapcnt = static_cast<std::size_t>(v);
+  if ((v = Decode32(tzh.tzh_ttisstdcnt)) < 0) return false;
+  ttisstdcnt = static_cast<std::size_t>(v);
+  if ((v = Decode32(tzh.tzh_ttisutcnt)) < 0) return false;
+  ttisutcnt = static_cast<std::size_t>(v);
+  return true;
+}
+
+// How many bytes of data are associated with this header. The result
+// depends upon whether this is a section with 4-byte or 8-byte times.
+std::size_t TimeZoneInfo::Header::DataLength(std::size_t time_len) const {
+  std::size_t len = 0;
+  len += (time_len + 1) * timecnt;  // unix_time + type_index
+  len += (4 + 1 + 1) * typecnt;     // utc_offset + is_dst + abbr_index
+  len += 1 * charcnt;               // abbreviations
+  len += (time_len + 4) * leapcnt;  // leap-time + TAI-UTC
+  len += 1 * ttisstdcnt;            // UTC/local indicators
+  len += 1 * ttisutcnt;             // standard/wall indicators
+  return len;
+}
+
+// zic(8) can generate no-op transitions when a zone changes rules at an
+// instant when there is actually no discontinuity.  So we check whether
+// two transitions have equivalent types (same offset/is_dst/abbr).
+bool TimeZoneInfo::EquivTransitions(std::uint_fast8_t tt1_index,
+                                    std::uint_fast8_t tt2_index) const {
+  if (tt1_index == tt2_index) return true;
+  const TransitionType& tt1(transition_types_[tt1_index]);
+  const TransitionType& tt2(transition_types_[tt2_index]);
+  if (tt1.utc_offset != tt2.utc_offset) return false;
+  if (tt1.is_dst != tt2.is_dst) return false;
+  if (tt1.abbr_index != tt2.abbr_index) return false;
+  return true;
+}
+
+// Find/make a transition type with these attributes.
+bool TimeZoneInfo::GetTransitionType(std::int_fast32_t utc_offset, bool is_dst,
+                                     const std::string& abbr,
+                                     std::uint_least8_t* index) {
+  std::size_t type_index = 0;
+  std::size_t abbr_index = abbreviations_.size();
+  for (; type_index != transition_types_.size(); ++type_index) {
+    const TransitionType& tt(transition_types_[type_index]);
+    const char* tt_abbr = &abbreviations_[tt.abbr_index];
+    if (tt_abbr == abbr) abbr_index = tt.abbr_index;
+    if (tt.utc_offset == utc_offset && tt.is_dst == is_dst) {
+      if (abbr_index == tt.abbr_index) break;  // reuse
+    }
+  }
+  if (type_index > 255 || abbr_index > 255) {
+    // No index space (8 bits) available for a new type or abbreviation.
+    return false;
+  }
+  if (type_index == transition_types_.size()) {
+    TransitionType& tt(*transition_types_.emplace(transition_types_.end()));
+    tt.utc_offset = static_cast<std::int_least32_t>(utc_offset);
+    tt.is_dst = is_dst;
+    if (abbr_index == abbreviations_.size()) {
+      abbreviations_.append(abbr);
+      abbreviations_.append(1, '\0');
+    }
+    tt.abbr_index = static_cast<std::uint_least8_t>(abbr_index);
+  }
+  *index = static_cast<std::uint_least8_t>(type_index);
+  return true;
+}
+
+// Use the POSIX-TZ-environment-variable-style string to handle times
+// in years after the last transition stored in the zoneinfo data.
+bool TimeZoneInfo::ExtendTransitions() {
+  extended_ = false;
+  if (future_spec_.empty()) return true;  // last transition prevails
+
+  PosixTimeZone posix;
+  if (!ParsePosixSpec(future_spec_, &posix)) return false;
+
+  // Find transition type for the future std specification.
+  std::uint_least8_t std_ti;
+  if (!GetTransitionType(posix.std_offset, false, posix.std_abbr, &std_ti))
+    return false;
+
+  if (posix.dst_abbr.empty()) {  // std only
+    // The future specification should match the last transition, and
+    // that means that handling the future will fall out naturally.
+    return EquivTransitions(transitions_.back().type_index, std_ti);
+  }
+
+  // Find transition type for the future dst specification.
+  std::uint_least8_t dst_ti;
+  if (!GetTransitionType(posix.dst_offset, true, posix.dst_abbr, &dst_ti))
+    return false;
+
+  // Extend the transitions for an additional 400 years using the
+  // future specification. Years beyond those can be handled by
+  // mapping back to a cycle-equivalent year within that range.
+  // We may need two additional transitions for the current year.
+  transitions_.reserve(transitions_.size() + 400 * 2 + 2);
+  extended_ = true;
+
+  const Transition& last(transitions_.back());
+  const std::int_fast64_t last_time = last.unix_time;
+  const TransitionType& last_tt(transition_types_[last.type_index]);
+  last_year_ = LocalTime(last_time, last_tt).cs.year();
+  bool leap_year = IsLeap(last_year_);
+  const civil_second jan1(last_year_);
+  std::int_fast64_t jan1_time = jan1 - civil_second();
+  int jan1_weekday = ToPosixWeekday(get_weekday(jan1));
+
+  Transition dst = {0, dst_ti, civil_second(), civil_second()};
+  Transition std = {0, std_ti, civil_second(), civil_second()};
+  for (const year_t limit = last_year_ + 400;; ++last_year_) {
+    auto dst_trans_off = TransOffset(leap_year, jan1_weekday, posix.dst_start);
+    auto std_trans_off = TransOffset(leap_year, jan1_weekday, posix.dst_end);
+    dst.unix_time = jan1_time + dst_trans_off - posix.std_offset;
+    std.unix_time = jan1_time + std_trans_off - posix.dst_offset;
+    const auto* ta = dst.unix_time < std.unix_time ? &dst : &std;
+    const auto* tb = dst.unix_time < std.unix_time ? &std : &dst;
+    if (last_time < tb->unix_time) {
+      if (last_time < ta->unix_time) transitions_.push_back(*ta);
+      transitions_.push_back(*tb);
+    }
+    if (last_year_ == limit) break;
+    jan1_time += kSecsPerYear[leap_year];
+    jan1_weekday = (jan1_weekday + kDaysPerYear[leap_year]) % 7;
+    leap_year = !leap_year && IsLeap(last_year_ + 1);
+  }
+
+  return true;
+}
+
+bool TimeZoneInfo::Load(ZoneInfoSource* zip) {
+  // Read and validate the header.
+  tzhead tzh;
+  if (zip->Read(&tzh, sizeof(tzh)) != sizeof(tzh)) return false;
+  if (strncmp(tzh.tzh_magic, TZ_MAGIC, sizeof(tzh.tzh_magic)) != 0)
+    return false;
+  Header hdr;
+  if (!hdr.Build(tzh)) return false;
+  std::size_t time_len = 4;
+  if (tzh.tzh_version[0] != '\0') {
+    // Skip the 4-byte data.
+    if (zip->Skip(hdr.DataLength(time_len)) != 0) return false;
+    // Read and validate the header for the 8-byte data.
+    if (zip->Read(&tzh, sizeof(tzh)) != sizeof(tzh)) return false;
+    if (strncmp(tzh.tzh_magic, TZ_MAGIC, sizeof(tzh.tzh_magic)) != 0)
+      return false;
+    if (tzh.tzh_version[0] == '\0') return false;
+    if (!hdr.Build(tzh)) return false;
+    time_len = 8;
+  }
+  if (hdr.typecnt == 0) return false;
+  if (hdr.leapcnt != 0) {
+    // This code assumes 60-second minutes so we do not want
+    // the leap-second encoded zoneinfo. We could reverse the
+    // compensation, but the "right" encoding is rarely used
+    // so currently we simply reject such data.
+    return false;
+  }
+  if (hdr.ttisstdcnt != 0 && hdr.ttisstdcnt != hdr.typecnt) return false;
+  if (hdr.ttisutcnt != 0 && hdr.ttisutcnt != hdr.typecnt) return false;
+
+  // Read the data into a local buffer.
+  std::size_t len = hdr.DataLength(time_len);
+  std::vector<char> tbuf(len);
+  if (zip->Read(tbuf.data(), len) != len) return false;
+  const char* bp = tbuf.data();
+
+  // Decode and validate the transitions.
+  transitions_.reserve(hdr.timecnt + 2);
+  transitions_.resize(hdr.timecnt);
+  for (std::size_t i = 0; i != hdr.timecnt; ++i) {
+    transitions_[i].unix_time = (time_len == 4) ? Decode32(bp) : Decode64(bp);
+    bp += time_len;
+    if (i != 0) {
+      // Check that the transitions are ordered by time (as zic guarantees).
+      if (!Transition::ByUnixTime()(transitions_[i - 1], transitions_[i]))
+        return false;  // out of order
+    }
+  }
+  bool seen_type_0 = false;
+  for (std::size_t i = 0; i != hdr.timecnt; ++i) {
+    transitions_[i].type_index = Decode8(bp++);
+    if (transitions_[i].type_index >= hdr.typecnt) return false;
+    if (transitions_[i].type_index == 0) seen_type_0 = true;
+  }
+
+  // Decode and validate the transition types.
+  transition_types_.reserve(hdr.typecnt + 2);
+  transition_types_.resize(hdr.typecnt);
+  for (std::size_t i = 0; i != hdr.typecnt; ++i) {
+    transition_types_[i].utc_offset =
+        static_cast<std::int_least32_t>(Decode32(bp));
+    if (transition_types_[i].utc_offset >= kSecsPerDay ||
+        transition_types_[i].utc_offset <= -kSecsPerDay)
+      return false;
+    bp += 4;
+    transition_types_[i].is_dst = (Decode8(bp++) != 0);
+    transition_types_[i].abbr_index = Decode8(bp++);
+    if (transition_types_[i].abbr_index >= hdr.charcnt) return false;
+  }
+
+  // Determine the before-first-transition type.
+  default_transition_type_ = 0;
+  if (seen_type_0 && hdr.timecnt != 0) {
+    std::uint_fast8_t index = 0;
+    if (transition_types_[0].is_dst) {
+      index = transitions_[0].type_index;
+      while (index != 0 && transition_types_[index].is_dst) --index;
+    }
+    while (index != hdr.typecnt && transition_types_[index].is_dst) ++index;
+    if (index != hdr.typecnt) default_transition_type_ = index;
+  }
+
+  // Copy all the abbreviations.
+  abbreviations_.reserve(hdr.charcnt + 10);
+  abbreviations_.assign(bp, hdr.charcnt);
+  bp += hdr.charcnt;
+
+  // Skip the unused portions. We've already dispensed with leap-second
+  // encoded zoneinfo. The ttisstd/ttisgmt indicators only apply when
+  // interpreting a POSIX spec that does not include start/end rules, and
+  // that isn't the case here (see "zic -p").
+  bp += (8 + 4) * hdr.leapcnt;  // leap-time + TAI-UTC
+  bp += 1 * hdr.ttisstdcnt;     // UTC/local indicators
+  bp += 1 * hdr.ttisutcnt;      // standard/wall indicators
+  assert(bp == tbuf.data() + tbuf.size());
+
+  future_spec_.clear();
+  if (tzh.tzh_version[0] != '\0') {
+    // Snarf up the NL-enclosed future POSIX spec. Note
+    // that version '3' files utilize an extended format.
+    auto get_char = [](ZoneInfoSource* azip) -> int {
+      unsigned char ch;  // all non-EOF results are positive
+      return (azip->Read(&ch, 1) == 1) ? ch : EOF;
+    };
+    if (get_char(zip) != '\n') return false;
+    for (int c = get_char(zip); c != '\n'; c = get_char(zip)) {
+      if (c == EOF) return false;
+      future_spec_.push_back(static_cast<char>(c));
+    }
+  }
+
+  // We don't check for EOF so that we're forwards compatible.
+
+  // If we did not find version information during the standard loading
+  // process (as of tzh_version '3' that is unsupported), then ask the
+  // ZoneInfoSource for any out-of-bound version string it may be privy to.
+  if (version_.empty()) {
+    version_ = zip->Version();
+  }
+
+  // Trim redundant transitions. zic may have added these to work around
+  // differences between the glibc and reference implementations (see
+  // zic.c:dontmerge) and the Qt library (see zic.c:WORK_AROUND_QTBUG_53071).
+  // For us, they just get in the way when we do future_spec_ extension.
+  while (hdr.timecnt > 1) {
+    if (!EquivTransitions(transitions_[hdr.timecnt - 1].type_index,
+                          transitions_[hdr.timecnt - 2].type_index)) {
+      break;
+    }
+    hdr.timecnt -= 1;
+  }
+  transitions_.resize(hdr.timecnt);
+
+  // Ensure that there is always a transition in the first half of the
+  // time line (the second half is handled below) so that the signed
+  // difference between a civil_second and the civil_second of its
+  // previous transition is always representable, without overflow.
+  if (transitions_.empty() || transitions_.front().unix_time >= 0) {
+    Transition& tr(*transitions_.emplace(transitions_.begin()));
+    tr.unix_time = -(1LL << 59);  // -18267312070-10-26T17:01:52+00:00
+    tr.type_index = default_transition_type_;
+  }
+
+  // Extend the transitions using the future specification.
+  if (!ExtendTransitions()) return false;
+
+  // Ensure that there is always a transition in the second half of the
+  // time line (the first half is handled above) so that the signed
+  // difference between a civil_second and the civil_second of its
+  // previous transition is always representable, without overflow.
+  const Transition& last(transitions_.back());
+  if (last.unix_time < 0) {
+    const std::uint_fast8_t type_index = last.type_index;
+    Transition& tr(*transitions_.emplace(transitions_.end()));
+    tr.unix_time = 2147483647;  // 2038-01-19T03:14:07+00:00
+    tr.type_index = type_index;
+  }
+
+  // Compute the local civil time for each transition and the preceding
+  // second. These will be used for reverse conversions in MakeTime().
+  const TransitionType* ttp = &transition_types_[default_transition_type_];
+  for (std::size_t i = 0; i != transitions_.size(); ++i) {
+    Transition& tr(transitions_[i]);
+    tr.prev_civil_sec = LocalTime(tr.unix_time, *ttp).cs - 1;
+    ttp = &transition_types_[tr.type_index];
+    tr.civil_sec = LocalTime(tr.unix_time, *ttp).cs;
+    if (i != 0) {
+      // Check that the transitions are ordered by civil time. Essentially
+      // this means that an offset change cannot cross another such change.
+      // No one does this in practice, and we depend on it in MakeTime().
+      if (!Transition::ByCivilTime()(transitions_[i - 1], tr))
+        return false;  // out of order
+    }
+  }
+
+  // Compute the maximum/minimum civil times that can be converted to a
+  // time_point<seconds> for each of the zone's transition types.
+  for (auto& tt : transition_types_) {
+    tt.civil_max = LocalTime(seconds::max().count(), tt).cs;
+    tt.civil_min = LocalTime(seconds::min().count(), tt).cs;
+  }
+
+  transitions_.shrink_to_fit();
+  return true;
+}
+
+namespace {
+
+// fopen(3) adaptor.
+inline FILE* FOpen(const char* path, const char* mode) {
+#if defined(_MSC_VER)
+  FILE* fp;
+  if (fopen_s(&fp, path, mode) != 0) fp = nullptr;
+  return fp;
+#else
+  return fopen(path, mode);  // TODO: Enable the close-on-exec flag.
+#endif
+}
+
+// A stdio(3)-backed implementation of ZoneInfoSource.
+class FileZoneInfoSource : public ZoneInfoSource {
+ public:
+  static std::unique_ptr<ZoneInfoSource> Open(const std::string& name);
+
+  std::size_t Read(void* ptr, std::size_t size) override {
+    size = std::min(size, len_);
+    std::size_t nread = fread(ptr, 1, size, fp_.get());
+    len_ -= nread;
+    return nread;
+  }
+  int Skip(std::size_t offset) override {
+    offset = std::min(offset, len_);
+    int rc = fseek(fp_.get(), static_cast<long>(offset), SEEK_CUR);
+    if (rc == 0) len_ -= offset;
+    return rc;
+  }
+  std::string Version() const override {
+    // TODO: It would nice if the zoneinfo data included the tzdb version.
+    return std::string();
+  }
+
+ protected:
+  explicit FileZoneInfoSource(
+      FILE* fp, std::size_t len = std::numeric_limits<std::size_t>::max())
+      : fp_(fp, fclose), len_(len) {}
+
+ private:
+  std::unique_ptr<FILE, int (*)(FILE*)> fp_;
+  std::size_t len_;
+};
+
+std::unique_ptr<ZoneInfoSource> FileZoneInfoSource::Open(
+    const std::string& name) {
+  // Use of the "file:" prefix is intended for testing purposes only.
+  const std::size_t pos = (name.compare(0, 5, "file:") == 0) ? 5 : 0;
+
+  // Map the time-zone name to a path name.
+  std::string path;
+  if (pos == name.size() || name[pos] != '/') {
+    const char* tzdir = "/usr/share/zoneinfo";
+    char* tzdir_env = nullptr;
+#if defined(_MSC_VER)
+    _dupenv_s(&tzdir_env, nullptr, "TZDIR");
+#else
+    tzdir_env = std::getenv("TZDIR");
+#endif
+    if (tzdir_env && *tzdir_env) tzdir = tzdir_env;
+    path += tzdir;
+    path += '/';
+#if defined(_MSC_VER)
+    free(tzdir_env);
+#endif
+  }
+  path.append(name, pos, std::string::npos);
+
+  // Open the zoneinfo file.
+  FILE* fp = FOpen(path.c_str(), "rb");
+  if (fp == nullptr) return nullptr;
+  std::size_t length = 0;
+  if (fseek(fp, 0, SEEK_END) == 0) {
+    long offset = ftell(fp);
+    if (offset >= 0) {
+      length = static_cast<std::size_t>(offset);
+    }
+    rewind(fp);
+  }
+  return std::unique_ptr<ZoneInfoSource>(new FileZoneInfoSource(fp, length));
+}
+
+class AndroidZoneInfoSource : public FileZoneInfoSource {
+ public:
+  static std::unique_ptr<ZoneInfoSource> Open(const std::string& name);
+  std::string Version() const override { return version_; }
+
+ private:
+  explicit AndroidZoneInfoSource(FILE* fp, std::size_t len, const char* vers)
+      : FileZoneInfoSource(fp, len), version_(vers) {}
+  std::string version_;
+};
+
+std::unique_ptr<ZoneInfoSource> AndroidZoneInfoSource::Open(
+    const std::string& name) {
+  // Use of the "file:" prefix is intended for testing purposes only.
+  const std::size_t pos = (name.compare(0, 5, "file:") == 0) ? 5 : 0;
+
+  // See Android's libc/tzcode/bionic.cpp for additional information.
+  for (const char* tzdata : {"/data/misc/zoneinfo/current/tzdata",
+                             "/system/usr/share/zoneinfo/tzdata"}) {
+    std::unique_ptr<FILE, int (*)(FILE*)> fp(FOpen(tzdata, "rb"), fclose);
+    if (fp.get() == nullptr) continue;
+
+    char hbuf[24];  // covers header.zonetab_offset too
+    if (fread(hbuf, 1, sizeof(hbuf), fp.get()) != sizeof(hbuf)) continue;
+    if (strncmp(hbuf, "tzdata", 6) != 0) continue;
+    const char* vers = (hbuf[11] == '\0') ? hbuf + 6 : "";
+    const std::int_fast32_t index_offset = Decode32(hbuf + 12);
+    const std::int_fast32_t data_offset = Decode32(hbuf + 16);
+    if (index_offset < 0 || data_offset < index_offset) continue;
+    if (fseek(fp.get(), static_cast<long>(index_offset), SEEK_SET) != 0)
+      continue;
+
+    char ebuf[52];  // covers entry.unused too
+    const std::size_t index_size =
+        static_cast<std::size_t>(data_offset - index_offset);
+    const std::size_t zonecnt = index_size / sizeof(ebuf);
+    if (zonecnt * sizeof(ebuf) != index_size) continue;
+    for (std::size_t i = 0; i != zonecnt; ++i) {
+      if (fread(ebuf, 1, sizeof(ebuf), fp.get()) != sizeof(ebuf)) break;
+      const std::int_fast32_t start = data_offset + Decode32(ebuf + 40);
+      const std::int_fast32_t length = Decode32(ebuf + 44);
+      if (start < 0 || length < 0) break;
+      ebuf[40] = '\0';  // ensure zone name is NUL terminated
+      if (strcmp(name.c_str() + pos, ebuf) == 0) {
+        if (fseek(fp.get(), static_cast<long>(start), SEEK_SET) != 0) break;
+        return std::unique_ptr<ZoneInfoSource>(new AndroidZoneInfoSource(
+            fp.release(), static_cast<std::size_t>(length), vers));
+      }
+    }
+  }
+
+  return nullptr;
+}
+
+}  // namespace
+
+bool TimeZoneInfo::Load(const std::string& name) {
+  // We can ensure that the loading of UTC or any other fixed-offset
+  // zone never fails because the simple, fixed-offset state can be
+  // internally generated. Note that this depends on our choice to not
+  // accept leap-second encoded ("right") zoneinfo.
+  auto offset = seconds::zero();
+  if (FixedOffsetFromName(name, &offset)) {
+    return ResetToBuiltinUTC(offset);
+  }
+
+  // Find and use a ZoneInfoSource to load the named zone.
+  auto zip = cctz_extension::zone_info_source_factory(
+      name, [](const std::string& n) -> std::unique_ptr<ZoneInfoSource> {
+        if (auto z = FileZoneInfoSource::Open(n)) return z;
+        if (auto z = AndroidZoneInfoSource::Open(n)) return z;
+        return nullptr;
+      });
+  return zip != nullptr && Load(zip.get());
+}
+
+// BreakTime() translation for a particular transition type.
+time_zone::absolute_lookup TimeZoneInfo::LocalTime(
+    std::int_fast64_t unix_time, const TransitionType& tt) const {
+  // A civil time in "+offset" looks like (time+offset) in UTC.
+  // Note: We perform two additions in the civil_second domain to
+  // sidestep the chance of overflow in (unix_time + tt.utc_offset).
+  return {(civil_second() + unix_time) + tt.utc_offset, tt.utc_offset,
+          tt.is_dst, &abbreviations_[tt.abbr_index]};
+}
+
+// BreakTime() translation for a particular transition.
+time_zone::absolute_lookup TimeZoneInfo::LocalTime(std::int_fast64_t unix_time,
+                                                   const Transition& tr) const {
+  const TransitionType& tt = transition_types_[tr.type_index];
+  // Note: (unix_time - tr.unix_time) will never overflow as we
+  // have ensured that there is always a "nearby" transition.
+  return {tr.civil_sec + (unix_time - tr.unix_time),  // TODO: Optimize.
+          tt.utc_offset, tt.is_dst, &abbreviations_[tt.abbr_index]};
+}
+
+// MakeTime() translation with a conversion-preserving +N * 400-year shift.
+time_zone::civil_lookup TimeZoneInfo::TimeLocal(const civil_second& cs,
+                                                year_t c4_shift) const {
+  assert(last_year_ - 400 < cs.year() && cs.year() <= last_year_);
+  time_zone::civil_lookup cl = MakeTime(cs);
+  if (c4_shift > seconds::max().count() / kSecsPer400Years) {
+    cl.pre = cl.trans = cl.post = time_point<seconds>::max();
+  } else {
+    const auto offset = seconds(c4_shift * kSecsPer400Years);
+    const auto limit = time_point<seconds>::max() - offset;
+    for (auto* tp : {&cl.pre, &cl.trans, &cl.post}) {
+      if (*tp > limit) {
+        *tp = time_point<seconds>::max();
+      } else {
+        *tp += offset;
+      }
+    }
+  }
+  return cl;
+}
+
+time_zone::absolute_lookup TimeZoneInfo::BreakTime(
+    const time_point<seconds>& tp) const {
+  std::int_fast64_t unix_time = ToUnixSeconds(tp);
+  const std::size_t timecnt = transitions_.size();
+  assert(timecnt != 0);  // We always add a transition.
+
+  if (unix_time < transitions_[0].unix_time) {
+    return LocalTime(unix_time, transition_types_[default_transition_type_]);
+  }
+  if (unix_time >= transitions_[timecnt - 1].unix_time) {
+    // After the last transition. If we extended the transitions using
+    // future_spec_, shift back to a supported year using the 400-year
+    // cycle of calendaric equivalence and then compensate accordingly.
+    if (extended_) {
+      const std::int_fast64_t diff =
+          unix_time - transitions_[timecnt - 1].unix_time;
+      const year_t shift = diff / kSecsPer400Years + 1;
+      const auto d = seconds(shift * kSecsPer400Years);
+      time_zone::absolute_lookup al = BreakTime(tp - d);
+      al.cs = YearShift(al.cs, shift * 400);
+      return al;
+    }
+    return LocalTime(unix_time, transitions_[timecnt - 1]);
+  }
+
+  const std::size_t hint = local_time_hint_.load(std::memory_order_relaxed);
+  if (0 < hint && hint < timecnt) {
+    if (transitions_[hint - 1].unix_time <= unix_time) {
+      if (unix_time < transitions_[hint].unix_time) {
+        return LocalTime(unix_time, transitions_[hint - 1]);
+      }
+    }
+  }
+
+  const Transition target = {unix_time, 0, civil_second(), civil_second()};
+  const Transition* begin = &transitions_[0];
+  const Transition* tr = std::upper_bound(begin, begin + timecnt, target,
+                                          Transition::ByUnixTime());
+  local_time_hint_.store(static_cast<std::size_t>(tr - begin),
+                         std::memory_order_relaxed);
+  return LocalTime(unix_time, *--tr);
+}
+
+time_zone::civil_lookup TimeZoneInfo::MakeTime(const civil_second& cs) const {
+  const std::size_t timecnt = transitions_.size();
+  assert(timecnt != 0);  // We always add a transition.
+
+  // Find the first transition after our target civil time.
+  const Transition* tr = nullptr;
+  const Transition* begin = &transitions_[0];
+  const Transition* end = begin + timecnt;
+  if (cs < begin->civil_sec) {
+    tr = begin;
+  } else if (cs >= transitions_[timecnt - 1].civil_sec) {
+    tr = end;
+  } else {
+    const std::size_t hint = time_local_hint_.load(std::memory_order_relaxed);
+    if (0 < hint && hint < timecnt) {
+      if (transitions_[hint - 1].civil_sec <= cs) {
+        if (cs < transitions_[hint].civil_sec) {
+          tr = begin + hint;
+        }
+      }
+    }
+    if (tr == nullptr) {
+      const Transition target = {0, 0, cs, civil_second()};
+      tr = std::upper_bound(begin, end, target, Transition::ByCivilTime());
+      time_local_hint_.store(static_cast<std::size_t>(tr - begin),
+                             std::memory_order_relaxed);
+    }
+  }
+
+  if (tr == begin) {
+    if (tr->prev_civil_sec >= cs) {
+      // Before first transition, so use the default offset.
+      const TransitionType& tt(transition_types_[default_transition_type_]);
+      if (cs < tt.civil_min) return MakeUnique(time_point<seconds>::min());
+      return MakeUnique(cs - (civil_second() + tt.utc_offset));
+    }
+    // tr->prev_civil_sec < cs < tr->civil_sec
+    return MakeSkipped(*tr, cs);
+  }
+
+  if (tr == end) {
+    if (cs > (--tr)->prev_civil_sec) {
+      // After the last transition. If we extended the transitions using
+      // future_spec_, shift back to a supported year using the 400-year
+      // cycle of calendaric equivalence and then compensate accordingly.
+      if (extended_ && cs.year() > last_year_) {
+        const year_t shift = (cs.year() - last_year_ - 1) / 400 + 1;
+        return TimeLocal(YearShift(cs, shift * -400), shift);
+      }
+      const TransitionType& tt(transition_types_[tr->type_index]);
+      if (cs > tt.civil_max) return MakeUnique(time_point<seconds>::max());
+      return MakeUnique(tr->unix_time + (cs - tr->civil_sec));
+    }
+    // tr->civil_sec <= cs <= tr->prev_civil_sec
+    return MakeRepeated(*tr, cs);
+  }
+
+  if (tr->prev_civil_sec < cs) {
+    // tr->prev_civil_sec < cs < tr->civil_sec
+    return MakeSkipped(*tr, cs);
+  }
+
+  if (cs <= (--tr)->prev_civil_sec) {
+    // tr->civil_sec <= cs <= tr->prev_civil_sec
+    return MakeRepeated(*tr, cs);
+  }
+
+  // In between transitions.
+  return MakeUnique(tr->unix_time + (cs - tr->civil_sec));
+}
+
+std::string TimeZoneInfo::Version() const { return version_; }
+
+std::string TimeZoneInfo::Description() const {
+  std::ostringstream oss;
+  oss << "#trans=" << transitions_.size();
+  oss << " #types=" << transition_types_.size();
+  oss << " spec='" << future_spec_ << "'";
+  return oss.str();
+}
+
+bool TimeZoneInfo::NextTransition(const time_point<seconds>& tp,
+                                  time_zone::civil_transition* trans) const {
+  if (transitions_.empty()) return false;
+  const Transition* begin = &transitions_[0];
+  const Transition* end = begin + transitions_.size();
+  if (begin->unix_time <= -(1LL << 59)) {
+    // Do not report the BIG_BANG found in some zoneinfo data as it is
+    // really a sentinel, not a transition.  See pre-2018f tz/zic.c.
+    ++begin;
+  }
+  std::int_fast64_t unix_time = ToUnixSeconds(tp);
+  const Transition target = {unix_time, 0, civil_second(), civil_second()};
+  const Transition* tr =
+      std::upper_bound(begin, end, target, Transition::ByUnixTime());
+  for (; tr != end; ++tr) {  // skip no-op transitions
+    std::uint_fast8_t prev_type_index =
+        (tr == begin) ? default_transition_type_ : tr[-1].type_index;
+    if (!EquivTransitions(prev_type_index, tr[0].type_index)) break;
+  }
+  // When tr == end we return false, ignoring future_spec_.
+  if (tr == end) return false;
+  trans->from = tr->prev_civil_sec + 1;
+  trans->to = tr->civil_sec;
+  return true;
+}
+
+bool TimeZoneInfo::PrevTransition(const time_point<seconds>& tp,
+                                  time_zone::civil_transition* trans) const {
+  if (transitions_.empty()) return false;
+  const Transition* begin = &transitions_[0];
+  const Transition* end = begin + transitions_.size();
+  if (begin->unix_time <= -(1LL << 59)) {
+    // Do not report the BIG_BANG found in some zoneinfo data as it is
+    // really a sentinel, not a transition.  See pre-2018f tz/zic.c.
+    ++begin;
+  }
+  std::int_fast64_t unix_time = ToUnixSeconds(tp);
+  if (FromUnixSeconds(unix_time) != tp) {
+    if (unix_time == std::numeric_limits<std::int_fast64_t>::max()) {
+      if (end == begin) return false;  // Ignore future_spec_.
+      trans->from = (--end)->prev_civil_sec + 1;
+      trans->to = end->civil_sec;
+      return true;
+    }
+    unix_time += 1;  // ceils
+  }
+  const Transition target = {unix_time, 0, civil_second(), civil_second()};
+  const Transition* tr =
+      std::lower_bound(begin, end, target, Transition::ByUnixTime());
+  for (; tr != begin; --tr) {  // skip no-op transitions
+    std::uint_fast8_t prev_type_index =
+        (tr - 1 == begin) ? default_transition_type_ : tr[-2].type_index;
+    if (!EquivTransitions(prev_type_index, tr[-1].type_index)) break;
+  }
+  // When tr == end we return the "last" transition, ignoring future_spec_.
+  if (tr == begin) return false;
+  trans->from = (--tr)->prev_civil_sec + 1;
+  trans->to = tr->civil_sec;
+  return true;
+}
+
+}  // namespace cctz
+}  // namespace time_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
diff --git a/src/absl/time/internal/cctz/src/time_zone_info.h b/src/absl/time/internal/cctz/src/time_zone_info.h
new file mode 100644 (file)
index 0000000..2467ff5
--- /dev/null
@@ -0,0 +1,137 @@
+// Copyright 2016 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//   https://www.apache.org/licenses/LICENSE-2.0
+//
+//   Unless required by applicable law or agreed to in writing, software
+//   distributed under the License is distributed on an "AS IS" BASIS,
+//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//   See the License for the specific language governing permissions and
+//   limitations under the License.
+
+#ifndef ABSL_TIME_INTERNAL_CCTZ_TIME_ZONE_INFO_H_
+#define ABSL_TIME_INTERNAL_CCTZ_TIME_ZONE_INFO_H_
+
+#include <atomic>
+#include <cstddef>
+#include <cstdint>
+#include <string>
+#include <vector>
+
+#include "absl/base/config.h"
+#include "absl/time/internal/cctz/include/cctz/civil_time.h"
+#include "absl/time/internal/cctz/include/cctz/time_zone.h"
+#include "absl/time/internal/cctz/include/cctz/zone_info_source.h"
+#include "time_zone_if.h"
+#include "tzfile.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace time_internal {
+namespace cctz {
+
+// A transition to a new UTC offset.
+struct Transition {
+  std::int_least64_t unix_time;   // the instant of this transition
+  std::uint_least8_t type_index;  // index of the transition type
+  civil_second civil_sec;         // local civil time of transition
+  civil_second prev_civil_sec;    // local civil time one second earlier
+
+  struct ByUnixTime {
+    inline bool operator()(const Transition& lhs, const Transition& rhs) const {
+      return lhs.unix_time < rhs.unix_time;
+    }
+  };
+  struct ByCivilTime {
+    inline bool operator()(const Transition& lhs, const Transition& rhs) const {
+      return lhs.civil_sec < rhs.civil_sec;
+    }
+  };
+};
+
+// The characteristics of a particular transition.
+struct TransitionType {
+  std::int_least32_t utc_offset;  // the new prevailing UTC offset
+  civil_second civil_max;         // max convertible civil time for offset
+  civil_second civil_min;         // min convertible civil time for offset
+  bool is_dst;                    // did we move into daylight-saving time
+  std::uint_least8_t abbr_index;  // index of the new abbreviation
+};
+
+// A time zone backed by the IANA Time Zone Database (zoneinfo).
+class TimeZoneInfo : public TimeZoneIf {
+ public:
+  TimeZoneInfo() = default;
+  TimeZoneInfo(const TimeZoneInfo&) = delete;
+  TimeZoneInfo& operator=(const TimeZoneInfo&) = delete;
+
+  // Loads the zoneinfo for the given name, returning true if successful.
+  bool Load(const std::string& name);
+
+  // TimeZoneIf implementations.
+  time_zone::absolute_lookup BreakTime(
+      const time_point<seconds>& tp) const override;
+  time_zone::civil_lookup MakeTime(const civil_second& cs) const override;
+  bool NextTransition(const time_point<seconds>& tp,
+                      time_zone::civil_transition* trans) const override;
+  bool PrevTransition(const time_point<seconds>& tp,
+                      time_zone::civil_transition* trans) const override;
+  std::string Version() const override;
+  std::string Description() const override;
+
+ private:
+  struct Header {            // counts of:
+    std::size_t timecnt;     // transition times
+    std::size_t typecnt;     // transition types
+    std::size_t charcnt;     // zone abbreviation characters
+    std::size_t leapcnt;     // leap seconds (we expect none)
+    std::size_t ttisstdcnt;  // UTC/local indicators (unused)
+    std::size_t ttisutcnt;   // standard/wall indicators (unused)
+
+    bool Build(const tzhead& tzh);
+    std::size_t DataLength(std::size_t time_len) const;
+  };
+
+  bool GetTransitionType(std::int_fast32_t utc_offset, bool is_dst,
+                         const std::string& abbr, std::uint_least8_t* index);
+  bool EquivTransitions(std::uint_fast8_t tt1_index,
+                        std::uint_fast8_t tt2_index) const;
+  bool ExtendTransitions();
+
+  bool ResetToBuiltinUTC(const seconds& offset);
+  bool Load(ZoneInfoSource* zip);
+
+  // Helpers for BreakTime() and MakeTime().
+  time_zone::absolute_lookup LocalTime(std::int_fast64_t unix_time,
+                                       const TransitionType& tt) const;
+  time_zone::absolute_lookup LocalTime(std::int_fast64_t unix_time,
+                                       const Transition& tr) const;
+  time_zone::civil_lookup TimeLocal(const civil_second& cs,
+                                    year_t c4_shift) const;
+
+  std::vector<Transition> transitions_;  // ordered by unix_time and civil_sec
+  std::vector<TransitionType> transition_types_;  // distinct transition types
+  std::uint_fast8_t default_transition_type_;     // for before first transition
+  std::string abbreviations_;  // all the NUL-terminated abbreviations
+
+  std::string version_;      // the tzdata version if available
+  std::string future_spec_;  // for after the last zic transition
+  bool extended_;            // future_spec_ was used to generate transitions
+  year_t last_year_;         // the final year of the generated transitions
+
+  // We remember the transitions found during the last BreakTime() and
+  // MakeTime() calls. If the next request is for the same transition we
+  // will avoid re-searching.
+  mutable std::atomic<std::size_t> local_time_hint_ = {};  // BreakTime() hint
+  mutable std::atomic<std::size_t> time_local_hint_ = {};  // MakeTime() hint
+};
+
+}  // namespace cctz
+}  // namespace time_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#endif  // ABSL_TIME_INTERNAL_CCTZ_TIME_ZONE_INFO_H_
diff --git a/src/absl/time/internal/cctz/src/time_zone_libc.cc b/src/absl/time/internal/cctz/src/time_zone_libc.cc
new file mode 100644 (file)
index 0000000..887dd09
--- /dev/null
@@ -0,0 +1,315 @@
+// Copyright 2016 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//   https://www.apache.org/licenses/LICENSE-2.0
+//
+//   Unless required by applicable law or agreed to in writing, software
+//   distributed under the License is distributed on an "AS IS" BASIS,
+//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//   See the License for the specific language governing permissions and
+//   limitations under the License.
+
+#if defined(_WIN32) || defined(_WIN64)
+#define _CRT_SECURE_NO_WARNINGS 1
+#endif
+
+#include "time_zone_libc.h"
+
+#include <chrono>
+#include <ctime>
+#include <limits>
+#include <utility>
+
+#include "absl/base/config.h"
+#include "absl/time/internal/cctz/include/cctz/civil_time.h"
+#include "absl/time/internal/cctz/include/cctz/time_zone.h"
+
+#if defined(_AIX)
+extern "C" {
+extern long altzone;
+}
+#endif
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace time_internal {
+namespace cctz {
+
+namespace {
+
+#if defined(_WIN32) || defined(_WIN64)
+// Uses the globals: '_timezone', '_dstbias' and '_tzname'.
+auto tm_gmtoff(const std::tm& tm) -> decltype(_timezone + _dstbias) {
+  const bool is_dst = tm.tm_isdst > 0;
+  return _timezone + (is_dst ? _dstbias : 0);
+}
+auto tm_zone(const std::tm& tm) -> decltype(_tzname[0]) {
+  const bool is_dst = tm.tm_isdst > 0;
+  return _tzname[is_dst];
+}
+#elif defined(__sun) || defined(_AIX)
+// Uses the globals: 'timezone', 'altzone' and 'tzname'.
+auto tm_gmtoff(const std::tm& tm) -> decltype(timezone) {
+  const bool is_dst = tm.tm_isdst > 0;
+  return is_dst ? altzone : timezone;
+}
+auto tm_zone(const std::tm& tm) -> decltype(tzname[0]) {
+  const bool is_dst = tm.tm_isdst > 0;
+  return tzname[is_dst];
+}
+#elif defined(__native_client__) || defined(__myriad2__) || \
+    defined(__EMSCRIPTEN__)
+// Uses the globals: 'timezone' and 'tzname'.
+auto tm_gmtoff(const std::tm& tm) -> decltype(_timezone + 0) {
+  const bool is_dst = tm.tm_isdst > 0;
+  return _timezone + (is_dst ? 60 * 60 : 0);
+}
+auto tm_zone(const std::tm& tm) -> decltype(tzname[0]) {
+  const bool is_dst = tm.tm_isdst > 0;
+  return tzname[is_dst];
+}
+#else
+// Adapt to different spellings of the struct std::tm extension fields.
+#if defined(tm_gmtoff)
+auto tm_gmtoff(const std::tm& tm) -> decltype(tm.tm_gmtoff) {
+  return tm.tm_gmtoff;
+}
+#elif defined(__tm_gmtoff)
+auto tm_gmtoff(const std::tm& tm) -> decltype(tm.__tm_gmtoff) {
+  return tm.__tm_gmtoff;
+}
+#else
+template <typename T>
+auto tm_gmtoff(const T& tm) -> decltype(tm.tm_gmtoff) {
+  return tm.tm_gmtoff;
+}
+template <typename T>
+auto tm_gmtoff(const T& tm) -> decltype(tm.__tm_gmtoff) {
+  return tm.__tm_gmtoff;
+}
+#endif  // tm_gmtoff
+#if defined(tm_zone)
+auto tm_zone(const std::tm& tm) -> decltype(tm.tm_zone) { return tm.tm_zone; }
+#elif defined(__tm_zone)
+auto tm_zone(const std::tm& tm) -> decltype(tm.__tm_zone) {
+  return tm.__tm_zone;
+}
+#else
+template <typename T>
+auto tm_zone(const T& tm) -> decltype(tm.tm_zone) {
+  return tm.tm_zone;
+}
+template <typename T>
+auto tm_zone(const T& tm) -> decltype(tm.__tm_zone) {
+  return tm.__tm_zone;
+}
+#endif  // tm_zone
+#endif
+
+inline std::tm* gm_time(const std::time_t* timep, std::tm* result) {
+#if defined(_WIN32) || defined(_WIN64)
+  return gmtime_s(result, timep) ? nullptr : result;
+#else
+  return gmtime_r(timep, result);
+#endif
+}
+
+inline std::tm* local_time(const std::time_t* timep, std::tm* result) {
+#if defined(_WIN32) || defined(_WIN64)
+  return localtime_s(result, timep) ? nullptr : result;
+#else
+  return localtime_r(timep, result);
+#endif
+}
+
+// Converts a civil second and "dst" flag into a time_t and UTC offset.
+// Returns false if time_t cannot represent the requested civil second.
+// Caller must have already checked that cs.year() will fit into a tm_year.
+bool make_time(const civil_second& cs, int is_dst, std::time_t* t, int* off) {
+  std::tm tm;
+  tm.tm_year = static_cast<int>(cs.year() - year_t{1900});
+  tm.tm_mon = cs.month() - 1;
+  tm.tm_mday = cs.day();
+  tm.tm_hour = cs.hour();
+  tm.tm_min = cs.minute();
+  tm.tm_sec = cs.second();
+  tm.tm_isdst = is_dst;
+  *t = std::mktime(&tm);
+  if (*t == std::time_t{-1}) {
+    std::tm tm2;
+    const std::tm* tmp = local_time(t, &tm2);
+    if (tmp == nullptr || tmp->tm_year != tm.tm_year ||
+        tmp->tm_mon != tm.tm_mon || tmp->tm_mday != tm.tm_mday ||
+        tmp->tm_hour != tm.tm_hour || tmp->tm_min != tm.tm_min ||
+        tmp->tm_sec != tm.tm_sec) {
+      // A true error (not just one second before the epoch).
+      return false;
+    }
+  }
+  *off = static_cast<int>(tm_gmtoff(tm));
+  return true;
+}
+
+// Find the least time_t in [lo:hi] where local time matches offset, given:
+// (1) lo doesn't match, (2) hi does, and (3) there is only one transition.
+std::time_t find_trans(std::time_t lo, std::time_t hi, int offset) {
+  std::tm tm;
+  while (lo + 1 != hi) {
+    const std::time_t mid = lo + (hi - lo) / 2;
+    std::tm* tmp = local_time(&mid, &tm);
+    if (tmp != nullptr) {
+      if (tm_gmtoff(*tmp) == offset) {
+        hi = mid;
+      } else {
+        lo = mid;
+      }
+    } else {
+      // If std::tm cannot hold some result we resort to a linear search,
+      // ignoring all failed conversions.  Slow, but never really happens.
+      while (++lo != hi) {
+        tmp = local_time(&lo, &tm);
+        if (tmp != nullptr) {
+          if (tm_gmtoff(*tmp) == offset) break;
+        }
+      }
+      return lo;
+    }
+  }
+  return hi;
+}
+
+}  // namespace
+
+TimeZoneLibC::TimeZoneLibC(const std::string& name)
+    : local_(name == "localtime") {}
+
+time_zone::absolute_lookup TimeZoneLibC::BreakTime(
+    const time_point<seconds>& tp) const {
+  time_zone::absolute_lookup al;
+  al.offset = 0;
+  al.is_dst = false;
+  al.abbr = "-00";
+
+  const std::int_fast64_t s = ToUnixSeconds(tp);
+
+  // If std::time_t cannot hold the input we saturate the output.
+  if (s < std::numeric_limits<std::time_t>::min()) {
+    al.cs = civil_second::min();
+    return al;
+  }
+  if (s > std::numeric_limits<std::time_t>::max()) {
+    al.cs = civil_second::max();
+    return al;
+  }
+
+  const std::time_t t = static_cast<std::time_t>(s);
+  std::tm tm;
+  std::tm* tmp = local_ ? local_time(&t, &tm) : gm_time(&t, &tm);
+
+  // If std::tm cannot hold the result we saturate the output.
+  if (tmp == nullptr) {
+    al.cs = (s < 0) ? civil_second::min() : civil_second::max();
+    return al;
+  }
+
+  const year_t year = tmp->tm_year + year_t{1900};
+  al.cs = civil_second(year, tmp->tm_mon + 1, tmp->tm_mday, tmp->tm_hour,
+                       tmp->tm_min, tmp->tm_sec);
+  al.offset = static_cast<int>(tm_gmtoff(*tmp));
+  al.abbr = local_ ? tm_zone(*tmp) : "UTC";  // as expected by cctz
+  al.is_dst = tmp->tm_isdst > 0;
+  return al;
+}
+
+time_zone::civil_lookup TimeZoneLibC::MakeTime(const civil_second& cs) const {
+  if (!local_) {
+    // If time_point<seconds> cannot hold the result we saturate.
+    static const civil_second min_tp_cs =
+        civil_second() + ToUnixSeconds(time_point<seconds>::min());
+    static const civil_second max_tp_cs =
+        civil_second() + ToUnixSeconds(time_point<seconds>::max());
+    const time_point<seconds> tp = (cs < min_tp_cs) ? time_point<seconds>::min()
+                                   : (cs > max_tp_cs)
+                                       ? time_point<seconds>::max()
+                                       : FromUnixSeconds(cs - civil_second());
+    return {time_zone::civil_lookup::UNIQUE, tp, tp, tp};
+  }
+
+  // If tm_year cannot hold the requested year we saturate the result.
+  if (cs.year() < 0) {
+    if (cs.year() < std::numeric_limits<int>::min() + year_t{1900}) {
+      const time_point<seconds> tp = time_point<seconds>::min();
+      return {time_zone::civil_lookup::UNIQUE, tp, tp, tp};
+    }
+  } else {
+    if (cs.year() - year_t{1900} > std::numeric_limits<int>::max()) {
+      const time_point<seconds> tp = time_point<seconds>::max();
+      return {time_zone::civil_lookup::UNIQUE, tp, tp, tp};
+    }
+  }
+
+  // We probe with "is_dst" values of 0 and 1 to try to distinguish unique
+  // civil seconds from skipped or repeated ones.  This is not always possible
+  // however, as the "dst" flag does not change over some offset transitions.
+  // We are also subject to the vagaries of mktime() implementations.
+  std::time_t t0, t1;
+  int offset0, offset1;
+  if (make_time(cs, 0, &t0, &offset0) && make_time(cs, 1, &t1, &offset1)) {
+    if (t0 == t1) {
+      // The civil time was singular (pre == trans == post).
+      const time_point<seconds> tp = FromUnixSeconds(t0);
+      return {time_zone::civil_lookup::UNIQUE, tp, tp, tp};
+    }
+
+    if (t0 > t1) {
+      std::swap(t0, t1);
+      std::swap(offset0, offset1);
+    }
+    const std::time_t tt = find_trans(t0, t1, offset1);
+    const time_point<seconds> trans = FromUnixSeconds(tt);
+
+    if (offset0 < offset1) {
+      // The civil time did not exist (pre >= trans > post).
+      const time_point<seconds> pre = FromUnixSeconds(t1);
+      const time_point<seconds> post = FromUnixSeconds(t0);
+      return {time_zone::civil_lookup::SKIPPED, pre, trans, post};
+    }
+
+    // The civil time was ambiguous (pre < trans <= post).
+    const time_point<seconds> pre = FromUnixSeconds(t0);
+    const time_point<seconds> post = FromUnixSeconds(t1);
+    return {time_zone::civil_lookup::REPEATED, pre, trans, post};
+  }
+
+  // make_time() failed somehow so we saturate the result.
+  const time_point<seconds> tp = (cs < civil_second())
+                                     ? time_point<seconds>::min()
+                                     : time_point<seconds>::max();
+  return {time_zone::civil_lookup::UNIQUE, tp, tp, tp};
+}
+
+bool TimeZoneLibC::NextTransition(const time_point<seconds>&,
+                                  time_zone::civil_transition*) const {
+  return false;
+}
+
+bool TimeZoneLibC::PrevTransition(const time_point<seconds>&,
+                                  time_zone::civil_transition*) const {
+  return false;
+}
+
+std::string TimeZoneLibC::Version() const {
+  return std::string();  // unknown
+}
+
+std::string TimeZoneLibC::Description() const {
+  return local_ ? "localtime" : "UTC";
+}
+
+}  // namespace cctz
+}  // namespace time_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
diff --git a/src/absl/time/internal/cctz/src/time_zone_libc.h b/src/absl/time/internal/cctz/src/time_zone_libc.h
new file mode 100644 (file)
index 0000000..1da9039
--- /dev/null
@@ -0,0 +1,55 @@
+// Copyright 2016 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//   https://www.apache.org/licenses/LICENSE-2.0
+//
+//   Unless required by applicable law or agreed to in writing, software
+//   distributed under the License is distributed on an "AS IS" BASIS,
+//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//   See the License for the specific language governing permissions and
+//   limitations under the License.
+
+#ifndef ABSL_TIME_INTERNAL_CCTZ_TIME_ZONE_LIBC_H_
+#define ABSL_TIME_INTERNAL_CCTZ_TIME_ZONE_LIBC_H_
+
+#include <string>
+
+#include "absl/base/config.h"
+#include "time_zone_if.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace time_internal {
+namespace cctz {
+
+// A time zone backed by gmtime_r(3), localtime_r(3), and mktime(3),
+// and which therefore only supports UTC and the local time zone.
+// TODO: Add support for fixed offsets from UTC.
+class TimeZoneLibC : public TimeZoneIf {
+ public:
+  explicit TimeZoneLibC(const std::string& name);
+
+  // TimeZoneIf implementations.
+  time_zone::absolute_lookup BreakTime(
+      const time_point<seconds>& tp) const override;
+  time_zone::civil_lookup MakeTime(const civil_second& cs) const override;
+  bool NextTransition(const time_point<seconds>& tp,
+                      time_zone::civil_transition* trans) const override;
+  bool PrevTransition(const time_point<seconds>& tp,
+                      time_zone::civil_transition* trans) const override;
+  std::string Version() const override;
+  std::string Description() const override;
+
+ private:
+  const bool local_;  // localtime or UTC
+};
+
+}  // namespace cctz
+}  // namespace time_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#endif  // ABSL_TIME_INTERNAL_CCTZ_TIME_ZONE_LIBC_H_
diff --git a/src/absl/time/internal/cctz/src/time_zone_lookup.cc b/src/absl/time/internal/cctz/src/time_zone_lookup.cc
new file mode 100644 (file)
index 0000000..efdea64
--- /dev/null
@@ -0,0 +1,187 @@
+// Copyright 2016 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//   https://www.apache.org/licenses/LICENSE-2.0
+//
+//   Unless required by applicable law or agreed to in writing, software
+//   distributed under the License is distributed on an "AS IS" BASIS,
+//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//   See the License for the specific language governing permissions and
+//   limitations under the License.
+
+#include "absl/base/config.h"
+#include "absl/time/internal/cctz/include/cctz/time_zone.h"
+
+#if defined(__ANDROID__)
+#include <sys/system_properties.h>
+#if defined(__ANDROID_API__) && __ANDROID_API__ >= 21
+#include <dlfcn.h>
+#endif
+#endif
+
+#if defined(__APPLE__)
+#include <CoreFoundation/CFTimeZone.h>
+
+#include <vector>
+#endif
+
+#include <cstdlib>
+#include <cstring>
+#include <string>
+
+#include "time_zone_fixed.h"
+#include "time_zone_impl.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace time_internal {
+namespace cctz {
+
+#if defined(__ANDROID__) && defined(__ANDROID_API__) && __ANDROID_API__ >= 21
+namespace {
+// Android 'L' removes __system_property_get() from the NDK, however
+// it is still a hidden symbol in libc so we use dlsym() to access it.
+// See Chromium's base/sys_info_android.cc for a similar example.
+
+using property_get_func = int (*)(const char*, char*);
+
+property_get_func LoadSystemPropertyGet() {
+  int flag = RTLD_LAZY | RTLD_GLOBAL;
+#if defined(RTLD_NOLOAD)
+  flag |= RTLD_NOLOAD;  // libc.so should already be resident
+#endif
+  if (void* handle = dlopen("libc.so", flag)) {
+    void* sym = dlsym(handle, "__system_property_get");
+    dlclose(handle);
+    return reinterpret_cast<property_get_func>(sym);
+  }
+  return nullptr;
+}
+
+int __system_property_get(const char* name, char* value) {
+  static property_get_func system_property_get = LoadSystemPropertyGet();
+  return system_property_get ? system_property_get(name, value) : -1;
+}
+
+}  // namespace
+#endif
+
+std::string time_zone::name() const { return effective_impl().Name(); }
+
+time_zone::absolute_lookup time_zone::lookup(
+    const time_point<seconds>& tp) const {
+  return effective_impl().BreakTime(tp);
+}
+
+time_zone::civil_lookup time_zone::lookup(const civil_second& cs) const {
+  return effective_impl().MakeTime(cs);
+}
+
+bool time_zone::next_transition(const time_point<seconds>& tp,
+                                civil_transition* trans) const {
+  return effective_impl().NextTransition(tp, trans);
+}
+
+bool time_zone::prev_transition(const time_point<seconds>& tp,
+                                civil_transition* trans) const {
+  return effective_impl().PrevTransition(tp, trans);
+}
+
+std::string time_zone::version() const { return effective_impl().Version(); }
+
+std::string time_zone::description() const {
+  return effective_impl().Description();
+}
+
+const time_zone::Impl& time_zone::effective_impl() const {
+  if (impl_ == nullptr) {
+    // Dereferencing an implicit-UTC time_zone is expected to be
+    // rare, so we don't mind paying a small synchronization cost.
+    return *time_zone::Impl::UTC().impl_;
+  }
+  return *impl_;
+}
+
+bool load_time_zone(const std::string& name, time_zone* tz) {
+  return time_zone::Impl::LoadTimeZone(name, tz);
+}
+
+time_zone utc_time_zone() {
+  return time_zone::Impl::UTC();  // avoid name lookup
+}
+
+time_zone fixed_time_zone(const seconds& offset) {
+  time_zone tz;
+  load_time_zone(FixedOffsetToName(offset), &tz);
+  return tz;
+}
+
+time_zone local_time_zone() {
+  const char* zone = ":localtime";
+#if defined(__ANDROID__)
+  char sysprop[PROP_VALUE_MAX];
+  if (__system_property_get("persist.sys.timezone", sysprop) > 0) {
+    zone = sysprop;
+  }
+#endif
+#if defined(__APPLE__)
+  std::vector<char> buffer;
+  CFTimeZoneRef tz_default = CFTimeZoneCopyDefault();
+  if (CFStringRef tz_name = CFTimeZoneGetName(tz_default)) {
+    CFStringEncoding encoding = kCFStringEncodingUTF8;
+    CFIndex length = CFStringGetLength(tz_name);
+    buffer.resize(CFStringGetMaximumSizeForEncoding(length, encoding) + 1);
+    if (CFStringGetCString(tz_name, &buffer[0], buffer.size(), encoding)) {
+      zone = &buffer[0];
+    }
+  }
+  CFRelease(tz_default);
+#endif
+
+  // Allow ${TZ} to override to default zone.
+  char* tz_env = nullptr;
+#if defined(_MSC_VER)
+  _dupenv_s(&tz_env, nullptr, "TZ");
+#else
+  tz_env = std::getenv("TZ");
+#endif
+  if (tz_env) zone = tz_env;
+
+  // We only support the "[:]<zone-name>" form.
+  if (*zone == ':') ++zone;
+
+  // Map "localtime" to a system-specific name, but
+  // allow ${LOCALTIME} to override the default name.
+  char* localtime_env = nullptr;
+  if (strcmp(zone, "localtime") == 0) {
+#if defined(_MSC_VER)
+    // System-specific default is just "localtime".
+    _dupenv_s(&localtime_env, nullptr, "LOCALTIME");
+#else
+    zone = "/etc/localtime";  // System-specific default.
+    localtime_env = std::getenv("LOCALTIME");
+#endif
+    if (localtime_env) zone = localtime_env;
+  }
+
+  const std::string name = zone;
+#if defined(_MSC_VER)
+  free(localtime_env);
+  free(tz_env);
+#endif
+
+  time_zone tz;
+  load_time_zone(name, &tz);  // Falls back to UTC.
+  // TODO: Follow the RFC3339 "Unknown Local Offset Convention" and
+  // arrange for %z to generate "-0000" when we don't know the local
+  // offset because the load_time_zone() failed and we're using UTC.
+  return tz;
+}
+
+}  // namespace cctz
+}  // namespace time_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
diff --git a/src/absl/time/internal/cctz/src/time_zone_posix.cc b/src/absl/time/internal/cctz/src/time_zone_posix.cc
new file mode 100644 (file)
index 0000000..5cdd09e
--- /dev/null
@@ -0,0 +1,159 @@
+// Copyright 2016 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//   https://www.apache.org/licenses/LICENSE-2.0
+//
+//   Unless required by applicable law or agreed to in writing, software
+//   distributed under the License is distributed on an "AS IS" BASIS,
+//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//   See the License for the specific language governing permissions and
+//   limitations under the License.
+
+#include "time_zone_posix.h"
+
+#include <cstddef>
+#include <cstring>
+#include <limits>
+#include <string>
+
+#include "absl/base/config.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace time_internal {
+namespace cctz {
+
+namespace {
+
+const char kDigits[] = "0123456789";
+
+const char* ParseInt(const char* p, int min, int max, int* vp) {
+  int value = 0;
+  const char* op = p;
+  const int kMaxInt = std::numeric_limits<int>::max();
+  for (; const char* dp = strchr(kDigits, *p); ++p) {
+    int d = static_cast<int>(dp - kDigits);
+    if (d >= 10) break;  // '\0'
+    if (value > kMaxInt / 10) return nullptr;
+    value *= 10;
+    if (value > kMaxInt - d) return nullptr;
+    value += d;
+  }
+  if (p == op || value < min || value > max) return nullptr;
+  *vp = value;
+  return p;
+}
+
+// abbr = <.*?> | [^-+,\d]{3,}
+const char* ParseAbbr(const char* p, std::string* abbr) {
+  const char* op = p;
+  if (*p == '<') {  // special zoneinfo <...> form
+    while (*++p != '>') {
+      if (*p == '\0') return nullptr;
+    }
+    abbr->assign(op + 1, static_cast<std::size_t>(p - op) - 1);
+    return ++p;
+  }
+  while (*p != '\0') {
+    if (strchr("-+,", *p)) break;
+    if (strchr(kDigits, *p)) break;
+    ++p;
+  }
+  if (p - op < 3) return nullptr;
+  abbr->assign(op, static_cast<std::size_t>(p - op));
+  return p;
+}
+
+// offset = [+|-]hh[:mm[:ss]] (aggregated into single seconds value)
+const char* ParseOffset(const char* p, int min_hour, int max_hour, int sign,
+                        std::int_fast32_t* offset) {
+  if (p == nullptr) return nullptr;
+  if (*p == '+' || *p == '-') {
+    if (*p++ == '-') sign = -sign;
+  }
+  int hours = 0;
+  int minutes = 0;
+  int seconds = 0;
+
+  p = ParseInt(p, min_hour, max_hour, &hours);
+  if (p == nullptr) return nullptr;
+  if (*p == ':') {
+    p = ParseInt(p + 1, 0, 59, &minutes);
+    if (p == nullptr) return nullptr;
+    if (*p == ':') {
+      p = ParseInt(p + 1, 0, 59, &seconds);
+      if (p == nullptr) return nullptr;
+    }
+  }
+  *offset = sign * ((((hours * 60) + minutes) * 60) + seconds);
+  return p;
+}
+
+// datetime = ( Jn | n | Mm.w.d ) [ / offset ]
+const char* ParseDateTime(const char* p, PosixTransition* res) {
+  if (p != nullptr && *p == ',') {
+    if (*++p == 'M') {
+      int month = 0;
+      if ((p = ParseInt(p + 1, 1, 12, &month)) != nullptr && *p == '.') {
+        int week = 0;
+        if ((p = ParseInt(p + 1, 1, 5, &week)) != nullptr && *p == '.') {
+          int weekday = 0;
+          if ((p = ParseInt(p + 1, 0, 6, &weekday)) != nullptr) {
+            res->date.fmt = PosixTransition::M;
+            res->date.m.month = static_cast<std::int_fast8_t>(month);
+            res->date.m.week = static_cast<std::int_fast8_t>(week);
+            res->date.m.weekday = static_cast<std::int_fast8_t>(weekday);
+          }
+        }
+      }
+    } else if (*p == 'J') {
+      int day = 0;
+      if ((p = ParseInt(p + 1, 1, 365, &day)) != nullptr) {
+        res->date.fmt = PosixTransition::J;
+        res->date.j.day = static_cast<std::int_fast16_t>(day);
+      }
+    } else {
+      int day = 0;
+      if ((p = ParseInt(p, 0, 365, &day)) != nullptr) {
+        res->date.fmt = PosixTransition::N;
+        res->date.n.day = static_cast<std::int_fast16_t>(day);
+      }
+    }
+  }
+  if (p != nullptr) {
+    res->time.offset = 2 * 60 * 60;  // default offset is 02:00:00
+    if (*p == '/') p = ParseOffset(p + 1, -167, 167, 1, &res->time.offset);
+  }
+  return p;
+}
+
+}  // namespace
+
+// spec = std offset [ dst [ offset ] , datetime , datetime ]
+bool ParsePosixSpec(const std::string& spec, PosixTimeZone* res) {
+  const char* p = spec.c_str();
+  if (*p == ':') return false;
+
+  p = ParseAbbr(p, &res->std_abbr);
+  p = ParseOffset(p, 0, 24, -1, &res->std_offset);
+  if (p == nullptr) return false;
+  if (*p == '\0') return true;
+
+  p = ParseAbbr(p, &res->dst_abbr);
+  if (p == nullptr) return false;
+  res->dst_offset = res->std_offset + (60 * 60);  // default
+  if (*p != ',') p = ParseOffset(p, 0, 24, -1, &res->dst_offset);
+
+  p = ParseDateTime(p, &res->dst_start);
+  p = ParseDateTime(p, &res->dst_end);
+
+  return p != nullptr && *p == '\0';
+}
+
+}  // namespace cctz
+}  // namespace time_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
diff --git a/src/absl/time/internal/cctz/src/time_zone_posix.h b/src/absl/time/internal/cctz/src/time_zone_posix.h
new file mode 100644 (file)
index 0000000..0cf2905
--- /dev/null
@@ -0,0 +1,132 @@
+// Copyright 2016 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//   https://www.apache.org/licenses/LICENSE-2.0
+//
+//   Unless required by applicable law or agreed to in writing, software
+//   distributed under the License is distributed on an "AS IS" BASIS,
+//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//   See the License for the specific language governing permissions and
+//   limitations under the License.
+
+// Parsing of a POSIX zone spec as described in the TZ part of section 8.3 in
+// http://pubs.opengroup.org/onlinepubs/009695399/basedefs/xbd_chap08.html.
+//
+// The current POSIX spec for America/Los_Angeles is "PST8PDT,M3.2.0,M11.1.0",
+// which would be broken down as ...
+//
+//   PosixTimeZone {
+//     std_abbr = "PST"
+//     std_offset = -28800
+//     dst_abbr = "PDT"
+//     dst_offset = -25200
+//     dst_start = PosixTransition {
+//       date {
+//         m {
+//           month = 3
+//           week = 2
+//           weekday = 0
+//         }
+//       }
+//       time {
+//         offset = 7200
+//       }
+//     }
+//     dst_end = PosixTransition {
+//       date {
+//         m {
+//           month = 11
+//           week = 1
+//           weekday = 0
+//         }
+//       }
+//       time {
+//         offset = 7200
+//       }
+//     }
+//   }
+
+#ifndef ABSL_TIME_INTERNAL_CCTZ_TIME_ZONE_POSIX_H_
+#define ABSL_TIME_INTERNAL_CCTZ_TIME_ZONE_POSIX_H_
+
+#include <cstdint>
+#include <string>
+
+#include "absl/base/config.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace time_internal {
+namespace cctz {
+
+// The date/time of the transition. The date is specified as either:
+// (J) the Nth day of the year (1 <= N <= 365), excluding leap days, or
+// (N) the Nth day of the year (0 <= N <= 365), including leap days, or
+// (M) the Nth weekday of a month (e.g., the 2nd Sunday in March).
+// The time, specified as a day offset, identifies the particular moment
+// of the transition, and may be negative or >= 24h, and in which case
+// it would take us to another day, and perhaps week, or even month.
+struct PosixTransition {
+  enum DateFormat { J, N, M };
+
+  struct Date {
+    struct NonLeapDay {
+      std::int_fast16_t day;  // day of non-leap year [1:365]
+    };
+    struct Day {
+      std::int_fast16_t day;  // day of year [0:365]
+    };
+    struct MonthWeekWeekday {
+      std::int_fast8_t month;    // month of year [1:12]
+      std::int_fast8_t week;     // week of month [1:5] (5==last)
+      std::int_fast8_t weekday;  // 0==Sun, ..., 6=Sat
+    };
+
+    DateFormat fmt;
+
+    union {
+      NonLeapDay j;
+      Day n;
+      MonthWeekWeekday m;
+    };
+  };
+
+  struct Time {
+    std::int_fast32_t offset;  // seconds before/after 00:00:00
+  };
+
+  Date date;
+  Time time;
+};
+
+// The entirety of a POSIX-string specified time-zone rule. The standard
+// abbreviation and offset are always given. If the time zone includes
+// daylight saving, then the daylight abbrevation is non-empty and the
+// remaining fields are also valid. Note that the start/end transitions
+// are not ordered---in the southern hemisphere the transition to end
+// daylight time occurs first in any particular year.
+struct PosixTimeZone {
+  std::string std_abbr;
+  std::int_fast32_t std_offset;
+
+  std::string dst_abbr;
+  std::int_fast32_t dst_offset;
+  PosixTransition dst_start;
+  PosixTransition dst_end;
+};
+
+// Breaks down a POSIX time-zone specification into its constituent pieces,
+// filling in any missing values (DST offset, or start/end transition times)
+// with the standard-defined defaults. Returns false if the specification
+// could not be parsed (although some fields of *res may have been altered).
+bool ParsePosixSpec(const std::string& spec, PosixTimeZone* res);
+
+}  // namespace cctz
+}  // namespace time_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#endif  // ABSL_TIME_INTERNAL_CCTZ_TIME_ZONE_POSIX_H_
diff --git a/src/absl/time/internal/cctz/src/tzfile.h b/src/absl/time/internal/cctz/src/tzfile.h
new file mode 100644 (file)
index 0000000..269fa36
--- /dev/null
@@ -0,0 +1,122 @@
+/* Layout and location of TZif files.  */
+
+#ifndef TZFILE_H
+
+#define TZFILE_H
+
+/*
+** This file is in the public domain, so clarified as of
+** 1996-06-05 by Arthur David Olson.
+*/
+
+/*
+** This header is for use ONLY with the time conversion code.
+** There is no guarantee that it will remain unchanged,
+** or that it will remain at all.
+** Do NOT copy it to any system include directory.
+** Thank you!
+*/
+
+/*
+** Information about time zone files.
+*/
+
+#ifndef TZDIR
+#define TZDIR "/usr/share/zoneinfo" /* Time zone object file directory */
+#endif                              /* !defined TZDIR */
+
+#ifndef TZDEFAULT
+#define TZDEFAULT "/etc/localtime"
+#endif /* !defined TZDEFAULT */
+
+#ifndef TZDEFRULES
+#define TZDEFRULES "posixrules"
+#endif /* !defined TZDEFRULES */
+
+/* See Internet RFC 8536 for more details about the following format.  */
+
+/*
+** Each file begins with. . .
+*/
+
+#define TZ_MAGIC "TZif"
+
+struct tzhead {
+  char tzh_magic[4];      /* TZ_MAGIC */
+  char tzh_version[1];    /* '\0' or '2' or '3' as of 2013 */
+  char tzh_reserved[15];  /* reserved; must be zero */
+  char tzh_ttisutcnt[4];  /* coded number of trans. time flags */
+  char tzh_ttisstdcnt[4]; /* coded number of trans. time flags */
+  char tzh_leapcnt[4];    /* coded number of leap seconds */
+  char tzh_timecnt[4];    /* coded number of transition times */
+  char tzh_typecnt[4];    /* coded number of local time types */
+  char tzh_charcnt[4];    /* coded number of abbr. chars */
+};
+
+/*
+** . . .followed by. . .
+**
+**     tzh_timecnt (char [4])s         coded transition times a la time(2)
+**     tzh_timecnt (unsigned char)s    types of local time starting at above
+**     tzh_typecnt repetitions of
+**             one (char [4])          coded UT offset in seconds
+**             one (unsigned char)     used to set tm_isdst
+**             one (unsigned char)     that's an abbreviation list index
+**     tzh_charcnt (char)s             '\0'-terminated zone abbreviations
+**     tzh_leapcnt repetitions of
+**             one (char [4])          coded leap second transition times
+**             one (char [4])          total correction after above
+**     tzh_ttisstdcnt (char)s          indexed by type; if 1, transition
+**                                     time is standard time, if 0,
+**                                     transition time is local (wall clock)
+**                                     time; if absent, transition times are
+**                                     assumed to be local time
+**     tzh_ttisutcnt (char)s           indexed by type; if 1, transition
+**                                     time is UT, if 0, transition time is
+**                                     local time; if absent, transition
+**                                     times are assumed to be local time.
+**                                     When this is 1, the corresponding
+**                                     std/wall indicator must also be 1.
+*/
+
+/*
+** If tzh_version is '2' or greater, the above is followed by a second instance
+** of tzhead and a second instance of the data in which each coded transition
+** time uses 8 rather than 4 chars,
+** then a POSIX-TZ-environment-variable-style string for use in handling
+** instants after the last transition time stored in the file
+** (with nothing between the newlines if there is no POSIX representation for
+** such instants).
+**
+** If tz_version is '3' or greater, the above is extended as follows.
+** First, the POSIX TZ string's hour offset may range from -167
+** through 167 as compared to the POSIX-required 0 through 24.
+** Second, its DST start time may be January 1 at 00:00 and its stop
+** time December 31 at 24:00 plus the difference between DST and
+** standard time, indicating DST all year.
+*/
+
+/*
+** In the current implementation, "tzset()" refuses to deal with files that
+** exceed any of the limits below.
+*/
+
+#ifndef TZ_MAX_TIMES
+#define TZ_MAX_TIMES 2000
+#endif /* !defined TZ_MAX_TIMES */
+
+#ifndef TZ_MAX_TYPES
+/* This must be at least 17 for Europe/Samara and Europe/Vilnius.  */
+#define TZ_MAX_TYPES 256 /* Limited by what (unsigned char)'s can hold */
+#endif                   /* !defined TZ_MAX_TYPES */
+
+#ifndef TZ_MAX_CHARS
+#define TZ_MAX_CHARS 50 /* Maximum number of abbreviation characters */
+                        /* (limited by what unsigned chars can hold) */
+#endif                  /* !defined TZ_MAX_CHARS */
+
+#ifndef TZ_MAX_LEAPS
+#define TZ_MAX_LEAPS 50 /* Maximum number of leap second corrections */
+#endif                  /* !defined TZ_MAX_LEAPS */
+
+#endif /* !defined TZFILE_H */
diff --git a/src/absl/time/internal/cctz/src/zone_info_source.cc b/src/absl/time/internal/cctz/src/zone_info_source.cc
new file mode 100644 (file)
index 0000000..7209533
--- /dev/null
@@ -0,0 +1,116 @@
+// Copyright 2016 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//   https://www.apache.org/licenses/LICENSE-2.0
+//
+//   Unless required by applicable law or agreed to in writing, software
+//   distributed under the License is distributed on an "AS IS" BASIS,
+//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//   See the License for the specific language governing permissions and
+//   limitations under the License.
+
+#include "absl/time/internal/cctz/include/cctz/zone_info_source.h"
+
+#include "absl/base/config.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace time_internal {
+namespace cctz {
+
+// Defined out-of-line to avoid emitting a weak vtable in all TUs.
+ZoneInfoSource::~ZoneInfoSource() {}
+std::string ZoneInfoSource::Version() const { return std::string(); }
+
+}  // namespace cctz
+}  // namespace time_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace time_internal {
+namespace cctz_extension {
+
+namespace {
+
+// A default for cctz_extension::zone_info_source_factory, which simply
+// defers to the fallback factory.
+std::unique_ptr<absl::time_internal::cctz::ZoneInfoSource> DefaultFactory(
+    const std::string& name,
+    const std::function<
+        std::unique_ptr<absl::time_internal::cctz::ZoneInfoSource>(
+            const std::string& name)>& fallback_factory) {
+  return fallback_factory(name);
+}
+
+}  // namespace
+
+// A "weak" definition for cctz_extension::zone_info_source_factory.
+// The user may override this with their own "strong" definition (see
+// zone_info_source.h).
+#if !defined(__has_attribute)
+#define __has_attribute(x) 0
+#endif
+// MinGW is GCC on Windows, so while it asserts __has_attribute(weak), the
+// Windows linker cannot handle that. Nor does the MinGW compiler know how to
+// pass "#pragma comment(linker, ...)" to the Windows linker.
+#if (__has_attribute(weak) || defined(__GNUC__)) && !defined(__MINGW32__)
+ZoneInfoSourceFactory zone_info_source_factory __attribute__((weak)) =
+    DefaultFactory;
+#elif defined(_MSC_VER) && !defined(__MINGW32__) && !defined(_LIBCPP_VERSION)
+extern ZoneInfoSourceFactory zone_info_source_factory;
+extern ZoneInfoSourceFactory default_factory;
+ZoneInfoSourceFactory default_factory = DefaultFactory;
+#if defined(_M_IX86)
+#pragma comment(                                                                                                         \
+    linker,                                                                                                              \
+    "/alternatename:?zone_info_source_factory@cctz_extension@time_internal@" ABSL_INTERNAL_MANGLED_NS                    \
+    "@@3P6A?AV?$unique_ptr@VZoneInfoSource@cctz@time_internal@" ABSL_INTERNAL_MANGLED_NS                                 \
+    "@@U?$default_delete@VZoneInfoSource@cctz@time_internal@" ABSL_INTERNAL_MANGLED_NS                                   \
+    "@@@std@@@std@@ABV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@" ABSL_INTERNAL_MANGLED_BACKREFERENCE      \
+    "@ABV?$function@$$A6A?AV?$unique_ptr@VZoneInfoSource@cctz@time_internal@" ABSL_INTERNAL_MANGLED_NS                   \
+    "@@U?$default_delete@VZoneInfoSource@cctz@time_internal@" ABSL_INTERNAL_MANGLED_NS                                   \
+    "@@@std@@@std@@ABV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@2@@Z@" ABSL_INTERNAL_MANGLED_BACKREFERENCE \
+    "@@ZA=?default_factory@cctz_extension@time_internal@" ABSL_INTERNAL_MANGLED_NS                                       \
+    "@@3P6A?AV?$unique_ptr@VZoneInfoSource@cctz@time_internal@" ABSL_INTERNAL_MANGLED_NS                                 \
+    "@@U?$default_delete@VZoneInfoSource@cctz@time_internal@" ABSL_INTERNAL_MANGLED_NS                                   \
+    "@@@std@@@std@@ABV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@" ABSL_INTERNAL_MANGLED_BACKREFERENCE      \
+    "@ABV?$function@$$A6A?AV?$unique_ptr@VZoneInfoSource@cctz@time_internal@" ABSL_INTERNAL_MANGLED_NS                   \
+    "@@U?$default_delete@VZoneInfoSource@cctz@time_internal@" ABSL_INTERNAL_MANGLED_NS                                   \
+    "@@@std@@@std@@ABV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@2@@Z@" ABSL_INTERNAL_MANGLED_BACKREFERENCE \
+    "@@ZA")
+#elif defined(_M_IA_64) || defined(_M_AMD64) || defined(_M_ARM) || \
+    defined(_M_ARM64)
+#pragma comment(                                                                                                          \
+    linker,                                                                                                               \
+    "/alternatename:?zone_info_source_factory@cctz_extension@time_internal@" ABSL_INTERNAL_MANGLED_NS                     \
+    "@@3P6A?AV?$unique_ptr@VZoneInfoSource@cctz@time_internal@" ABSL_INTERNAL_MANGLED_NS                                  \
+    "@@U?$default_delete@VZoneInfoSource@cctz@time_internal@" ABSL_INTERNAL_MANGLED_NS                                    \
+    "@@@std@@@std@@AEBV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@" ABSL_INTERNAL_MANGLED_BACKREFERENCE      \
+    "@AEBV?$function@$$A6A?AV?$unique_ptr@VZoneInfoSource@cctz@time_internal@" ABSL_INTERNAL_MANGLED_NS                   \
+    "@@U?$default_delete@VZoneInfoSource@cctz@time_internal@" ABSL_INTERNAL_MANGLED_NS                                    \
+    "@@@std@@@std@@AEBV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@2@@Z@" ABSL_INTERNAL_MANGLED_BACKREFERENCE \
+    "@@ZEA=?default_factory@cctz_extension@time_internal@" ABSL_INTERNAL_MANGLED_NS                                       \
+    "@@3P6A?AV?$unique_ptr@VZoneInfoSource@cctz@time_internal@" ABSL_INTERNAL_MANGLED_NS                                  \
+    "@@U?$default_delete@VZoneInfoSource@cctz@time_internal@" ABSL_INTERNAL_MANGLED_NS                                    \
+    "@@@std@@@std@@AEBV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@" ABSL_INTERNAL_MANGLED_BACKREFERENCE      \
+    "@AEBV?$function@$$A6A?AV?$unique_ptr@VZoneInfoSource@cctz@time_internal@" ABSL_INTERNAL_MANGLED_NS                   \
+    "@@U?$default_delete@VZoneInfoSource@cctz@time_internal@" ABSL_INTERNAL_MANGLED_NS                                    \
+    "@@@std@@@std@@AEBV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@2@@Z@" ABSL_INTERNAL_MANGLED_BACKREFERENCE \
+    "@@ZEA")
+#else
+#error Unsupported MSVC platform
+#endif  // _M_<PLATFORM>
+#else
+// Make it a "strong" definition if we have no other choice.
+ZoneInfoSourceFactory zone_info_source_factory = DefaultFactory;
+#endif
+
+}  // namespace cctz_extension
+}  // namespace time_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
diff --git a/src/absl/time/internal/get_current_time_chrono.inc b/src/absl/time/internal/get_current_time_chrono.inc
new file mode 100644 (file)
index 0000000..5eeb640
--- /dev/null
@@ -0,0 +1,31 @@
+// Copyright 2018 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <chrono>
+#include <cstdint>
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace time_internal {
+
+static int64_t GetCurrentTimeNanosFromSystem() {
+  return std::chrono::duration_cast<std::chrono::nanoseconds>(
+             std::chrono::system_clock::now() -
+             std::chrono::system_clock::from_time_t(0))
+      .count();
+}
+
+}  // namespace time_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
diff --git a/src/absl/time/internal/get_current_time_posix.inc b/src/absl/time/internal/get_current_time_posix.inc
new file mode 100644 (file)
index 0000000..4207200
--- /dev/null
@@ -0,0 +1,24 @@
+#include "absl/time/clock.h"
+
+#include <sys/time.h>
+#include <ctime>
+#include <cstdint>
+
+#include "absl/base/internal/raw_logging.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace time_internal {
+
+static int64_t GetCurrentTimeNanosFromSystem() {
+  const int64_t kNanosPerSecond = 1000 * 1000 * 1000;
+  struct timespec ts;
+  ABSL_RAW_CHECK(clock_gettime(CLOCK_REALTIME, &ts) == 0,
+                 "Failed to read real-time clock.");
+  return (int64_t{ts.tv_sec} * kNanosPerSecond +
+          int64_t{ts.tv_nsec});
+}
+
+}  // namespace time_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
diff --git a/src/absl/time/internal/zoneinfo.inc b/src/absl/time/internal/zoneinfo.inc
new file mode 100644 (file)
index 0000000..bfed829
--- /dev/null
@@ -0,0 +1,729 @@
+unsigned char America_Los_Angeles[] = {
+  0x54, 0x5a, 0x69, 0x66, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05,
+  0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xba,
+  0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x14, 0x80, 0x00, 0x00, 0x00,
+  0x9e, 0xa6, 0x48, 0xa0, 0x9f, 0xbb, 0x15, 0x90, 0xa0, 0x86, 0x2a, 0xa0,
+  0xa1, 0x9a, 0xf7, 0x90, 0xcb, 0x89, 0x1a, 0xa0, 0xd2, 0x23, 0xf4, 0x70,
+  0xd2, 0x61, 0x26, 0x10, 0xd6, 0xfe, 0x74, 0x5c, 0xd8, 0x80, 0xad, 0x90,
+  0xda, 0xfe, 0xc3, 0x90, 0xdb, 0xc0, 0x90, 0x10, 0xdc, 0xde, 0xa5, 0x90,
+  0xdd, 0xa9, 0xac, 0x90, 0xde, 0xbe, 0x87, 0x90, 0xdf, 0x89, 0x8e, 0x90,
+  0xe0, 0x9e, 0x69, 0x90, 0xe1, 0x69, 0x70, 0x90, 0xe2, 0x7e, 0x4b, 0x90,
+  0xe3, 0x49, 0x52, 0x90, 0xe4, 0x5e, 0x2d, 0x90, 0xe5, 0x29, 0x34, 0x90,
+  0xe6, 0x47, 0x4a, 0x10, 0xe7, 0x12, 0x51, 0x10, 0xe8, 0x27, 0x2c, 0x10,
+  0xe8, 0xf2, 0x33, 0x10, 0xea, 0x07, 0x0e, 0x10, 0xea, 0xd2, 0x15, 0x10,
+  0xeb, 0xe6, 0xf0, 0x10, 0xec, 0xb1, 0xf7, 0x10, 0xed, 0xc6, 0xd2, 0x10,
+  0xee, 0x91, 0xd9, 0x10, 0xef, 0xaf, 0xee, 0x90, 0xf0, 0x71, 0xbb, 0x10,
+  0xf1, 0x8f, 0xd0, 0x90, 0xf2, 0x7f, 0xc1, 0x90, 0xf3, 0x6f, 0xb2, 0x90,
+  0xf4, 0x5f, 0xa3, 0x90, 0xf5, 0x4f, 0x94, 0x90, 0xf6, 0x3f, 0x85, 0x90,
+  0xf7, 0x2f, 0x76, 0x90, 0xf8, 0x28, 0xa2, 0x10, 0xf9, 0x0f, 0x58, 0x90,
+  0xfa, 0x08, 0x84, 0x10, 0xfa, 0xf8, 0x83, 0x20, 0xfb, 0xe8, 0x66, 0x10,
+  0xfc, 0xd8, 0x65, 0x20, 0xfd, 0xc8, 0x48, 0x10, 0xfe, 0xb8, 0x47, 0x20,
+  0xff, 0xa8, 0x2a, 0x10, 0x00, 0x98, 0x29, 0x20, 0x01, 0x88, 0x0c, 0x10,
+  0x02, 0x78, 0x0b, 0x20, 0x03, 0x71, 0x28, 0x90, 0x04, 0x61, 0x27, 0xa0,
+  0x05, 0x51, 0x0a, 0x90, 0x06, 0x41, 0x09, 0xa0, 0x07, 0x30, 0xec, 0x90,
+  0x07, 0x8d, 0x43, 0xa0, 0x09, 0x10, 0xce, 0x90, 0x09, 0xad, 0xbf, 0x20,
+  0x0a, 0xf0, 0xb0, 0x90, 0x0b, 0xe0, 0xaf, 0xa0, 0x0c, 0xd9, 0xcd, 0x10,
+  0x0d, 0xc0, 0x91, 0xa0, 0x0e, 0xb9, 0xaf, 0x10, 0x0f, 0xa9, 0xae, 0x20,
+  0x10, 0x99, 0x91, 0x10, 0x11, 0x89, 0x90, 0x20, 0x12, 0x79, 0x73, 0x10,
+  0x13, 0x69, 0x72, 0x20, 0x14, 0x59, 0x55, 0x10, 0x15, 0x49, 0x54, 0x20,
+  0x16, 0x39, 0x37, 0x10, 0x17, 0x29, 0x36, 0x20, 0x18, 0x22, 0x53, 0x90,
+  0x19, 0x09, 0x18, 0x20, 0x1a, 0x02, 0x35, 0x90, 0x1a, 0xf2, 0x34, 0xa0,
+  0x1b, 0xe2, 0x17, 0x90, 0x1c, 0xd2, 0x16, 0xa0, 0x1d, 0xc1, 0xf9, 0x90,
+  0x1e, 0xb1, 0xf8, 0xa0, 0x1f, 0xa1, 0xdb, 0x90, 0x20, 0x76, 0x2b, 0x20,
+  0x21, 0x81, 0xbd, 0x90, 0x22, 0x56, 0x0d, 0x20, 0x23, 0x6a, 0xda, 0x10,
+  0x24, 0x35, 0xef, 0x20, 0x25, 0x4a, 0xbc, 0x10, 0x26, 0x15, 0xd1, 0x20,
+  0x27, 0x2a, 0x9e, 0x10, 0x27, 0xfe, 0xed, 0xa0, 0x29, 0x0a, 0x80, 0x10,
+  0x29, 0xde, 0xcf, 0xa0, 0x2a, 0xea, 0x62, 0x10, 0x2b, 0xbe, 0xb1, 0xa0,
+  0x2c, 0xd3, 0x7e, 0x90, 0x2d, 0x9e, 0x93, 0xa0, 0x2e, 0xb3, 0x60, 0x90,
+  0x2f, 0x7e, 0x75, 0xa0, 0x30, 0x93, 0x42, 0x90, 0x31, 0x67, 0x92, 0x20,
+  0x32, 0x73, 0x24, 0x90, 0x33, 0x47, 0x74, 0x20, 0x34, 0x53, 0x06, 0x90,
+  0x35, 0x27, 0x56, 0x20, 0x36, 0x32, 0xe8, 0x90, 0x37, 0x07, 0x38, 0x20,
+  0x38, 0x1c, 0x05, 0x10, 0x38, 0xe7, 0x1a, 0x20, 0x39, 0xfb, 0xe7, 0x10,
+  0x3a, 0xc6, 0xfc, 0x20, 0x3b, 0xdb, 0xc9, 0x10, 0x3c, 0xb0, 0x18, 0xa0,
+  0x3d, 0xbb, 0xab, 0x10, 0x3e, 0x8f, 0xfa, 0xa0, 0x3f, 0x9b, 0x8d, 0x10,
+  0x40, 0x6f, 0xdc, 0xa0, 0x41, 0x84, 0xa9, 0x90, 0x42, 0x4f, 0xbe, 0xa0,
+  0x43, 0x64, 0x8b, 0x90, 0x44, 0x2f, 0xa0, 0xa0, 0x45, 0x44, 0x6d, 0x90,
+  0x45, 0xf3, 0xd3, 0x20, 0x47, 0x2d, 0x8a, 0x10, 0x47, 0xd3, 0xb5, 0x20,
+  0x49, 0x0d, 0x6c, 0x10, 0x49, 0xb3, 0x97, 0x20, 0x4a, 0xed, 0x4e, 0x10,
+  0x4b, 0x9c, 0xb3, 0xa0, 0x4c, 0xd6, 0x6a, 0x90, 0x4d, 0x7c, 0x95, 0xa0,
+  0x4e, 0xb6, 0x4c, 0x90, 0x4f, 0x5c, 0x77, 0xa0, 0x50, 0x96, 0x2e, 0x90,
+  0x51, 0x3c, 0x59, 0xa0, 0x52, 0x76, 0x10, 0x90, 0x53, 0x1c, 0x3b, 0xa0,
+  0x54, 0x55, 0xf2, 0x90, 0x54, 0xfc, 0x1d, 0xa0, 0x56, 0x35, 0xd4, 0x90,
+  0x56, 0xe5, 0x3a, 0x20, 0x58, 0x1e, 0xf1, 0x10, 0x58, 0xc5, 0x1c, 0x20,
+  0x59, 0xfe, 0xd3, 0x10, 0x5a, 0xa4, 0xfe, 0x20, 0x5b, 0xde, 0xb5, 0x10,
+  0x5c, 0x84, 0xe0, 0x20, 0x5d, 0xbe, 0x97, 0x10, 0x5e, 0x64, 0xc2, 0x20,
+  0x5f, 0x9e, 0x79, 0x10, 0x60, 0x4d, 0xde, 0xa0, 0x61, 0x87, 0x95, 0x90,
+  0x62, 0x2d, 0xc0, 0xa0, 0x63, 0x67, 0x77, 0x90, 0x64, 0x0d, 0xa2, 0xa0,
+  0x65, 0x47, 0x59, 0x90, 0x65, 0xed, 0x84, 0xa0, 0x67, 0x27, 0x3b, 0x90,
+  0x67, 0xcd, 0x66, 0xa0, 0x69, 0x07, 0x1d, 0x90, 0x69, 0xad, 0x48, 0xa0,
+  0x6a, 0xe6, 0xff, 0x90, 0x6b, 0x96, 0x65, 0x20, 0x6c, 0xd0, 0x1c, 0x10,
+  0x6d, 0x76, 0x47, 0x20, 0x6e, 0xaf, 0xfe, 0x10, 0x6f, 0x56, 0x29, 0x20,
+  0x70, 0x8f, 0xe0, 0x10, 0x71, 0x36, 0x0b, 0x20, 0x72, 0x6f, 0xc2, 0x10,
+  0x73, 0x15, 0xed, 0x20, 0x74, 0x4f, 0xa4, 0x10, 0x74, 0xff, 0x09, 0xa0,
+  0x76, 0x38, 0xc0, 0x90, 0x76, 0xde, 0xeb, 0xa0, 0x78, 0x18, 0xa2, 0x90,
+  0x78, 0xbe, 0xcd, 0xa0, 0x79, 0xf8, 0x84, 0x90, 0x7a, 0x9e, 0xaf, 0xa0,
+  0x7b, 0xd8, 0x66, 0x90, 0x7c, 0x7e, 0x91, 0xa0, 0x7d, 0xb8, 0x48, 0x90,
+  0x7e, 0x5e, 0x73, 0xa0, 0x7f, 0x98, 0x2a, 0x90, 0x02, 0x01, 0x02, 0x01,
+  0x02, 0x03, 0x04, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02,
+  0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02,
+  0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02,
+  0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02,
+  0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02,
+  0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02,
+  0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02,
+  0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02,
+  0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02,
+  0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02,
+  0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02,
+  0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02,
+  0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02,
+  0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02,
+  0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02,
+  0x01, 0x02, 0xff, 0xff, 0x91, 0x26, 0x00, 0x00, 0xff, 0xff, 0x9d, 0x90,
+  0x01, 0x04, 0xff, 0xff, 0x8f, 0x80, 0x00, 0x08, 0xff, 0xff, 0x9d, 0x90,
+  0x01, 0x0c, 0xff, 0xff, 0x9d, 0x90, 0x01, 0x10, 0x4c, 0x4d, 0x54, 0x00,
+  0x50, 0x44, 0x54, 0x00, 0x50, 0x53, 0x54, 0x00, 0x50, 0x57, 0x54, 0x00,
+  0x50, 0x50, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+  0x00, 0x01, 0x54, 0x5a, 0x69, 0x66, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x05, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0xbb, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x14, 0xf8, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x5e, 0x04,
+  0x1a, 0xc0, 0xff, 0xff, 0xff, 0xff, 0x9e, 0xa6, 0x48, 0xa0, 0xff, 0xff,
+  0xff, 0xff, 0x9f, 0xbb, 0x15, 0x90, 0xff, 0xff, 0xff, 0xff, 0xa0, 0x86,
+  0x2a, 0xa0, 0xff, 0xff, 0xff, 0xff, 0xa1, 0x9a, 0xf7, 0x90, 0xff, 0xff,
+  0xff, 0xff, 0xcb, 0x89, 0x1a, 0xa0, 0xff, 0xff, 0xff, 0xff, 0xd2, 0x23,
+  0xf4, 0x70, 0xff, 0xff, 0xff, 0xff, 0xd2, 0x61, 0x26, 0x10, 0xff, 0xff,
+  0xff, 0xff, 0xd6, 0xfe, 0x74, 0x5c, 0xff, 0xff, 0xff, 0xff, 0xd8, 0x80,
+  0xad, 0x90, 0xff, 0xff, 0xff, 0xff, 0xda, 0xfe, 0xc3, 0x90, 0xff, 0xff,
+  0xff, 0xff, 0xdb, 0xc0, 0x90, 0x10, 0xff, 0xff, 0xff, 0xff, 0xdc, 0xde,
+  0xa5, 0x90, 0xff, 0xff, 0xff, 0xff, 0xdd, 0xa9, 0xac, 0x90, 0xff, 0xff,
+  0xff, 0xff, 0xde, 0xbe, 0x87, 0x90, 0xff, 0xff, 0xff, 0xff, 0xdf, 0x89,
+  0x8e, 0x90, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x9e, 0x69, 0x90, 0xff, 0xff,
+  0xff, 0xff, 0xe1, 0x69, 0x70, 0x90, 0xff, 0xff, 0xff, 0xff, 0xe2, 0x7e,
+  0x4b, 0x90, 0xff, 0xff, 0xff, 0xff, 0xe3, 0x49, 0x52, 0x90, 0xff, 0xff,
+  0xff, 0xff, 0xe4, 0x5e, 0x2d, 0x90, 0xff, 0xff, 0xff, 0xff, 0xe5, 0x29,
+  0x34, 0x90, 0xff, 0xff, 0xff, 0xff, 0xe6, 0x47, 0x4a, 0x10, 0xff, 0xff,
+  0xff, 0xff, 0xe7, 0x12, 0x51, 0x10, 0xff, 0xff, 0xff, 0xff, 0xe8, 0x27,
+  0x2c, 0x10, 0xff, 0xff, 0xff, 0xff, 0xe8, 0xf2, 0x33, 0x10, 0xff, 0xff,
+  0xff, 0xff, 0xea, 0x07, 0x0e, 0x10, 0xff, 0xff, 0xff, 0xff, 0xea, 0xd2,
+  0x15, 0x10, 0xff, 0xff, 0xff, 0xff, 0xeb, 0xe6, 0xf0, 0x10, 0xff, 0xff,
+  0xff, 0xff, 0xec, 0xb1, 0xf7, 0x10, 0xff, 0xff, 0xff, 0xff, 0xed, 0xc6,
+  0xd2, 0x10, 0xff, 0xff, 0xff, 0xff, 0xee, 0x91, 0xd9, 0x10, 0xff, 0xff,
+  0xff, 0xff, 0xef, 0xaf, 0xee, 0x90, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x71,
+  0xbb, 0x10, 0xff, 0xff, 0xff, 0xff, 0xf1, 0x8f, 0xd0, 0x90, 0xff, 0xff,
+  0xff, 0xff, 0xf2, 0x7f, 0xc1, 0x90, 0xff, 0xff, 0xff, 0xff, 0xf3, 0x6f,
+  0xb2, 0x90, 0xff, 0xff, 0xff, 0xff, 0xf4, 0x5f, 0xa3, 0x90, 0xff, 0xff,
+  0xff, 0xff, 0xf5, 0x4f, 0x94, 0x90, 0xff, 0xff, 0xff, 0xff, 0xf6, 0x3f,
+  0x85, 0x90, 0xff, 0xff, 0xff, 0xff, 0xf7, 0x2f, 0x76, 0x90, 0xff, 0xff,
+  0xff, 0xff, 0xf8, 0x28, 0xa2, 0x10, 0xff, 0xff, 0xff, 0xff, 0xf9, 0x0f,
+  0x58, 0x90, 0xff, 0xff, 0xff, 0xff, 0xfa, 0x08, 0x84, 0x10, 0xff, 0xff,
+  0xff, 0xff, 0xfa, 0xf8, 0x83, 0x20, 0xff, 0xff, 0xff, 0xff, 0xfb, 0xe8,
+  0x66, 0x10, 0xff, 0xff, 0xff, 0xff, 0xfc, 0xd8, 0x65, 0x20, 0xff, 0xff,
+  0xff, 0xff, 0xfd, 0xc8, 0x48, 0x10, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xb8,
+  0x47, 0x20, 0xff, 0xff, 0xff, 0xff, 0xff, 0xa8, 0x2a, 0x10, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x98, 0x29, 0x20, 0x00, 0x00, 0x00, 0x00, 0x01, 0x88,
+  0x0c, 0x10, 0x00, 0x00, 0x00, 0x00, 0x02, 0x78, 0x0b, 0x20, 0x00, 0x00,
+  0x00, 0x00, 0x03, 0x71, 0x28, 0x90, 0x00, 0x00, 0x00, 0x00, 0x04, 0x61,
+  0x27, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x05, 0x51, 0x0a, 0x90, 0x00, 0x00,
+  0x00, 0x00, 0x06, 0x41, 0x09, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x07, 0x30,
+  0xec, 0x90, 0x00, 0x00, 0x00, 0x00, 0x07, 0x8d, 0x43, 0xa0, 0x00, 0x00,
+  0x00, 0x00, 0x09, 0x10, 0xce, 0x90, 0x00, 0x00, 0x00, 0x00, 0x09, 0xad,
+  0xbf, 0x20, 0x00, 0x00, 0x00, 0x00, 0x0a, 0xf0, 0xb0, 0x90, 0x00, 0x00,
+  0x00, 0x00, 0x0b, 0xe0, 0xaf, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x0c, 0xd9,
+  0xcd, 0x10, 0x00, 0x00, 0x00, 0x00, 0x0d, 0xc0, 0x91, 0xa0, 0x00, 0x00,
+  0x00, 0x00, 0x0e, 0xb9, 0xaf, 0x10, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xa9,
+  0xae, 0x20, 0x00, 0x00, 0x00, 0x00, 0x10, 0x99, 0x91, 0x10, 0x00, 0x00,
+  0x00, 0x00, 0x11, 0x89, 0x90, 0x20, 0x00, 0x00, 0x00, 0x00, 0x12, 0x79,
+  0x73, 0x10, 0x00, 0x00, 0x00, 0x00, 0x13, 0x69, 0x72, 0x20, 0x00, 0x00,
+  0x00, 0x00, 0x14, 0x59, 0x55, 0x10, 0x00, 0x00, 0x00, 0x00, 0x15, 0x49,
+  0x54, 0x20, 0x00, 0x00, 0x00, 0x00, 0x16, 0x39, 0x37, 0x10, 0x00, 0x00,
+  0x00, 0x00, 0x17, 0x29, 0x36, 0x20, 0x00, 0x00, 0x00, 0x00, 0x18, 0x22,
+  0x53, 0x90, 0x00, 0x00, 0x00, 0x00, 0x19, 0x09, 0x18, 0x20, 0x00, 0x00,
+  0x00, 0x00, 0x1a, 0x02, 0x35, 0x90, 0x00, 0x00, 0x00, 0x00, 0x1a, 0xf2,
+  0x34, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x1b, 0xe2, 0x17, 0x90, 0x00, 0x00,
+  0x00, 0x00, 0x1c, 0xd2, 0x16, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x1d, 0xc1,
+  0xf9, 0x90, 0x00, 0x00, 0x00, 0x00, 0x1e, 0xb1, 0xf8, 0xa0, 0x00, 0x00,
+  0x00, 0x00, 0x1f, 0xa1, 0xdb, 0x90, 0x00, 0x00, 0x00, 0x00, 0x20, 0x76,
+  0x2b, 0x20, 0x00, 0x00, 0x00, 0x00, 0x21, 0x81, 0xbd, 0x90, 0x00, 0x00,
+  0x00, 0x00, 0x22, 0x56, 0x0d, 0x20, 0x00, 0x00, 0x00, 0x00, 0x23, 0x6a,
+  0xda, 0x10, 0x00, 0x00, 0x00, 0x00, 0x24, 0x35, 0xef, 0x20, 0x00, 0x00,
+  0x00, 0x00, 0x25, 0x4a, 0xbc, 0x10, 0x00, 0x00, 0x00, 0x00, 0x26, 0x15,
+  0xd1, 0x20, 0x00, 0x00, 0x00, 0x00, 0x27, 0x2a, 0x9e, 0x10, 0x00, 0x00,
+  0x00, 0x00, 0x27, 0xfe, 0xed, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x29, 0x0a,
+  0x80, 0x10, 0x00, 0x00, 0x00, 0x00, 0x29, 0xde, 0xcf, 0xa0, 0x00, 0x00,
+  0x00, 0x00, 0x2a, 0xea, 0x62, 0x10, 0x00, 0x00, 0x00, 0x00, 0x2b, 0xbe,
+  0xb1, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x2c, 0xd3, 0x7e, 0x90, 0x00, 0x00,
+  0x00, 0x00, 0x2d, 0x9e, 0x93, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x2e, 0xb3,
+  0x60, 0x90, 0x00, 0x00, 0x00, 0x00, 0x2f, 0x7e, 0x75, 0xa0, 0x00, 0x00,
+  0x00, 0x00, 0x30, 0x93, 0x42, 0x90, 0x00, 0x00, 0x00, 0x00, 0x31, 0x67,
+  0x92, 0x20, 0x00, 0x00, 0x00, 0x00, 0x32, 0x73, 0x24, 0x90, 0x00, 0x00,
+  0x00, 0x00, 0x33, 0x47, 0x74, 0x20, 0x00, 0x00, 0x00, 0x00, 0x34, 0x53,
+  0x06, 0x90, 0x00, 0x00, 0x00, 0x00, 0x35, 0x27, 0x56, 0x20, 0x00, 0x00,
+  0x00, 0x00, 0x36, 0x32, 0xe8, 0x90, 0x00, 0x00, 0x00, 0x00, 0x37, 0x07,
+  0x38, 0x20, 0x00, 0x00, 0x00, 0x00, 0x38, 0x1c, 0x05, 0x10, 0x00, 0x00,
+  0x00, 0x00, 0x38, 0xe7, 0x1a, 0x20, 0x00, 0x00, 0x00, 0x00, 0x39, 0xfb,
+  0xe7, 0x10, 0x00, 0x00, 0x00, 0x00, 0x3a, 0xc6, 0xfc, 0x20, 0x00, 0x00,
+  0x00, 0x00, 0x3b, 0xdb, 0xc9, 0x10, 0x00, 0x00, 0x00, 0x00, 0x3c, 0xb0,
+  0x18, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x3d, 0xbb, 0xab, 0x10, 0x00, 0x00,
+  0x00, 0x00, 0x3e, 0x8f, 0xfa, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x9b,
+  0x8d, 0x10, 0x00, 0x00, 0x00, 0x00, 0x40, 0x6f, 0xdc, 0xa0, 0x00, 0x00,
+  0x00, 0x00, 0x41, 0x84, 0xa9, 0x90, 0x00, 0x00, 0x00, 0x00, 0x42, 0x4f,
+  0xbe, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x43, 0x64, 0x8b, 0x90, 0x00, 0x00,
+  0x00, 0x00, 0x44, 0x2f, 0xa0, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x45, 0x44,
+  0x6d, 0x90, 0x00, 0x00, 0x00, 0x00, 0x45, 0xf3, 0xd3, 0x20, 0x00, 0x00,
+  0x00, 0x00, 0x47, 0x2d, 0x8a, 0x10, 0x00, 0x00, 0x00, 0x00, 0x47, 0xd3,
+  0xb5, 0x20, 0x00, 0x00, 0x00, 0x00, 0x49, 0x0d, 0x6c, 0x10, 0x00, 0x00,
+  0x00, 0x00, 0x49, 0xb3, 0x97, 0x20, 0x00, 0x00, 0x00, 0x00, 0x4a, 0xed,
+  0x4e, 0x10, 0x00, 0x00, 0x00, 0x00, 0x4b, 0x9c, 0xb3, 0xa0, 0x00, 0x00,
+  0x00, 0x00, 0x4c, 0xd6, 0x6a, 0x90, 0x00, 0x00, 0x00, 0x00, 0x4d, 0x7c,
+  0x95, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x4e, 0xb6, 0x4c, 0x90, 0x00, 0x00,
+  0x00, 0x00, 0x4f, 0x5c, 0x77, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x50, 0x96,
+  0x2e, 0x90, 0x00, 0x00, 0x00, 0x00, 0x51, 0x3c, 0x59, 0xa0, 0x00, 0x00,
+  0x00, 0x00, 0x52, 0x76, 0x10, 0x90, 0x00, 0x00, 0x00, 0x00, 0x53, 0x1c,
+  0x3b, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x54, 0x55, 0xf2, 0x90, 0x00, 0x00,
+  0x00, 0x00, 0x54, 0xfc, 0x1d, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x56, 0x35,
+  0xd4, 0x90, 0x00, 0x00, 0x00, 0x00, 0x56, 0xe5, 0x3a, 0x20, 0x00, 0x00,
+  0x00, 0x00, 0x58, 0x1e, 0xf1, 0x10, 0x00, 0x00, 0x00, 0x00, 0x58, 0xc5,
+  0x1c, 0x20, 0x00, 0x00, 0x00, 0x00, 0x59, 0xfe, 0xd3, 0x10, 0x00, 0x00,
+  0x00, 0x00, 0x5a, 0xa4, 0xfe, 0x20, 0x00, 0x00, 0x00, 0x00, 0x5b, 0xde,
+  0xb5, 0x10, 0x00, 0x00, 0x00, 0x00, 0x5c, 0x84, 0xe0, 0x20, 0x00, 0x00,
+  0x00, 0x00, 0x5d, 0xbe, 0x97, 0x10, 0x00, 0x00, 0x00, 0x00, 0x5e, 0x64,
+  0xc2, 0x20, 0x00, 0x00, 0x00, 0x00, 0x5f, 0x9e, 0x79, 0x10, 0x00, 0x00,
+  0x00, 0x00, 0x60, 0x4d, 0xde, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x61, 0x87,
+  0x95, 0x90, 0x00, 0x00, 0x00, 0x00, 0x62, 0x2d, 0xc0, 0xa0, 0x00, 0x00,
+  0x00, 0x00, 0x63, 0x67, 0x77, 0x90, 0x00, 0x00, 0x00, 0x00, 0x64, 0x0d,
+  0xa2, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x65, 0x47, 0x59, 0x90, 0x00, 0x00,
+  0x00, 0x00, 0x65, 0xed, 0x84, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x67, 0x27,
+  0x3b, 0x90, 0x00, 0x00, 0x00, 0x00, 0x67, 0xcd, 0x66, 0xa0, 0x00, 0x00,
+  0x00, 0x00, 0x69, 0x07, 0x1d, 0x90, 0x00, 0x00, 0x00, 0x00, 0x69, 0xad,
+  0x48, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x6a, 0xe6, 0xff, 0x90, 0x00, 0x00,
+  0x00, 0x00, 0x6b, 0x96, 0x65, 0x20, 0x00, 0x00, 0x00, 0x00, 0x6c, 0xd0,
+  0x1c, 0x10, 0x00, 0x00, 0x00, 0x00, 0x6d, 0x76, 0x47, 0x20, 0x00, 0x00,
+  0x00, 0x00, 0x6e, 0xaf, 0xfe, 0x10, 0x00, 0x00, 0x00, 0x00, 0x6f, 0x56,
+  0x29, 0x20, 0x00, 0x00, 0x00, 0x00, 0x70, 0x8f, 0xe0, 0x10, 0x00, 0x00,
+  0x00, 0x00, 0x71, 0x36, 0x0b, 0x20, 0x00, 0x00, 0x00, 0x00, 0x72, 0x6f,
+  0xc2, 0x10, 0x00, 0x00, 0x00, 0x00, 0x73, 0x15, 0xed, 0x20, 0x00, 0x00,
+  0x00, 0x00, 0x74, 0x4f, 0xa4, 0x10, 0x00, 0x00, 0x00, 0x00, 0x74, 0xff,
+  0x09, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x76, 0x38, 0xc0, 0x90, 0x00, 0x00,
+  0x00, 0x00, 0x76, 0xde, 0xeb, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x78, 0x18,
+  0xa2, 0x90, 0x00, 0x00, 0x00, 0x00, 0x78, 0xbe, 0xcd, 0xa0, 0x00, 0x00,
+  0x00, 0x00, 0x79, 0xf8, 0x84, 0x90, 0x00, 0x00, 0x00, 0x00, 0x7a, 0x9e,
+  0xaf, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x7b, 0xd8, 0x66, 0x90, 0x00, 0x00,
+  0x00, 0x00, 0x7c, 0x7e, 0x91, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x7d, 0xb8,
+  0x48, 0x90, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x5e, 0x73, 0xa0, 0x00, 0x00,
+  0x00, 0x00, 0x7f, 0x98, 0x2a, 0x90, 0x00, 0x02, 0x01, 0x02, 0x01, 0x02,
+  0x03, 0x04, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01,
+  0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01,
+  0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01,
+  0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01,
+  0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01,
+  0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01,
+  0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01,
+  0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01,
+  0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01,
+  0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01,
+  0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01,
+  0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01,
+  0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01,
+  0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01,
+  0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01,
+  0x02, 0xff, 0xff, 0x91, 0x26, 0x00, 0x00, 0xff, 0xff, 0x9d, 0x90, 0x01,
+  0x04, 0xff, 0xff, 0x8f, 0x80, 0x00, 0x08, 0xff, 0xff, 0x9d, 0x90, 0x01,
+  0x0c, 0xff, 0xff, 0x9d, 0x90, 0x01, 0x10, 0x4c, 0x4d, 0x54, 0x00, 0x50,
+  0x44, 0x54, 0x00, 0x50, 0x53, 0x54, 0x00, 0x50, 0x57, 0x54, 0x00, 0x50,
+  0x50, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
+  0x01, 0x0a, 0x50, 0x53, 0x54, 0x38, 0x50, 0x44, 0x54, 0x2c, 0x4d, 0x33,
+  0x2e, 0x32, 0x2e, 0x30, 0x2c, 0x4d, 0x31, 0x31, 0x2e, 0x31, 0x2e, 0x30,
+  0x0a
+};
+unsigned int America_Los_Angeles_len = 2845;
+unsigned char America_New_York[] = {
+  0x54, 0x5a, 0x69, 0x66, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05,
+  0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xec,
+  0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x14, 0x80, 0x00, 0x00, 0x00,
+  0x9e, 0xa6, 0x1e, 0x70, 0x9f, 0xba, 0xeb, 0x60, 0xa0, 0x86, 0x00, 0x70,
+  0xa1, 0x9a, 0xcd, 0x60, 0xa2, 0x65, 0xe2, 0x70, 0xa3, 0x83, 0xe9, 0xe0,
+  0xa4, 0x6a, 0xae, 0x70, 0xa5, 0x35, 0xa7, 0x60, 0xa6, 0x53, 0xca, 0xf0,
+  0xa7, 0x15, 0x89, 0x60, 0xa8, 0x33, 0xac, 0xf0, 0xa8, 0xfe, 0xa5, 0xe0,
+  0xaa, 0x13, 0x8e, 0xf0, 0xaa, 0xde, 0x87, 0xe0, 0xab, 0xf3, 0x70, 0xf0,
+  0xac, 0xbe, 0x69, 0xe0, 0xad, 0xd3, 0x52, 0xf0, 0xae, 0x9e, 0x4b, 0xe0,
+  0xaf, 0xb3, 0x34, 0xf0, 0xb0, 0x7e, 0x2d, 0xe0, 0xb1, 0x9c, 0x51, 0x70,
+  0xb2, 0x67, 0x4a, 0x60, 0xb3, 0x7c, 0x33, 0x70, 0xb4, 0x47, 0x2c, 0x60,
+  0xb5, 0x5c, 0x15, 0x70, 0xb6, 0x27, 0x0e, 0x60, 0xb7, 0x3b, 0xf7, 0x70,
+  0xb8, 0x06, 0xf0, 0x60, 0xb9, 0x1b, 0xd9, 0x70, 0xb9, 0xe6, 0xd2, 0x60,
+  0xbb, 0x04, 0xf5, 0xf0, 0xbb, 0xc6, 0xb4, 0x60, 0xbc, 0xe4, 0xd7, 0xf0,
+  0xbd, 0xaf, 0xd0, 0xe0, 0xbe, 0xc4, 0xb9, 0xf0, 0xbf, 0x8f, 0xb2, 0xe0,
+  0xc0, 0xa4, 0x9b, 0xf0, 0xc1, 0x6f, 0x94, 0xe0, 0xc2, 0x84, 0x7d, 0xf0,
+  0xc3, 0x4f, 0x76, 0xe0, 0xc4, 0x64, 0x5f, 0xf0, 0xc5, 0x2f, 0x58, 0xe0,
+  0xc6, 0x4d, 0x7c, 0x70, 0xc7, 0x0f, 0x3a, 0xe0, 0xc8, 0x2d, 0x5e, 0x70,
+  0xc8, 0xf8, 0x57, 0x60, 0xca, 0x0d, 0x40, 0x70, 0xca, 0xd8, 0x39, 0x60,
+  0xcb, 0x88, 0xf0, 0x70, 0xd2, 0x23, 0xf4, 0x70, 0xd2, 0x60, 0xfb, 0xe0,
+  0xd3, 0x75, 0xe4, 0xf0, 0xd4, 0x40, 0xdd, 0xe0, 0xd5, 0x55, 0xc6, 0xf0,
+  0xd6, 0x20, 0xbf, 0xe0, 0xd7, 0x35, 0xa8, 0xf0, 0xd8, 0x00, 0xa1, 0xe0,
+  0xd9, 0x15, 0x8a, 0xf0, 0xd9, 0xe0, 0x83, 0xe0, 0xda, 0xfe, 0xa7, 0x70,
+  0xdb, 0xc0, 0x65, 0xe0, 0xdc, 0xde, 0x89, 0x70, 0xdd, 0xa9, 0x82, 0x60,
+  0xde, 0xbe, 0x6b, 0x70, 0xdf, 0x89, 0x64, 0x60, 0xe0, 0x9e, 0x4d, 0x70,
+  0xe1, 0x69, 0x46, 0x60, 0xe2, 0x7e, 0x2f, 0x70, 0xe3, 0x49, 0x28, 0x60,
+  0xe4, 0x5e, 0x11, 0x70, 0xe5, 0x57, 0x2e, 0xe0, 0xe6, 0x47, 0x2d, 0xf0,
+  0xe7, 0x37, 0x10, 0xe0, 0xe8, 0x27, 0x0f, 0xf0, 0xe9, 0x16, 0xf2, 0xe0,
+  0xea, 0x06, 0xf1, 0xf0, 0xea, 0xf6, 0xd4, 0xe0, 0xeb, 0xe6, 0xd3, 0xf0,
+  0xec, 0xd6, 0xb6, 0xe0, 0xed, 0xc6, 0xb5, 0xf0, 0xee, 0xbf, 0xd3, 0x60,
+  0xef, 0xaf, 0xd2, 0x70, 0xf0, 0x9f, 0xb5, 0x60, 0xf1, 0x8f, 0xb4, 0x70,
+  0xf2, 0x7f, 0x97, 0x60, 0xf3, 0x6f, 0x96, 0x70, 0xf4, 0x5f, 0x79, 0x60,
+  0xf5, 0x4f, 0x78, 0x70, 0xf6, 0x3f, 0x5b, 0x60, 0xf7, 0x2f, 0x5a, 0x70,
+  0xf8, 0x28, 0x77, 0xe0, 0xf9, 0x0f, 0x3c, 0x70, 0xfa, 0x08, 0x59, 0xe0,
+  0xfa, 0xf8, 0x58, 0xf0, 0xfb, 0xe8, 0x3b, 0xe0, 0xfc, 0xd8, 0x3a, 0xf0,
+  0xfd, 0xc8, 0x1d, 0xe0, 0xfe, 0xb8, 0x1c, 0xf0, 0xff, 0xa7, 0xff, 0xe0,
+  0x00, 0x97, 0xfe, 0xf0, 0x01, 0x87, 0xe1, 0xe0, 0x02, 0x77, 0xe0, 0xf0,
+  0x03, 0x70, 0xfe, 0x60, 0x04, 0x60, 0xfd, 0x70, 0x05, 0x50, 0xe0, 0x60,
+  0x06, 0x40, 0xdf, 0x70, 0x07, 0x30, 0xc2, 0x60, 0x07, 0x8d, 0x19, 0x70,
+  0x09, 0x10, 0xa4, 0x60, 0x09, 0xad, 0x94, 0xf0, 0x0a, 0xf0, 0x86, 0x60,
+  0x0b, 0xe0, 0x85, 0x70, 0x0c, 0xd9, 0xa2, 0xe0, 0x0d, 0xc0, 0x67, 0x70,
+  0x0e, 0xb9, 0x84, 0xe0, 0x0f, 0xa9, 0x83, 0xf0, 0x10, 0x99, 0x66, 0xe0,
+  0x11, 0x89, 0x65, 0xf0, 0x12, 0x79, 0x48, 0xe0, 0x13, 0x69, 0x47, 0xf0,
+  0x14, 0x59, 0x2a, 0xe0, 0x15, 0x49, 0x29, 0xf0, 0x16, 0x39, 0x0c, 0xe0,
+  0x17, 0x29, 0x0b, 0xf0, 0x18, 0x22, 0x29, 0x60, 0x19, 0x08, 0xed, 0xf0,
+  0x1a, 0x02, 0x0b, 0x60, 0x1a, 0xf2, 0x0a, 0x70, 0x1b, 0xe1, 0xed, 0x60,
+  0x1c, 0xd1, 0xec, 0x70, 0x1d, 0xc1, 0xcf, 0x60, 0x1e, 0xb1, 0xce, 0x70,
+  0x1f, 0xa1, 0xb1, 0x60, 0x20, 0x76, 0x00, 0xf0, 0x21, 0x81, 0x93, 0x60,
+  0x22, 0x55, 0xe2, 0xf0, 0x23, 0x6a, 0xaf, 0xe0, 0x24, 0x35, 0xc4, 0xf0,
+  0x25, 0x4a, 0x91, 0xe0, 0x26, 0x15, 0xa6, 0xf0, 0x27, 0x2a, 0x73, 0xe0,
+  0x27, 0xfe, 0xc3, 0x70, 0x29, 0x0a, 0x55, 0xe0, 0x29, 0xde, 0xa5, 0x70,
+  0x2a, 0xea, 0x37, 0xe0, 0x2b, 0xbe, 0x87, 0x70, 0x2c, 0xd3, 0x54, 0x60,
+  0x2d, 0x9e, 0x69, 0x70, 0x2e, 0xb3, 0x36, 0x60, 0x2f, 0x7e, 0x4b, 0x70,
+  0x30, 0x93, 0x18, 0x60, 0x31, 0x67, 0x67, 0xf0, 0x32, 0x72, 0xfa, 0x60,
+  0x33, 0x47, 0x49, 0xf0, 0x34, 0x52, 0xdc, 0x60, 0x35, 0x27, 0x2b, 0xf0,
+  0x36, 0x32, 0xbe, 0x60, 0x37, 0x07, 0x0d, 0xf0, 0x38, 0x1b, 0xda, 0xe0,
+  0x38, 0xe6, 0xef, 0xf0, 0x39, 0xfb, 0xbc, 0xe0, 0x3a, 0xc6, 0xd1, 0xf0,
+  0x3b, 0xdb, 0x9e, 0xe0, 0x3c, 0xaf, 0xee, 0x70, 0x3d, 0xbb, 0x80, 0xe0,
+  0x3e, 0x8f, 0xd0, 0x70, 0x3f, 0x9b, 0x62, 0xe0, 0x40, 0x6f, 0xb2, 0x70,
+  0x41, 0x84, 0x7f, 0x60, 0x42, 0x4f, 0x94, 0x70, 0x43, 0x64, 0x61, 0x60,
+  0x44, 0x2f, 0x76, 0x70, 0x45, 0x44, 0x43, 0x60, 0x45, 0xf3, 0xa8, 0xf0,
+  0x47, 0x2d, 0x5f, 0xe0, 0x47, 0xd3, 0x8a, 0xf0, 0x49, 0x0d, 0x41, 0xe0,
+  0x49, 0xb3, 0x6c, 0xf0, 0x4a, 0xed, 0x23, 0xe0, 0x4b, 0x9c, 0x89, 0x70,
+  0x4c, 0xd6, 0x40, 0x60, 0x4d, 0x7c, 0x6b, 0x70, 0x4e, 0xb6, 0x22, 0x60,
+  0x4f, 0x5c, 0x4d, 0x70, 0x50, 0x96, 0x04, 0x60, 0x51, 0x3c, 0x2f, 0x70,
+  0x52, 0x75, 0xe6, 0x60, 0x53, 0x1c, 0x11, 0x70, 0x54, 0x55, 0xc8, 0x60,
+  0x54, 0xfb, 0xf3, 0x70, 0x56, 0x35, 0xaa, 0x60, 0x56, 0xe5, 0x0f, 0xf0,
+  0x58, 0x1e, 0xc6, 0xe0, 0x58, 0xc4, 0xf1, 0xf0, 0x59, 0xfe, 0xa8, 0xe0,
+  0x5a, 0xa4, 0xd3, 0xf0, 0x5b, 0xde, 0x8a, 0xe0, 0x5c, 0x84, 0xb5, 0xf0,
+  0x5d, 0xbe, 0x6c, 0xe0, 0x5e, 0x64, 0x97, 0xf0, 0x5f, 0x9e, 0x4e, 0xe0,
+  0x60, 0x4d, 0xb4, 0x70, 0x61, 0x87, 0x6b, 0x60, 0x62, 0x2d, 0x96, 0x70,
+  0x63, 0x67, 0x4d, 0x60, 0x64, 0x0d, 0x78, 0x70, 0x65, 0x47, 0x2f, 0x60,
+  0x65, 0xed, 0x5a, 0x70, 0x67, 0x27, 0x11, 0x60, 0x67, 0xcd, 0x3c, 0x70,
+  0x69, 0x06, 0xf3, 0x60, 0x69, 0xad, 0x1e, 0x70, 0x6a, 0xe6, 0xd5, 0x60,
+  0x6b, 0x96, 0x3a, 0xf0, 0x6c, 0xcf, 0xf1, 0xe0, 0x6d, 0x76, 0x1c, 0xf0,
+  0x6e, 0xaf, 0xd3, 0xe0, 0x6f, 0x55, 0xfe, 0xf0, 0x70, 0x8f, 0xb5, 0xe0,
+  0x71, 0x35, 0xe0, 0xf0, 0x72, 0x6f, 0x97, 0xe0, 0x73, 0x15, 0xc2, 0xf0,
+  0x74, 0x4f, 0x79, 0xe0, 0x74, 0xfe, 0xdf, 0x70, 0x76, 0x38, 0x96, 0x60,
+  0x76, 0xde, 0xc1, 0x70, 0x78, 0x18, 0x78, 0x60, 0x78, 0xbe, 0xa3, 0x70,
+  0x79, 0xf8, 0x5a, 0x60, 0x7a, 0x9e, 0x85, 0x70, 0x7b, 0xd8, 0x3c, 0x60,
+  0x7c, 0x7e, 0x67, 0x70, 0x7d, 0xb8, 0x1e, 0x60, 0x7e, 0x5e, 0x49, 0x70,
+  0x7f, 0x98, 0x00, 0x60, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01,
+  0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01,
+  0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01,
+  0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01,
+  0x02, 0x01, 0x02, 0x01, 0x02, 0x03, 0x04, 0x02, 0x01, 0x02, 0x01, 0x02,
+  0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02,
+  0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02,
+  0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02,
+  0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02,
+  0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02,
+  0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02,
+  0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02,
+  0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02,
+  0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02,
+  0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02,
+  0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02,
+  0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02,
+  0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02,
+  0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02,
+  0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02,
+  0xff, 0xff, 0xba, 0x9e, 0x00, 0x00, 0xff, 0xff, 0xc7, 0xc0, 0x01, 0x04,
+  0xff, 0xff, 0xb9, 0xb0, 0x00, 0x08, 0xff, 0xff, 0xc7, 0xc0, 0x01, 0x0c,
+  0xff, 0xff, 0xc7, 0xc0, 0x01, 0x10, 0x4c, 0x4d, 0x54, 0x00, 0x45, 0x44,
+  0x54, 0x00, 0x45, 0x53, 0x54, 0x00, 0x45, 0x57, 0x54, 0x00, 0x45, 0x50,
+  0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01,
+  0x54, 0x5a, 0x69, 0x66, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05,
+  0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xed,
+  0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x14, 0xf8, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x5e, 0x03, 0xf0, 0x90,
+  0xff, 0xff, 0xff, 0xff, 0x9e, 0xa6, 0x1e, 0x70, 0xff, 0xff, 0xff, 0xff,
+  0x9f, 0xba, 0xeb, 0x60, 0xff, 0xff, 0xff, 0xff, 0xa0, 0x86, 0x00, 0x70,
+  0xff, 0xff, 0xff, 0xff, 0xa1, 0x9a, 0xcd, 0x60, 0xff, 0xff, 0xff, 0xff,
+  0xa2, 0x65, 0xe2, 0x70, 0xff, 0xff, 0xff, 0xff, 0xa3, 0x83, 0xe9, 0xe0,
+  0xff, 0xff, 0xff, 0xff, 0xa4, 0x6a, 0xae, 0x70, 0xff, 0xff, 0xff, 0xff,
+  0xa5, 0x35, 0xa7, 0x60, 0xff, 0xff, 0xff, 0xff, 0xa6, 0x53, 0xca, 0xf0,
+  0xff, 0xff, 0xff, 0xff, 0xa7, 0x15, 0x89, 0x60, 0xff, 0xff, 0xff, 0xff,
+  0xa8, 0x33, 0xac, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xa8, 0xfe, 0xa5, 0xe0,
+  0xff, 0xff, 0xff, 0xff, 0xaa, 0x13, 0x8e, 0xf0, 0xff, 0xff, 0xff, 0xff,
+  0xaa, 0xde, 0x87, 0xe0, 0xff, 0xff, 0xff, 0xff, 0xab, 0xf3, 0x70, 0xf0,
+  0xff, 0xff, 0xff, 0xff, 0xac, 0xbe, 0x69, 0xe0, 0xff, 0xff, 0xff, 0xff,
+  0xad, 0xd3, 0x52, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xae, 0x9e, 0x4b, 0xe0,
+  0xff, 0xff, 0xff, 0xff, 0xaf, 0xb3, 0x34, 0xf0, 0xff, 0xff, 0xff, 0xff,
+  0xb0, 0x7e, 0x2d, 0xe0, 0xff, 0xff, 0xff, 0xff, 0xb1, 0x9c, 0x51, 0x70,
+  0xff, 0xff, 0xff, 0xff, 0xb2, 0x67, 0x4a, 0x60, 0xff, 0xff, 0xff, 0xff,
+  0xb3, 0x7c, 0x33, 0x70, 0xff, 0xff, 0xff, 0xff, 0xb4, 0x47, 0x2c, 0x60,
+  0xff, 0xff, 0xff, 0xff, 0xb5, 0x5c, 0x15, 0x70, 0xff, 0xff, 0xff, 0xff,
+  0xb6, 0x27, 0x0e, 0x60, 0xff, 0xff, 0xff, 0xff, 0xb7, 0x3b, 0xf7, 0x70,
+  0xff, 0xff, 0xff, 0xff, 0xb8, 0x06, 0xf0, 0x60, 0xff, 0xff, 0xff, 0xff,
+  0xb9, 0x1b, 0xd9, 0x70, 0xff, 0xff, 0xff, 0xff, 0xb9, 0xe6, 0xd2, 0x60,
+  0xff, 0xff, 0xff, 0xff, 0xbb, 0x04, 0xf5, 0xf0, 0xff, 0xff, 0xff, 0xff,
+  0xbb, 0xc6, 0xb4, 0x60, 0xff, 0xff, 0xff, 0xff, 0xbc, 0xe4, 0xd7, 0xf0,
+  0xff, 0xff, 0xff, 0xff, 0xbd, 0xaf, 0xd0, 0xe0, 0xff, 0xff, 0xff, 0xff,
+  0xbe, 0xc4, 0xb9, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xbf, 0x8f, 0xb2, 0xe0,
+  0xff, 0xff, 0xff, 0xff, 0xc0, 0xa4, 0x9b, 0xf0, 0xff, 0xff, 0xff, 0xff,
+  0xc1, 0x6f, 0x94, 0xe0, 0xff, 0xff, 0xff, 0xff, 0xc2, 0x84, 0x7d, 0xf0,
+  0xff, 0xff, 0xff, 0xff, 0xc3, 0x4f, 0x76, 0xe0, 0xff, 0xff, 0xff, 0xff,
+  0xc4, 0x64, 0x5f, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xc5, 0x2f, 0x58, 0xe0,
+  0xff, 0xff, 0xff, 0xff, 0xc6, 0x4d, 0x7c, 0x70, 0xff, 0xff, 0xff, 0xff,
+  0xc7, 0x0f, 0x3a, 0xe0, 0xff, 0xff, 0xff, 0xff, 0xc8, 0x2d, 0x5e, 0x70,
+  0xff, 0xff, 0xff, 0xff, 0xc8, 0xf8, 0x57, 0x60, 0xff, 0xff, 0xff, 0xff,
+  0xca, 0x0d, 0x40, 0x70, 0xff, 0xff, 0xff, 0xff, 0xca, 0xd8, 0x39, 0x60,
+  0xff, 0xff, 0xff, 0xff, 0xcb, 0x88, 0xf0, 0x70, 0xff, 0xff, 0xff, 0xff,
+  0xd2, 0x23, 0xf4, 0x70, 0xff, 0xff, 0xff, 0xff, 0xd2, 0x60, 0xfb, 0xe0,
+  0xff, 0xff, 0xff, 0xff, 0xd3, 0x75, 0xe4, 0xf0, 0xff, 0xff, 0xff, 0xff,
+  0xd4, 0x40, 0xdd, 0xe0, 0xff, 0xff, 0xff, 0xff, 0xd5, 0x55, 0xc6, 0xf0,
+  0xff, 0xff, 0xff, 0xff, 0xd6, 0x20, 0xbf, 0xe0, 0xff, 0xff, 0xff, 0xff,
+  0xd7, 0x35, 0xa8, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xd8, 0x00, 0xa1, 0xe0,
+  0xff, 0xff, 0xff, 0xff, 0xd9, 0x15, 0x8a, 0xf0, 0xff, 0xff, 0xff, 0xff,
+  0xd9, 0xe0, 0x83, 0xe0, 0xff, 0xff, 0xff, 0xff, 0xda, 0xfe, 0xa7, 0x70,
+  0xff, 0xff, 0xff, 0xff, 0xdb, 0xc0, 0x65, 0xe0, 0xff, 0xff, 0xff, 0xff,
+  0xdc, 0xde, 0x89, 0x70, 0xff, 0xff, 0xff, 0xff, 0xdd, 0xa9, 0x82, 0x60,
+  0xff, 0xff, 0xff, 0xff, 0xde, 0xbe, 0x6b, 0x70, 0xff, 0xff, 0xff, 0xff,
+  0xdf, 0x89, 0x64, 0x60, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x9e, 0x4d, 0x70,
+  0xff, 0xff, 0xff, 0xff, 0xe1, 0x69, 0x46, 0x60, 0xff, 0xff, 0xff, 0xff,
+  0xe2, 0x7e, 0x2f, 0x70, 0xff, 0xff, 0xff, 0xff, 0xe3, 0x49, 0x28, 0x60,
+  0xff, 0xff, 0xff, 0xff, 0xe4, 0x5e, 0x11, 0x70, 0xff, 0xff, 0xff, 0xff,
+  0xe5, 0x57, 0x2e, 0xe0, 0xff, 0xff, 0xff, 0xff, 0xe6, 0x47, 0x2d, 0xf0,
+  0xff, 0xff, 0xff, 0xff, 0xe7, 0x37, 0x10, 0xe0, 0xff, 0xff, 0xff, 0xff,
+  0xe8, 0x27, 0x0f, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xe9, 0x16, 0xf2, 0xe0,
+  0xff, 0xff, 0xff, 0xff, 0xea, 0x06, 0xf1, 0xf0, 0xff, 0xff, 0xff, 0xff,
+  0xea, 0xf6, 0xd4, 0xe0, 0xff, 0xff, 0xff, 0xff, 0xeb, 0xe6, 0xd3, 0xf0,
+  0xff, 0xff, 0xff, 0xff, 0xec, 0xd6, 0xb6, 0xe0, 0xff, 0xff, 0xff, 0xff,
+  0xed, 0xc6, 0xb5, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xee, 0xbf, 0xd3, 0x60,
+  0xff, 0xff, 0xff, 0xff, 0xef, 0xaf, 0xd2, 0x70, 0xff, 0xff, 0xff, 0xff,
+  0xf0, 0x9f, 0xb5, 0x60, 0xff, 0xff, 0xff, 0xff, 0xf1, 0x8f, 0xb4, 0x70,
+  0xff, 0xff, 0xff, 0xff, 0xf2, 0x7f, 0x97, 0x60, 0xff, 0xff, 0xff, 0xff,
+  0xf3, 0x6f, 0x96, 0x70, 0xff, 0xff, 0xff, 0xff, 0xf4, 0x5f, 0x79, 0x60,
+  0xff, 0xff, 0xff, 0xff, 0xf5, 0x4f, 0x78, 0x70, 0xff, 0xff, 0xff, 0xff,
+  0xf6, 0x3f, 0x5b, 0x60, 0xff, 0xff, 0xff, 0xff, 0xf7, 0x2f, 0x5a, 0x70,
+  0xff, 0xff, 0xff, 0xff, 0xf8, 0x28, 0x77, 0xe0, 0xff, 0xff, 0xff, 0xff,
+  0xf9, 0x0f, 0x3c, 0x70, 0xff, 0xff, 0xff, 0xff, 0xfa, 0x08, 0x59, 0xe0,
+  0xff, 0xff, 0xff, 0xff, 0xfa, 0xf8, 0x58, 0xf0, 0xff, 0xff, 0xff, 0xff,
+  0xfb, 0xe8, 0x3b, 0xe0, 0xff, 0xff, 0xff, 0xff, 0xfc, 0xd8, 0x3a, 0xf0,
+  0xff, 0xff, 0xff, 0xff, 0xfd, 0xc8, 0x1d, 0xe0, 0xff, 0xff, 0xff, 0xff,
+  0xfe, 0xb8, 0x1c, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xa7, 0xff, 0xe0,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x97, 0xfe, 0xf0, 0x00, 0x00, 0x00, 0x00,
+  0x01, 0x87, 0xe1, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x02, 0x77, 0xe0, 0xf0,
+  0x00, 0x00, 0x00, 0x00, 0x03, 0x70, 0xfe, 0x60, 0x00, 0x00, 0x00, 0x00,
+  0x04, 0x60, 0xfd, 0x70, 0x00, 0x00, 0x00, 0x00, 0x05, 0x50, 0xe0, 0x60,
+  0x00, 0x00, 0x00, 0x00, 0x06, 0x40, 0xdf, 0x70, 0x00, 0x00, 0x00, 0x00,
+  0x07, 0x30, 0xc2, 0x60, 0x00, 0x00, 0x00, 0x00, 0x07, 0x8d, 0x19, 0x70,
+  0x00, 0x00, 0x00, 0x00, 0x09, 0x10, 0xa4, 0x60, 0x00, 0x00, 0x00, 0x00,
+  0x09, 0xad, 0x94, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x0a, 0xf0, 0x86, 0x60,
+  0x00, 0x00, 0x00, 0x00, 0x0b, 0xe0, 0x85, 0x70, 0x00, 0x00, 0x00, 0x00,
+  0x0c, 0xd9, 0xa2, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x0d, 0xc0, 0x67, 0x70,
+  0x00, 0x00, 0x00, 0x00, 0x0e, 0xb9, 0x84, 0xe0, 0x00, 0x00, 0x00, 0x00,
+  0x0f, 0xa9, 0x83, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x10, 0x99, 0x66, 0xe0,
+  0x00, 0x00, 0x00, 0x00, 0x11, 0x89, 0x65, 0xf0, 0x00, 0x00, 0x00, 0x00,
+  0x12, 0x79, 0x48, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x13, 0x69, 0x47, 0xf0,
+  0x00, 0x00, 0x00, 0x00, 0x14, 0x59, 0x2a, 0xe0, 0x00, 0x00, 0x00, 0x00,
+  0x15, 0x49, 0x29, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x16, 0x39, 0x0c, 0xe0,
+  0x00, 0x00, 0x00, 0x00, 0x17, 0x29, 0x0b, 0xf0, 0x00, 0x00, 0x00, 0x00,
+  0x18, 0x22, 0x29, 0x60, 0x00, 0x00, 0x00, 0x00, 0x19, 0x08, 0xed, 0xf0,
+  0x00, 0x00, 0x00, 0x00, 0x1a, 0x02, 0x0b, 0x60, 0x00, 0x00, 0x00, 0x00,
+  0x1a, 0xf2, 0x0a, 0x70, 0x00, 0x00, 0x00, 0x00, 0x1b, 0xe1, 0xed, 0x60,
+  0x00, 0x00, 0x00, 0x00, 0x1c, 0xd1, 0xec, 0x70, 0x00, 0x00, 0x00, 0x00,
+  0x1d, 0xc1, 0xcf, 0x60, 0x00, 0x00, 0x00, 0x00, 0x1e, 0xb1, 0xce, 0x70,
+  0x00, 0x00, 0x00, 0x00, 0x1f, 0xa1, 0xb1, 0x60, 0x00, 0x00, 0x00, 0x00,
+  0x20, 0x76, 0x00, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x21, 0x81, 0x93, 0x60,
+  0x00, 0x00, 0x00, 0x00, 0x22, 0x55, 0xe2, 0xf0, 0x00, 0x00, 0x00, 0x00,
+  0x23, 0x6a, 0xaf, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x24, 0x35, 0xc4, 0xf0,
+  0x00, 0x00, 0x00, 0x00, 0x25, 0x4a, 0x91, 0xe0, 0x00, 0x00, 0x00, 0x00,
+  0x26, 0x15, 0xa6, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x27, 0x2a, 0x73, 0xe0,
+  0x00, 0x00, 0x00, 0x00, 0x27, 0xfe, 0xc3, 0x70, 0x00, 0x00, 0x00, 0x00,
+  0x29, 0x0a, 0x55, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x29, 0xde, 0xa5, 0x70,
+  0x00, 0x00, 0x00, 0x00, 0x2a, 0xea, 0x37, 0xe0, 0x00, 0x00, 0x00, 0x00,
+  0x2b, 0xbe, 0x87, 0x70, 0x00, 0x00, 0x00, 0x00, 0x2c, 0xd3, 0x54, 0x60,
+  0x00, 0x00, 0x00, 0x00, 0x2d, 0x9e, 0x69, 0x70, 0x00, 0x00, 0x00, 0x00,
+  0x2e, 0xb3, 0x36, 0x60, 0x00, 0x00, 0x00, 0x00, 0x2f, 0x7e, 0x4b, 0x70,
+  0x00, 0x00, 0x00, 0x00, 0x30, 0x93, 0x18, 0x60, 0x00, 0x00, 0x00, 0x00,
+  0x31, 0x67, 0x67, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x32, 0x72, 0xfa, 0x60,
+  0x00, 0x00, 0x00, 0x00, 0x33, 0x47, 0x49, 0xf0, 0x00, 0x00, 0x00, 0x00,
+  0x34, 0x52, 0xdc, 0x60, 0x00, 0x00, 0x00, 0x00, 0x35, 0x27, 0x2b, 0xf0,
+  0x00, 0x00, 0x00, 0x00, 0x36, 0x32, 0xbe, 0x60, 0x00, 0x00, 0x00, 0x00,
+  0x37, 0x07, 0x0d, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x38, 0x1b, 0xda, 0xe0,
+  0x00, 0x00, 0x00, 0x00, 0x38, 0xe6, 0xef, 0xf0, 0x00, 0x00, 0x00, 0x00,
+  0x39, 0xfb, 0xbc, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x3a, 0xc6, 0xd1, 0xf0,
+  0x00, 0x00, 0x00, 0x00, 0x3b, 0xdb, 0x9e, 0xe0, 0x00, 0x00, 0x00, 0x00,
+  0x3c, 0xaf, 0xee, 0x70, 0x00, 0x00, 0x00, 0x00, 0x3d, 0xbb, 0x80, 0xe0,
+  0x00, 0x00, 0x00, 0x00, 0x3e, 0x8f, 0xd0, 0x70, 0x00, 0x00, 0x00, 0x00,
+  0x3f, 0x9b, 0x62, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x40, 0x6f, 0xb2, 0x70,
+  0x00, 0x00, 0x00, 0x00, 0x41, 0x84, 0x7f, 0x60, 0x00, 0x00, 0x00, 0x00,
+  0x42, 0x4f, 0x94, 0x70, 0x00, 0x00, 0x00, 0x00, 0x43, 0x64, 0x61, 0x60,
+  0x00, 0x00, 0x00, 0x00, 0x44, 0x2f, 0x76, 0x70, 0x00, 0x00, 0x00, 0x00,
+  0x45, 0x44, 0x43, 0x60, 0x00, 0x00, 0x00, 0x00, 0x45, 0xf3, 0xa8, 0xf0,
+  0x00, 0x00, 0x00, 0x00, 0x47, 0x2d, 0x5f, 0xe0, 0x00, 0x00, 0x00, 0x00,
+  0x47, 0xd3, 0x8a, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x49, 0x0d, 0x41, 0xe0,
+  0x00, 0x00, 0x00, 0x00, 0x49, 0xb3, 0x6c, 0xf0, 0x00, 0x00, 0x00, 0x00,
+  0x4a, 0xed, 0x23, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x4b, 0x9c, 0x89, 0x70,
+  0x00, 0x00, 0x00, 0x00, 0x4c, 0xd6, 0x40, 0x60, 0x00, 0x00, 0x00, 0x00,
+  0x4d, 0x7c, 0x6b, 0x70, 0x00, 0x00, 0x00, 0x00, 0x4e, 0xb6, 0x22, 0x60,
+  0x00, 0x00, 0x00, 0x00, 0x4f, 0x5c, 0x4d, 0x70, 0x00, 0x00, 0x00, 0x00,
+  0x50, 0x96, 0x04, 0x60, 0x00, 0x00, 0x00, 0x00, 0x51, 0x3c, 0x2f, 0x70,
+  0x00, 0x00, 0x00, 0x00, 0x52, 0x75, 0xe6, 0x60, 0x00, 0x00, 0x00, 0x00,
+  0x53, 0x1c, 0x11, 0x70, 0x00, 0x00, 0x00, 0x00, 0x54, 0x55, 0xc8, 0x60,
+  0x00, 0x00, 0x00, 0x00, 0x54, 0xfb, 0xf3, 0x70, 0x00, 0x00, 0x00, 0x00,
+  0x56, 0x35, 0xaa, 0x60, 0x00, 0x00, 0x00, 0x00, 0x56, 0xe5, 0x0f, 0xf0,
+  0x00, 0x00, 0x00, 0x00, 0x58, 0x1e, 0xc6, 0xe0, 0x00, 0x00, 0x00, 0x00,
+  0x58, 0xc4, 0xf1, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x59, 0xfe, 0xa8, 0xe0,
+  0x00, 0x00, 0x00, 0x00, 0x5a, 0xa4, 0xd3, 0xf0, 0x00, 0x00, 0x00, 0x00,
+  0x5b, 0xde, 0x8a, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x5c, 0x84, 0xb5, 0xf0,
+  0x00, 0x00, 0x00, 0x00, 0x5d, 0xbe, 0x6c, 0xe0, 0x00, 0x00, 0x00, 0x00,
+  0x5e, 0x64, 0x97, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x5f, 0x9e, 0x4e, 0xe0,
+  0x00, 0x00, 0x00, 0x00, 0x60, 0x4d, 0xb4, 0x70, 0x00, 0x00, 0x00, 0x00,
+  0x61, 0x87, 0x6b, 0x60, 0x00, 0x00, 0x00, 0x00, 0x62, 0x2d, 0x96, 0x70,
+  0x00, 0x00, 0x00, 0x00, 0x63, 0x67, 0x4d, 0x60, 0x00, 0x00, 0x00, 0x00,
+  0x64, 0x0d, 0x78, 0x70, 0x00, 0x00, 0x00, 0x00, 0x65, 0x47, 0x2f, 0x60,
+  0x00, 0x00, 0x00, 0x00, 0x65, 0xed, 0x5a, 0x70, 0x00, 0x00, 0x00, 0x00,
+  0x67, 0x27, 0x11, 0x60, 0x00, 0x00, 0x00, 0x00, 0x67, 0xcd, 0x3c, 0x70,
+  0x00, 0x00, 0x00, 0x00, 0x69, 0x06, 0xf3, 0x60, 0x00, 0x00, 0x00, 0x00,
+  0x69, 0xad, 0x1e, 0x70, 0x00, 0x00, 0x00, 0x00, 0x6a, 0xe6, 0xd5, 0x60,
+  0x00, 0x00, 0x00, 0x00, 0x6b, 0x96, 0x3a, 0xf0, 0x00, 0x00, 0x00, 0x00,
+  0x6c, 0xcf, 0xf1, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x6d, 0x76, 0x1c, 0xf0,
+  0x00, 0x00, 0x00, 0x00, 0x6e, 0xaf, 0xd3, 0xe0, 0x00, 0x00, 0x00, 0x00,
+  0x6f, 0x55, 0xfe, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x70, 0x8f, 0xb5, 0xe0,
+  0x00, 0x00, 0x00, 0x00, 0x71, 0x35, 0xe0, 0xf0, 0x00, 0x00, 0x00, 0x00,
+  0x72, 0x6f, 0x97, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x73, 0x15, 0xc2, 0xf0,
+  0x00, 0x00, 0x00, 0x00, 0x74, 0x4f, 0x79, 0xe0, 0x00, 0x00, 0x00, 0x00,
+  0x74, 0xfe, 0xdf, 0x70, 0x00, 0x00, 0x00, 0x00, 0x76, 0x38, 0x96, 0x60,
+  0x00, 0x00, 0x00, 0x00, 0x76, 0xde, 0xc1, 0x70, 0x00, 0x00, 0x00, 0x00,
+  0x78, 0x18, 0x78, 0x60, 0x00, 0x00, 0x00, 0x00, 0x78, 0xbe, 0xa3, 0x70,
+  0x00, 0x00, 0x00, 0x00, 0x79, 0xf8, 0x5a, 0x60, 0x00, 0x00, 0x00, 0x00,
+  0x7a, 0x9e, 0x85, 0x70, 0x00, 0x00, 0x00, 0x00, 0x7b, 0xd8, 0x3c, 0x60,
+  0x00, 0x00, 0x00, 0x00, 0x7c, 0x7e, 0x67, 0x70, 0x00, 0x00, 0x00, 0x00,
+  0x7d, 0xb8, 0x1e, 0x60, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x5e, 0x49, 0x70,
+  0x00, 0x00, 0x00, 0x00, 0x7f, 0x98, 0x00, 0x60, 0x00, 0x02, 0x01, 0x02,
+  0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02,
+  0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02,
+  0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02,
+  0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x03, 0x04,
+  0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01,
+  0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01,
+  0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01,
+  0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01,
+  0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01,
+  0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01,
+  0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01,
+  0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01,
+  0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01,
+  0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01,
+  0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01,
+  0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01,
+  0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01,
+  0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01,
+  0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01,
+  0x02, 0x01, 0x02, 0x01, 0x02, 0xff, 0xff, 0xba, 0x9e, 0x00, 0x00, 0xff,
+  0xff, 0xc7, 0xc0, 0x01, 0x04, 0xff, 0xff, 0xb9, 0xb0, 0x00, 0x08, 0xff,
+  0xff, 0xc7, 0xc0, 0x01, 0x0c, 0xff, 0xff, 0xc7, 0xc0, 0x01, 0x10, 0x4c,
+  0x4d, 0x54, 0x00, 0x45, 0x44, 0x54, 0x00, 0x45, 0x53, 0x54, 0x00, 0x45,
+  0x57, 0x54, 0x00, 0x45, 0x50, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+  0x00, 0x00, 0x00, 0x00, 0x01, 0x0a, 0x45, 0x53, 0x54, 0x35, 0x45, 0x44,
+  0x54, 0x2c, 0x4d, 0x33, 0x2e, 0x32, 0x2e, 0x30, 0x2c, 0x4d, 0x31, 0x31,
+  0x2e, 0x31, 0x2e, 0x30, 0x0a
+};
+unsigned int America_New_York_len = 3545;
+unsigned char Australia_Sydney[] = {
+  0x54, 0x5a, 0x69, 0x66, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05,
+  0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8e,
+  0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x0e, 0x80, 0x00, 0x00, 0x00,
+  0x9c, 0x4e, 0xa6, 0x9c, 0x9c, 0xbc, 0x20, 0xf0, 0xcb, 0x54, 0xb3, 0x00,
+  0xcb, 0xc7, 0x57, 0x70, 0xcc, 0xb7, 0x56, 0x80, 0xcd, 0xa7, 0x39, 0x70,
+  0xce, 0xa0, 0x73, 0x00, 0xcf, 0x87, 0x1b, 0x70, 0x03, 0x70, 0x39, 0x80,
+  0x04, 0x0d, 0x1c, 0x00, 0x05, 0x50, 0x1b, 0x80, 0x05, 0xf6, 0x38, 0x80,
+  0x07, 0x2f, 0xfd, 0x80, 0x07, 0xd6, 0x1a, 0x80, 0x09, 0x0f, 0xdf, 0x80,
+  0x09, 0xb5, 0xfc, 0x80, 0x0a, 0xef, 0xc1, 0x80, 0x0b, 0x9f, 0x19, 0x00,
+  0x0c, 0xd8, 0xde, 0x00, 0x0d, 0x7e, 0xfb, 0x00, 0x0e, 0xb8, 0xc0, 0x00,
+  0x0f, 0x5e, 0xdd, 0x00, 0x10, 0x98, 0xa2, 0x00, 0x11, 0x3e, 0xbf, 0x00,
+  0x12, 0x78, 0x84, 0x00, 0x13, 0x1e, 0xa1, 0x00, 0x14, 0x58, 0x66, 0x00,
+  0x14, 0xfe, 0x83, 0x00, 0x16, 0x38, 0x48, 0x00, 0x17, 0x0c, 0x89, 0x80,
+  0x18, 0x21, 0x64, 0x80, 0x18, 0xc7, 0x81, 0x80, 0x1a, 0x01, 0x46, 0x80,
+  0x1a, 0xa7, 0x63, 0x80, 0x1b, 0xe1, 0x28, 0x80, 0x1c, 0x87, 0x45, 0x80,
+  0x1d, 0xc1, 0x0a, 0x80, 0x1e, 0x79, 0x9c, 0x80, 0x1f, 0x97, 0xb2, 0x00,
+  0x20, 0x59, 0x7e, 0x80, 0x21, 0x80, 0xce, 0x80, 0x22, 0x42, 0x9b, 0x00,
+  0x23, 0x69, 0xeb, 0x00, 0x24, 0x22, 0x7d, 0x00, 0x25, 0x49, 0xcd, 0x00,
+  0x25, 0xef, 0xea, 0x00, 0x27, 0x29, 0xaf, 0x00, 0x27, 0xcf, 0xcc, 0x00,
+  0x29, 0x09, 0x91, 0x00, 0x29, 0xaf, 0xae, 0x00, 0x2a, 0xe9, 0x73, 0x00,
+  0x2b, 0x98, 0xca, 0x80, 0x2c, 0xd2, 0x8f, 0x80, 0x2d, 0x78, 0xac, 0x80,
+  0x2e, 0xb2, 0x71, 0x80, 0x2f, 0x58, 0x8e, 0x80, 0x30, 0x92, 0x53, 0x80,
+  0x31, 0x5d, 0x5a, 0x80, 0x32, 0x72, 0x35, 0x80, 0x33, 0x3d, 0x3c, 0x80,
+  0x34, 0x52, 0x17, 0x80, 0x35, 0x1d, 0x1e, 0x80, 0x36, 0x31, 0xf9, 0x80,
+  0x36, 0xfd, 0x00, 0x80, 0x38, 0x1b, 0x16, 0x00, 0x38, 0xdc, 0xe2, 0x80,
+  0x39, 0xa7, 0xe9, 0x80, 0x3a, 0xbc, 0xc4, 0x80, 0x3b, 0xda, 0xda, 0x00,
+  0x3c, 0xa5, 0xe1, 0x00, 0x3d, 0xba, 0xbc, 0x00, 0x3e, 0x85, 0xc3, 0x00,
+  0x3f, 0x9a, 0x9e, 0x00, 0x40, 0x65, 0xa5, 0x00, 0x41, 0x83, 0xba, 0x80,
+  0x42, 0x45, 0x87, 0x00, 0x43, 0x63, 0x9c, 0x80, 0x44, 0x2e, 0xa3, 0x80,
+  0x45, 0x43, 0x7e, 0x80, 0x46, 0x05, 0x4b, 0x00, 0x47, 0x23, 0x60, 0x80,
+  0x47, 0xf7, 0xa2, 0x00, 0x48, 0xe7, 0x93, 0x00, 0x49, 0xd7, 0x84, 0x00,
+  0x4a, 0xc7, 0x75, 0x00, 0x4b, 0xb7, 0x66, 0x00, 0x4c, 0xa7, 0x57, 0x00,
+  0x4d, 0x97, 0x48, 0x00, 0x4e, 0x87, 0x39, 0x00, 0x4f, 0x77, 0x2a, 0x00,
+  0x50, 0x70, 0x55, 0x80, 0x51, 0x60, 0x46, 0x80, 0x52, 0x50, 0x37, 0x80,
+  0x53, 0x40, 0x28, 0x80, 0x54, 0x30, 0x19, 0x80, 0x55, 0x20, 0x0a, 0x80,
+  0x56, 0x0f, 0xfb, 0x80, 0x56, 0xff, 0xec, 0x80, 0x57, 0xef, 0xdd, 0x80,
+  0x58, 0xdf, 0xce, 0x80, 0x59, 0xcf, 0xbf, 0x80, 0x5a, 0xbf, 0xb0, 0x80,
+  0x5b, 0xb8, 0xdc, 0x00, 0x5c, 0xa8, 0xcd, 0x00, 0x5d, 0x98, 0xbe, 0x00,
+  0x5e, 0x88, 0xaf, 0x00, 0x5f, 0x78, 0xa0, 0x00, 0x60, 0x68, 0x91, 0x00,
+  0x61, 0x58, 0x82, 0x00, 0x62, 0x48, 0x73, 0x00, 0x63, 0x38, 0x64, 0x00,
+  0x64, 0x28, 0x55, 0x00, 0x65, 0x18, 0x46, 0x00, 0x66, 0x11, 0x71, 0x80,
+  0x67, 0x01, 0x62, 0x80, 0x67, 0xf1, 0x53, 0x80, 0x68, 0xe1, 0x44, 0x80,
+  0x69, 0xd1, 0x35, 0x80, 0x6a, 0xc1, 0x26, 0x80, 0x6b, 0xb1, 0x17, 0x80,
+  0x6c, 0xa1, 0x08, 0x80, 0x6d, 0x90, 0xf9, 0x80, 0x6e, 0x80, 0xea, 0x80,
+  0x6f, 0x70, 0xdb, 0x80, 0x70, 0x6a, 0x07, 0x00, 0x71, 0x59, 0xf8, 0x00,
+  0x72, 0x49, 0xe9, 0x00, 0x73, 0x39, 0xda, 0x00, 0x74, 0x29, 0xcb, 0x00,
+  0x75, 0x19, 0xbc, 0x00, 0x76, 0x09, 0xad, 0x00, 0x76, 0xf9, 0x9e, 0x00,
+  0x77, 0xe9, 0x8f, 0x00, 0x78, 0xd9, 0x80, 0x00, 0x79, 0xc9, 0x71, 0x00,
+  0x7a, 0xb9, 0x62, 0x00, 0x7b, 0xb2, 0x8d, 0x80, 0x7c, 0xa2, 0x7e, 0x80,
+  0x7d, 0x92, 0x6f, 0x80, 0x7e, 0x82, 0x60, 0x80, 0x7f, 0x72, 0x51, 0x80,
+  0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x03, 0x04, 0x03,
+  0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03,
+  0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03,
+  0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03,
+  0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03,
+  0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03,
+  0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03,
+  0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03,
+  0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03,
+  0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03,
+  0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03,
+  0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x00, 0x00,
+  0x8d, 0xc4, 0x00, 0x00, 0x00, 0x00, 0x9a, 0xb0, 0x01, 0x04, 0x00, 0x00,
+  0x8c, 0xa0, 0x00, 0x09, 0x00, 0x00, 0x9a, 0xb0, 0x01, 0x04, 0x00, 0x00,
+  0x8c, 0xa0, 0x00, 0x09, 0x4c, 0x4d, 0x54, 0x00, 0x41, 0x45, 0x44, 0x54,
+  0x00, 0x41, 0x45, 0x53, 0x54, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x54, 0x5a, 0x69, 0x66, 0x32, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x8f, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x0e,
+  0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
+  0x73, 0x16, 0x7f, 0x3c, 0xff, 0xff, 0xff, 0xff, 0x9c, 0x4e, 0xa6, 0x9c,
+  0xff, 0xff, 0xff, 0xff, 0x9c, 0xbc, 0x20, 0xf0, 0xff, 0xff, 0xff, 0xff,
+  0xcb, 0x54, 0xb3, 0x00, 0xff, 0xff, 0xff, 0xff, 0xcb, 0xc7, 0x57, 0x70,
+  0xff, 0xff, 0xff, 0xff, 0xcc, 0xb7, 0x56, 0x80, 0xff, 0xff, 0xff, 0xff,
+  0xcd, 0xa7, 0x39, 0x70, 0xff, 0xff, 0xff, 0xff, 0xce, 0xa0, 0x73, 0x00,
+  0xff, 0xff, 0xff, 0xff, 0xcf, 0x87, 0x1b, 0x70, 0x00, 0x00, 0x00, 0x00,
+  0x03, 0x70, 0x39, 0x80, 0x00, 0x00, 0x00, 0x00, 0x04, 0x0d, 0x1c, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x05, 0x50, 0x1b, 0x80, 0x00, 0x00, 0x00, 0x00,
+  0x05, 0xf6, 0x38, 0x80, 0x00, 0x00, 0x00, 0x00, 0x07, 0x2f, 0xfd, 0x80,
+  0x00, 0x00, 0x00, 0x00, 0x07, 0xd6, 0x1a, 0x80, 0x00, 0x00, 0x00, 0x00,
+  0x09, 0x0f, 0xdf, 0x80, 0x00, 0x00, 0x00, 0x00, 0x09, 0xb5, 0xfc, 0x80,
+  0x00, 0x00, 0x00, 0x00, 0x0a, 0xef, 0xc1, 0x80, 0x00, 0x00, 0x00, 0x00,
+  0x0b, 0x9f, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0xd8, 0xde, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x0d, 0x7e, 0xfb, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x0e, 0xb8, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x5e, 0xdd, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x10, 0x98, 0xa2, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x11, 0x3e, 0xbf, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x78, 0x84, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x13, 0x1e, 0xa1, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x14, 0x58, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0xfe, 0x83, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x16, 0x38, 0x48, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x17, 0x0c, 0x89, 0x80, 0x00, 0x00, 0x00, 0x00, 0x18, 0x21, 0x64, 0x80,
+  0x00, 0x00, 0x00, 0x00, 0x18, 0xc7, 0x81, 0x80, 0x00, 0x00, 0x00, 0x00,
+  0x1a, 0x01, 0x46, 0x80, 0x00, 0x00, 0x00, 0x00, 0x1a, 0xa7, 0x63, 0x80,
+  0x00, 0x00, 0x00, 0x00, 0x1b, 0xe1, 0x28, 0x80, 0x00, 0x00, 0x00, 0x00,
+  0x1c, 0x87, 0x45, 0x80, 0x00, 0x00, 0x00, 0x00, 0x1d, 0xc1, 0x0a, 0x80,
+  0x00, 0x00, 0x00, 0x00, 0x1e, 0x79, 0x9c, 0x80, 0x00, 0x00, 0x00, 0x00,
+  0x1f, 0x97, 0xb2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x59, 0x7e, 0x80,
+  0x00, 0x00, 0x00, 0x00, 0x21, 0x80, 0xce, 0x80, 0x00, 0x00, 0x00, 0x00,
+  0x22, 0x42, 0x9b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x23, 0x69, 0xeb, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x24, 0x22, 0x7d, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x25, 0x49, 0xcd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x25, 0xef, 0xea, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x27, 0x29, 0xaf, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x27, 0xcf, 0xcc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x29, 0x09, 0x91, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x29, 0xaf, 0xae, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x2a, 0xe9, 0x73, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2b, 0x98, 0xca, 0x80,
+  0x00, 0x00, 0x00, 0x00, 0x2c, 0xd2, 0x8f, 0x80, 0x00, 0x00, 0x00, 0x00,
+  0x2d, 0x78, 0xac, 0x80, 0x00, 0x00, 0x00, 0x00, 0x2e, 0xb2, 0x71, 0x80,
+  0x00, 0x00, 0x00, 0x00, 0x2f, 0x58, 0x8e, 0x80, 0x00, 0x00, 0x00, 0x00,
+  0x30, 0x92, 0x53, 0x80, 0x00, 0x00, 0x00, 0x00, 0x31, 0x5d, 0x5a, 0x80,
+  0x00, 0x00, 0x00, 0x00, 0x32, 0x72, 0x35, 0x80, 0x00, 0x00, 0x00, 0x00,
+  0x33, 0x3d, 0x3c, 0x80, 0x00, 0x00, 0x00, 0x00, 0x34, 0x52, 0x17, 0x80,
+  0x00, 0x00, 0x00, 0x00, 0x35, 0x1d, 0x1e, 0x80, 0x00, 0x00, 0x00, 0x00,
+  0x36, 0x31, 0xf9, 0x80, 0x00, 0x00, 0x00, 0x00, 0x36, 0xfd, 0x00, 0x80,
+  0x00, 0x00, 0x00, 0x00, 0x38, 0x1b, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x38, 0xdc, 0xe2, 0x80, 0x00, 0x00, 0x00, 0x00, 0x39, 0xa7, 0xe9, 0x80,
+  0x00, 0x00, 0x00, 0x00, 0x3a, 0xbc, 0xc4, 0x80, 0x00, 0x00, 0x00, 0x00,
+  0x3b, 0xda, 0xda, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0xa5, 0xe1, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x3d, 0xba, 0xbc, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x3e, 0x85, 0xc3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x9a, 0x9e, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x40, 0x65, 0xa5, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x41, 0x83, 0xba, 0x80, 0x00, 0x00, 0x00, 0x00, 0x42, 0x45, 0x87, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x43, 0x63, 0x9c, 0x80, 0x00, 0x00, 0x00, 0x00,
+  0x44, 0x2e, 0xa3, 0x80, 0x00, 0x00, 0x00, 0x00, 0x45, 0x43, 0x7e, 0x80,
+  0x00, 0x00, 0x00, 0x00, 0x46, 0x05, 0x4b, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x47, 0x23, 0x60, 0x80, 0x00, 0x00, 0x00, 0x00, 0x47, 0xf7, 0xa2, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x48, 0xe7, 0x93, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x49, 0xd7, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4a, 0xc7, 0x75, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x4b, 0xb7, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x4c, 0xa7, 0x57, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4d, 0x97, 0x48, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x4e, 0x87, 0x39, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x4f, 0x77, 0x2a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x70, 0x55, 0x80,
+  0x00, 0x00, 0x00, 0x00, 0x51, 0x60, 0x46, 0x80, 0x00, 0x00, 0x00, 0x00,
+  0x52, 0x50, 0x37, 0x80, 0x00, 0x00, 0x00, 0x00, 0x53, 0x40, 0x28, 0x80,
+  0x00, 0x00, 0x00, 0x00, 0x54, 0x30, 0x19, 0x80, 0x00, 0x00, 0x00, 0x00,
+  0x55, 0x20, 0x0a, 0x80, 0x00, 0x00, 0x00, 0x00, 0x56, 0x0f, 0xfb, 0x80,
+  0x00, 0x00, 0x00, 0x00, 0x56, 0xff, 0xec, 0x80, 0x00, 0x00, 0x00, 0x00,
+  0x57, 0xef, 0xdd, 0x80, 0x00, 0x00, 0x00, 0x00, 0x58, 0xdf, 0xce, 0x80,
+  0x00, 0x00, 0x00, 0x00, 0x59, 0xcf, 0xbf, 0x80, 0x00, 0x00, 0x00, 0x00,
+  0x5a, 0xbf, 0xb0, 0x80, 0x00, 0x00, 0x00, 0x00, 0x5b, 0xb8, 0xdc, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x5c, 0xa8, 0xcd, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x5d, 0x98, 0xbe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5e, 0x88, 0xaf, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x5f, 0x78, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x60, 0x68, 0x91, 0x00, 0x00, 0x00, 0x00, 0x00, 0x61, 0x58, 0x82, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x62, 0x48, 0x73, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x63, 0x38, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x28, 0x55, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x65, 0x18, 0x46, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x66, 0x11, 0x71, 0x80, 0x00, 0x00, 0x00, 0x00, 0x67, 0x01, 0x62, 0x80,
+  0x00, 0x00, 0x00, 0x00, 0x67, 0xf1, 0x53, 0x80, 0x00, 0x00, 0x00, 0x00,
+  0x68, 0xe1, 0x44, 0x80, 0x00, 0x00, 0x00, 0x00, 0x69, 0xd1, 0x35, 0x80,
+  0x00, 0x00, 0x00, 0x00, 0x6a, 0xc1, 0x26, 0x80, 0x00, 0x00, 0x00, 0x00,
+  0x6b, 0xb1, 0x17, 0x80, 0x00, 0x00, 0x00, 0x00, 0x6c, 0xa1, 0x08, 0x80,
+  0x00, 0x00, 0x00, 0x00, 0x6d, 0x90, 0xf9, 0x80, 0x00, 0x00, 0x00, 0x00,
+  0x6e, 0x80, 0xea, 0x80, 0x00, 0x00, 0x00, 0x00, 0x6f, 0x70, 0xdb, 0x80,
+  0x00, 0x00, 0x00, 0x00, 0x70, 0x6a, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x71, 0x59, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x72, 0x49, 0xe9, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x73, 0x39, 0xda, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x74, 0x29, 0xcb, 0x00, 0x00, 0x00, 0x00, 0x00, 0x75, 0x19, 0xbc, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x76, 0x09, 0xad, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x76, 0xf9, 0x9e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0xe9, 0x8f, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x78, 0xd9, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x79, 0xc9, 0x71, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7a, 0xb9, 0x62, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x7b, 0xb2, 0x8d, 0x80, 0x00, 0x00, 0x00, 0x00,
+  0x7c, 0xa2, 0x7e, 0x80, 0x00, 0x00, 0x00, 0x00, 0x7d, 0x92, 0x6f, 0x80,
+  0x00, 0x00, 0x00, 0x00, 0x7e, 0x82, 0x60, 0x80, 0x00, 0x00, 0x00, 0x00,
+  0x7f, 0x72, 0x51, 0x80, 0x00, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02,
+  0x01, 0x02, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04,
+  0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04,
+  0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04,
+  0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04,
+  0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04,
+  0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04,
+  0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04,
+  0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04,
+  0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04,
+  0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04,
+  0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04,
+  0x03, 0x04, 0x03, 0x00, 0x00, 0x8d, 0xc4, 0x00, 0x00, 0x00, 0x00, 0x9a,
+  0xb0, 0x01, 0x04, 0x00, 0x00, 0x8c, 0xa0, 0x00, 0x09, 0x00, 0x00, 0x9a,
+  0xb0, 0x01, 0x04, 0x00, 0x00, 0x8c, 0xa0, 0x00, 0x09, 0x4c, 0x4d, 0x54,
+  0x00, 0x41, 0x45, 0x44, 0x54, 0x00, 0x41, 0x45, 0x53, 0x54, 0x00, 0x00,
+  0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x41, 0x45,
+  0x53, 0x54, 0x2d, 0x31, 0x30, 0x41, 0x45, 0x44, 0x54, 0x2c, 0x4d, 0x31,
+  0x30, 0x2e, 0x31, 0x2e, 0x30, 0x2c, 0x4d, 0x34, 0x2e, 0x31, 0x2e, 0x30,
+  0x2f, 0x33, 0x0a
+};
+unsigned int Australia_Sydney_len = 2223;
diff --git a/src/absl/time/time.cc b/src/absl/time/time.cc
new file mode 100644 (file)
index 0000000..1ec2026
--- /dev/null
@@ -0,0 +1,500 @@
+// Copyright 2017 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// The implementation of the absl::Time class, which is declared in
+// //absl/time.h.
+//
+// The representation for an absl::Time is an absl::Duration offset from the
+// epoch.  We use the traditional Unix epoch (1970-01-01 00:00:00 +0000)
+// for convenience, but this is not exposed in the API and could be changed.
+//
+// NOTE: To keep type verbosity to a minimum, the following variable naming
+// conventions are used throughout this file.
+//
+// tz: An absl::TimeZone
+// ci: An absl::TimeZone::CivilInfo
+// ti: An absl::TimeZone::TimeInfo
+// cd: An absl::CivilDay or a cctz::civil_day
+// cs: An absl::CivilSecond or a cctz::civil_second
+// bd: An absl::Time::Breakdown
+// cl: A cctz::time_zone::civil_lookup
+// al: A cctz::time_zone::absolute_lookup
+
+#include "absl/time/time.h"
+
+#if defined(_MSC_VER)
+#include <winsock2.h>  // for timeval
+#endif
+
+#include <cstring>
+#include <ctime>
+#include <limits>
+
+#include "absl/time/internal/cctz/include/cctz/civil_time.h"
+#include "absl/time/internal/cctz/include/cctz/time_zone.h"
+
+namespace cctz = absl::time_internal::cctz;
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+
+namespace {
+
+inline cctz::time_point<cctz::seconds> unix_epoch() {
+  return std::chrono::time_point_cast<cctz::seconds>(
+      std::chrono::system_clock::from_time_t(0));
+}
+
+// Floors d to the next unit boundary closer to negative infinity.
+inline int64_t FloorToUnit(absl::Duration d, absl::Duration unit) {
+  absl::Duration rem;
+  int64_t q = absl::IDivDuration(d, unit, &rem);
+  return (q > 0 || rem >= ZeroDuration() ||
+          q == std::numeric_limits<int64_t>::min())
+             ? q
+             : q - 1;
+}
+
+inline absl::Time::Breakdown InfiniteFutureBreakdown() {
+  absl::Time::Breakdown bd;
+  bd.year = std::numeric_limits<int64_t>::max();
+  bd.month = 12;
+  bd.day = 31;
+  bd.hour = 23;
+  bd.minute = 59;
+  bd.second = 59;
+  bd.subsecond = absl::InfiniteDuration();
+  bd.weekday = 4;
+  bd.yearday = 365;
+  bd.offset = 0;
+  bd.is_dst = false;
+  bd.zone_abbr = "-00";
+  return bd;
+}
+
+inline absl::Time::Breakdown InfinitePastBreakdown() {
+  Time::Breakdown bd;
+  bd.year = std::numeric_limits<int64_t>::min();
+  bd.month = 1;
+  bd.day = 1;
+  bd.hour = 0;
+  bd.minute = 0;
+  bd.second = 0;
+  bd.subsecond = -absl::InfiniteDuration();
+  bd.weekday = 7;
+  bd.yearday = 1;
+  bd.offset = 0;
+  bd.is_dst = false;
+  bd.zone_abbr = "-00";
+  return bd;
+}
+
+inline absl::TimeZone::CivilInfo InfiniteFutureCivilInfo() {
+  TimeZone::CivilInfo ci;
+  ci.cs = CivilSecond::max();
+  ci.subsecond = InfiniteDuration();
+  ci.offset = 0;
+  ci.is_dst = false;
+  ci.zone_abbr = "-00";
+  return ci;
+}
+
+inline absl::TimeZone::CivilInfo InfinitePastCivilInfo() {
+  TimeZone::CivilInfo ci;
+  ci.cs = CivilSecond::min();
+  ci.subsecond = -InfiniteDuration();
+  ci.offset = 0;
+  ci.is_dst = false;
+  ci.zone_abbr = "-00";
+  return ci;
+}
+
+inline absl::TimeConversion InfiniteFutureTimeConversion() {
+  absl::TimeConversion tc;
+  tc.pre = tc.trans = tc.post = absl::InfiniteFuture();
+  tc.kind = absl::TimeConversion::UNIQUE;
+  tc.normalized = true;
+  return tc;
+}
+
+inline TimeConversion InfinitePastTimeConversion() {
+  absl::TimeConversion tc;
+  tc.pre = tc.trans = tc.post = absl::InfinitePast();
+  tc.kind = absl::TimeConversion::UNIQUE;
+  tc.normalized = true;
+  return tc;
+}
+
+// Makes a Time from sec, overflowing to InfiniteFuture/InfinitePast as
+// necessary. If sec is min/max, then consult cs+tz to check for overlow.
+Time MakeTimeWithOverflow(const cctz::time_point<cctz::seconds>& sec,
+                          const cctz::civil_second& cs,
+                          const cctz::time_zone& tz,
+                          bool* normalized = nullptr) {
+  const auto max = cctz::time_point<cctz::seconds>::max();
+  const auto min = cctz::time_point<cctz::seconds>::min();
+  if (sec == max) {
+    const auto al = tz.lookup(max);
+    if (cs > al.cs) {
+      if (normalized) *normalized = true;
+      return absl::InfiniteFuture();
+    }
+  }
+  if (sec == min) {
+    const auto al = tz.lookup(min);
+    if (cs < al.cs) {
+      if (normalized) *normalized = true;
+      return absl::InfinitePast();
+    }
+  }
+  const auto hi = (sec - unix_epoch()).count();
+  return time_internal::FromUnixDuration(time_internal::MakeDuration(hi));
+}
+
+// Returns Mon=1..Sun=7.
+inline int MapWeekday(const cctz::weekday& wd) {
+  switch (wd) {
+    case cctz::weekday::monday:
+      return 1;
+    case cctz::weekday::tuesday:
+      return 2;
+    case cctz::weekday::wednesday:
+      return 3;
+    case cctz::weekday::thursday:
+      return 4;
+    case cctz::weekday::friday:
+      return 5;
+    case cctz::weekday::saturday:
+      return 6;
+    case cctz::weekday::sunday:
+      return 7;
+  }
+  return 1;
+}
+
+bool FindTransition(const cctz::time_zone& tz,
+                    bool (cctz::time_zone::*find_transition)(
+                        const cctz::time_point<cctz::seconds>& tp,
+                        cctz::time_zone::civil_transition* trans) const,
+                    Time t, TimeZone::CivilTransition* trans) {
+  // Transitions are second-aligned, so we can discard any fractional part.
+  const auto tp = unix_epoch() + cctz::seconds(ToUnixSeconds(t));
+  cctz::time_zone::civil_transition tr;
+  if (!(tz.*find_transition)(tp, &tr)) return false;
+  trans->from = CivilSecond(tr.from);
+  trans->to = CivilSecond(tr.to);
+  return true;
+}
+
+}  // namespace
+
+//
+// Time
+//
+
+absl::Time::Breakdown Time::In(absl::TimeZone tz) const {
+  if (*this == absl::InfiniteFuture()) return InfiniteFutureBreakdown();
+  if (*this == absl::InfinitePast()) return InfinitePastBreakdown();
+
+  const auto tp = unix_epoch() + cctz::seconds(time_internal::GetRepHi(rep_));
+  const auto al = cctz::time_zone(tz).lookup(tp);
+  const auto cs = al.cs;
+  const auto cd = cctz::civil_day(cs);
+
+  absl::Time::Breakdown bd;
+  bd.year = cs.year();
+  bd.month = cs.month();
+  bd.day = cs.day();
+  bd.hour = cs.hour();
+  bd.minute = cs.minute();
+  bd.second = cs.second();
+  bd.subsecond = time_internal::MakeDuration(0, time_internal::GetRepLo(rep_));
+  bd.weekday = MapWeekday(cctz::get_weekday(cd));
+  bd.yearday = cctz::get_yearday(cd);
+  bd.offset = al.offset;
+  bd.is_dst = al.is_dst;
+  bd.zone_abbr = al.abbr;
+  return bd;
+}
+
+//
+// Conversions from/to other time types.
+//
+
+absl::Time FromUDate(double udate) {
+  return time_internal::FromUnixDuration(absl::Milliseconds(udate));
+}
+
+absl::Time FromUniversal(int64_t universal) {
+  return absl::UniversalEpoch() + 100 * absl::Nanoseconds(universal);
+}
+
+int64_t ToUnixNanos(Time t) {
+  if (time_internal::GetRepHi(time_internal::ToUnixDuration(t)) >= 0 &&
+      time_internal::GetRepHi(time_internal::ToUnixDuration(t)) >> 33 == 0) {
+    return (time_internal::GetRepHi(time_internal::ToUnixDuration(t)) *
+            1000 * 1000 * 1000) +
+           (time_internal::GetRepLo(time_internal::ToUnixDuration(t)) / 4);
+  }
+  return FloorToUnit(time_internal::ToUnixDuration(t), absl::Nanoseconds(1));
+}
+
+int64_t ToUnixMicros(Time t) {
+  if (time_internal::GetRepHi(time_internal::ToUnixDuration(t)) >= 0 &&
+      time_internal::GetRepHi(time_internal::ToUnixDuration(t)) >> 43 == 0) {
+    return (time_internal::GetRepHi(time_internal::ToUnixDuration(t)) *
+            1000 * 1000) +
+           (time_internal::GetRepLo(time_internal::ToUnixDuration(t)) / 4000);
+  }
+  return FloorToUnit(time_internal::ToUnixDuration(t), absl::Microseconds(1));
+}
+
+int64_t ToUnixMillis(Time t) {
+  if (time_internal::GetRepHi(time_internal::ToUnixDuration(t)) >= 0 &&
+      time_internal::GetRepHi(time_internal::ToUnixDuration(t)) >> 53 == 0) {
+    return (time_internal::GetRepHi(time_internal::ToUnixDuration(t)) * 1000) +
+           (time_internal::GetRepLo(time_internal::ToUnixDuration(t)) /
+            (4000 * 1000));
+  }
+  return FloorToUnit(time_internal::ToUnixDuration(t), absl::Milliseconds(1));
+}
+
+int64_t ToUnixSeconds(Time t) {
+  return time_internal::GetRepHi(time_internal::ToUnixDuration(t));
+}
+
+time_t ToTimeT(Time t) { return absl::ToTimespec(t).tv_sec; }
+
+double ToUDate(Time t) {
+  return absl::FDivDuration(time_internal::ToUnixDuration(t),
+                            absl::Milliseconds(1));
+}
+
+int64_t ToUniversal(absl::Time t) {
+  return absl::FloorToUnit(t - absl::UniversalEpoch(), absl::Nanoseconds(100));
+}
+
+absl::Time TimeFromTimespec(timespec ts) {
+  return time_internal::FromUnixDuration(absl::DurationFromTimespec(ts));
+}
+
+absl::Time TimeFromTimeval(timeval tv) {
+  return time_internal::FromUnixDuration(absl::DurationFromTimeval(tv));
+}
+
+timespec ToTimespec(Time t) {
+  timespec ts;
+  absl::Duration d = time_internal::ToUnixDuration(t);
+  if (!time_internal::IsInfiniteDuration(d)) {
+    ts.tv_sec = time_internal::GetRepHi(d);
+    if (ts.tv_sec == time_internal::GetRepHi(d)) {  // no time_t narrowing
+      ts.tv_nsec = time_internal::GetRepLo(d) / 4;  // floor
+      return ts;
+    }
+  }
+  if (d >= absl::ZeroDuration()) {
+    ts.tv_sec = std::numeric_limits<time_t>::max();
+    ts.tv_nsec = 1000 * 1000 * 1000 - 1;
+  } else {
+    ts.tv_sec = std::numeric_limits<time_t>::min();
+    ts.tv_nsec = 0;
+  }
+  return ts;
+}
+
+timeval ToTimeval(Time t) {
+  timeval tv;
+  timespec ts = absl::ToTimespec(t);
+  tv.tv_sec = ts.tv_sec;
+  if (tv.tv_sec != ts.tv_sec) {  // narrowing
+    if (ts.tv_sec < 0) {
+      tv.tv_sec = std::numeric_limits<decltype(tv.tv_sec)>::min();
+      tv.tv_usec = 0;
+    } else {
+      tv.tv_sec = std::numeric_limits<decltype(tv.tv_sec)>::max();
+      tv.tv_usec = 1000 * 1000 - 1;
+    }
+    return tv;
+  }
+  tv.tv_usec = static_cast<int>(ts.tv_nsec / 1000);  // suseconds_t
+  return tv;
+}
+
+Time FromChrono(const std::chrono::system_clock::time_point& tp) {
+  return time_internal::FromUnixDuration(time_internal::FromChrono(
+      tp - std::chrono::system_clock::from_time_t(0)));
+}
+
+std::chrono::system_clock::time_point ToChronoTime(absl::Time t) {
+  using D = std::chrono::system_clock::duration;
+  auto d = time_internal::ToUnixDuration(t);
+  if (d < ZeroDuration()) d = Floor(d, FromChrono(D{1}));
+  return std::chrono::system_clock::from_time_t(0) +
+         time_internal::ToChronoDuration<D>(d);
+}
+
+//
+// TimeZone
+//
+
+absl::TimeZone::CivilInfo TimeZone::At(Time t) const {
+  if (t == absl::InfiniteFuture()) return InfiniteFutureCivilInfo();
+  if (t == absl::InfinitePast()) return InfinitePastCivilInfo();
+
+  const auto ud = time_internal::ToUnixDuration(t);
+  const auto tp = unix_epoch() + cctz::seconds(time_internal::GetRepHi(ud));
+  const auto al = cz_.lookup(tp);
+
+  TimeZone::CivilInfo ci;
+  ci.cs = CivilSecond(al.cs);
+  ci.subsecond = time_internal::MakeDuration(0, time_internal::GetRepLo(ud));
+  ci.offset = al.offset;
+  ci.is_dst = al.is_dst;
+  ci.zone_abbr = al.abbr;
+  return ci;
+}
+
+absl::TimeZone::TimeInfo TimeZone::At(CivilSecond ct) const {
+  const cctz::civil_second cs(ct);
+  const auto cl = cz_.lookup(cs);
+
+  TimeZone::TimeInfo ti;
+  switch (cl.kind) {
+    case cctz::time_zone::civil_lookup::UNIQUE:
+      ti.kind = TimeZone::TimeInfo::UNIQUE;
+      break;
+    case cctz::time_zone::civil_lookup::SKIPPED:
+      ti.kind = TimeZone::TimeInfo::SKIPPED;
+      break;
+    case cctz::time_zone::civil_lookup::REPEATED:
+      ti.kind = TimeZone::TimeInfo::REPEATED;
+      break;
+  }
+  ti.pre = MakeTimeWithOverflow(cl.pre, cs, cz_);
+  ti.trans = MakeTimeWithOverflow(cl.trans, cs, cz_);
+  ti.post = MakeTimeWithOverflow(cl.post, cs, cz_);
+  return ti;
+}
+
+bool TimeZone::NextTransition(Time t, CivilTransition* trans) const {
+  return FindTransition(cz_, &cctz::time_zone::next_transition, t, trans);
+}
+
+bool TimeZone::PrevTransition(Time t, CivilTransition* trans) const {
+  return FindTransition(cz_, &cctz::time_zone::prev_transition, t, trans);
+}
+
+//
+// Conversions involving time zones.
+//
+
+absl::TimeConversion ConvertDateTime(int64_t year, int mon, int day, int hour,
+                                     int min, int sec, TimeZone tz) {
+  // Avoids years that are too extreme for CivilSecond to normalize.
+  if (year > 300000000000) return InfiniteFutureTimeConversion();
+  if (year < -300000000000) return InfinitePastTimeConversion();
+
+  const CivilSecond cs(year, mon, day, hour, min, sec);
+  const auto ti = tz.At(cs);
+
+  TimeConversion tc;
+  tc.pre = ti.pre;
+  tc.trans = ti.trans;
+  tc.post = ti.post;
+  switch (ti.kind) {
+    case TimeZone::TimeInfo::UNIQUE:
+      tc.kind = TimeConversion::UNIQUE;
+      break;
+    case TimeZone::TimeInfo::SKIPPED:
+      tc.kind = TimeConversion::SKIPPED;
+      break;
+    case TimeZone::TimeInfo::REPEATED:
+      tc.kind = TimeConversion::REPEATED;
+      break;
+  }
+  tc.normalized = false;
+  if (year != cs.year() || mon != cs.month() || day != cs.day() ||
+      hour != cs.hour() || min != cs.minute() || sec != cs.second()) {
+    tc.normalized = true;
+  }
+  return tc;
+}
+
+absl::Time FromTM(const struct tm& tm, absl::TimeZone tz) {
+  civil_year_t tm_year = tm.tm_year;
+  // Avoids years that are too extreme for CivilSecond to normalize.
+  if (tm_year > 300000000000ll) return InfiniteFuture();
+  if (tm_year < -300000000000ll) return InfinitePast();
+  int tm_mon = tm.tm_mon;
+  if (tm_mon == std::numeric_limits<int>::max()) {
+    tm_mon -= 12;
+    tm_year += 1;
+  }
+  const auto ti = tz.At(CivilSecond(tm_year + 1900, tm_mon + 1, tm.tm_mday,
+                                    tm.tm_hour, tm.tm_min, tm.tm_sec));
+  return tm.tm_isdst == 0 ? ti.post : ti.pre;
+}
+
+struct tm ToTM(absl::Time t, absl::TimeZone tz) {
+  struct tm tm = {};
+
+  const auto ci = tz.At(t);
+  const auto& cs = ci.cs;
+  tm.tm_sec = cs.second();
+  tm.tm_min = cs.minute();
+  tm.tm_hour = cs.hour();
+  tm.tm_mday = cs.day();
+  tm.tm_mon = cs.month() - 1;
+
+  // Saturates tm.tm_year in cases of over/underflow, accounting for the fact
+  // that tm.tm_year is years since 1900.
+  if (cs.year() < std::numeric_limits<int>::min() + 1900) {
+    tm.tm_year = std::numeric_limits<int>::min();
+  } else if (cs.year() > std::numeric_limits<int>::max()) {
+    tm.tm_year = std::numeric_limits<int>::max() - 1900;
+  } else {
+    tm.tm_year = static_cast<int>(cs.year() - 1900);
+  }
+
+  switch (GetWeekday(cs)) {
+    case Weekday::sunday:
+      tm.tm_wday = 0;
+      break;
+    case Weekday::monday:
+      tm.tm_wday = 1;
+      break;
+    case Weekday::tuesday:
+      tm.tm_wday = 2;
+      break;
+    case Weekday::wednesday:
+      tm.tm_wday = 3;
+      break;
+    case Weekday::thursday:
+      tm.tm_wday = 4;
+      break;
+    case Weekday::friday:
+      tm.tm_wday = 5;
+      break;
+    case Weekday::saturday:
+      tm.tm_wday = 6;
+      break;
+  }
+  tm.tm_yday = GetYearDay(cs) - 1;
+  tm.tm_isdst = ci.is_dst ? 1 : 0;
+
+  return tm;
+}
+
+ABSL_NAMESPACE_END
+}  // namespace absl
diff --git a/src/absl/time/time.h b/src/absl/time/time.h
new file mode 100644 (file)
index 0000000..2df6858
--- /dev/null
@@ -0,0 +1,1585 @@
+// Copyright 2017 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// -----------------------------------------------------------------------------
+// File: time.h
+// -----------------------------------------------------------------------------
+//
+// This header file defines abstractions for computing with absolute points
+// in time, durations of time, and formatting and parsing time within a given
+// time zone. The following abstractions are defined:
+//
+//  * `absl::Time` defines an absolute, specific instance in time
+//  * `absl::Duration` defines a signed, fixed-length span of time
+//  * `absl::TimeZone` defines geopolitical time zone regions (as collected
+//     within the IANA Time Zone database (https://www.iana.org/time-zones)).
+//
+// Note: Absolute times are distinct from civil times, which refer to the
+// human-scale time commonly represented by `YYYY-MM-DD hh:mm:ss`. The mapping
+// between absolute and civil times can be specified by use of time zones
+// (`absl::TimeZone` within this API). That is:
+//
+//   Civil Time = F(Absolute Time, Time Zone)
+//   Absolute Time = G(Civil Time, Time Zone)
+//
+// See civil_time.h for abstractions related to constructing and manipulating
+// civil time.
+//
+// Example:
+//
+//   absl::TimeZone nyc;
+//   // LoadTimeZone() may fail so it's always better to check for success.
+//   if (!absl::LoadTimeZone("America/New_York", &nyc)) {
+//      // handle error case
+//   }
+//
+//   // My flight leaves NYC on Jan 2, 2017 at 03:04:05
+//   absl::CivilSecond cs(2017, 1, 2, 3, 4, 5);
+//   absl::Time takeoff = absl::FromCivil(cs, nyc);
+//
+//   absl::Duration flight_duration = absl::Hours(21) + absl::Minutes(35);
+//   absl::Time landing = takeoff + flight_duration;
+//
+//   absl::TimeZone syd;
+//   if (!absl::LoadTimeZone("Australia/Sydney", &syd)) {
+//      // handle error case
+//   }
+//   std::string s = absl::FormatTime(
+//       "My flight will land in Sydney on %Y-%m-%d at %H:%M:%S",
+//       landing, syd);
+
+#ifndef ABSL_TIME_TIME_H_
+#define ABSL_TIME_TIME_H_
+
+#if !defined(_MSC_VER)
+#include <sys/time.h>
+#else
+// We don't include `winsock2.h` because it drags in `windows.h` and friends,
+// and they define conflicting macros like OPAQUE, ERROR, and more. This has the
+// potential to break Abseil users.
+//
+// Instead we only forward declare `timeval` and require Windows users include
+// `winsock2.h` themselves. This is both inconsistent and troublesome, but so is
+// including 'windows.h' so we are picking the lesser of two evils here.
+struct timeval;
+#endif
+#include <chrono>  // NOLINT(build/c++11)
+#include <cmath>
+#include <cstdint>
+#include <ctime>
+#include <ostream>
+#include <string>
+#include <type_traits>
+#include <utility>
+
+#include "absl/base/macros.h"
+#include "absl/strings/string_view.h"
+#include "absl/time/civil_time.h"
+#include "absl/time/internal/cctz/include/cctz/time_zone.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+
+class Duration;  // Defined below
+class Time;      // Defined below
+class TimeZone;  // Defined below
+
+namespace time_internal {
+int64_t IDivDuration(bool satq, Duration num, Duration den, Duration* rem);
+constexpr Time FromUnixDuration(Duration d);
+constexpr Duration ToUnixDuration(Time t);
+constexpr int64_t GetRepHi(Duration d);
+constexpr uint32_t GetRepLo(Duration d);
+constexpr Duration MakeDuration(int64_t hi, uint32_t lo);
+constexpr Duration MakeDuration(int64_t hi, int64_t lo);
+inline Duration MakePosDoubleDuration(double n);
+constexpr int64_t kTicksPerNanosecond = 4;
+constexpr int64_t kTicksPerSecond = 1000 * 1000 * 1000 * kTicksPerNanosecond;
+template <std::intmax_t N>
+constexpr Duration FromInt64(int64_t v, std::ratio<1, N>);
+constexpr Duration FromInt64(int64_t v, std::ratio<60>);
+constexpr Duration FromInt64(int64_t v, std::ratio<3600>);
+template <typename T>
+using EnableIfIntegral = typename std::enable_if<
+    std::is_integral<T>::value || std::is_enum<T>::value, int>::type;
+template <typename T>
+using EnableIfFloat =
+    typename std::enable_if<std::is_floating_point<T>::value, int>::type;
+}  // namespace time_internal
+
+// Duration
+//
+// The `absl::Duration` class represents a signed, fixed-length span of time.
+// A `Duration` is generated using a unit-specific factory function, or is
+// the result of subtracting one `absl::Time` from another. Durations behave
+// like unit-safe integers and they support all the natural integer-like
+// arithmetic operations. Arithmetic overflows and saturates at +/- infinity.
+// `Duration` should be passed by value rather than const reference.
+//
+// Factory functions `Nanoseconds()`, `Microseconds()`, `Milliseconds()`,
+// `Seconds()`, `Minutes()`, `Hours()` and `InfiniteDuration()` allow for
+// creation of constexpr `Duration` values
+//
+// Examples:
+//
+//   constexpr absl::Duration ten_ns = absl::Nanoseconds(10);
+//   constexpr absl::Duration min = absl::Minutes(1);
+//   constexpr absl::Duration hour = absl::Hours(1);
+//   absl::Duration dur = 60 * min;  // dur == hour
+//   absl::Duration half_sec = absl::Milliseconds(500);
+//   absl::Duration quarter_sec = 0.25 * absl::Seconds(1);
+//
+// `Duration` values can be easily converted to an integral number of units
+// using the division operator.
+//
+// Example:
+//
+//   constexpr absl::Duration dur = absl::Milliseconds(1500);
+//   int64_t ns = dur / absl::Nanoseconds(1);   // ns == 1500000000
+//   int64_t ms = dur / absl::Milliseconds(1);  // ms == 1500
+//   int64_t sec = dur / absl::Seconds(1);    // sec == 1 (subseconds truncated)
+//   int64_t min = dur / absl::Minutes(1);    // min == 0
+//
+// See the `IDivDuration()` and `FDivDuration()` functions below for details on
+// how to access the fractional parts of the quotient.
+//
+// Alternatively, conversions can be performed using helpers such as
+// `ToInt64Microseconds()` and `ToDoubleSeconds()`.
+class Duration {
+ public:
+  // Value semantics.
+  constexpr Duration() : rep_hi_(0), rep_lo_(0) {}  // zero-length duration
+
+  // Copyable.
+#if !defined(__clang__) && defined(_MSC_VER) && _MSC_VER < 1910
+  // Explicitly defining the constexpr copy constructor avoids an MSVC bug.
+  constexpr Duration(const Duration& d)
+      : rep_hi_(d.rep_hi_), rep_lo_(d.rep_lo_) {}
+#else
+  constexpr Duration(const Duration& d) = default;
+#endif
+  Duration& operator=(const Duration& d) = default;
+
+  // Compound assignment operators.
+  Duration& operator+=(Duration d);
+  Duration& operator-=(Duration d);
+  Duration& operator*=(int64_t r);
+  Duration& operator*=(double r);
+  Duration& operator/=(int64_t r);
+  Duration& operator/=(double r);
+  Duration& operator%=(Duration rhs);
+
+  // Overloads that forward to either the int64_t or double overloads above.
+  // Integer operands must be representable as int64_t.
+  template <typename T>
+  Duration& operator*=(T r) {
+    int64_t x = r;
+    return *this *= x;
+  }
+  template <typename T>
+  Duration& operator/=(T r) {
+    int64_t x = r;
+    return *this /= x;
+  }
+  Duration& operator*=(float r) { return *this *= static_cast<double>(r); }
+  Duration& operator/=(float r) { return *this /= static_cast<double>(r); }
+
+  template <typename H>
+  friend H AbslHashValue(H h, Duration d) {
+    return H::combine(std::move(h), d.rep_hi_, d.rep_lo_);
+  }
+
+ private:
+  friend constexpr int64_t time_internal::GetRepHi(Duration d);
+  friend constexpr uint32_t time_internal::GetRepLo(Duration d);
+  friend constexpr Duration time_internal::MakeDuration(int64_t hi,
+                                                        uint32_t lo);
+  constexpr Duration(int64_t hi, uint32_t lo) : rep_hi_(hi), rep_lo_(lo) {}
+  int64_t rep_hi_;
+  uint32_t rep_lo_;
+};
+
+// Relational Operators
+constexpr bool operator<(Duration lhs, Duration rhs);
+constexpr bool operator>(Duration lhs, Duration rhs) { return rhs < lhs; }
+constexpr bool operator>=(Duration lhs, Duration rhs) { return !(lhs < rhs); }
+constexpr bool operator<=(Duration lhs, Duration rhs) { return !(rhs < lhs); }
+constexpr bool operator==(Duration lhs, Duration rhs);
+constexpr bool operator!=(Duration lhs, Duration rhs) { return !(lhs == rhs); }
+
+// Additive Operators
+constexpr Duration operator-(Duration d);
+inline Duration operator+(Duration lhs, Duration rhs) { return lhs += rhs; }
+inline Duration operator-(Duration lhs, Duration rhs) { return lhs -= rhs; }
+
+// Multiplicative Operators
+// Integer operands must be representable as int64_t.
+template <typename T>
+Duration operator*(Duration lhs, T rhs) {
+  return lhs *= rhs;
+}
+template <typename T>
+Duration operator*(T lhs, Duration rhs) {
+  return rhs *= lhs;
+}
+template <typename T>
+Duration operator/(Duration lhs, T rhs) {
+  return lhs /= rhs;
+}
+inline int64_t operator/(Duration lhs, Duration rhs) {
+  return time_internal::IDivDuration(true, lhs, rhs,
+                                     &lhs);  // trunc towards zero
+}
+inline Duration operator%(Duration lhs, Duration rhs) { return lhs %= rhs; }
+
+// IDivDuration()
+//
+// Divides a numerator `Duration` by a denominator `Duration`, returning the
+// quotient and remainder. The remainder always has the same sign as the
+// numerator. The returned quotient and remainder respect the identity:
+//
+//   numerator = denominator * quotient + remainder
+//
+// Returned quotients are capped to the range of `int64_t`, with the difference
+// spilling into the remainder to uphold the above identity. This means that the
+// remainder returned could differ from the remainder returned by
+// `Duration::operator%` for huge quotients.
+//
+// See also the notes on `InfiniteDuration()` below regarding the behavior of
+// division involving zero and infinite durations.
+//
+// Example:
+//
+//   constexpr absl::Duration a =
+//       absl::Seconds(std::numeric_limits<int64_t>::max());  // big
+//   constexpr absl::Duration b = absl::Nanoseconds(1);       // small
+//
+//   absl::Duration rem = a % b;
+//   // rem == absl::ZeroDuration()
+//
+//   // Here, q would overflow int64_t, so rem accounts for the difference.
+//   int64_t q = absl::IDivDuration(a, b, &rem);
+//   // q == std::numeric_limits<int64_t>::max(), rem == a - b * q
+inline int64_t IDivDuration(Duration num, Duration den, Duration* rem) {
+  return time_internal::IDivDuration(true, num, den,
+                                     rem);  // trunc towards zero
+}
+
+// FDivDuration()
+//
+// Divides a `Duration` numerator into a fractional number of units of a
+// `Duration` denominator.
+//
+// See also the notes on `InfiniteDuration()` below regarding the behavior of
+// division involving zero and infinite durations.
+//
+// Example:
+//
+//   double d = absl::FDivDuration(absl::Milliseconds(1500), absl::Seconds(1));
+//   // d == 1.5
+double FDivDuration(Duration num, Duration den);
+
+// ZeroDuration()
+//
+// Returns a zero-length duration. This function behaves just like the default
+// constructor, but the name helps make the semantics clear at call sites.
+constexpr Duration ZeroDuration() { return Duration(); }
+
+// AbsDuration()
+//
+// Returns the absolute value of a duration.
+inline Duration AbsDuration(Duration d) {
+  return (d < ZeroDuration()) ? -d : d;
+}
+
+// Trunc()
+//
+// Truncates a duration (toward zero) to a multiple of a non-zero unit.
+//
+// Example:
+//
+//   absl::Duration d = absl::Nanoseconds(123456789);
+//   absl::Duration a = absl::Trunc(d, absl::Microseconds(1));  // 123456us
+Duration Trunc(Duration d, Duration unit);
+
+// Floor()
+//
+// Floors a duration using the passed duration unit to its largest value not
+// greater than the duration.
+//
+// Example:
+//
+//   absl::Duration d = absl::Nanoseconds(123456789);
+//   absl::Duration b = absl::Floor(d, absl::Microseconds(1));  // 123456us
+Duration Floor(Duration d, Duration unit);
+
+// Ceil()
+//
+// Returns the ceiling of a duration using the passed duration unit to its
+// smallest value not less than the duration.
+//
+// Example:
+//
+//   absl::Duration d = absl::Nanoseconds(123456789);
+//   absl::Duration c = absl::Ceil(d, absl::Microseconds(1));   // 123457us
+Duration Ceil(Duration d, Duration unit);
+
+// InfiniteDuration()
+//
+// Returns an infinite `Duration`.  To get a `Duration` representing negative
+// infinity, use `-InfiniteDuration()`.
+//
+// Duration arithmetic overflows to +/- infinity and saturates. In general,
+// arithmetic with `Duration` infinities is similar to IEEE 754 infinities
+// except where IEEE 754 NaN would be involved, in which case +/-
+// `InfiniteDuration()` is used in place of a "nan" Duration.
+//
+// Examples:
+//
+//   constexpr absl::Duration inf = absl::InfiniteDuration();
+//   const absl::Duration d = ... any finite duration ...
+//
+//   inf == inf + inf
+//   inf == inf + d
+//   inf == inf - inf
+//   -inf == d - inf
+//
+//   inf == d * 1e100
+//   inf == inf / 2
+//   0 == d / inf
+//   INT64_MAX == inf / d
+//
+//   d < inf
+//   -inf < d
+//
+//   // Division by zero returns infinity, or INT64_MIN/MAX where appropriate.
+//   inf == d / 0
+//   INT64_MAX == d / absl::ZeroDuration()
+//
+// The examples involving the `/` operator above also apply to `IDivDuration()`
+// and `FDivDuration()`.
+constexpr Duration InfiniteDuration();
+
+// Nanoseconds()
+// Microseconds()
+// Milliseconds()
+// Seconds()
+// Minutes()
+// Hours()
+//
+// Factory functions for constructing `Duration` values from an integral number
+// of the unit indicated by the factory function's name. The number must be
+// representable as int64_t.
+//
+// NOTE: no "Days()" factory function exists because "a day" is ambiguous.
+// Civil days are not always 24 hours long, and a 24-hour duration often does
+// not correspond with a civil day. If a 24-hour duration is needed, use
+// `absl::Hours(24)`. If you actually want a civil day, use absl::CivilDay
+// from civil_time.h.
+//
+// Example:
+//
+//   absl::Duration a = absl::Seconds(60);
+//   absl::Duration b = absl::Minutes(1);  // b == a
+constexpr Duration Nanoseconds(int64_t n);
+constexpr Duration Microseconds(int64_t n);
+constexpr Duration Milliseconds(int64_t n);
+constexpr Duration Seconds(int64_t n);
+constexpr Duration Minutes(int64_t n);
+constexpr Duration Hours(int64_t n);
+
+// Factory overloads for constructing `Duration` values from a floating-point
+// number of the unit indicated by the factory function's name. These functions
+// exist for convenience, but they are not as efficient as the integral
+// factories, which should be preferred.
+//
+// Example:
+//
+//   auto a = absl::Seconds(1.5);        // OK
+//   auto b = absl::Milliseconds(1500);  // BETTER
+template <typename T, time_internal::EnableIfFloat<T> = 0>
+Duration Nanoseconds(T n) {
+  return n * Nanoseconds(1);
+}
+template <typename T, time_internal::EnableIfFloat<T> = 0>
+Duration Microseconds(T n) {
+  return n * Microseconds(1);
+}
+template <typename T, time_internal::EnableIfFloat<T> = 0>
+Duration Milliseconds(T n) {
+  return n * Milliseconds(1);
+}
+template <typename T, time_internal::EnableIfFloat<T> = 0>
+Duration Seconds(T n) {
+  if (n >= 0) {  // Note: `NaN >= 0` is false.
+    if (n >= static_cast<T>((std::numeric_limits<int64_t>::max)())) {
+      return InfiniteDuration();
+    }
+    return time_internal::MakePosDoubleDuration(n);
+  } else {
+    if (std::isnan(n))
+      return std::signbit(n) ? -InfiniteDuration() : InfiniteDuration();
+    if (n <= (std::numeric_limits<int64_t>::min)()) return -InfiniteDuration();
+    return -time_internal::MakePosDoubleDuration(-n);
+  }
+}
+template <typename T, time_internal::EnableIfFloat<T> = 0>
+Duration Minutes(T n) {
+  return n * Minutes(1);
+}
+template <typename T, time_internal::EnableIfFloat<T> = 0>
+Duration Hours(T n) {
+  return n * Hours(1);
+}
+
+// ToInt64Nanoseconds()
+// ToInt64Microseconds()
+// ToInt64Milliseconds()
+// ToInt64Seconds()
+// ToInt64Minutes()
+// ToInt64Hours()
+//
+// Helper functions that convert a Duration to an integral count of the
+// indicated unit. These functions are shorthand for the `IDivDuration()`
+// function above; see its documentation for details about overflow, etc.
+//
+// Example:
+//
+//   absl::Duration d = absl::Milliseconds(1500);
+//   int64_t isec = absl::ToInt64Seconds(d);  // isec == 1
+ABSL_ATTRIBUTE_PURE_FUNCTION int64_t ToInt64Nanoseconds(Duration d);
+ABSL_ATTRIBUTE_PURE_FUNCTION int64_t ToInt64Microseconds(Duration d);
+ABSL_ATTRIBUTE_PURE_FUNCTION int64_t ToInt64Milliseconds(Duration d);
+ABSL_ATTRIBUTE_PURE_FUNCTION int64_t ToInt64Seconds(Duration d);
+ABSL_ATTRIBUTE_PURE_FUNCTION int64_t ToInt64Minutes(Duration d);
+ABSL_ATTRIBUTE_PURE_FUNCTION int64_t ToInt64Hours(Duration d);
+
+// ToDoubleNanoSeconds()
+// ToDoubleMicroseconds()
+// ToDoubleMilliseconds()
+// ToDoubleSeconds()
+// ToDoubleMinutes()
+// ToDoubleHours()
+//
+// Helper functions that convert a Duration to a floating point count of the
+// indicated unit. These functions are shorthand for the `FDivDuration()`
+// function above; see its documentation for details about overflow, etc.
+//
+// Example:
+//
+//   absl::Duration d = absl::Milliseconds(1500);
+//   double dsec = absl::ToDoubleSeconds(d);  // dsec == 1.5
+ABSL_ATTRIBUTE_PURE_FUNCTION double ToDoubleNanoseconds(Duration d);
+ABSL_ATTRIBUTE_PURE_FUNCTION double ToDoubleMicroseconds(Duration d);
+ABSL_ATTRIBUTE_PURE_FUNCTION double ToDoubleMilliseconds(Duration d);
+ABSL_ATTRIBUTE_PURE_FUNCTION double ToDoubleSeconds(Duration d);
+ABSL_ATTRIBUTE_PURE_FUNCTION double ToDoubleMinutes(Duration d);
+ABSL_ATTRIBUTE_PURE_FUNCTION double ToDoubleHours(Duration d);
+
+// FromChrono()
+//
+// Converts any of the pre-defined std::chrono durations to an absl::Duration.
+//
+// Example:
+//
+//   std::chrono::milliseconds ms(123);
+//   absl::Duration d = absl::FromChrono(ms);
+constexpr Duration FromChrono(const std::chrono::nanoseconds& d);
+constexpr Duration FromChrono(const std::chrono::microseconds& d);
+constexpr Duration FromChrono(const std::chrono::milliseconds& d);
+constexpr Duration FromChrono(const std::chrono::seconds& d);
+constexpr Duration FromChrono(const std::chrono::minutes& d);
+constexpr Duration FromChrono(const std::chrono::hours& d);
+
+// ToChronoNanoseconds()
+// ToChronoMicroseconds()
+// ToChronoMilliseconds()
+// ToChronoSeconds()
+// ToChronoMinutes()
+// ToChronoHours()
+//
+// Converts an absl::Duration to any of the pre-defined std::chrono durations.
+// If overflow would occur, the returned value will saturate at the min/max
+// chrono duration value instead.
+//
+// Example:
+//
+//   absl::Duration d = absl::Microseconds(123);
+//   auto x = absl::ToChronoMicroseconds(d);
+//   auto y = absl::ToChronoNanoseconds(d);  // x == y
+//   auto z = absl::ToChronoSeconds(absl::InfiniteDuration());
+//   // z == std::chrono::seconds::max()
+std::chrono::nanoseconds ToChronoNanoseconds(Duration d);
+std::chrono::microseconds ToChronoMicroseconds(Duration d);
+std::chrono::milliseconds ToChronoMilliseconds(Duration d);
+std::chrono::seconds ToChronoSeconds(Duration d);
+std::chrono::minutes ToChronoMinutes(Duration d);
+std::chrono::hours ToChronoHours(Duration d);
+
+// FormatDuration()
+//
+// Returns a string representing the duration in the form "72h3m0.5s".
+// Returns "inf" or "-inf" for +/- `InfiniteDuration()`.
+std::string FormatDuration(Duration d);
+
+// Output stream operator.
+inline std::ostream& operator<<(std::ostream& os, Duration d) {
+  return os << FormatDuration(d);
+}
+
+// ParseDuration()
+//
+// Parses a duration string consisting of a possibly signed sequence of
+// decimal numbers, each with an optional fractional part and a unit
+// suffix.  The valid suffixes are "ns", "us" "ms", "s", "m", and "h".
+// Simple examples include "300ms", "-1.5h", and "2h45m".  Parses "0" as
+// `ZeroDuration()`. Parses "inf" and "-inf" as +/- `InfiniteDuration()`.
+bool ParseDuration(absl::string_view dur_string, Duration* d);
+
+// Support for flag values of type Duration. Duration flags must be specified
+// in a format that is valid input for absl::ParseDuration().
+bool AbslParseFlag(absl::string_view text, Duration* dst, std::string* error);
+std::string AbslUnparseFlag(Duration d);
+ABSL_DEPRECATED("Use AbslParseFlag() instead.")
+bool ParseFlag(const std::string& text, Duration* dst, std::string* error);
+ABSL_DEPRECATED("Use AbslUnparseFlag() instead.")
+std::string UnparseFlag(Duration d);
+
+// Time
+//
+// An `absl::Time` represents a specific instant in time. Arithmetic operators
+// are provided for naturally expressing time calculations. Instances are
+// created using `absl::Now()` and the `absl::From*()` factory functions that
+// accept the gamut of other time representations. Formatting and parsing
+// functions are provided for conversion to and from strings.  `absl::Time`
+// should be passed by value rather than const reference.
+//
+// `absl::Time` assumes there are 60 seconds in a minute, which means the
+// underlying time scales must be "smeared" to eliminate leap seconds.
+// See https://developers.google.com/time/smear.
+//
+// Even though `absl::Time` supports a wide range of timestamps, exercise
+// caution when using values in the distant past. `absl::Time` uses the
+// Proleptic Gregorian calendar, which extends the Gregorian calendar backward
+// to dates before its introduction in 1582.
+// See https://en.wikipedia.org/wiki/Proleptic_Gregorian_calendar
+// for more information. Use the ICU calendar classes to convert a date in
+// some other calendar (http://userguide.icu-project.org/datetime/calendar).
+//
+// Similarly, standardized time zones are a reasonably recent innovation, with
+// the Greenwich prime meridian being established in 1884. The TZ database
+// itself does not profess accurate offsets for timestamps prior to 1970. The
+// breakdown of future timestamps is subject to the whim of regional
+// governments.
+//
+// The `absl::Time` class represents an instant in time as a count of clock
+// ticks of some granularity (resolution) from some starting point (epoch).
+//
+// `absl::Time` uses a resolution that is high enough to avoid loss in
+// precision, and a range that is wide enough to avoid overflow, when
+// converting between tick counts in most Google time scales (i.e., resolution
+// of at least one nanosecond, and range +/-100 billion years).  Conversions
+// between the time scales are performed by truncating (towards negative
+// infinity) to the nearest representable point.
+//
+// Examples:
+//
+//   absl::Time t1 = ...;
+//   absl::Time t2 = t1 + absl::Minutes(2);
+//   absl::Duration d = t2 - t1;  // == absl::Minutes(2)
+//
+class Time {
+ public:
+  // Value semantics.
+
+  // Returns the Unix epoch.  However, those reading your code may not know
+  // or expect the Unix epoch as the default value, so make your code more
+  // readable by explicitly initializing all instances before use.
+  //
+  // Example:
+  //   absl::Time t = absl::UnixEpoch();
+  //   absl::Time t = absl::Now();
+  //   absl::Time t = absl::TimeFromTimeval(tv);
+  //   absl::Time t = absl::InfinitePast();
+  constexpr Time() = default;
+
+  // Copyable.
+  constexpr Time(const Time& t) = default;
+  Time& operator=(const Time& t) = default;
+
+  // Assignment operators.
+  Time& operator+=(Duration d) {
+    rep_ += d;
+    return *this;
+  }
+  Time& operator-=(Duration d) {
+    rep_ -= d;
+    return *this;
+  }
+
+  // Time::Breakdown
+  //
+  // The calendar and wall-clock (aka "civil time") components of an
+  // `absl::Time` in a certain `absl::TimeZone`. This struct is not
+  // intended to represent an instant in time. So, rather than passing
+  // a `Time::Breakdown` to a function, pass an `absl::Time` and an
+  // `absl::TimeZone`.
+  //
+  // Deprecated. Use `absl::TimeZone::CivilInfo`.
+  struct
+      Breakdown {
+    int64_t year;        // year (e.g., 2013)
+    int month;           // month of year [1:12]
+    int day;             // day of month [1:31]
+    int hour;            // hour of day [0:23]
+    int minute;          // minute of hour [0:59]
+    int second;          // second of minute [0:59]
+    Duration subsecond;  // [Seconds(0):Seconds(1)) if finite
+    int weekday;         // 1==Mon, ..., 7=Sun
+    int yearday;         // day of year [1:366]
+
+    // Note: The following fields exist for backward compatibility
+    // with older APIs.  Accessing these fields directly is a sign of
+    // imprudent logic in the calling code.  Modern time-related code
+    // should only access this data indirectly by way of FormatTime().
+    // These fields are undefined for InfiniteFuture() and InfinitePast().
+    int offset;             // seconds east of UTC
+    bool is_dst;            // is offset non-standard?
+    const char* zone_abbr;  // time-zone abbreviation (e.g., "PST")
+  };
+
+  // Time::In()
+  //
+  // Returns the breakdown of this instant in the given TimeZone.
+  //
+  // Deprecated. Use `absl::TimeZone::At(Time)`.
+  Breakdown In(TimeZone tz) const;
+
+  template <typename H>
+  friend H AbslHashValue(H h, Time t) {
+    return H::combine(std::move(h), t.rep_);
+  }
+
+ private:
+  friend constexpr Time time_internal::FromUnixDuration(Duration d);
+  friend constexpr Duration time_internal::ToUnixDuration(Time t);
+  friend constexpr bool operator<(Time lhs, Time rhs);
+  friend constexpr bool operator==(Time lhs, Time rhs);
+  friend Duration operator-(Time lhs, Time rhs);
+  friend constexpr Time UniversalEpoch();
+  friend constexpr Time InfiniteFuture();
+  friend constexpr Time InfinitePast();
+  constexpr explicit Time(Duration rep) : rep_(rep) {}
+  Duration rep_;
+};
+
+// Relational Operators
+constexpr bool operator<(Time lhs, Time rhs) { return lhs.rep_ < rhs.rep_; }
+constexpr bool operator>(Time lhs, Time rhs) { return rhs < lhs; }
+constexpr bool operator>=(Time lhs, Time rhs) { return !(lhs < rhs); }
+constexpr bool operator<=(Time lhs, Time rhs) { return !(rhs < lhs); }
+constexpr bool operator==(Time lhs, Time rhs) { return lhs.rep_ == rhs.rep_; }
+constexpr bool operator!=(Time lhs, Time rhs) { return !(lhs == rhs); }
+
+// Additive Operators
+inline Time operator+(Time lhs, Duration rhs) { return lhs += rhs; }
+inline Time operator+(Duration lhs, Time rhs) { return rhs += lhs; }
+inline Time operator-(Time lhs, Duration rhs) { return lhs -= rhs; }
+inline Duration operator-(Time lhs, Time rhs) { return lhs.rep_ - rhs.rep_; }
+
+// UnixEpoch()
+//
+// Returns the `absl::Time` representing "1970-01-01 00:00:00.0 +0000".
+constexpr Time UnixEpoch() { return Time(); }
+
+// UniversalEpoch()
+//
+// Returns the `absl::Time` representing "0001-01-01 00:00:00.0 +0000", the
+// epoch of the ICU Universal Time Scale.
+constexpr Time UniversalEpoch() {
+  // 719162 is the number of days from 0001-01-01 to 1970-01-01,
+  // assuming the Gregorian calendar.
+  return Time(time_internal::MakeDuration(-24 * 719162 * int64_t{3600}, 0U));
+}
+
+// InfiniteFuture()
+//
+// Returns an `absl::Time` that is infinitely far in the future.
+constexpr Time InfiniteFuture() {
+  return Time(
+      time_internal::MakeDuration((std::numeric_limits<int64_t>::max)(), ~0U));
+}
+
+// InfinitePast()
+//
+// Returns an `absl::Time` that is infinitely far in the past.
+constexpr Time InfinitePast() {
+  return Time(
+      time_internal::MakeDuration((std::numeric_limits<int64_t>::min)(), ~0U));
+}
+
+// FromUnixNanos()
+// FromUnixMicros()
+// FromUnixMillis()
+// FromUnixSeconds()
+// FromTimeT()
+// FromUDate()
+// FromUniversal()
+//
+// Creates an `absl::Time` from a variety of other representations.
+constexpr Time FromUnixNanos(int64_t ns);
+constexpr Time FromUnixMicros(int64_t us);
+constexpr Time FromUnixMillis(int64_t ms);
+constexpr Time FromUnixSeconds(int64_t s);
+constexpr Time FromTimeT(time_t t);
+Time FromUDate(double udate);
+Time FromUniversal(int64_t universal);
+
+// ToUnixNanos()
+// ToUnixMicros()
+// ToUnixMillis()
+// ToUnixSeconds()
+// ToTimeT()
+// ToUDate()
+// ToUniversal()
+//
+// Converts an `absl::Time` to a variety of other representations.  Note that
+// these operations round down toward negative infinity where necessary to
+// adjust to the resolution of the result type.  Beware of possible time_t
+// over/underflow in ToTime{T,val,spec}() on 32-bit platforms.
+int64_t ToUnixNanos(Time t);
+int64_t ToUnixMicros(Time t);
+int64_t ToUnixMillis(Time t);
+int64_t ToUnixSeconds(Time t);
+time_t ToTimeT(Time t);
+double ToUDate(Time t);
+int64_t ToUniversal(Time t);
+
+// DurationFromTimespec()
+// DurationFromTimeval()
+// ToTimespec()
+// ToTimeval()
+// TimeFromTimespec()
+// TimeFromTimeval()
+// ToTimespec()
+// ToTimeval()
+//
+// Some APIs use a timespec or a timeval as a Duration (e.g., nanosleep(2)
+// and select(2)), while others use them as a Time (e.g. clock_gettime(2)
+// and gettimeofday(2)), so conversion functions are provided for both cases.
+// The "to timespec/val" direction is easily handled via overloading, but
+// for "from timespec/val" the desired type is part of the function name.
+Duration DurationFromTimespec(timespec ts);
+Duration DurationFromTimeval(timeval tv);
+timespec ToTimespec(Duration d);
+timeval ToTimeval(Duration d);
+Time TimeFromTimespec(timespec ts);
+Time TimeFromTimeval(timeval tv);
+timespec ToTimespec(Time t);
+timeval ToTimeval(Time t);
+
+// FromChrono()
+//
+// Converts a std::chrono::system_clock::time_point to an absl::Time.
+//
+// Example:
+//
+//   auto tp = std::chrono::system_clock::from_time_t(123);
+//   absl::Time t = absl::FromChrono(tp);
+//   // t == absl::FromTimeT(123)
+Time FromChrono(const std::chrono::system_clock::time_point& tp);
+
+// ToChronoTime()
+//
+// Converts an absl::Time to a std::chrono::system_clock::time_point. If
+// overflow would occur, the returned value will saturate at the min/max time
+// point value instead.
+//
+// Example:
+//
+//   absl::Time t = absl::FromTimeT(123);
+//   auto tp = absl::ToChronoTime(t);
+//   // tp == std::chrono::system_clock::from_time_t(123);
+std::chrono::system_clock::time_point ToChronoTime(Time);
+
+// Support for flag values of type Time. Time flags must be specified in a
+// format that matches absl::RFC3339_full. For example:
+//
+//   --start_time=2016-01-02T03:04:05.678+08:00
+//
+// Note: A UTC offset (or 'Z' indicating a zero-offset from UTC) is required.
+//
+// Additionally, if you'd like to specify a time as a count of
+// seconds/milliseconds/etc from the Unix epoch, use an absl::Duration flag
+// and add that duration to absl::UnixEpoch() to get an absl::Time.
+bool AbslParseFlag(absl::string_view text, Time* t, std::string* error);
+std::string AbslUnparseFlag(Time t);
+ABSL_DEPRECATED("Use AbslParseFlag() instead.")
+bool ParseFlag(const std::string& text, Time* t, std::string* error);
+ABSL_DEPRECATED("Use AbslUnparseFlag() instead.")
+std::string UnparseFlag(Time t);
+
+// TimeZone
+//
+// The `absl::TimeZone` is an opaque, small, value-type class representing a
+// geo-political region within which particular rules are used for converting
+// between absolute and civil times (see https://git.io/v59Ly). `absl::TimeZone`
+// values are named using the TZ identifiers from the IANA Time Zone Database,
+// such as "America/Los_Angeles" or "Australia/Sydney". `absl::TimeZone` values
+// are created from factory functions such as `absl::LoadTimeZone()`. Note:
+// strings like "PST" and "EDT" are not valid TZ identifiers. Prefer to pass by
+// value rather than const reference.
+//
+// For more on the fundamental concepts of time zones, absolute times, and civil
+// times, see https://github.com/google/cctz#fundamental-concepts
+//
+// Examples:
+//
+//   absl::TimeZone utc = absl::UTCTimeZone();
+//   absl::TimeZone pst = absl::FixedTimeZone(-8 * 60 * 60);
+//   absl::TimeZone loc = absl::LocalTimeZone();
+//   absl::TimeZone lax;
+//   if (!absl::LoadTimeZone("America/Los_Angeles", &lax)) {
+//     // handle error case
+//   }
+//
+// See also:
+// - https://github.com/google/cctz
+// - https://www.iana.org/time-zones
+// - https://en.wikipedia.org/wiki/Zoneinfo
+class TimeZone {
+ public:
+  explicit TimeZone(time_internal::cctz::time_zone tz) : cz_(tz) {}
+  TimeZone() = default;  // UTC, but prefer UTCTimeZone() to be explicit.
+
+  // Copyable.
+  TimeZone(const TimeZone&) = default;
+  TimeZone& operator=(const TimeZone&) = default;
+
+  explicit operator time_internal::cctz::time_zone() const { return cz_; }
+
+  std::string name() const { return cz_.name(); }
+
+  // TimeZone::CivilInfo
+  //
+  // Information about the civil time corresponding to an absolute time.
+  // This struct is not intended to represent an instant in time. So, rather
+  // than passing a `TimeZone::CivilInfo` to a function, pass an `absl::Time`
+  // and an `absl::TimeZone`.
+  struct CivilInfo {
+    CivilSecond cs;
+    Duration subsecond;
+
+    // Note: The following fields exist for backward compatibility
+    // with older APIs.  Accessing these fields directly is a sign of
+    // imprudent logic in the calling code.  Modern time-related code
+    // should only access this data indirectly by way of FormatTime().
+    // These fields are undefined for InfiniteFuture() and InfinitePast().
+    int offset;             // seconds east of UTC
+    bool is_dst;            // is offset non-standard?
+    const char* zone_abbr;  // time-zone abbreviation (e.g., "PST")
+  };
+
+  // TimeZone::At(Time)
+  //
+  // Returns the civil time for this TimeZone at a certain `absl::Time`.
+  // If the input time is infinite, the output civil second will be set to
+  // CivilSecond::max() or min(), and the subsecond will be infinite.
+  //
+  // Example:
+  //
+  //   const auto epoch = lax.At(absl::UnixEpoch());
+  //   // epoch.cs == 1969-12-31 16:00:00
+  //   // epoch.subsecond == absl::ZeroDuration()
+  //   // epoch.offset == -28800
+  //   // epoch.is_dst == false
+  //   // epoch.abbr == "PST"
+  CivilInfo At(Time t) const;
+
+  // TimeZone::TimeInfo
+  //
+  // Information about the absolute times corresponding to a civil time.
+  // (Subseconds must be handled separately.)
+  //
+  // It is possible for a caller to pass a civil-time value that does
+  // not represent an actual or unique instant in time (due to a shift
+  // in UTC offset in the TimeZone, which results in a discontinuity in
+  // the civil-time components). For example, a daylight-saving-time
+  // transition skips or repeats civil times---in the United States,
+  // March 13, 2011 02:15 never occurred, while November 6, 2011 01:15
+  // occurred twice---so requests for such times are not well-defined.
+  // To account for these possibilities, `absl::TimeZone::TimeInfo` is
+  // richer than just a single `absl::Time`.
+  struct TimeInfo {
+    enum CivilKind {
+      UNIQUE,    // the civil time was singular (pre == trans == post)
+      SKIPPED,   // the civil time did not exist (pre >= trans > post)
+      REPEATED,  // the civil time was ambiguous (pre < trans <= post)
+    } kind;
+    Time pre;    // time calculated using the pre-transition offset
+    Time trans;  // when the civil-time discontinuity occurred
+    Time post;   // time calculated using the post-transition offset
+  };
+
+  // TimeZone::At(CivilSecond)
+  //
+  // Returns an `absl::TimeInfo` containing the absolute time(s) for this
+  // TimeZone at an `absl::CivilSecond`. When the civil time is skipped or
+  // repeated, returns times calculated using the pre-transition and post-
+  // transition UTC offsets, plus the transition time itself.
+  //
+  // Examples:
+  //
+  //   // A unique civil time
+  //   const auto jan01 = lax.At(absl::CivilSecond(2011, 1, 1, 0, 0, 0));
+  //   // jan01.kind == TimeZone::TimeInfo::UNIQUE
+  //   // jan01.pre    is 2011-01-01 00:00:00 -0800
+  //   // jan01.trans  is 2011-01-01 00:00:00 -0800
+  //   // jan01.post   is 2011-01-01 00:00:00 -0800
+  //
+  //   // A Spring DST transition, when there is a gap in civil time
+  //   const auto mar13 = lax.At(absl::CivilSecond(2011, 3, 13, 2, 15, 0));
+  //   // mar13.kind == TimeZone::TimeInfo::SKIPPED
+  //   // mar13.pre   is 2011-03-13 03:15:00 -0700
+  //   // mar13.trans is 2011-03-13 03:00:00 -0700
+  //   // mar13.post  is 2011-03-13 01:15:00 -0800
+  //
+  //   // A Fall DST transition, when civil times are repeated
+  //   const auto nov06 = lax.At(absl::CivilSecond(2011, 11, 6, 1, 15, 0));
+  //   // nov06.kind == TimeZone::TimeInfo::REPEATED
+  //   // nov06.pre   is 2011-11-06 01:15:00 -0700
+  //   // nov06.trans is 2011-11-06 01:00:00 -0800
+  //   // nov06.post  is 2011-11-06 01:15:00 -0800
+  TimeInfo At(CivilSecond ct) const;
+
+  // TimeZone::NextTransition()
+  // TimeZone::PrevTransition()
+  //
+  // Finds the time of the next/previous offset change in this time zone.
+  //
+  // By definition, `NextTransition(t, &trans)` returns false when `t` is
+  // `InfiniteFuture()`, and `PrevTransition(t, &trans)` returns false
+  // when `t` is `InfinitePast()`. If the zone has no transitions, the
+  // result will also be false no matter what the argument.
+  //
+  // Otherwise, when `t` is `InfinitePast()`, `NextTransition(t, &trans)`
+  // returns true and sets `trans` to the first recorded transition. Chains
+  // of calls to `NextTransition()/PrevTransition()` will eventually return
+  // false, but it is unspecified exactly when `NextTransition(t, &trans)`
+  // jumps to false, or what time is set by `PrevTransition(t, &trans)` for
+  // a very distant `t`.
+  //
+  // Note: Enumeration of time-zone transitions is for informational purposes
+  // only. Modern time-related code should not care about when offset changes
+  // occur.
+  //
+  // Example:
+  //   absl::TimeZone nyc;
+  //   if (!absl::LoadTimeZone("America/New_York", &nyc)) { ... }
+  //   const auto now = absl::Now();
+  //   auto t = absl::InfinitePast();
+  //   absl::TimeZone::CivilTransition trans;
+  //   while (t <= now && nyc.NextTransition(t, &trans)) {
+  //     // transition: trans.from -> trans.to
+  //     t = nyc.At(trans.to).trans;
+  //   }
+  struct CivilTransition {
+    CivilSecond from;  // the civil time we jump from
+    CivilSecond to;    // the civil time we jump to
+  };
+  bool NextTransition(Time t, CivilTransition* trans) const;
+  bool PrevTransition(Time t, CivilTransition* trans) const;
+
+  template <typename H>
+  friend H AbslHashValue(H h, TimeZone tz) {
+    return H::combine(std::move(h), tz.cz_);
+  }
+
+ private:
+  friend bool operator==(TimeZone a, TimeZone b) { return a.cz_ == b.cz_; }
+  friend bool operator!=(TimeZone a, TimeZone b) { return a.cz_ != b.cz_; }
+  friend std::ostream& operator<<(std::ostream& os, TimeZone tz) {
+    return os << tz.name();
+  }
+
+  time_internal::cctz::time_zone cz_;
+};
+
+// LoadTimeZone()
+//
+// Loads the named zone. May perform I/O on the initial load of the named
+// zone. If the name is invalid, or some other kind of error occurs, returns
+// `false` and `*tz` is set to the UTC time zone.
+inline bool LoadTimeZone(absl::string_view name, TimeZone* tz) {
+  if (name == "localtime") {
+    *tz = TimeZone(time_internal::cctz::local_time_zone());
+    return true;
+  }
+  time_internal::cctz::time_zone cz;
+  const bool b = time_internal::cctz::load_time_zone(std::string(name), &cz);
+  *tz = TimeZone(cz);
+  return b;
+}
+
+// FixedTimeZone()
+//
+// Returns a TimeZone that is a fixed offset (seconds east) from UTC.
+// Note: If the absolute value of the offset is greater than 24 hours
+// you'll get UTC (i.e., no offset) instead.
+inline TimeZone FixedTimeZone(int seconds) {
+  return TimeZone(
+      time_internal::cctz::fixed_time_zone(std::chrono::seconds(seconds)));
+}
+
+// UTCTimeZone()
+//
+// Convenience method returning the UTC time zone.
+inline TimeZone UTCTimeZone() {
+  return TimeZone(time_internal::cctz::utc_time_zone());
+}
+
+// LocalTimeZone()
+//
+// Convenience method returning the local time zone, or UTC if there is
+// no configured local zone.  Warning: Be wary of using LocalTimeZone(),
+// and particularly so in a server process, as the zone configured for the
+// local machine should be irrelevant.  Prefer an explicit zone name.
+inline TimeZone LocalTimeZone() {
+  return TimeZone(time_internal::cctz::local_time_zone());
+}
+
+// ToCivilSecond()
+// ToCivilMinute()
+// ToCivilHour()
+// ToCivilDay()
+// ToCivilMonth()
+// ToCivilYear()
+//
+// Helpers for TimeZone::At(Time) to return particularly aligned civil times.
+//
+// Example:
+//
+//   absl::Time t = ...;
+//   absl::TimeZone tz = ...;
+//   const auto cd = absl::ToCivilDay(t, tz);
+inline CivilSecond ToCivilSecond(Time t, TimeZone tz) {
+  return tz.At(t).cs;  // already a CivilSecond
+}
+inline CivilMinute ToCivilMinute(Time t, TimeZone tz) {
+  return CivilMinute(tz.At(t).cs);
+}
+inline CivilHour ToCivilHour(Time t, TimeZone tz) {
+  return CivilHour(tz.At(t).cs);
+}
+inline CivilDay ToCivilDay(Time t, TimeZone tz) {
+  return CivilDay(tz.At(t).cs);
+}
+inline CivilMonth ToCivilMonth(Time t, TimeZone tz) {
+  return CivilMonth(tz.At(t).cs);
+}
+inline CivilYear ToCivilYear(Time t, TimeZone tz) {
+  return CivilYear(tz.At(t).cs);
+}
+
+// FromCivil()
+//
+// Helper for TimeZone::At(CivilSecond) that provides "order-preserving
+// semantics." If the civil time maps to a unique time, that time is
+// returned. If the civil time is repeated in the given time zone, the
+// time using the pre-transition offset is returned. Otherwise, the
+// civil time is skipped in the given time zone, and the transition time
+// is returned. This means that for any two civil times, ct1 and ct2,
+// (ct1 < ct2) => (FromCivil(ct1) <= FromCivil(ct2)), the equal case
+// being when two non-existent civil times map to the same transition time.
+//
+// Note: Accepts civil times of any alignment.
+inline Time FromCivil(CivilSecond ct, TimeZone tz) {
+  const auto ti = tz.At(ct);
+  if (ti.kind == TimeZone::TimeInfo::SKIPPED) return ti.trans;
+  return ti.pre;
+}
+
+// TimeConversion
+//
+// An `absl::TimeConversion` represents the conversion of year, month, day,
+// hour, minute, and second values (i.e., a civil time), in a particular
+// `absl::TimeZone`, to a time instant (an absolute time), as returned by
+// `absl::ConvertDateTime()`. Legacy version of `absl::TimeZone::TimeInfo`.
+//
+// Deprecated. Use `absl::TimeZone::TimeInfo`.
+struct
+    TimeConversion {
+  Time pre;    // time calculated using the pre-transition offset
+  Time trans;  // when the civil-time discontinuity occurred
+  Time post;   // time calculated using the post-transition offset
+
+  enum Kind {
+    UNIQUE,    // the civil time was singular (pre == trans == post)
+    SKIPPED,   // the civil time did not exist
+    REPEATED,  // the civil time was ambiguous
+  };
+  Kind kind;
+
+  bool normalized;  // input values were outside their valid ranges
+};
+
+// ConvertDateTime()
+//
+// Legacy version of `absl::TimeZone::At(absl::CivilSecond)` that takes
+// the civil time as six, separate values (YMDHMS).
+//
+// The input month, day, hour, minute, and second values can be outside
+// of their valid ranges, in which case they will be "normalized" during
+// the conversion.
+//
+// Example:
+//
+//   // "October 32" normalizes to "November 1".
+//   absl::TimeConversion tc =
+//       absl::ConvertDateTime(2013, 10, 32, 8, 30, 0, lax);
+//   // tc.kind == TimeConversion::UNIQUE && tc.normalized == true
+//   // absl::ToCivilDay(tc.pre, tz).month() == 11
+//   // absl::ToCivilDay(tc.pre, tz).day() == 1
+//
+// Deprecated. Use `absl::TimeZone::At(CivilSecond)`.
+TimeConversion ConvertDateTime(int64_t year, int mon, int day, int hour,
+                               int min, int sec, TimeZone tz);
+
+// FromDateTime()
+//
+// A convenience wrapper for `absl::ConvertDateTime()` that simply returns
+// the "pre" `absl::Time`.  That is, the unique result, or the instant that
+// is correct using the pre-transition offset (as if the transition never
+// happened).
+//
+// Example:
+//
+//   absl::Time t = absl::FromDateTime(2017, 9, 26, 9, 30, 0, lax);
+//   // t = 2017-09-26 09:30:00 -0700
+//
+// Deprecated. Use `absl::FromCivil(CivilSecond, TimeZone)`. Note that the
+// behavior of `FromCivil()` differs from `FromDateTime()` for skipped civil
+// times. If you care about that see `absl::TimeZone::At(absl::CivilSecond)`.
+inline Time FromDateTime(int64_t year, int mon, int day, int hour,
+                         int min, int sec, TimeZone tz) {
+  return ConvertDateTime(year, mon, day, hour, min, sec, tz).pre;
+}
+
+// FromTM()
+//
+// Converts the `tm_year`, `tm_mon`, `tm_mday`, `tm_hour`, `tm_min`, and
+// `tm_sec` fields to an `absl::Time` using the given time zone. See ctime(3)
+// for a description of the expected values of the tm fields. If the civil time
+// is unique (see `absl::TimeZone::At(absl::CivilSecond)` above), the matching
+// time instant is returned.  Otherwise, the `tm_isdst` field is consulted to
+// choose between the possible results.  For a repeated civil time, `tm_isdst !=
+// 0` returns the matching DST instant, while `tm_isdst == 0` returns the
+// matching non-DST instant.  For a skipped civil time there is no matching
+// instant, so `tm_isdst != 0` returns the DST instant, and `tm_isdst == 0`
+// returns the non-DST instant, that would have matched if the transition never
+// happened.
+Time FromTM(const struct tm& tm, TimeZone tz);
+
+// ToTM()
+//
+// Converts the given `absl::Time` to a struct tm using the given time zone.
+// See ctime(3) for a description of the values of the tm fields.
+struct tm ToTM(Time t, TimeZone tz);
+
+// RFC3339_full
+// RFC3339_sec
+//
+// FormatTime()/ParseTime() format specifiers for RFC3339 date/time strings,
+// with trailing zeros trimmed or with fractional seconds omitted altogether.
+//
+// Note that RFC3339_sec[] matches an ISO 8601 extended format for date and
+// time with UTC offset.  Also note the use of "%Y": RFC3339 mandates that
+// years have exactly four digits, but we allow them to take their natural
+// width.
+ABSL_DLL extern const char RFC3339_full[];  // %Y-%m-%d%ET%H:%M:%E*S%Ez
+ABSL_DLL extern const char RFC3339_sec[];   // %Y-%m-%d%ET%H:%M:%S%Ez
+
+// RFC1123_full
+// RFC1123_no_wday
+//
+// FormatTime()/ParseTime() format specifiers for RFC1123 date/time strings.
+ABSL_DLL extern const char RFC1123_full[];     // %a, %d %b %E4Y %H:%M:%S %z
+ABSL_DLL extern const char RFC1123_no_wday[];  // %d %b %E4Y %H:%M:%S %z
+
+// FormatTime()
+//
+// Formats the given `absl::Time` in the `absl::TimeZone` according to the
+// provided format string. Uses strftime()-like formatting options, with
+// the following extensions:
+//
+//   - %Ez  - RFC3339-compatible numeric UTC offset (+hh:mm or -hh:mm)
+//   - %E*z - Full-resolution numeric UTC offset (+hh:mm:ss or -hh:mm:ss)
+//   - %E#S - Seconds with # digits of fractional precision
+//   - %E*S - Seconds with full fractional precision (a literal '*')
+//   - %E#f - Fractional seconds with # digits of precision
+//   - %E*f - Fractional seconds with full precision (a literal '*')
+//   - %E4Y - Four-character years (-999 ... -001, 0000, 0001 ... 9999)
+//   - %ET  - The RFC3339 "date-time" separator "T"
+//
+// Note that %E0S behaves like %S, and %E0f produces no characters.  In
+// contrast %E*f always produces at least one digit, which may be '0'.
+//
+// Note that %Y produces as many characters as it takes to fully render the
+// year.  A year outside of [-999:9999] when formatted with %E4Y will produce
+// more than four characters, just like %Y.
+//
+// We recommend that format strings include the UTC offset (%z, %Ez, or %E*z)
+// so that the result uniquely identifies a time instant.
+//
+// Example:
+//
+//   absl::CivilSecond cs(2013, 1, 2, 3, 4, 5);
+//   absl::Time t = absl::FromCivil(cs, lax);
+//   std::string f = absl::FormatTime("%H:%M:%S", t, lax);  // "03:04:05"
+//   f = absl::FormatTime("%H:%M:%E3S", t, lax);  // "03:04:05.000"
+//
+// Note: If the given `absl::Time` is `absl::InfiniteFuture()`, the returned
+// string will be exactly "infinite-future". If the given `absl::Time` is
+// `absl::InfinitePast()`, the returned string will be exactly "infinite-past".
+// In both cases the given format string and `absl::TimeZone` are ignored.
+//
+std::string FormatTime(absl::string_view format, Time t, TimeZone tz);
+
+// Convenience functions that format the given time using the RFC3339_full
+// format.  The first overload uses the provided TimeZone, while the second
+// uses LocalTimeZone().
+std::string FormatTime(Time t, TimeZone tz);
+std::string FormatTime(Time t);
+
+// Output stream operator.
+inline std::ostream& operator<<(std::ostream& os, Time t) {
+  return os << FormatTime(t);
+}
+
+// ParseTime()
+//
+// Parses an input string according to the provided format string and
+// returns the corresponding `absl::Time`. Uses strftime()-like formatting
+// options, with the same extensions as FormatTime(), but with the
+// exceptions that %E#S is interpreted as %E*S, and %E#f as %E*f.  %Ez
+// and %E*z also accept the same inputs, which (along with %z) includes
+// 'z' and 'Z' as synonyms for +00:00.  %ET accepts either 'T' or 't'.
+//
+// %Y consumes as many numeric characters as it can, so the matching data
+// should always be terminated with a non-numeric.  %E4Y always consumes
+// exactly four characters, including any sign.
+//
+// Unspecified fields are taken from the default date and time of ...
+//
+//   "1970-01-01 00:00:00.0 +0000"
+//
+// For example, parsing a string of "15:45" (%H:%M) will return an absl::Time
+// that represents "1970-01-01 15:45:00.0 +0000".
+//
+// Note that since ParseTime() returns time instants, it makes the most sense
+// to parse fully-specified date/time strings that include a UTC offset (%z,
+// %Ez, or %E*z).
+//
+// Note also that `absl::ParseTime()` only heeds the fields year, month, day,
+// hour, minute, (fractional) second, and UTC offset.  Other fields, like
+// weekday (%a or %A), while parsed for syntactic validity, are ignored
+// in the conversion.
+//
+// Date and time fields that are out-of-range will be treated as errors
+// rather than normalizing them like `absl::CivilSecond` does.  For example,
+// it is an error to parse the date "Oct 32, 2013" because 32 is out of range.
+//
+// A leap second of ":60" is normalized to ":00" of the following minute
+// with fractional seconds discarded.  The following table shows how the
+// given seconds and subseconds will be parsed:
+//
+//   "59.x" -> 59.x  // exact
+//   "60.x" -> 00.0  // normalized
+//   "00.x" -> 00.x  // exact
+//
+// Errors are indicated by returning false and assigning an error message
+// to the "err" out param if it is non-null.
+//
+// Note: If the input string is exactly "infinite-future", the returned
+// `absl::Time` will be `absl::InfiniteFuture()` and `true` will be returned.
+// If the input string is "infinite-past", the returned `absl::Time` will be
+// `absl::InfinitePast()` and `true` will be returned.
+//
+bool ParseTime(absl::string_view format, absl::string_view input, Time* time,
+               std::string* err);
+
+// Like ParseTime() above, but if the format string does not contain a UTC
+// offset specification (%z/%Ez/%E*z) then the input is interpreted in the
+// given TimeZone.  This means that the input, by itself, does not identify a
+// unique instant.  Being time-zone dependent, it also admits the possibility
+// of ambiguity or non-existence, in which case the "pre" time (as defined
+// by TimeZone::TimeInfo) is returned.  For these reasons we recommend that
+// all date/time strings include a UTC offset so they're context independent.
+bool ParseTime(absl::string_view format, absl::string_view input, TimeZone tz,
+               Time* time, std::string* err);
+
+// ============================================================================
+// Implementation Details Follow
+// ============================================================================
+
+namespace time_internal {
+
+// Creates a Duration with a given representation.
+// REQUIRES: hi,lo is a valid representation of a Duration as specified
+// in time/duration.cc.
+constexpr Duration MakeDuration(int64_t hi, uint32_t lo = 0) {
+  return Duration(hi, lo);
+}
+
+constexpr Duration MakeDuration(int64_t hi, int64_t lo) {
+  return MakeDuration(hi, static_cast<uint32_t>(lo));
+}
+
+// Make a Duration value from a floating-point number, as long as that number
+// is in the range [ 0 .. numeric_limits<int64_t>::max ), that is, as long as
+// it's positive and can be converted to int64_t without risk of UB.
+inline Duration MakePosDoubleDuration(double n) {
+  const int64_t int_secs = static_cast<int64_t>(n);
+  const uint32_t ticks = static_cast<uint32_t>(
+      (n - static_cast<double>(int_secs)) * kTicksPerSecond + 0.5);
+  return ticks < kTicksPerSecond
+             ? MakeDuration(int_secs, ticks)
+             : MakeDuration(int_secs + 1, ticks - kTicksPerSecond);
+}
+
+// Creates a normalized Duration from an almost-normalized (sec,ticks)
+// pair. sec may be positive or negative.  ticks must be in the range
+// -kTicksPerSecond < *ticks < kTicksPerSecond.  If ticks is negative it
+// will be normalized to a positive value in the resulting Duration.
+constexpr Duration MakeNormalizedDuration(int64_t sec, int64_t ticks) {
+  return (ticks < 0) ? MakeDuration(sec - 1, ticks + kTicksPerSecond)
+                     : MakeDuration(sec, ticks);
+}
+
+// Provide access to the Duration representation.
+constexpr int64_t GetRepHi(Duration d) { return d.rep_hi_; }
+constexpr uint32_t GetRepLo(Duration d) { return d.rep_lo_; }
+
+// Returns true iff d is positive or negative infinity.
+constexpr bool IsInfiniteDuration(Duration d) { return GetRepLo(d) == ~0U; }
+
+// Returns an infinite Duration with the opposite sign.
+// REQUIRES: IsInfiniteDuration(d)
+constexpr Duration OppositeInfinity(Duration d) {
+  return GetRepHi(d) < 0
+             ? MakeDuration((std::numeric_limits<int64_t>::max)(), ~0U)
+             : MakeDuration((std::numeric_limits<int64_t>::min)(), ~0U);
+}
+
+// Returns (-n)-1 (equivalently -(n+1)) without avoidable overflow.
+constexpr int64_t NegateAndSubtractOne(int64_t n) {
+  // Note: Good compilers will optimize this expression to ~n when using
+  // a two's-complement representation (which is required for int64_t).
+  return (n < 0) ? -(n + 1) : (-n) - 1;
+}
+
+// Map between a Time and a Duration since the Unix epoch.  Note that these
+// functions depend on the above mentioned choice of the Unix epoch for the
+// Time representation (and both need to be Time friends).  Without this
+// knowledge, we would need to add-in/subtract-out UnixEpoch() respectively.
+constexpr Time FromUnixDuration(Duration d) { return Time(d); }
+constexpr Duration ToUnixDuration(Time t) { return t.rep_; }
+
+template <std::intmax_t N>
+constexpr Duration FromInt64(int64_t v, std::ratio<1, N>) {
+  static_assert(0 < N && N <= 1000 * 1000 * 1000, "Unsupported ratio");
+  // Subsecond ratios cannot overflow.
+  return MakeNormalizedDuration(
+      v / N, v % N * kTicksPerNanosecond * 1000 * 1000 * 1000 / N);
+}
+constexpr Duration FromInt64(int64_t v, std::ratio<60>) {
+  return (v <= (std::numeric_limits<int64_t>::max)() / 60 &&
+          v >= (std::numeric_limits<int64_t>::min)() / 60)
+             ? MakeDuration(v * 60)
+             : v > 0 ? InfiniteDuration() : -InfiniteDuration();
+}
+constexpr Duration FromInt64(int64_t v, std::ratio<3600>) {
+  return (v <= (std::numeric_limits<int64_t>::max)() / 3600 &&
+          v >= (std::numeric_limits<int64_t>::min)() / 3600)
+             ? MakeDuration(v * 3600)
+             : v > 0 ? InfiniteDuration() : -InfiniteDuration();
+}
+
+// IsValidRep64<T>(0) is true if the expression `int64_t{std::declval<T>()}` is
+// valid. That is, if a T can be assigned to an int64_t without narrowing.
+template <typename T>
+constexpr auto IsValidRep64(int) -> decltype(int64_t{std::declval<T>()} == 0) {
+  return true;
+}
+template <typename T>
+constexpr auto IsValidRep64(char) -> bool {
+  return false;
+}
+
+// Converts a std::chrono::duration to an absl::Duration.
+template <typename Rep, typename Period>
+constexpr Duration FromChrono(const std::chrono::duration<Rep, Period>& d) {
+  static_assert(IsValidRep64<Rep>(0), "duration::rep is invalid");
+  return FromInt64(int64_t{d.count()}, Period{});
+}
+
+template <typename Ratio>
+int64_t ToInt64(Duration d, Ratio) {
+  // Note: This may be used on MSVC, which may have a system_clock period of
+  // std::ratio<1, 10 * 1000 * 1000>
+  return ToInt64Seconds(d * Ratio::den / Ratio::num);
+}
+// Fastpath implementations for the 6 common duration units.
+inline int64_t ToInt64(Duration d, std::nano) {
+  return ToInt64Nanoseconds(d);
+}
+inline int64_t ToInt64(Duration d, std::micro) {
+  return ToInt64Microseconds(d);
+}
+inline int64_t ToInt64(Duration d, std::milli) {
+  return ToInt64Milliseconds(d);
+}
+inline int64_t ToInt64(Duration d, std::ratio<1>) {
+  return ToInt64Seconds(d);
+}
+inline int64_t ToInt64(Duration d, std::ratio<60>) {
+  return ToInt64Minutes(d);
+}
+inline int64_t ToInt64(Duration d, std::ratio<3600>) {
+  return ToInt64Hours(d);
+}
+
+// Converts an absl::Duration to a chrono duration of type T.
+template <typename T>
+T ToChronoDuration(Duration d) {
+  using Rep = typename T::rep;
+  using Period = typename T::period;
+  static_assert(IsValidRep64<Rep>(0), "duration::rep is invalid");
+  if (time_internal::IsInfiniteDuration(d))
+    return d < ZeroDuration() ? (T::min)() : (T::max)();
+  const auto v = ToInt64(d, Period{});
+  if (v > (std::numeric_limits<Rep>::max)()) return (T::max)();
+  if (v < (std::numeric_limits<Rep>::min)()) return (T::min)();
+  return T{v};
+}
+
+}  // namespace time_internal
+
+constexpr Duration Nanoseconds(int64_t n) {
+  return time_internal::FromInt64(n, std::nano{});
+}
+constexpr Duration Microseconds(int64_t n) {
+  return time_internal::FromInt64(n, std::micro{});
+}
+constexpr Duration Milliseconds(int64_t n) {
+  return time_internal::FromInt64(n, std::milli{});
+}
+constexpr Duration Seconds(int64_t n) {
+  return time_internal::FromInt64(n, std::ratio<1>{});
+}
+constexpr Duration Minutes(int64_t n) {
+  return time_internal::FromInt64(n, std::ratio<60>{});
+}
+constexpr Duration Hours(int64_t n) {
+  return time_internal::FromInt64(n, std::ratio<3600>{});
+}
+
+constexpr bool operator<(Duration lhs, Duration rhs) {
+  return time_internal::GetRepHi(lhs) != time_internal::GetRepHi(rhs)
+             ? time_internal::GetRepHi(lhs) < time_internal::GetRepHi(rhs)
+         : time_internal::GetRepHi(lhs) == (std::numeric_limits<int64_t>::min)()
+             ? time_internal::GetRepLo(lhs) + 1 <
+                   time_internal::GetRepLo(rhs) + 1
+             : time_internal::GetRepLo(lhs) < time_internal::GetRepLo(rhs);
+}
+
+constexpr bool operator==(Duration lhs, Duration rhs) {
+  return time_internal::GetRepHi(lhs) == time_internal::GetRepHi(rhs) &&
+         time_internal::GetRepLo(lhs) == time_internal::GetRepLo(rhs);
+}
+
+constexpr Duration operator-(Duration d) {
+  // This is a little interesting because of the special cases.
+  //
+  // If rep_lo_ is zero, we have it easy; it's safe to negate rep_hi_, we're
+  // dealing with an integral number of seconds, and the only special case is
+  // the maximum negative finite duration, which can't be negated.
+  //
+  // Infinities stay infinite, and just change direction.
+  //
+  // Finally we're in the case where rep_lo_ is non-zero, and we can borrow
+  // a second's worth of ticks and avoid overflow (as negating int64_t-min + 1
+  // is safe).
+  return time_internal::GetRepLo(d) == 0
+             ? time_internal::GetRepHi(d) ==
+                       (std::numeric_limits<int64_t>::min)()
+                   ? InfiniteDuration()
+                   : time_internal::MakeDuration(-time_internal::GetRepHi(d))
+             : time_internal::IsInfiniteDuration(d)
+                   ? time_internal::OppositeInfinity(d)
+                   : time_internal::MakeDuration(
+                         time_internal::NegateAndSubtractOne(
+                             time_internal::GetRepHi(d)),
+                         time_internal::kTicksPerSecond -
+                             time_internal::GetRepLo(d));
+}
+
+constexpr Duration InfiniteDuration() {
+  return time_internal::MakeDuration((std::numeric_limits<int64_t>::max)(),
+                                     ~0U);
+}
+
+constexpr Duration FromChrono(const std::chrono::nanoseconds& d) {
+  return time_internal::FromChrono(d);
+}
+constexpr Duration FromChrono(const std::chrono::microseconds& d) {
+  return time_internal::FromChrono(d);
+}
+constexpr Duration FromChrono(const std::chrono::milliseconds& d) {
+  return time_internal::FromChrono(d);
+}
+constexpr Duration FromChrono(const std::chrono::seconds& d) {
+  return time_internal::FromChrono(d);
+}
+constexpr Duration FromChrono(const std::chrono::minutes& d) {
+  return time_internal::FromChrono(d);
+}
+constexpr Duration FromChrono(const std::chrono::hours& d) {
+  return time_internal::FromChrono(d);
+}
+
+constexpr Time FromUnixNanos(int64_t ns) {
+  return time_internal::FromUnixDuration(Nanoseconds(ns));
+}
+
+constexpr Time FromUnixMicros(int64_t us) {
+  return time_internal::FromUnixDuration(Microseconds(us));
+}
+
+constexpr Time FromUnixMillis(int64_t ms) {
+  return time_internal::FromUnixDuration(Milliseconds(ms));
+}
+
+constexpr Time FromUnixSeconds(int64_t s) {
+  return time_internal::FromUnixDuration(Seconds(s));
+}
+
+constexpr Time FromTimeT(time_t t) {
+  return time_internal::FromUnixDuration(Seconds(t));
+}
+
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#endif  // ABSL_TIME_TIME_H_
diff --git a/src/absl/types/any.h b/src/absl/types/any.h
new file mode 100644 (file)
index 0000000..fc5a074
--- /dev/null
@@ -0,0 +1,528 @@
+//
+// Copyright 2017 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// -----------------------------------------------------------------------------
+// any.h
+// -----------------------------------------------------------------------------
+//
+// This header file define the `absl::any` type for holding a type-safe value
+// of any type. The 'absl::any` type is useful for providing a way to hold
+// something that is, as yet, unspecified. Such unspecified types
+// traditionally are passed between API boundaries until they are later cast to
+// their "destination" types. To cast to such a destination type, use
+// `absl::any_cast()`. Note that when casting an `absl::any`, you must cast it
+// to an explicit type; implicit conversions will throw.
+//
+// Example:
+//
+//   auto a = absl::any(65);
+//   absl::any_cast<int>(a);         // 65
+//   absl::any_cast<char>(a);        // throws absl::bad_any_cast
+//   absl::any_cast<std::string>(a); // throws absl::bad_any_cast
+//
+// `absl::any` is a C++11 compatible version of the C++17 `std::any` abstraction
+// and is designed to be a drop-in replacement for code compliant with C++17.
+//
+// Traditionally, the behavior of casting to a temporary unspecified type has
+// been accomplished with the `void *` paradigm, where the pointer was to some
+// other unspecified type. `absl::any` provides an "owning" version of `void *`
+// that avoids issues of pointer management.
+//
+// Note: just as in the case of `void *`, use of `absl::any` (and its C++17
+// version `std::any`) is a code smell indicating that your API might not be
+// constructed correctly. We have seen that most uses of `any` are unwarranted,
+// and `absl::any`, like `std::any`, is difficult to use properly. Before using
+// this abstraction, make sure that you should not instead be rewriting your
+// code to be more specific.
+//
+// Abseil has also released an `absl::variant` type (a C++11 compatible version
+// of the C++17 `std::variant`), which is generally preferred for use over
+// `absl::any`.
+#ifndef ABSL_TYPES_ANY_H_
+#define ABSL_TYPES_ANY_H_
+
+#include "absl/base/config.h"
+#include "absl/utility/utility.h"
+
+#ifdef ABSL_USES_STD_ANY
+
+#include <any>  // IWYU pragma: export
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+using std::any;
+using std::any_cast;
+using std::bad_any_cast;
+using std::make_any;
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#else  // ABSL_USES_STD_ANY
+
+#include <algorithm>
+#include <cstddef>
+#include <initializer_list>
+#include <memory>
+#include <stdexcept>
+#include <type_traits>
+#include <typeinfo>
+#include <utility>
+
+#include "absl/base/internal/fast_type_id.h"
+#include "absl/base/macros.h"
+#include "absl/meta/type_traits.h"
+#include "absl/types/bad_any_cast.h"
+
+// NOTE: This macro is an implementation detail that is undefined at the bottom
+// of the file. It is not intended for expansion directly from user code.
+#ifdef ABSL_ANY_DETAIL_HAS_RTTI
+#error ABSL_ANY_DETAIL_HAS_RTTI cannot be directly set
+#elif !defined(__GNUC__) || defined(__GXX_RTTI)
+#define ABSL_ANY_DETAIL_HAS_RTTI 1
+#endif  // !defined(__GNUC__) || defined(__GXX_RTTI)
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+
+class any;
+
+// swap()
+//
+// Swaps two `absl::any` values. Equivalent to `x.swap(y) where `x` and `y` are
+// `absl::any` types.
+void swap(any& x, any& y) noexcept;
+
+// make_any()
+//
+// Constructs an `absl::any` of type `T` with the given arguments.
+template <typename T, typename... Args>
+any make_any(Args&&... args);
+
+// Overload of `absl::make_any()` for constructing an `absl::any` type from an
+// initializer list.
+template <typename T, typename U, typename... Args>
+any make_any(std::initializer_list<U> il, Args&&... args);
+
+// any_cast()
+//
+// Statically casts the value of a `const absl::any` type to the given type.
+// This function will throw `absl::bad_any_cast` if the stored value type of the
+// `absl::any` does not match the cast.
+//
+// `any_cast()` can also be used to get a reference to the internal storage iff
+// a reference type is passed as its `ValueType`:
+//
+// Example:
+//
+//   absl::any my_any = std::vector<int>();
+//   absl::any_cast<std::vector<int>&>(my_any).push_back(42);
+template <typename ValueType>
+ValueType any_cast(const any& operand);
+
+// Overload of `any_cast()` to statically cast the value of a non-const
+// `absl::any` type to the given type. This function will throw
+// `absl::bad_any_cast` if the stored value type of the `absl::any` does not
+// match the cast.
+template <typename ValueType>
+ValueType any_cast(any& operand);  // NOLINT(runtime/references)
+
+// Overload of `any_cast()` to statically cast the rvalue of an `absl::any`
+// type. This function will throw `absl::bad_any_cast` if the stored value type
+// of the `absl::any` does not match the cast.
+template <typename ValueType>
+ValueType any_cast(any&& operand);
+
+// Overload of `any_cast()` to statically cast the value of a const pointer
+// `absl::any` type to the given pointer type, or `nullptr` if the stored value
+// type of the `absl::any` does not match the cast.
+template <typename ValueType>
+const ValueType* any_cast(const any* operand) noexcept;
+
+// Overload of `any_cast()` to statically cast the value of a pointer
+// `absl::any` type to the given pointer type, or `nullptr` if the stored value
+// type of the `absl::any` does not match the cast.
+template <typename ValueType>
+ValueType* any_cast(any* operand) noexcept;
+
+// -----------------------------------------------------------------------------
+// absl::any
+// -----------------------------------------------------------------------------
+//
+// An `absl::any` object provides the facility to either store an instance of a
+// type, known as the "contained object", or no value. An `absl::any` is used to
+// store values of types that are unknown at compile time. The `absl::any`
+// object, when containing a value, must contain a value type; storing a
+// reference type is neither desired nor supported.
+//
+// An `absl::any` can only store a type that is copy-constructible; move-only
+// types are not allowed within an `any` object.
+//
+// Example:
+//
+//   auto a = absl::any(65);                 // Literal, copyable
+//   auto b = absl::any(std::vector<int>()); // Default-initialized, copyable
+//   std::unique_ptr<Foo> my_foo;
+//   auto c = absl::any(std::move(my_foo));  // Error, not copy-constructible
+//
+// Note that `absl::any` makes use of decayed types (`absl::decay_t` in this
+// context) to remove const-volatile qualifiers (known as "cv qualifiers"),
+// decay functions to function pointers, etc. We essentially "decay" a given
+// type into its essential type.
+//
+// `absl::any` makes use of decayed types when determining the basic type `T` of
+// the value to store in the any's contained object. In the documentation below,
+// we explicitly denote this by using the phrase "a decayed type of `T`".
+//
+// Example:
+//
+//   const int a = 4;
+//   absl::any foo(a);  // Decay ensures we store an "int", not a "const int&".
+//
+//   void my_function() {}
+//   absl::any bar(my_function);  // Decay ensures we store a function pointer.
+//
+// `absl::any` is a C++11 compatible version of the C++17 `std::any` abstraction
+// and is designed to be a drop-in replacement for code compliant with C++17.
+class any {
+ private:
+  template <typename T>
+  struct IsInPlaceType;
+
+ public:
+  // Constructors
+
+  // Constructs an empty `absl::any` object (`any::has_value()` will return
+  // `false`).
+  constexpr any() noexcept;
+
+  // Copy constructs an `absl::any` object with a "contained object" of the
+  // passed type of `other` (or an empty `absl::any` if `other.has_value()` is
+  // `false`.
+  any(const any& other)
+      : obj_(other.has_value() ? other.obj_->Clone()
+                               : std::unique_ptr<ObjInterface>()) {}
+
+  // Move constructs an `absl::any` object with a "contained object" of the
+  // passed type of `other` (or an empty `absl::any` if `other.has_value()` is
+  // `false`).
+  any(any&& other) noexcept = default;
+
+  // Constructs an `absl::any` object with a "contained object" of the decayed
+  // type of `T`, which is initialized via `std::forward<T>(value)`.
+  //
+  // This constructor will not participate in overload resolution if the
+  // decayed type of `T` is not copy-constructible.
+  template <
+      typename T, typename VT = absl::decay_t<T>,
+      absl::enable_if_t<!absl::disjunction<
+          std::is_same<any, VT>, IsInPlaceType<VT>,
+          absl::negation<std::is_copy_constructible<VT> > >::value>* = nullptr>
+  any(T&& value) : obj_(new Obj<VT>(in_place, std::forward<T>(value))) {}
+
+  // Constructs an `absl::any` object with a "contained object" of the decayed
+  // type of `T`, which is initialized via `std::forward<T>(value)`.
+  template <typename T, typename... Args, typename VT = absl::decay_t<T>,
+            absl::enable_if_t<absl::conjunction<
+                std::is_copy_constructible<VT>,
+                std::is_constructible<VT, Args...>>::value>* = nullptr>
+  explicit any(in_place_type_t<T> /*tag*/, Args&&... args)
+      : obj_(new Obj<VT>(in_place, std::forward<Args>(args)...)) {}
+
+  // Constructs an `absl::any` object with a "contained object" of the passed
+  // type `VT` as a decayed type of `T`. `VT` is initialized as if
+  // direct-non-list-initializing an object of type `VT` with the arguments
+  // `initializer_list, std::forward<Args>(args)...`.
+  template <
+      typename T, typename U, typename... Args, typename VT = absl::decay_t<T>,
+      absl::enable_if_t<
+          absl::conjunction<std::is_copy_constructible<VT>,
+                            std::is_constructible<VT, std::initializer_list<U>&,
+                                                  Args...>>::value>* = nullptr>
+  explicit any(in_place_type_t<T> /*tag*/, std::initializer_list<U> ilist,
+               Args&&... args)
+      : obj_(new Obj<VT>(in_place, ilist, std::forward<Args>(args)...)) {}
+
+  // Assignment operators
+
+  // Copy assigns an `absl::any` object with a "contained object" of the
+  // passed type.
+  any& operator=(const any& rhs) {
+    any(rhs).swap(*this);
+    return *this;
+  }
+
+  // Move assigns an `absl::any` object with a "contained object" of the
+  // passed type. `rhs` is left in a valid but otherwise unspecified state.
+  any& operator=(any&& rhs) noexcept {
+    any(std::move(rhs)).swap(*this);
+    return *this;
+  }
+
+  // Assigns an `absl::any` object with a "contained object" of the passed type.
+  template <typename T, typename VT = absl::decay_t<T>,
+            absl::enable_if_t<absl::conjunction<
+                absl::negation<std::is_same<VT, any>>,
+                std::is_copy_constructible<VT>>::value>* = nullptr>
+  any& operator=(T&& rhs) {
+    any tmp(in_place_type_t<VT>(), std::forward<T>(rhs));
+    tmp.swap(*this);
+    return *this;
+  }
+
+  // Modifiers
+
+  // any::emplace()
+  //
+  // Emplaces a value within an `absl::any` object by calling `any::reset()`,
+  // initializing the contained value as if direct-non-list-initializing an
+  // object of type `VT` with the arguments `std::forward<Args>(args)...`, and
+  // returning a reference to the new contained value.
+  //
+  // Note: If an exception is thrown during the call to `VT`'s constructor,
+  // `*this` does not contain a value, and any previously contained value has
+  // been destroyed.
+  template <
+      typename T, typename... Args, typename VT = absl::decay_t<T>,
+      absl::enable_if_t<std::is_copy_constructible<VT>::value &&
+                        std::is_constructible<VT, Args...>::value>* = nullptr>
+  VT& emplace(Args&&... args) {
+    reset();  // NOTE: reset() is required here even in the world of exceptions.
+    Obj<VT>* const object_ptr =
+        new Obj<VT>(in_place, std::forward<Args>(args)...);
+    obj_ = std::unique_ptr<ObjInterface>(object_ptr);
+    return object_ptr->value;
+  }
+
+  // Overload of `any::emplace()` to emplace a value within an `absl::any`
+  // object by calling `any::reset()`, initializing the contained value as if
+  // direct-non-list-initializing an object of type `VT` with the arguments
+  // `initializer_list, std::forward<Args>(args)...`, and returning a reference
+  // to the new contained value.
+  //
+  // Note: If an exception is thrown during the call to `VT`'s constructor,
+  // `*this` does not contain a value, and any previously contained value has
+  // been destroyed. The function shall not participate in overload resolution
+  // unless `is_copy_constructible_v<VT>` is `true` and
+  // `is_constructible_v<VT, initializer_list<U>&, Args...>` is `true`.
+  template <
+      typename T, typename U, typename... Args, typename VT = absl::decay_t<T>,
+      absl::enable_if_t<std::is_copy_constructible<VT>::value &&
+                        std::is_constructible<VT, std::initializer_list<U>&,
+                                              Args...>::value>* = nullptr>
+  VT& emplace(std::initializer_list<U> ilist, Args&&... args) {
+    reset();  // NOTE: reset() is required here even in the world of exceptions.
+    Obj<VT>* const object_ptr =
+        new Obj<VT>(in_place, ilist, std::forward<Args>(args)...);
+    obj_ = std::unique_ptr<ObjInterface>(object_ptr);
+    return object_ptr->value;
+  }
+
+  // any::reset()
+  //
+  // Resets the state of the `absl::any` object, destroying the contained object
+  // if present.
+  void reset() noexcept { obj_ = nullptr; }
+
+  // any::swap()
+  //
+  // Swaps the passed value and the value of this `absl::any` object.
+  void swap(any& other) noexcept { obj_.swap(other.obj_); }
+
+  // Observers
+
+  // any::has_value()
+  //
+  // Returns `true` if the `any` object has a contained value, otherwise
+  // returns `false`.
+  bool has_value() const noexcept { return obj_ != nullptr; }
+
+#if ABSL_ANY_DETAIL_HAS_RTTI
+  // Returns: typeid(T) if *this has a contained object of type T, otherwise
+  // typeid(void).
+  const std::type_info& type() const noexcept {
+    if (has_value()) {
+      return obj_->Type();
+    }
+
+    return typeid(void);
+  }
+#endif  // ABSL_ANY_DETAIL_HAS_RTTI
+
+ private:
+  // Tagged type-erased abstraction for holding a cloneable object.
+  class ObjInterface {
+   public:
+    virtual ~ObjInterface() = default;
+    virtual std::unique_ptr<ObjInterface> Clone() const = 0;
+    virtual const void* ObjTypeId() const noexcept = 0;
+#if ABSL_ANY_DETAIL_HAS_RTTI
+    virtual const std::type_info& Type() const noexcept = 0;
+#endif  // ABSL_ANY_DETAIL_HAS_RTTI
+  };
+
+  // Hold a value of some queryable type, with an ability to Clone it.
+  template <typename T>
+  class Obj : public ObjInterface {
+   public:
+    template <typename... Args>
+    explicit Obj(in_place_t /*tag*/, Args&&... args)
+        : value(std::forward<Args>(args)...) {}
+
+    std::unique_ptr<ObjInterface> Clone() const final {
+      return std::unique_ptr<ObjInterface>(new Obj(in_place, value));
+    }
+
+    const void* ObjTypeId() const noexcept final { return IdForType<T>(); }
+
+#if ABSL_ANY_DETAIL_HAS_RTTI
+    const std::type_info& Type() const noexcept final { return typeid(T); }
+#endif  // ABSL_ANY_DETAIL_HAS_RTTI
+
+    T value;
+  };
+
+  std::unique_ptr<ObjInterface> CloneObj() const {
+    if (!obj_) return nullptr;
+    return obj_->Clone();
+  }
+
+  template <typename T>
+  constexpr static const void* IdForType() {
+    // Note: This type dance is to make the behavior consistent with typeid.
+    using NormalizedType =
+        typename std::remove_cv<typename std::remove_reference<T>::type>::type;
+
+    return base_internal::FastTypeId<NormalizedType>();
+  }
+
+  const void* GetObjTypeId() const {
+    return obj_ ? obj_->ObjTypeId() : base_internal::FastTypeId<void>();
+  }
+
+  // `absl::any` nonmember functions //
+
+  // Description at the declaration site (top of file).
+  template <typename ValueType>
+  friend ValueType any_cast(const any& operand);
+
+  // Description at the declaration site (top of file).
+  template <typename ValueType>
+  friend ValueType any_cast(any& operand);  // NOLINT(runtime/references)
+
+  // Description at the declaration site (top of file).
+  template <typename T>
+  friend const T* any_cast(const any* operand) noexcept;
+
+  // Description at the declaration site (top of file).
+  template <typename T>
+  friend T* any_cast(any* operand) noexcept;
+
+  std::unique_ptr<ObjInterface> obj_;
+};
+
+// -----------------------------------------------------------------------------
+// Implementation Details
+// -----------------------------------------------------------------------------
+
+constexpr any::any() noexcept = default;
+
+template <typename T>
+struct any::IsInPlaceType : std::false_type {};
+
+template <typename T>
+struct any::IsInPlaceType<in_place_type_t<T>> : std::true_type {};
+
+inline void swap(any& x, any& y) noexcept { x.swap(y); }
+
+// Description at the declaration site (top of file).
+template <typename T, typename... Args>
+any make_any(Args&&... args) {
+  return any(in_place_type_t<T>(), std::forward<Args>(args)...);
+}
+
+// Description at the declaration site (top of file).
+template <typename T, typename U, typename... Args>
+any make_any(std::initializer_list<U> il, Args&&... args) {
+  return any(in_place_type_t<T>(), il, std::forward<Args>(args)...);
+}
+
+// Description at the declaration site (top of file).
+template <typename ValueType>
+ValueType any_cast(const any& operand) {
+  using U = typename std::remove_cv<
+      typename std::remove_reference<ValueType>::type>::type;
+  static_assert(std::is_constructible<ValueType, const U&>::value,
+                "Invalid ValueType");
+  auto* const result = (any_cast<U>)(&operand);
+  if (result == nullptr) {
+    any_internal::ThrowBadAnyCast();
+  }
+  return static_cast<ValueType>(*result);
+}
+
+// Description at the declaration site (top of file).
+template <typename ValueType>
+ValueType any_cast(any& operand) {  // NOLINT(runtime/references)
+  using U = typename std::remove_cv<
+      typename std::remove_reference<ValueType>::type>::type;
+  static_assert(std::is_constructible<ValueType, U&>::value,
+                "Invalid ValueType");
+  auto* result = (any_cast<U>)(&operand);
+  if (result == nullptr) {
+    any_internal::ThrowBadAnyCast();
+  }
+  return static_cast<ValueType>(*result);
+}
+
+// Description at the declaration site (top of file).
+template <typename ValueType>
+ValueType any_cast(any&& operand) {
+  using U = typename std::remove_cv<
+      typename std::remove_reference<ValueType>::type>::type;
+  static_assert(std::is_constructible<ValueType, U>::value,
+                "Invalid ValueType");
+  return static_cast<ValueType>(std::move((any_cast<U&>)(operand)));
+}
+
+// Description at the declaration site (top of file).
+template <typename T>
+const T* any_cast(const any* operand) noexcept {
+  using U =
+      typename std::remove_cv<typename std::remove_reference<T>::type>::type;
+  return operand && operand->GetObjTypeId() == any::IdForType<U>()
+             ? std::addressof(
+                   static_cast<const any::Obj<U>*>(operand->obj_.get())->value)
+             : nullptr;
+}
+
+// Description at the declaration site (top of file).
+template <typename T>
+T* any_cast(any* operand) noexcept {
+  using U =
+      typename std::remove_cv<typename std::remove_reference<T>::type>::type;
+  return operand && operand->GetObjTypeId() == any::IdForType<U>()
+             ? std::addressof(
+                   static_cast<any::Obj<U>*>(operand->obj_.get())->value)
+             : nullptr;
+}
+
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#undef ABSL_ANY_DETAIL_HAS_RTTI
+
+#endif  // ABSL_USES_STD_ANY
+
+#endif  // ABSL_TYPES_ANY_H_
diff --git a/src/absl/types/bad_any_cast.cc b/src/absl/types/bad_any_cast.cc
new file mode 100644 (file)
index 0000000..b0592cc
--- /dev/null
@@ -0,0 +1,46 @@
+// Copyright 2017 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "absl/types/bad_any_cast.h"
+
+#ifndef ABSL_USES_STD_ANY
+
+#include <cstdlib>
+
+#include "absl/base/config.h"
+#include "absl/base/internal/raw_logging.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+
+bad_any_cast::~bad_any_cast() = default;
+
+const char* bad_any_cast::what() const noexcept { return "Bad any cast"; }
+
+namespace any_internal {
+
+void ThrowBadAnyCast() {
+#ifdef ABSL_HAVE_EXCEPTIONS
+  throw bad_any_cast();
+#else
+  ABSL_RAW_LOG(FATAL, "Bad any cast");
+  std::abort();
+#endif
+}
+
+}  // namespace any_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#endif  // ABSL_USES_STD_ANY
diff --git a/src/absl/types/bad_any_cast.h b/src/absl/types/bad_any_cast.h
new file mode 100644 (file)
index 0000000..114cef8
--- /dev/null
@@ -0,0 +1,75 @@
+// Copyright 2018 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// -----------------------------------------------------------------------------
+// bad_any_cast.h
+// -----------------------------------------------------------------------------
+//
+// This header file defines the `absl::bad_any_cast` type.
+
+#ifndef ABSL_TYPES_BAD_ANY_CAST_H_
+#define ABSL_TYPES_BAD_ANY_CAST_H_
+
+#include <typeinfo>
+
+#include "absl/base/config.h"
+
+#ifdef ABSL_USES_STD_ANY
+
+#include <any>
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+using std::bad_any_cast;
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#else  // ABSL_USES_STD_ANY
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+
+// -----------------------------------------------------------------------------
+// bad_any_cast
+// -----------------------------------------------------------------------------
+//
+// An `absl::bad_any_cast` type is an exception type that is thrown when
+// failing to successfully cast the return value of an `absl::any` object.
+//
+// Example:
+//
+//   auto a = absl::any(65);
+//   absl::any_cast<int>(a);         // 65
+//   try {
+//     absl::any_cast<char>(a);
+//   } catch(const absl::bad_any_cast& e) {
+//     std::cout << "Bad any cast: " << e.what() << '\n';
+//   }
+class bad_any_cast : public std::bad_cast {
+ public:
+  ~bad_any_cast() override;
+  const char* what() const noexcept override;
+};
+
+namespace any_internal {
+
+[[noreturn]] void ThrowBadAnyCast();
+
+}  // namespace any_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#endif  // ABSL_USES_STD_ANY
+
+#endif  // ABSL_TYPES_BAD_ANY_CAST_H_
diff --git a/src/absl/types/bad_optional_access.cc b/src/absl/types/bad_optional_access.cc
new file mode 100644 (file)
index 0000000..26aca70
--- /dev/null
@@ -0,0 +1,48 @@
+// Copyright 2017 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "absl/types/bad_optional_access.h"
+
+#ifndef ABSL_USES_STD_OPTIONAL
+
+#include <cstdlib>
+
+#include "absl/base/config.h"
+#include "absl/base/internal/raw_logging.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+
+bad_optional_access::~bad_optional_access() = default;
+
+const char* bad_optional_access::what() const noexcept {
+  return "optional has no value";
+}
+
+namespace optional_internal {
+
+void throw_bad_optional_access() {
+#ifdef ABSL_HAVE_EXCEPTIONS
+  throw bad_optional_access();
+#else
+  ABSL_RAW_LOG(FATAL, "Bad optional access");
+  abort();
+#endif
+}
+
+}  // namespace optional_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#endif  // ABSL_USES_STD_OPTIONAL
diff --git a/src/absl/types/bad_optional_access.h b/src/absl/types/bad_optional_access.h
new file mode 100644 (file)
index 0000000..a500286
--- /dev/null
@@ -0,0 +1,78 @@
+// Copyright 2018 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// -----------------------------------------------------------------------------
+// bad_optional_access.h
+// -----------------------------------------------------------------------------
+//
+// This header file defines the `absl::bad_optional_access` type.
+
+#ifndef ABSL_TYPES_BAD_OPTIONAL_ACCESS_H_
+#define ABSL_TYPES_BAD_OPTIONAL_ACCESS_H_
+
+#include <stdexcept>
+
+#include "absl/base/config.h"
+
+#ifdef ABSL_USES_STD_OPTIONAL
+
+#include <optional>
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+using std::bad_optional_access;
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#else  // ABSL_USES_STD_OPTIONAL
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+
+// -----------------------------------------------------------------------------
+// bad_optional_access
+// -----------------------------------------------------------------------------
+//
+// An `absl::bad_optional_access` type is an exception type that is thrown when
+// attempting to access an `absl::optional` object that does not contain a
+// value.
+//
+// Example:
+//
+//   absl::optional<int> o;
+//
+//   try {
+//     int n = o.value();
+//   } catch(const absl::bad_optional_access& e) {
+//     std::cout << "Bad optional access: " << e.what() << '\n';
+//   }
+class bad_optional_access : public std::exception {
+ public:
+  bad_optional_access() = default;
+  ~bad_optional_access() override;
+  const char* what() const noexcept override;
+};
+
+namespace optional_internal {
+
+// throw delegator
+[[noreturn]] void throw_bad_optional_access();
+
+}  // namespace optional_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#endif  // ABSL_USES_STD_OPTIONAL
+
+#endif  // ABSL_TYPES_BAD_OPTIONAL_ACCESS_H_
diff --git a/src/absl/types/bad_variant_access.cc b/src/absl/types/bad_variant_access.cc
new file mode 100644 (file)
index 0000000..3dc88cc
--- /dev/null
@@ -0,0 +1,64 @@
+// Copyright 2017 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "absl/types/bad_variant_access.h"
+
+#ifndef ABSL_USES_STD_VARIANT
+
+#include <cstdlib>
+#include <stdexcept>
+
+#include "absl/base/config.h"
+#include "absl/base/internal/raw_logging.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+
+//////////////////////////
+// [variant.bad.access] //
+//////////////////////////
+
+bad_variant_access::~bad_variant_access() = default;
+
+const char* bad_variant_access::what() const noexcept {
+  return "Bad variant access";
+}
+
+namespace variant_internal {
+
+void ThrowBadVariantAccess() {
+#ifdef ABSL_HAVE_EXCEPTIONS
+  throw bad_variant_access();
+#else
+  ABSL_RAW_LOG(FATAL, "Bad variant access");
+  abort();  // TODO(calabrese) Remove once RAW_LOG FATAL is noreturn.
+#endif
+}
+
+void Rethrow() {
+#ifdef ABSL_HAVE_EXCEPTIONS
+  throw;
+#else
+  ABSL_RAW_LOG(FATAL,
+               "Internal error in absl::variant implementation. Attempted to "
+               "rethrow an exception when building with exceptions disabled.");
+  abort();  // TODO(calabrese) Remove once RAW_LOG FATAL is noreturn.
+#endif
+}
+
+}  // namespace variant_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#endif  // ABSL_USES_STD_VARIANT
diff --git a/src/absl/types/bad_variant_access.h b/src/absl/types/bad_variant_access.h
new file mode 100644 (file)
index 0000000..095969f
--- /dev/null
@@ -0,0 +1,82 @@
+// Copyright 2018 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// -----------------------------------------------------------------------------
+// bad_variant_access.h
+// -----------------------------------------------------------------------------
+//
+// This header file defines the `absl::bad_variant_access` type.
+
+#ifndef ABSL_TYPES_BAD_VARIANT_ACCESS_H_
+#define ABSL_TYPES_BAD_VARIANT_ACCESS_H_
+
+#include <stdexcept>
+
+#include "absl/base/config.h"
+
+#ifdef ABSL_USES_STD_VARIANT
+
+#include <variant>
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+using std::bad_variant_access;
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#else  // ABSL_USES_STD_VARIANT
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+
+// -----------------------------------------------------------------------------
+// bad_variant_access
+// -----------------------------------------------------------------------------
+//
+// An `absl::bad_variant_access` type is an exception type that is thrown in
+// the following cases:
+//
+//   * Calling `absl::get(absl::variant) with an index or type that does not
+//     match the currently selected alternative type
+//   * Calling `absl::visit on an `absl::variant` that is in the
+//     `variant::valueless_by_exception` state.
+//
+// Example:
+//
+//   absl::variant<int, std::string> v;
+//   v = 1;
+//   try {
+//     absl::get<std::string>(v);
+//   } catch(const absl::bad_variant_access& e) {
+//     std::cout << "Bad variant access: " << e.what() << '\n';
+//   }
+class bad_variant_access : public std::exception {
+ public:
+  bad_variant_access() noexcept = default;
+  ~bad_variant_access() override;
+  const char* what() const noexcept override;
+};
+
+namespace variant_internal {
+
+[[noreturn]] void ThrowBadVariantAccess();
+[[noreturn]] void Rethrow();
+
+}  // namespace variant_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#endif  // ABSL_USES_STD_VARIANT
+
+#endif  // ABSL_TYPES_BAD_VARIANT_ACCESS_H_
diff --git a/src/absl/types/compare.h b/src/absl/types/compare.h
new file mode 100644 (file)
index 0000000..19b076e
--- /dev/null
@@ -0,0 +1,600 @@
+// Copyright 2018 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// -----------------------------------------------------------------------------
+// compare.h
+// -----------------------------------------------------------------------------
+//
+// This header file defines the `absl::weak_equality`, `absl::strong_equality`,
+// `absl::partial_ordering`, `absl::weak_ordering`, and `absl::strong_ordering`
+// types for storing the results of three way comparisons.
+//
+// Example:
+//   absl::weak_ordering compare(const std::string& a, const std::string& b);
+//
+// These are C++11 compatible versions of the C++20 corresponding types
+// (`std::weak_equality`, etc.) and are designed to be drop-in replacements
+// for code compliant with C++20.
+
+#ifndef ABSL_TYPES_COMPARE_H_
+#define ABSL_TYPES_COMPARE_H_
+
+#include <cstddef>
+#include <cstdint>
+#include <cstdlib>
+#include <type_traits>
+
+#include "absl/base/attributes.h"
+#include "absl/meta/type_traits.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace compare_internal {
+
+using value_type = int8_t;
+
+template <typename T>
+struct Fail {
+  static_assert(sizeof(T) < 0, "Only literal `0` is allowed.");
+};
+
+// We need the NullPtrT template to avoid triggering the modernize-use-nullptr
+// ClangTidy warning in user code.
+template <typename NullPtrT = std::nullptr_t>
+struct OnlyLiteralZero {
+  constexpr OnlyLiteralZero(NullPtrT) noexcept {}  // NOLINT
+
+  // Fails compilation when `nullptr` or integral type arguments other than
+  // `int` are passed. This constructor doesn't accept `int` because literal `0`
+  // has type `int`. Literal `0` arguments will be implicitly converted to
+  // `std::nullptr_t` and accepted by the above constructor, while other `int`
+  // arguments will fail to be converted and cause compilation failure.
+  template <
+      typename T,
+      typename = typename std::enable_if<
+          std::is_same<T, std::nullptr_t>::value ||
+          (std::is_integral<T>::value && !std::is_same<T, int>::value)>::type,
+      typename = typename Fail<T>::type>
+  OnlyLiteralZero(T);  // NOLINT
+};
+
+enum class eq : value_type {
+  equal = 0,
+  equivalent = equal,
+  nonequal = 1,
+  nonequivalent = nonequal,
+};
+
+enum class ord : value_type { less = -1, greater = 1 };
+
+enum class ncmp : value_type { unordered = -127 };
+
+// Define macros to allow for creation or emulation of C++17 inline variables
+// based on whether the feature is supported. Note: we can't use
+// ABSL_INTERNAL_INLINE_CONSTEXPR here because the variables here are of
+// incomplete types so they need to be defined after the types are complete.
+#ifdef __cpp_inline_variables
+
+// A no-op expansion that can be followed by a semicolon at class level.
+#define ABSL_COMPARE_INLINE_BASECLASS_DECL(name) static_assert(true, "")
+
+#define ABSL_COMPARE_INLINE_SUBCLASS_DECL(type, name) \
+  static const type name
+
+#define ABSL_COMPARE_INLINE_INIT(type, name, init) \
+  inline constexpr type type::name(init)
+
+#else  // __cpp_inline_variables
+
+#define ABSL_COMPARE_INLINE_BASECLASS_DECL(name) \
+  ABSL_CONST_INIT static const T name
+
+// A no-op expansion that can be followed by a semicolon at class level.
+#define ABSL_COMPARE_INLINE_SUBCLASS_DECL(type, name) static_assert(true, "")
+
+#define ABSL_COMPARE_INLINE_INIT(type, name, init) \
+  template <typename T>                            \
+  const T compare_internal::type##_base<T>::name(init)
+
+#endif  // __cpp_inline_variables
+
+// These template base classes allow for defining the values of the constants
+// in the header file (for performance) without using inline variables (which
+// aren't available in C++11).
+template <typename T>
+struct weak_equality_base {
+  ABSL_COMPARE_INLINE_BASECLASS_DECL(equivalent);
+  ABSL_COMPARE_INLINE_BASECLASS_DECL(nonequivalent);
+};
+
+template <typename T>
+struct strong_equality_base {
+  ABSL_COMPARE_INLINE_BASECLASS_DECL(equal);
+  ABSL_COMPARE_INLINE_BASECLASS_DECL(nonequal);
+  ABSL_COMPARE_INLINE_BASECLASS_DECL(equivalent);
+  ABSL_COMPARE_INLINE_BASECLASS_DECL(nonequivalent);
+};
+
+template <typename T>
+struct partial_ordering_base {
+  ABSL_COMPARE_INLINE_BASECLASS_DECL(less);
+  ABSL_COMPARE_INLINE_BASECLASS_DECL(equivalent);
+  ABSL_COMPARE_INLINE_BASECLASS_DECL(greater);
+  ABSL_COMPARE_INLINE_BASECLASS_DECL(unordered);
+};
+
+template <typename T>
+struct weak_ordering_base {
+  ABSL_COMPARE_INLINE_BASECLASS_DECL(less);
+  ABSL_COMPARE_INLINE_BASECLASS_DECL(equivalent);
+  ABSL_COMPARE_INLINE_BASECLASS_DECL(greater);
+};
+
+template <typename T>
+struct strong_ordering_base {
+  ABSL_COMPARE_INLINE_BASECLASS_DECL(less);
+  ABSL_COMPARE_INLINE_BASECLASS_DECL(equal);
+  ABSL_COMPARE_INLINE_BASECLASS_DECL(equivalent);
+  ABSL_COMPARE_INLINE_BASECLASS_DECL(greater);
+};
+
+}  // namespace compare_internal
+
+class weak_equality
+    : public compare_internal::weak_equality_base<weak_equality> {
+  explicit constexpr weak_equality(compare_internal::eq v) noexcept
+      : value_(static_cast<compare_internal::value_type>(v)) {}
+  friend struct compare_internal::weak_equality_base<weak_equality>;
+
+ public:
+  ABSL_COMPARE_INLINE_SUBCLASS_DECL(weak_equality, equivalent);
+  ABSL_COMPARE_INLINE_SUBCLASS_DECL(weak_equality, nonequivalent);
+
+  // Comparisons
+  friend constexpr bool operator==(
+      weak_equality v, compare_internal::OnlyLiteralZero<>) noexcept {
+    return v.value_ == 0;
+  }
+  friend constexpr bool operator!=(
+      weak_equality v, compare_internal::OnlyLiteralZero<>) noexcept {
+    return v.value_ != 0;
+  }
+  friend constexpr bool operator==(compare_internal::OnlyLiteralZero<>,
+                                   weak_equality v) noexcept {
+    return 0 == v.value_;
+  }
+  friend constexpr bool operator!=(compare_internal::OnlyLiteralZero<>,
+                                   weak_equality v) noexcept {
+    return 0 != v.value_;
+  }
+  friend constexpr bool operator==(weak_equality v1,
+                                   weak_equality v2) noexcept {
+    return v1.value_ == v2.value_;
+  }
+  friend constexpr bool operator!=(weak_equality v1,
+                                   weak_equality v2) noexcept {
+    return v1.value_ != v2.value_;
+  }
+
+ private:
+  compare_internal::value_type value_;
+};
+ABSL_COMPARE_INLINE_INIT(weak_equality, equivalent,
+                         compare_internal::eq::equivalent);
+ABSL_COMPARE_INLINE_INIT(weak_equality, nonequivalent,
+                         compare_internal::eq::nonequivalent);
+
+class strong_equality
+    : public compare_internal::strong_equality_base<strong_equality> {
+  explicit constexpr strong_equality(compare_internal::eq v) noexcept
+      : value_(static_cast<compare_internal::value_type>(v)) {}
+  friend struct compare_internal::strong_equality_base<strong_equality>;
+
+ public:
+  ABSL_COMPARE_INLINE_SUBCLASS_DECL(strong_equality, equal);
+  ABSL_COMPARE_INLINE_SUBCLASS_DECL(strong_equality, nonequal);
+  ABSL_COMPARE_INLINE_SUBCLASS_DECL(strong_equality, equivalent);
+  ABSL_COMPARE_INLINE_SUBCLASS_DECL(strong_equality, nonequivalent);
+
+  // Conversion
+  constexpr operator weak_equality() const noexcept {  // NOLINT
+    return value_ == 0 ? weak_equality::equivalent
+                       : weak_equality::nonequivalent;
+  }
+  // Comparisons
+  friend constexpr bool operator==(
+      strong_equality v, compare_internal::OnlyLiteralZero<>) noexcept {
+    return v.value_ == 0;
+  }
+  friend constexpr bool operator!=(
+      strong_equality v, compare_internal::OnlyLiteralZero<>) noexcept {
+    return v.value_ != 0;
+  }
+  friend constexpr bool operator==(compare_internal::OnlyLiteralZero<>,
+                                   strong_equality v) noexcept {
+    return 0 == v.value_;
+  }
+  friend constexpr bool operator!=(compare_internal::OnlyLiteralZero<>,
+                                   strong_equality v) noexcept {
+    return 0 != v.value_;
+  }
+  friend constexpr bool operator==(strong_equality v1,
+                                   strong_equality v2) noexcept {
+    return v1.value_ == v2.value_;
+  }
+  friend constexpr bool operator!=(strong_equality v1,
+                                   strong_equality v2) noexcept {
+    return v1.value_ != v2.value_;
+  }
+
+ private:
+  compare_internal::value_type value_;
+};
+ABSL_COMPARE_INLINE_INIT(strong_equality, equal, compare_internal::eq::equal);
+ABSL_COMPARE_INLINE_INIT(strong_equality, nonequal,
+                         compare_internal::eq::nonequal);
+ABSL_COMPARE_INLINE_INIT(strong_equality, equivalent,
+                         compare_internal::eq::equivalent);
+ABSL_COMPARE_INLINE_INIT(strong_equality, nonequivalent,
+                         compare_internal::eq::nonequivalent);
+
+class partial_ordering
+    : public compare_internal::partial_ordering_base<partial_ordering> {
+  explicit constexpr partial_ordering(compare_internal::eq v) noexcept
+      : value_(static_cast<compare_internal::value_type>(v)) {}
+  explicit constexpr partial_ordering(compare_internal::ord v) noexcept
+      : value_(static_cast<compare_internal::value_type>(v)) {}
+  explicit constexpr partial_ordering(compare_internal::ncmp v) noexcept
+      : value_(static_cast<compare_internal::value_type>(v)) {}
+  friend struct compare_internal::partial_ordering_base<partial_ordering>;
+
+  constexpr bool is_ordered() const noexcept {
+    return value_ !=
+           compare_internal::value_type(compare_internal::ncmp::unordered);
+  }
+
+ public:
+  ABSL_COMPARE_INLINE_SUBCLASS_DECL(partial_ordering, less);
+  ABSL_COMPARE_INLINE_SUBCLASS_DECL(partial_ordering, equivalent);
+  ABSL_COMPARE_INLINE_SUBCLASS_DECL(partial_ordering, greater);
+  ABSL_COMPARE_INLINE_SUBCLASS_DECL(partial_ordering, unordered);
+
+  // Conversion
+  constexpr operator weak_equality() const noexcept {  // NOLINT
+    return value_ == 0 ? weak_equality::equivalent
+                       : weak_equality::nonequivalent;
+  }
+  // Comparisons
+  friend constexpr bool operator==(
+      partial_ordering v, compare_internal::OnlyLiteralZero<>) noexcept {
+    return v.is_ordered() && v.value_ == 0;
+  }
+  friend constexpr bool operator!=(
+      partial_ordering v, compare_internal::OnlyLiteralZero<>) noexcept {
+    return !v.is_ordered() || v.value_ != 0;
+  }
+  friend constexpr bool operator<(
+      partial_ordering v, compare_internal::OnlyLiteralZero<>) noexcept {
+    return v.is_ordered() && v.value_ < 0;
+  }
+  friend constexpr bool operator<=(
+      partial_ordering v, compare_internal::OnlyLiteralZero<>) noexcept {
+    return v.is_ordered() && v.value_ <= 0;
+  }
+  friend constexpr bool operator>(
+      partial_ordering v, compare_internal::OnlyLiteralZero<>) noexcept {
+    return v.is_ordered() && v.value_ > 0;
+  }
+  friend constexpr bool operator>=(
+      partial_ordering v, compare_internal::OnlyLiteralZero<>) noexcept {
+    return v.is_ordered() && v.value_ >= 0;
+  }
+  friend constexpr bool operator==(compare_internal::OnlyLiteralZero<>,
+                                   partial_ordering v) noexcept {
+    return v.is_ordered() && 0 == v.value_;
+  }
+  friend constexpr bool operator!=(compare_internal::OnlyLiteralZero<>,
+                                   partial_ordering v) noexcept {
+    return !v.is_ordered() || 0 != v.value_;
+  }
+  friend constexpr bool operator<(compare_internal::OnlyLiteralZero<>,
+                                  partial_ordering v) noexcept {
+    return v.is_ordered() && 0 < v.value_;
+  }
+  friend constexpr bool operator<=(compare_internal::OnlyLiteralZero<>,
+                                   partial_ordering v) noexcept {
+    return v.is_ordered() && 0 <= v.value_;
+  }
+  friend constexpr bool operator>(compare_internal::OnlyLiteralZero<>,
+                                  partial_ordering v) noexcept {
+    return v.is_ordered() && 0 > v.value_;
+  }
+  friend constexpr bool operator>=(compare_internal::OnlyLiteralZero<>,
+                                   partial_ordering v) noexcept {
+    return v.is_ordered() && 0 >= v.value_;
+  }
+  friend constexpr bool operator==(partial_ordering v1,
+                                   partial_ordering v2) noexcept {
+    return v1.value_ == v2.value_;
+  }
+  friend constexpr bool operator!=(partial_ordering v1,
+                                   partial_ordering v2) noexcept {
+    return v1.value_ != v2.value_;
+  }
+
+ private:
+  compare_internal::value_type value_;
+};
+ABSL_COMPARE_INLINE_INIT(partial_ordering, less, compare_internal::ord::less);
+ABSL_COMPARE_INLINE_INIT(partial_ordering, equivalent,
+                         compare_internal::eq::equivalent);
+ABSL_COMPARE_INLINE_INIT(partial_ordering, greater,
+                         compare_internal::ord::greater);
+ABSL_COMPARE_INLINE_INIT(partial_ordering, unordered,
+                         compare_internal::ncmp::unordered);
+
+class weak_ordering
+    : public compare_internal::weak_ordering_base<weak_ordering> {
+  explicit constexpr weak_ordering(compare_internal::eq v) noexcept
+      : value_(static_cast<compare_internal::value_type>(v)) {}
+  explicit constexpr weak_ordering(compare_internal::ord v) noexcept
+      : value_(static_cast<compare_internal::value_type>(v)) {}
+  friend struct compare_internal::weak_ordering_base<weak_ordering>;
+
+ public:
+  ABSL_COMPARE_INLINE_SUBCLASS_DECL(weak_ordering, less);
+  ABSL_COMPARE_INLINE_SUBCLASS_DECL(weak_ordering, equivalent);
+  ABSL_COMPARE_INLINE_SUBCLASS_DECL(weak_ordering, greater);
+
+  // Conversions
+  constexpr operator weak_equality() const noexcept {  // NOLINT
+    return value_ == 0 ? weak_equality::equivalent
+                       : weak_equality::nonequivalent;
+  }
+  constexpr operator partial_ordering() const noexcept {  // NOLINT
+    return value_ == 0 ? partial_ordering::equivalent
+                       : (value_ < 0 ? partial_ordering::less
+                                     : partial_ordering::greater);
+  }
+  // Comparisons
+  friend constexpr bool operator==(
+      weak_ordering v, compare_internal::OnlyLiteralZero<>) noexcept {
+    return v.value_ == 0;
+  }
+  friend constexpr bool operator!=(
+      weak_ordering v, compare_internal::OnlyLiteralZero<>) noexcept {
+    return v.value_ != 0;
+  }
+  friend constexpr bool operator<(
+      weak_ordering v, compare_internal::OnlyLiteralZero<>) noexcept {
+    return v.value_ < 0;
+  }
+  friend constexpr bool operator<=(
+      weak_ordering v, compare_internal::OnlyLiteralZero<>) noexcept {
+    return v.value_ <= 0;
+  }
+  friend constexpr bool operator>(
+      weak_ordering v, compare_internal::OnlyLiteralZero<>) noexcept {
+    return v.value_ > 0;
+  }
+  friend constexpr bool operator>=(
+      weak_ordering v, compare_internal::OnlyLiteralZero<>) noexcept {
+    return v.value_ >= 0;
+  }
+  friend constexpr bool operator==(compare_internal::OnlyLiteralZero<>,
+                                   weak_ordering v) noexcept {
+    return 0 == v.value_;
+  }
+  friend constexpr bool operator!=(compare_internal::OnlyLiteralZero<>,
+                                   weak_ordering v) noexcept {
+    return 0 != v.value_;
+  }
+  friend constexpr bool operator<(compare_internal::OnlyLiteralZero<>,
+                                  weak_ordering v) noexcept {
+    return 0 < v.value_;
+  }
+  friend constexpr bool operator<=(compare_internal::OnlyLiteralZero<>,
+                                   weak_ordering v) noexcept {
+    return 0 <= v.value_;
+  }
+  friend constexpr bool operator>(compare_internal::OnlyLiteralZero<>,
+                                  weak_ordering v) noexcept {
+    return 0 > v.value_;
+  }
+  friend constexpr bool operator>=(compare_internal::OnlyLiteralZero<>,
+                                   weak_ordering v) noexcept {
+    return 0 >= v.value_;
+  }
+  friend constexpr bool operator==(weak_ordering v1,
+                                   weak_ordering v2) noexcept {
+    return v1.value_ == v2.value_;
+  }
+  friend constexpr bool operator!=(weak_ordering v1,
+                                   weak_ordering v2) noexcept {
+    return v1.value_ != v2.value_;
+  }
+
+ private:
+  compare_internal::value_type value_;
+};
+ABSL_COMPARE_INLINE_INIT(weak_ordering, less, compare_internal::ord::less);
+ABSL_COMPARE_INLINE_INIT(weak_ordering, equivalent,
+                         compare_internal::eq::equivalent);
+ABSL_COMPARE_INLINE_INIT(weak_ordering, greater,
+                         compare_internal::ord::greater);
+
+class strong_ordering
+    : public compare_internal::strong_ordering_base<strong_ordering> {
+  explicit constexpr strong_ordering(compare_internal::eq v) noexcept
+      : value_(static_cast<compare_internal::value_type>(v)) {}
+  explicit constexpr strong_ordering(compare_internal::ord v) noexcept
+      : value_(static_cast<compare_internal::value_type>(v)) {}
+  friend struct compare_internal::strong_ordering_base<strong_ordering>;
+
+ public:
+  ABSL_COMPARE_INLINE_SUBCLASS_DECL(strong_ordering, less);
+  ABSL_COMPARE_INLINE_SUBCLASS_DECL(strong_ordering, equal);
+  ABSL_COMPARE_INLINE_SUBCLASS_DECL(strong_ordering, equivalent);
+  ABSL_COMPARE_INLINE_SUBCLASS_DECL(strong_ordering, greater);
+
+  // Conversions
+  constexpr operator weak_equality() const noexcept {  // NOLINT
+    return value_ == 0 ? weak_equality::equivalent
+                       : weak_equality::nonequivalent;
+  }
+  constexpr operator strong_equality() const noexcept {  // NOLINT
+    return value_ == 0 ? strong_equality::equal : strong_equality::nonequal;
+  }
+  constexpr operator partial_ordering() const noexcept {  // NOLINT
+    return value_ == 0 ? partial_ordering::equivalent
+                       : (value_ < 0 ? partial_ordering::less
+                                     : partial_ordering::greater);
+  }
+  constexpr operator weak_ordering() const noexcept {  // NOLINT
+    return value_ == 0
+               ? weak_ordering::equivalent
+               : (value_ < 0 ? weak_ordering::less : weak_ordering::greater);
+  }
+  // Comparisons
+  friend constexpr bool operator==(
+      strong_ordering v, compare_internal::OnlyLiteralZero<>) noexcept {
+    return v.value_ == 0;
+  }
+  friend constexpr bool operator!=(
+      strong_ordering v, compare_internal::OnlyLiteralZero<>) noexcept {
+    return v.value_ != 0;
+  }
+  friend constexpr bool operator<(
+      strong_ordering v, compare_internal::OnlyLiteralZero<>) noexcept {
+    return v.value_ < 0;
+  }
+  friend constexpr bool operator<=(
+      strong_ordering v, compare_internal::OnlyLiteralZero<>) noexcept {
+    return v.value_ <= 0;
+  }
+  friend constexpr bool operator>(
+      strong_ordering v, compare_internal::OnlyLiteralZero<>) noexcept {
+    return v.value_ > 0;
+  }
+  friend constexpr bool operator>=(
+      strong_ordering v, compare_internal::OnlyLiteralZero<>) noexcept {
+    return v.value_ >= 0;
+  }
+  friend constexpr bool operator==(compare_internal::OnlyLiteralZero<>,
+                                   strong_ordering v) noexcept {
+    return 0 == v.value_;
+  }
+  friend constexpr bool operator!=(compare_internal::OnlyLiteralZero<>,
+                                   strong_ordering v) noexcept {
+    return 0 != v.value_;
+  }
+  friend constexpr bool operator<(compare_internal::OnlyLiteralZero<>,
+                                  strong_ordering v) noexcept {
+    return 0 < v.value_;
+  }
+  friend constexpr bool operator<=(compare_internal::OnlyLiteralZero<>,
+                                   strong_ordering v) noexcept {
+    return 0 <= v.value_;
+  }
+  friend constexpr bool operator>(compare_internal::OnlyLiteralZero<>,
+                                  strong_ordering v) noexcept {
+    return 0 > v.value_;
+  }
+  friend constexpr bool operator>=(compare_internal::OnlyLiteralZero<>,
+                                   strong_ordering v) noexcept {
+    return 0 >= v.value_;
+  }
+  friend constexpr bool operator==(strong_ordering v1,
+                                   strong_ordering v2) noexcept {
+    return v1.value_ == v2.value_;
+  }
+  friend constexpr bool operator!=(strong_ordering v1,
+                                   strong_ordering v2) noexcept {
+    return v1.value_ != v2.value_;
+  }
+
+ private:
+  compare_internal::value_type value_;
+};
+ABSL_COMPARE_INLINE_INIT(strong_ordering, less, compare_internal::ord::less);
+ABSL_COMPARE_INLINE_INIT(strong_ordering, equal, compare_internal::eq::equal);
+ABSL_COMPARE_INLINE_INIT(strong_ordering, equivalent,
+                         compare_internal::eq::equivalent);
+ABSL_COMPARE_INLINE_INIT(strong_ordering, greater,
+                         compare_internal::ord::greater);
+
+#undef ABSL_COMPARE_INLINE_BASECLASS_DECL
+#undef ABSL_COMPARE_INLINE_SUBCLASS_DECL
+#undef ABSL_COMPARE_INLINE_INIT
+
+namespace compare_internal {
+// We also provide these comparator adapter functions for internal absl use.
+
+// Helper functions to do a boolean comparison of two keys given a boolean
+// or three-way comparator.
+// SFINAE prevents implicit conversions to bool (such as from int).
+template <typename Bool,
+          absl::enable_if_t<std::is_same<bool, Bool>::value, int> = 0>
+constexpr bool compare_result_as_less_than(const Bool r) { return r; }
+constexpr bool compare_result_as_less_than(const absl::weak_ordering r) {
+  return r < 0;
+}
+
+template <typename Compare, typename K, typename LK>
+constexpr bool do_less_than_comparison(const Compare &compare, const K &x,
+                                       const LK &y) {
+  return compare_result_as_less_than(compare(x, y));
+}
+
+// Helper functions to do a three-way comparison of two keys given a boolean or
+// three-way comparator.
+// SFINAE prevents implicit conversions to int (such as from bool).
+template <typename Int,
+          absl::enable_if_t<std::is_same<int, Int>::value, int> = 0>
+constexpr absl::weak_ordering compare_result_as_ordering(const Int c) {
+  return c < 0 ? absl::weak_ordering::less
+               : c == 0 ? absl::weak_ordering::equivalent
+                        : absl::weak_ordering::greater;
+}
+constexpr absl::weak_ordering compare_result_as_ordering(
+    const absl::weak_ordering c) {
+  return c;
+}
+
+template <
+    typename Compare, typename K, typename LK,
+    absl::enable_if_t<!std::is_same<bool, absl::result_of_t<Compare(
+                                              const K &, const LK &)>>::value,
+                      int> = 0>
+constexpr absl::weak_ordering do_three_way_comparison(const Compare &compare,
+                                                      const K &x, const LK &y) {
+  return compare_result_as_ordering(compare(x, y));
+}
+template <
+    typename Compare, typename K, typename LK,
+    absl::enable_if_t<std::is_same<bool, absl::result_of_t<Compare(
+                                             const K &, const LK &)>>::value,
+                      int> = 0>
+constexpr absl::weak_ordering do_three_way_comparison(const Compare &compare,
+                                                      const K &x, const LK &y) {
+  return compare(x, y) ? absl::weak_ordering::less
+                       : compare(y, x) ? absl::weak_ordering::greater
+                                       : absl::weak_ordering::equivalent;
+}
+
+}  // namespace compare_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#endif  // ABSL_TYPES_COMPARE_H_
diff --git a/src/absl/types/internal/conformance_aliases.h b/src/absl/types/internal/conformance_aliases.h
new file mode 100644 (file)
index 0000000..0cc6884
--- /dev/null
@@ -0,0 +1,447 @@
+// Copyright 2018 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// -----------------------------------------------------------------------------
+// regularity_aliases.h
+// -----------------------------------------------------------------------------
+//
+// This file contains type aliases of common ConformanceProfiles and Archetypes
+// so that they can be directly used by name without creating them from scratch.
+
+#ifndef ABSL_TYPES_INTERNAL_CONFORMANCE_ALIASES_H_
+#define ABSL_TYPES_INTERNAL_CONFORMANCE_ALIASES_H_
+
+#include "absl/types/internal/conformance_archetype.h"
+#include "absl/types/internal/conformance_profile.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace types_internal {
+
+// Creates both a Profile and a corresponding Archetype with root name "name".
+#define ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS(name, ...)                \
+  struct name##Profile : __VA_ARGS__ {};                                    \
+                                                                            \
+  using name##Archetype = ::absl::types_internal::Archetype<name##Profile>; \
+                                                                            \
+  template <class AbslInternalProfileTag>                                   \
+  using name##Archetype##_ = ::absl::types_internal::Archetype<             \
+      ::absl::types_internal::StrongProfileTypedef<name##Profile,           \
+                                                   AbslInternalProfileTag>>
+
+ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS(
+    HasTrivialDefaultConstructor,
+    ConformanceProfile<default_constructible::trivial>);
+
+ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS(
+    HasNothrowDefaultConstructor,
+    ConformanceProfile<default_constructible::nothrow>);
+
+ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS(
+    HasDefaultConstructor, ConformanceProfile<default_constructible::yes>);
+
+ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS(
+    HasTrivialMoveConstructor, ConformanceProfile<default_constructible::maybe,
+                                                  move_constructible::trivial>);
+
+ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS(
+    HasNothrowMoveConstructor, ConformanceProfile<default_constructible::maybe,
+                                                  move_constructible::nothrow>);
+
+ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS(
+    HasMoveConstructor,
+    ConformanceProfile<default_constructible::maybe, move_constructible::yes>);
+
+ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS(
+    HasTrivialCopyConstructor,
+    ConformanceProfile<default_constructible::maybe, move_constructible::maybe,
+                       copy_constructible::trivial>);
+
+ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS(
+    HasNothrowCopyConstructor,
+    ConformanceProfile<default_constructible::maybe, move_constructible::maybe,
+                       copy_constructible::nothrow>);
+
+ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS(
+    HasCopyConstructor,
+    ConformanceProfile<default_constructible::maybe, move_constructible::maybe,
+                       copy_constructible::yes>);
+
+ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS(
+    HasTrivialMoveAssign,
+    ConformanceProfile<default_constructible::maybe, move_constructible::maybe,
+                       copy_constructible::maybe, move_assignable::trivial>);
+
+ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS(
+    HasNothrowMoveAssign,
+    ConformanceProfile<default_constructible::maybe, move_constructible::maybe,
+                       copy_constructible::maybe, move_assignable::nothrow>);
+
+ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS(
+    HasMoveAssign,
+    ConformanceProfile<default_constructible::maybe, move_constructible::maybe,
+                       copy_constructible::maybe, move_assignable::yes>);
+
+ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS(
+    HasTrivialCopyAssign,
+    ConformanceProfile<default_constructible::maybe, move_constructible::maybe,
+                       copy_constructible::maybe, move_assignable::maybe,
+                       copy_assignable::trivial>);
+
+ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS(
+    HasNothrowCopyAssign,
+    ConformanceProfile<default_constructible::maybe, move_constructible::maybe,
+                       copy_constructible::maybe, move_assignable::maybe,
+                       copy_assignable::nothrow>);
+
+ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS(
+    HasCopyAssign,
+    ConformanceProfile<default_constructible::maybe, move_constructible::maybe,
+                       copy_constructible::maybe, move_assignable::maybe,
+                       copy_assignable::yes>);
+
+ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS(
+    HasTrivialDestructor,
+    ConformanceProfile<default_constructible::maybe, move_constructible::maybe,
+                       copy_constructible::maybe, move_assignable::maybe,
+                       copy_assignable::maybe, destructible::trivial>);
+
+ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS(
+    HasNothrowDestructor,
+    ConformanceProfile<default_constructible::maybe, move_constructible::maybe,
+                       copy_constructible::maybe, move_assignable::maybe,
+                       copy_assignable::maybe, destructible::nothrow>);
+
+ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS(
+    HasDestructor,
+    ConformanceProfile<default_constructible::maybe, move_constructible::maybe,
+                       copy_constructible::maybe, move_assignable::maybe,
+                       copy_assignable::maybe, destructible::yes>);
+
+ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS(
+    HasNothrowEquality,
+    ConformanceProfile<default_constructible::maybe, move_constructible::maybe,
+                       copy_constructible::maybe, move_assignable::maybe,
+                       copy_assignable::maybe, destructible::maybe,
+                       equality_comparable::nothrow>);
+
+ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS(
+    HasEquality,
+    ConformanceProfile<default_constructible::maybe, move_constructible::maybe,
+                       copy_constructible::maybe, move_assignable::maybe,
+                       copy_assignable::maybe, destructible::maybe,
+                       equality_comparable::yes>);
+
+ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS(
+    HasNothrowInequality,
+    ConformanceProfile<default_constructible::maybe, move_constructible::maybe,
+                       copy_constructible::maybe, move_assignable::maybe,
+                       copy_assignable::maybe, destructible::maybe,
+                       equality_comparable::maybe,
+                       inequality_comparable::nothrow>);
+
+ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS(
+    HasInequality,
+    ConformanceProfile<default_constructible::maybe, move_constructible::maybe,
+                       copy_constructible::maybe, move_assignable::maybe,
+                       copy_assignable::maybe, destructible::maybe,
+                       equality_comparable::maybe, inequality_comparable::yes>);
+
+ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS(
+    HasNothrowLessThan,
+    ConformanceProfile<default_constructible::maybe, move_constructible::maybe,
+                       copy_constructible::maybe, move_assignable::maybe,
+                       copy_assignable::maybe, destructible::maybe,
+                       equality_comparable::maybe, inequality_comparable::maybe,
+                       less_than_comparable::nothrow>);
+
+ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS(
+    HasLessThan,
+    ConformanceProfile<default_constructible::maybe, move_constructible::maybe,
+                       copy_constructible::maybe, move_assignable::maybe,
+                       copy_assignable::maybe, destructible::maybe,
+                       equality_comparable::maybe, inequality_comparable::maybe,
+                       less_than_comparable::yes>);
+
+ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS(
+    HasNothrowLessEqual,
+    ConformanceProfile<default_constructible::maybe, move_constructible::maybe,
+                       copy_constructible::maybe, move_assignable::maybe,
+                       copy_assignable::maybe, destructible::maybe,
+                       equality_comparable::maybe, inequality_comparable::maybe,
+                       less_than_comparable::maybe,
+                       less_equal_comparable::nothrow>);
+
+ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS(
+    HasLessEqual,
+    ConformanceProfile<default_constructible::maybe, move_constructible::maybe,
+                       copy_constructible::maybe, move_assignable::maybe,
+                       copy_assignable::maybe, destructible::maybe,
+                       equality_comparable::maybe, inequality_comparable::maybe,
+                       less_than_comparable::maybe,
+                       less_equal_comparable::yes>);
+
+ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS(
+    HasNothrowGreaterEqual,
+    ConformanceProfile<
+        default_constructible::maybe, move_constructible::maybe,
+        copy_constructible::maybe, move_assignable::maybe,
+        copy_assignable::maybe, destructible::maybe, equality_comparable::maybe,
+        inequality_comparable::maybe, less_than_comparable::maybe,
+        less_equal_comparable::maybe, greater_equal_comparable::nothrow>);
+
+ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS(
+    HasGreaterEqual,
+    ConformanceProfile<
+        default_constructible::maybe, move_constructible::maybe,
+        copy_constructible::maybe, move_assignable::maybe,
+        copy_assignable::maybe, destructible::maybe, equality_comparable::maybe,
+        inequality_comparable::maybe, less_than_comparable::maybe,
+        less_equal_comparable::maybe, greater_equal_comparable::yes>);
+
+ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS(
+    HasNothrowGreaterThan,
+    ConformanceProfile<
+        default_constructible::maybe, move_constructible::maybe,
+        copy_constructible::maybe, move_assignable::maybe,
+        copy_assignable::maybe, destructible::maybe, equality_comparable::maybe,
+        inequality_comparable::maybe, less_than_comparable::maybe,
+        less_equal_comparable::maybe, greater_equal_comparable::maybe,
+        greater_than_comparable::nothrow>);
+
+ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS(
+    HasGreaterThan,
+    ConformanceProfile<
+        default_constructible::maybe, move_constructible::maybe,
+        copy_constructible::maybe, move_assignable::maybe,
+        copy_assignable::maybe, destructible::maybe, equality_comparable::maybe,
+        inequality_comparable::maybe, less_than_comparable::maybe,
+        less_equal_comparable::maybe, greater_equal_comparable::maybe,
+        greater_than_comparable::yes>);
+
+ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS(
+    HasNothrowSwap,
+    ConformanceProfile<
+        default_constructible::maybe, move_constructible::maybe,
+        copy_constructible::maybe, move_assignable::maybe,
+        copy_assignable::maybe, destructible::maybe, equality_comparable::maybe,
+        inequality_comparable::maybe, less_than_comparable::maybe,
+        less_equal_comparable::maybe, greater_equal_comparable::maybe,
+        greater_than_comparable::maybe, swappable::nothrow>);
+
+ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS(
+    HasSwap,
+    ConformanceProfile<
+        default_constructible::maybe, move_constructible::maybe,
+        copy_constructible::maybe, move_assignable::maybe,
+        copy_assignable::maybe, destructible::maybe, equality_comparable::maybe,
+        inequality_comparable::maybe, less_than_comparable::maybe,
+        less_equal_comparable::maybe, greater_equal_comparable::maybe,
+        greater_than_comparable::maybe, swappable::yes>);
+
+ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS(
+    HasStdHashSpecialization,
+    ConformanceProfile<
+        default_constructible::maybe, move_constructible::maybe,
+        copy_constructible::maybe, move_assignable::maybe,
+        copy_assignable::maybe, destructible::maybe, equality_comparable::maybe,
+        inequality_comparable::maybe, less_than_comparable::maybe,
+        less_equal_comparable::maybe, greater_equal_comparable::maybe,
+        greater_than_comparable::maybe, swappable::maybe, hashable::yes>);
+
+////////////////////////////////////////////////////////////////////////////////
+////     The remaining aliases are combinations of the previous aliases.    ////
+////////////////////////////////////////////////////////////////////////////////
+
+ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS(
+    Equatable, CombineProfiles<HasEqualityProfile, HasInequalityProfile>);
+
+ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS(
+    Comparable,
+    CombineProfiles<EquatableProfile, HasLessThanProfile, HasLessEqualProfile,
+                    HasGreaterEqualProfile, HasGreaterThanProfile>);
+
+ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS(
+    NothrowEquatable,
+    CombineProfiles<HasNothrowEqualityProfile, HasNothrowInequalityProfile>);
+
+ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS(
+    NothrowComparable,
+    CombineProfiles<NothrowEquatableProfile, HasNothrowLessThanProfile,
+                    HasNothrowLessEqualProfile, HasNothrowGreaterEqualProfile,
+                    HasNothrowGreaterThanProfile>);
+
+ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS(
+    Value,
+    CombineProfiles<HasNothrowMoveConstructorProfile, HasCopyConstructorProfile,
+                    HasNothrowMoveAssignProfile, HasCopyAssignProfile,
+                    HasNothrowDestructorProfile, HasNothrowSwapProfile>);
+
+ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS(
+    EquatableValue, CombineProfiles<EquatableProfile, ValueProfile>);
+
+ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS(
+    ComparableValue, CombineProfiles<ComparableProfile, ValueProfile>);
+
+ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS(
+    DefaultConstructibleValue,
+    CombineProfiles<HasDefaultConstructorProfile, ValueProfile>);
+
+ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS(
+    NothrowMoveConstructible, CombineProfiles<HasNothrowMoveConstructorProfile,
+                                              HasNothrowDestructorProfile>);
+
+ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS(
+    EquatableNothrowMoveConstructible,
+    CombineProfiles<EquatableProfile, NothrowMoveConstructibleProfile>);
+
+ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS(
+    ComparableNothrowMoveConstructible,
+    CombineProfiles<ComparableProfile, NothrowMoveConstructibleProfile>);
+
+ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS(
+    DefaultConstructibleNothrowMoveConstructible,
+    CombineProfiles<HasDefaultConstructorProfile,
+                    NothrowMoveConstructibleProfile>);
+
+ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS(
+    CopyConstructible,
+    CombineProfiles<HasNothrowMoveConstructorProfile, HasCopyConstructorProfile,
+                    HasNothrowDestructorProfile>);
+
+ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS(
+    EquatableCopyConstructible,
+    CombineProfiles<EquatableProfile, CopyConstructibleProfile>);
+
+ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS(
+    ComparableCopyConstructible,
+    CombineProfiles<ComparableProfile, CopyConstructibleProfile>);
+
+ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS(
+    DefaultConstructibleCopyConstructible,
+    CombineProfiles<HasDefaultConstructorProfile, CopyConstructibleProfile>);
+
+ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS(
+    NothrowMovable,
+    CombineProfiles<HasNothrowMoveConstructorProfile,
+                    HasNothrowMoveAssignProfile, HasNothrowDestructorProfile,
+                    HasNothrowSwapProfile>);
+
+ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS(
+    EquatableNothrowMovable,
+    CombineProfiles<EquatableProfile, NothrowMovableProfile>);
+
+ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS(
+    ComparableNothrowMovable,
+    CombineProfiles<ComparableProfile, NothrowMovableProfile>);
+
+ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS(
+    DefaultConstructibleNothrowMovable,
+    CombineProfiles<HasDefaultConstructorProfile, NothrowMovableProfile>);
+
+ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS(
+    TrivialSpecialMemberFunctions,
+    CombineProfiles<HasTrivialDefaultConstructorProfile,
+                    HasTrivialMoveConstructorProfile,
+                    HasTrivialCopyConstructorProfile,
+                    HasTrivialMoveAssignProfile, HasTrivialCopyAssignProfile,
+                    HasTrivialDestructorProfile, HasNothrowSwapProfile>);
+
+ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS(
+    TriviallyComplete,
+    CombineProfiles<TrivialSpecialMemberFunctionsProfile, ComparableProfile,
+                    HasStdHashSpecializationProfile>);
+
+ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS(
+    HashableNothrowMoveConstructible,
+    CombineProfiles<HasStdHashSpecializationProfile,
+                    NothrowMoveConstructibleProfile>);
+
+ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS(
+    HashableCopyConstructible,
+    CombineProfiles<HasStdHashSpecializationProfile, CopyConstructibleProfile>);
+
+ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS(
+    HashableNothrowMovable,
+    CombineProfiles<HasStdHashSpecializationProfile, NothrowMovableProfile>);
+
+ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS(
+    HashableValue,
+    CombineProfiles<HasStdHashSpecializationProfile, ValueProfile>);
+
+ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS(
+    ComparableHashableValue,
+    CombineProfiles<HashableValueProfile, ComparableProfile>);
+
+// The "preferred" profiles that we support in Abseil.
+template <template <class...> class Receiver>
+using ExpandBasicProfiles =
+    Receiver<NothrowMoveConstructibleProfile, CopyConstructibleProfile,
+             NothrowMovableProfile, ValueProfile>;
+
+// The basic profiles except that they are also all Equatable.
+template <template <class...> class Receiver>
+using ExpandBasicEquatableProfiles =
+    Receiver<EquatableNothrowMoveConstructibleProfile,
+             EquatableCopyConstructibleProfile, EquatableNothrowMovableProfile,
+             EquatableValueProfile>;
+
+// The basic profiles except that they are also all Comparable.
+template <template <class...> class Receiver>
+using ExpandBasicComparableProfiles =
+    Receiver<ComparableNothrowMoveConstructibleProfile,
+             ComparableCopyConstructibleProfile,
+             ComparableNothrowMovableProfile, ComparableValueProfile>;
+
+// The basic profiles except that they are also all Hashable.
+template <template <class...> class Receiver>
+using ExpandBasicHashableProfiles =
+    Receiver<HashableNothrowMoveConstructibleProfile,
+             HashableCopyConstructibleProfile, HashableNothrowMovableProfile,
+             HashableValueProfile>;
+
+// The basic profiles except that they are also all DefaultConstructible.
+template <template <class...> class Receiver>
+using ExpandBasicDefaultConstructibleProfiles =
+    Receiver<DefaultConstructibleNothrowMoveConstructibleProfile,
+             DefaultConstructibleCopyConstructibleProfile,
+             DefaultConstructibleNothrowMovableProfile,
+             DefaultConstructibleValueProfile>;
+
+// The type profiles that we support in Abseil (all of the previous lists).
+template <template <class...> class Receiver>
+using ExpandSupportedProfiles = Receiver<
+    NothrowMoveConstructibleProfile, CopyConstructibleProfile,
+    NothrowMovableProfile, ValueProfile,
+    EquatableNothrowMoveConstructibleProfile, EquatableCopyConstructibleProfile,
+    EquatableNothrowMovableProfile, EquatableValueProfile,
+    ComparableNothrowMoveConstructibleProfile,
+    ComparableCopyConstructibleProfile, ComparableNothrowMovableProfile,
+    ComparableValueProfile, DefaultConstructibleNothrowMoveConstructibleProfile,
+    DefaultConstructibleCopyConstructibleProfile,
+    DefaultConstructibleNothrowMovableProfile, DefaultConstructibleValueProfile,
+    HashableNothrowMoveConstructibleProfile, HashableCopyConstructibleProfile,
+    HashableNothrowMovableProfile, HashableValueProfile>;
+
+// TODO(calabrese) Include types that have throwing move constructors, since in
+// practice we still need to support them because of standard library types with
+// (potentially) non-noexcept moves.
+
+}  // namespace types_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#undef ABSL_INTERNAL_PROFILE_AND_ARCHETYPE_ALIAS
+
+#endif  // ABSL_TYPES_INTERNAL_CONFORMANCE_ALIASES_H_
diff --git a/src/absl/types/internal/conformance_archetype.h b/src/absl/types/internal/conformance_archetype.h
new file mode 100644 (file)
index 0000000..2349e0f
--- /dev/null
@@ -0,0 +1,978 @@
+// Copyright 2019 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// -----------------------------------------------------------------------------
+// conformance_archetype.h
+// -----------------------------------------------------------------------------
+//
+// This file contains a facility for generating "archetypes" of out of
+// "Conformance Profiles" (see "conformance_profiles.h" for more information
+// about Conformance Profiles). An archetype is a type that aims to support the
+// bare minimum requirements of a given Conformance Profile. For instance, an
+// archetype that corresponds to an ImmutableProfile has exactly a nothrow
+// move-constructor, a potentially-throwing copy constructor, a nothrow
+// destructor, with all other special-member-functions deleted. These archetypes
+// are useful for testing to make sure that templates are able to work with the
+// kinds of types that they claim to support (i.e. that they do not accidentally
+// under-constrain),
+//
+// The main type template in this file is the Archetype template, which takes
+// a Conformance Profile as a template argument and its instantiations are a
+// minimum-conforming model of that profile.
+
+#ifndef ABSL_TYPES_INTERNAL_CONFORMANCE_ARCHETYPE_H_
+#define ABSL_TYPES_INTERNAL_CONFORMANCE_ARCHETYPE_H_
+
+#include <cstddef>
+#include <functional>
+#include <type_traits>
+#include <utility>
+
+#include "absl/meta/type_traits.h"
+#include "absl/types/internal/conformance_profile.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace types_internal {
+
+// A minimum-conforming implementation of a type with properties specified in
+// `Prof`, where `Prof` is a valid Conformance Profile.
+template <class Prof, class /*Enabler*/ = void>
+class Archetype;
+
+// Given an Archetype, obtain the properties of the profile associated with that
+// archetype.
+template <class Archetype>
+struct PropertiesOfArchetype;
+
+template <class Prof>
+struct PropertiesOfArchetype<Archetype<Prof>> {
+  using type = PropertiesOfT<Prof>;
+};
+
+template <class Archetype>
+using PropertiesOfArchetypeT = typename PropertiesOfArchetype<Archetype>::type;
+
+// A metafunction to determine if a type is an `Archetype`.
+template <class T>
+struct IsArchetype : std::false_type {};
+
+template <class Prof>
+struct IsArchetype<Archetype<Prof>> : std::true_type {};
+
+// A constructor tag type used when creating an Archetype with internal state.
+struct MakeArchetypeState {};
+
+// Data stored within an archetype that is copied/compared/hashed when the
+// corresponding operations are used.
+using ArchetypeState = std::size_t;
+
+////////////////////////////////////////////////////////////////////////////////
+//   This section of the file defines a chain of base classes for Archetype,  //
+//   where each base defines a specific special member function with the      //
+//   appropriate properties (deleted, noexcept(false), noexcept, or trivial). //
+////////////////////////////////////////////////////////////////////////////////
+
+// The bottom-most base, which contains the state and the default constructor.
+template <default_constructible DefaultConstructibleValue>
+struct ArchetypeStateBase {
+  static_assert(DefaultConstructibleValue == default_constructible::yes ||
+                    DefaultConstructibleValue == default_constructible::nothrow,
+                "");
+
+  ArchetypeStateBase() noexcept(
+      DefaultConstructibleValue ==
+      default_constructible::
+          nothrow) /*Vacuous archetype_state initialization*/ {}
+  explicit ArchetypeStateBase(MakeArchetypeState, ArchetypeState state) noexcept
+      : archetype_state(state) {}
+
+  ArchetypeState archetype_state;
+};
+
+template <>
+struct ArchetypeStateBase<default_constructible::maybe> {
+  explicit ArchetypeStateBase() = delete;
+  explicit ArchetypeStateBase(MakeArchetypeState, ArchetypeState state) noexcept
+      : archetype_state(state) {}
+
+  ArchetypeState archetype_state;
+};
+
+template <>
+struct ArchetypeStateBase<default_constructible::trivial> {
+  ArchetypeStateBase() = default;
+  explicit ArchetypeStateBase(MakeArchetypeState, ArchetypeState state) noexcept
+      : archetype_state(state) {}
+
+  ArchetypeState archetype_state;
+};
+
+// The move-constructor base
+template <default_constructible DefaultConstructibleValue,
+          move_constructible MoveConstructibleValue>
+struct ArchetypeMoveConstructor
+    : ArchetypeStateBase<DefaultConstructibleValue> {
+  static_assert(MoveConstructibleValue == move_constructible::yes ||
+                    MoveConstructibleValue == move_constructible::nothrow,
+                "");
+
+  explicit ArchetypeMoveConstructor(MakeArchetypeState,
+                                    ArchetypeState state) noexcept
+      : ArchetypeStateBase<DefaultConstructibleValue>(MakeArchetypeState(),
+                                                      state) {}
+
+  ArchetypeMoveConstructor() = default;
+  ArchetypeMoveConstructor(ArchetypeMoveConstructor&& other) noexcept(
+      MoveConstructibleValue == move_constructible::nothrow)
+      : ArchetypeStateBase<DefaultConstructibleValue>(MakeArchetypeState(),
+                                                      other.archetype_state) {}
+  ArchetypeMoveConstructor(const ArchetypeMoveConstructor&) = default;
+  ArchetypeMoveConstructor& operator=(ArchetypeMoveConstructor&&) = default;
+  ArchetypeMoveConstructor& operator=(const ArchetypeMoveConstructor&) =
+      default;
+};
+
+template <default_constructible DefaultConstructibleValue>
+struct ArchetypeMoveConstructor<DefaultConstructibleValue,
+                                move_constructible::trivial>
+    : ArchetypeStateBase<DefaultConstructibleValue> {
+  explicit ArchetypeMoveConstructor(MakeArchetypeState,
+                                    ArchetypeState state) noexcept
+      : ArchetypeStateBase<DefaultConstructibleValue>(MakeArchetypeState(),
+                                                      state) {}
+
+  ArchetypeMoveConstructor() = default;
+};
+
+// The copy-constructor base
+template <default_constructible DefaultConstructibleValue,
+          move_constructible MoveConstructibleValue,
+          copy_constructible CopyConstructibleValue>
+struct ArchetypeCopyConstructor
+    : ArchetypeMoveConstructor<DefaultConstructibleValue,
+                               MoveConstructibleValue> {
+  static_assert(CopyConstructibleValue == copy_constructible::yes ||
+                    CopyConstructibleValue == copy_constructible::nothrow,
+                "");
+  explicit ArchetypeCopyConstructor(MakeArchetypeState,
+                                    ArchetypeState state) noexcept
+      : ArchetypeMoveConstructor<DefaultConstructibleValue,
+                                 MoveConstructibleValue>(MakeArchetypeState(),
+                                                         state) {}
+
+  ArchetypeCopyConstructor() = default;
+  ArchetypeCopyConstructor(ArchetypeCopyConstructor&&) = default;
+  ArchetypeCopyConstructor(const ArchetypeCopyConstructor& other) noexcept(
+      CopyConstructibleValue == copy_constructible::nothrow)
+      : ArchetypeMoveConstructor<DefaultConstructibleValue,
+                                 MoveConstructibleValue>(
+            MakeArchetypeState(), other.archetype_state) {}
+  ArchetypeCopyConstructor& operator=(ArchetypeCopyConstructor&&) = default;
+  ArchetypeCopyConstructor& operator=(const ArchetypeCopyConstructor&) =
+      default;
+};
+
+template <default_constructible DefaultConstructibleValue,
+          move_constructible MoveConstructibleValue>
+struct ArchetypeCopyConstructor<DefaultConstructibleValue,
+                                MoveConstructibleValue,
+                                copy_constructible::maybe>
+    : ArchetypeMoveConstructor<DefaultConstructibleValue,
+                               MoveConstructibleValue> {
+  explicit ArchetypeCopyConstructor(MakeArchetypeState,
+                                    ArchetypeState state) noexcept
+      : ArchetypeMoveConstructor<DefaultConstructibleValue,
+                                 MoveConstructibleValue>(MakeArchetypeState(),
+                                                         state) {}
+
+  ArchetypeCopyConstructor() = default;
+  ArchetypeCopyConstructor(ArchetypeCopyConstructor&&) = default;
+  ArchetypeCopyConstructor(const ArchetypeCopyConstructor&) = delete;
+  ArchetypeCopyConstructor& operator=(ArchetypeCopyConstructor&&) = default;
+  ArchetypeCopyConstructor& operator=(const ArchetypeCopyConstructor&) =
+      default;
+};
+
+template <default_constructible DefaultConstructibleValue,
+          move_constructible MoveConstructibleValue>
+struct ArchetypeCopyConstructor<DefaultConstructibleValue,
+                                MoveConstructibleValue,
+                                copy_constructible::trivial>
+    : ArchetypeMoveConstructor<DefaultConstructibleValue,
+                               MoveConstructibleValue> {
+  explicit ArchetypeCopyConstructor(MakeArchetypeState,
+                                    ArchetypeState state) noexcept
+      : ArchetypeMoveConstructor<DefaultConstructibleValue,
+                                 MoveConstructibleValue>(MakeArchetypeState(),
+                                                         state) {}
+
+  ArchetypeCopyConstructor() = default;
+};
+
+// The move-assign base
+template <default_constructible DefaultConstructibleValue,
+          move_constructible MoveConstructibleValue,
+          copy_constructible CopyConstructibleValue,
+          move_assignable MoveAssignableValue>
+struct ArchetypeMoveAssign
+    : ArchetypeCopyConstructor<DefaultConstructibleValue,
+                               MoveConstructibleValue, CopyConstructibleValue> {
+  static_assert(MoveAssignableValue == move_assignable::yes ||
+                    MoveAssignableValue == move_assignable::nothrow,
+                "");
+  explicit ArchetypeMoveAssign(MakeArchetypeState,
+                               ArchetypeState state) noexcept
+      : ArchetypeCopyConstructor<DefaultConstructibleValue,
+                                 MoveConstructibleValue,
+                                 CopyConstructibleValue>(MakeArchetypeState(),
+                                                         state) {}
+
+  ArchetypeMoveAssign() = default;
+  ArchetypeMoveAssign(ArchetypeMoveAssign&&) = default;
+  ArchetypeMoveAssign(const ArchetypeMoveAssign&) = default;
+  ArchetypeMoveAssign& operator=(ArchetypeMoveAssign&& other) noexcept(
+      MoveAssignableValue == move_assignable::nothrow) {
+    this->archetype_state = other.archetype_state;
+    return *this;
+  }
+
+  ArchetypeMoveAssign& operator=(const ArchetypeMoveAssign&) = default;
+};
+
+template <default_constructible DefaultConstructibleValue,
+          move_constructible MoveConstructibleValue,
+          copy_constructible CopyConstructibleValue>
+struct ArchetypeMoveAssign<DefaultConstructibleValue, MoveConstructibleValue,
+                           CopyConstructibleValue, move_assignable::trivial>
+    : ArchetypeCopyConstructor<DefaultConstructibleValue,
+                               MoveConstructibleValue, CopyConstructibleValue> {
+  explicit ArchetypeMoveAssign(MakeArchetypeState,
+                               ArchetypeState state) noexcept
+      : ArchetypeCopyConstructor<DefaultConstructibleValue,
+                                 MoveConstructibleValue,
+                                 CopyConstructibleValue>(MakeArchetypeState(),
+                                                         state) {}
+
+  ArchetypeMoveAssign() = default;
+};
+
+// The copy-assign base
+template <default_constructible DefaultConstructibleValue,
+          move_constructible MoveConstructibleValue,
+          copy_constructible CopyConstructibleValue,
+          move_assignable MoveAssignableValue,
+          copy_assignable CopyAssignableValue>
+struct ArchetypeCopyAssign
+    : ArchetypeMoveAssign<DefaultConstructibleValue, MoveConstructibleValue,
+                          CopyConstructibleValue, MoveAssignableValue> {
+  static_assert(CopyAssignableValue == copy_assignable::yes ||
+                    CopyAssignableValue == copy_assignable::nothrow,
+                "");
+  explicit ArchetypeCopyAssign(MakeArchetypeState,
+                               ArchetypeState state) noexcept
+      : ArchetypeMoveAssign<DefaultConstructibleValue, MoveConstructibleValue,
+                            CopyConstructibleValue, MoveAssignableValue>(
+            MakeArchetypeState(), state) {}
+
+  ArchetypeCopyAssign() = default;
+  ArchetypeCopyAssign(ArchetypeCopyAssign&&) = default;
+  ArchetypeCopyAssign(const ArchetypeCopyAssign&) = default;
+  ArchetypeCopyAssign& operator=(ArchetypeCopyAssign&&) = default;
+
+  ArchetypeCopyAssign& operator=(const ArchetypeCopyAssign& other) noexcept(
+      CopyAssignableValue == copy_assignable::nothrow) {
+    this->archetype_state = other.archetype_state;
+    return *this;
+  }
+};
+
+template <default_constructible DefaultConstructibleValue,
+          move_constructible MoveConstructibleValue,
+          copy_constructible CopyConstructibleValue,
+          move_assignable MoveAssignableValue>
+struct ArchetypeCopyAssign<DefaultConstructibleValue, MoveConstructibleValue,
+                           CopyConstructibleValue, MoveAssignableValue,
+                           copy_assignable::maybe>
+    : ArchetypeMoveAssign<DefaultConstructibleValue, MoveConstructibleValue,
+                          CopyConstructibleValue, MoveAssignableValue> {
+  explicit ArchetypeCopyAssign(MakeArchetypeState,
+                               ArchetypeState state) noexcept
+      : ArchetypeMoveAssign<DefaultConstructibleValue, MoveConstructibleValue,
+                            CopyConstructibleValue, MoveAssignableValue>(
+            MakeArchetypeState(), state) {}
+
+  ArchetypeCopyAssign() = default;
+  ArchetypeCopyAssign(ArchetypeCopyAssign&&) = default;
+  ArchetypeCopyAssign(const ArchetypeCopyAssign&) = default;
+  ArchetypeCopyAssign& operator=(ArchetypeCopyAssign&&) = default;
+  ArchetypeCopyAssign& operator=(const ArchetypeCopyAssign&) = delete;
+};
+
+template <default_constructible DefaultConstructibleValue,
+          move_constructible MoveConstructibleValue,
+          copy_constructible CopyConstructibleValue,
+          move_assignable MoveAssignableValue>
+struct ArchetypeCopyAssign<DefaultConstructibleValue, MoveConstructibleValue,
+                           CopyConstructibleValue, MoveAssignableValue,
+                           copy_assignable::trivial>
+    : ArchetypeMoveAssign<DefaultConstructibleValue, MoveConstructibleValue,
+                          CopyConstructibleValue, MoveAssignableValue> {
+  explicit ArchetypeCopyAssign(MakeArchetypeState,
+                               ArchetypeState state) noexcept
+      : ArchetypeMoveAssign<DefaultConstructibleValue, MoveConstructibleValue,
+                            CopyConstructibleValue, MoveAssignableValue>(
+            MakeArchetypeState(), state) {}
+
+  ArchetypeCopyAssign() = default;
+};
+
+// The destructor base
+template <default_constructible DefaultConstructibleValue,
+          move_constructible MoveConstructibleValue,
+          copy_constructible CopyConstructibleValue,
+          move_assignable MoveAssignableValue,
+          copy_assignable CopyAssignableValue, destructible DestructibleValue>
+struct ArchetypeDestructor
+    : ArchetypeCopyAssign<DefaultConstructibleValue, MoveConstructibleValue,
+                          CopyConstructibleValue, MoveAssignableValue,
+                          CopyAssignableValue> {
+  static_assert(DestructibleValue == destructible::yes ||
+                    DestructibleValue == destructible::nothrow,
+                "");
+
+  explicit ArchetypeDestructor(MakeArchetypeState,
+                               ArchetypeState state) noexcept
+      : ArchetypeCopyAssign<DefaultConstructibleValue, MoveConstructibleValue,
+                            CopyConstructibleValue, MoveAssignableValue,
+                            CopyAssignableValue>(MakeArchetypeState(), state) {}
+
+  ArchetypeDestructor() = default;
+  ArchetypeDestructor(ArchetypeDestructor&&) = default;
+  ArchetypeDestructor(const ArchetypeDestructor&) = default;
+  ArchetypeDestructor& operator=(ArchetypeDestructor&&) = default;
+  ArchetypeDestructor& operator=(const ArchetypeDestructor&) = default;
+  ~ArchetypeDestructor() noexcept(DestructibleValue == destructible::nothrow) {}
+};
+
+template <default_constructible DefaultConstructibleValue,
+          move_constructible MoveConstructibleValue,
+          copy_constructible CopyConstructibleValue,
+          move_assignable MoveAssignableValue,
+          copy_assignable CopyAssignableValue>
+struct ArchetypeDestructor<DefaultConstructibleValue, MoveConstructibleValue,
+                           CopyConstructibleValue, MoveAssignableValue,
+                           CopyAssignableValue, destructible::trivial>
+    : ArchetypeCopyAssign<DefaultConstructibleValue, MoveConstructibleValue,
+                          CopyConstructibleValue, MoveAssignableValue,
+                          CopyAssignableValue> {
+  explicit ArchetypeDestructor(MakeArchetypeState,
+                               ArchetypeState state) noexcept
+      : ArchetypeCopyAssign<DefaultConstructibleValue, MoveConstructibleValue,
+                            CopyConstructibleValue, MoveAssignableValue,
+                            CopyAssignableValue>(MakeArchetypeState(), state) {}
+
+  ArchetypeDestructor() = default;
+};
+
+// An alias to the top of the chain of bases for special-member functions.
+// NOTE: move_constructible::maybe, move_assignable::maybe, and
+// destructible::maybe are handled in the top-level type by way of SFINAE.
+// Because of this, we never instantiate the base classes with
+// move_constructible::maybe, move_assignable::maybe, or destructible::maybe so
+// that we minimize the number of different possible type-template
+// instantiations.
+template <default_constructible DefaultConstructibleValue,
+          move_constructible MoveConstructibleValue,
+          copy_constructible CopyConstructibleValue,
+          move_assignable MoveAssignableValue,
+          copy_assignable CopyAssignableValue, destructible DestructibleValue>
+using ArchetypeSpecialMembersBase = ArchetypeDestructor<
+    DefaultConstructibleValue,
+    MoveConstructibleValue != move_constructible::maybe
+        ? MoveConstructibleValue
+        : move_constructible::nothrow,
+    CopyConstructibleValue,
+    MoveAssignableValue != move_assignable::maybe ? MoveAssignableValue
+                                                  : move_assignable::nothrow,
+    CopyAssignableValue,
+    DestructibleValue != destructible::maybe ? DestructibleValue
+                                             : destructible::nothrow>;
+
+// A function that is used to create an archetype with some associated state.
+template <class Arch>
+Arch MakeArchetype(ArchetypeState state) noexcept {
+  static_assert(IsArchetype<Arch>::value,
+                "The explicit template argument to MakeArchetype is required "
+                "to be an Archetype.");
+  return Arch(MakeArchetypeState(), state);
+}
+
+// This is used to conditionally delete "copy" and "move" constructors in a way
+// that is consistent with what the ConformanceProfile requires and that also
+// strictly enforces the arguments to the copy/move to not come from implicit
+// conversions when dealing with the Archetype.
+template <class Prof, class T>
+constexpr bool ShouldDeleteConstructor() {
+  return !((PropertiesOfT<Prof>::move_constructible_support !=
+                move_constructible::maybe &&
+            std::is_same<T, Archetype<Prof>>::value) ||
+           (PropertiesOfT<Prof>::copy_constructible_support !=
+                copy_constructible::maybe &&
+            (std::is_same<T, const Archetype<Prof>&>::value ||
+             std::is_same<T, Archetype<Prof>&>::value ||
+             std::is_same<T, const Archetype<Prof>>::value)));
+}
+
+// This is used to conditionally delete "copy" and "move" assigns in a way
+// that is consistent with what the ConformanceProfile requires and that also
+// strictly enforces the arguments to the copy/move to not come from implicit
+// conversions when dealing with the Archetype.
+template <class Prof, class T>
+constexpr bool ShouldDeleteAssign() {
+  return !(
+      (PropertiesOfT<Prof>::move_assignable_support != move_assignable::maybe &&
+       std::is_same<T, Archetype<Prof>>::value) ||
+      (PropertiesOfT<Prof>::copy_assignable_support != copy_assignable::maybe &&
+       (std::is_same<T, const Archetype<Prof>&>::value ||
+        std::is_same<T, Archetype<Prof>&>::value ||
+        std::is_same<T, const Archetype<Prof>>::value)));
+}
+
+// TODO(calabrese) Inherit from a chain of secondary bases to pull in the
+// associated functions of other concepts.
+template <class Prof, class Enabler>
+class Archetype : ArchetypeSpecialMembersBase<
+                      PropertiesOfT<Prof>::default_constructible_support,
+                      PropertiesOfT<Prof>::move_constructible_support,
+                      PropertiesOfT<Prof>::copy_constructible_support,
+                      PropertiesOfT<Prof>::move_assignable_support,
+                      PropertiesOfT<Prof>::copy_assignable_support,
+                      PropertiesOfT<Prof>::destructible_support> {
+  static_assert(std::is_same<Enabler, void>::value,
+                "An explicit type must not be passed as the second template "
+                "argument to 'Archetype`.");
+
+  // The cases mentioned in these static_asserts are expected to be handled in
+  // the partial template specializations of Archetype that follow this
+  // definition.
+  static_assert(PropertiesOfT<Prof>::destructible_support !=
+                    destructible::maybe,
+                "");
+  static_assert(PropertiesOfT<Prof>::move_constructible_support !=
+                        move_constructible::maybe ||
+                    PropertiesOfT<Prof>::copy_constructible_support ==
+                        copy_constructible::maybe,
+                "");
+  static_assert(PropertiesOfT<Prof>::move_assignable_support !=
+                        move_assignable::maybe ||
+                    PropertiesOfT<Prof>::copy_assignable_support ==
+                        copy_assignable::maybe,
+                "");
+
+ public:
+  Archetype() = default;
+
+  // Disallow moves when requested, and disallow implicit conversions.
+  template <class T, typename std::enable_if<
+                         ShouldDeleteConstructor<Prof, T>()>::type* = nullptr>
+  Archetype(T&&) = delete;
+
+  // Disallow moves when requested, and disallow implicit conversions.
+  template <class T, typename std::enable_if<
+                         ShouldDeleteAssign<Prof, T>()>::type* = nullptr>
+  Archetype& operator=(T&&) = delete;
+
+  using ArchetypeSpecialMembersBase<
+      PropertiesOfT<Prof>::default_constructible_support,
+      PropertiesOfT<Prof>::move_constructible_support,
+      PropertiesOfT<Prof>::copy_constructible_support,
+      PropertiesOfT<Prof>::move_assignable_support,
+      PropertiesOfT<Prof>::copy_assignable_support,
+      PropertiesOfT<Prof>::destructible_support>::archetype_state;
+
+ private:
+  explicit Archetype(MakeArchetypeState, ArchetypeState state) noexcept
+      : ArchetypeSpecialMembersBase<
+            PropertiesOfT<Prof>::default_constructible_support,
+            PropertiesOfT<Prof>::move_constructible_support,
+            PropertiesOfT<Prof>::copy_constructible_support,
+            PropertiesOfT<Prof>::move_assignable_support,
+            PropertiesOfT<Prof>::copy_assignable_support,
+            PropertiesOfT<Prof>::destructible_support>(MakeArchetypeState(),
+                                                       state) {}
+
+  friend Archetype MakeArchetype<Archetype>(ArchetypeState) noexcept;
+};
+
+template <class Prof>
+class Archetype<Prof, typename std::enable_if<
+                          PropertiesOfT<Prof>::move_constructible_support !=
+                              move_constructible::maybe &&
+                          PropertiesOfT<Prof>::move_assignable_support ==
+                              move_assignable::maybe &&
+                          PropertiesOfT<Prof>::destructible_support !=
+                              destructible::maybe>::type>
+    : ArchetypeSpecialMembersBase<
+          PropertiesOfT<Prof>::default_constructible_support,
+          PropertiesOfT<Prof>::move_constructible_support,
+          PropertiesOfT<Prof>::copy_constructible_support,
+          PropertiesOfT<Prof>::move_assignable_support,
+          PropertiesOfT<Prof>::copy_assignable_support,
+          PropertiesOfT<Prof>::destructible_support> {
+ public:
+  Archetype() = default;
+  Archetype(Archetype&&) = default;
+  Archetype(const Archetype&) = default;
+  Archetype& operator=(Archetype&&) = delete;
+  Archetype& operator=(const Archetype&) = default;
+
+  // Disallow moves when requested, and disallow implicit conversions.
+  template <class T, typename std::enable_if<
+                         ShouldDeleteConstructor<Prof, T>()>::type* = nullptr>
+  Archetype(T&&) = delete;
+
+  // Disallow moves when requested, and disallow implicit conversions.
+  template <class T, typename std::enable_if<
+                         ShouldDeleteAssign<Prof, T>()>::type* = nullptr>
+  Archetype& operator=(T&&) = delete;
+
+  using ArchetypeSpecialMembersBase<
+      PropertiesOfT<Prof>::default_constructible_support,
+      PropertiesOfT<Prof>::move_constructible_support,
+      PropertiesOfT<Prof>::copy_constructible_support,
+      PropertiesOfT<Prof>::move_assignable_support,
+      PropertiesOfT<Prof>::copy_assignable_support,
+      PropertiesOfT<Prof>::destructible_support>::archetype_state;
+
+ private:
+  explicit Archetype(MakeArchetypeState, ArchetypeState state) noexcept
+      : ArchetypeSpecialMembersBase<
+            PropertiesOfT<Prof>::default_constructible_support,
+            PropertiesOfT<Prof>::move_constructible_support,
+            PropertiesOfT<Prof>::copy_constructible_support,
+            PropertiesOfT<Prof>::move_assignable_support,
+            PropertiesOfT<Prof>::copy_assignable_support,
+            PropertiesOfT<Prof>::destructible_support>(MakeArchetypeState(),
+                                                       state) {}
+
+  friend Archetype MakeArchetype<Archetype>(ArchetypeState) noexcept;
+};
+
+template <class Prof>
+class Archetype<Prof, typename std::enable_if<
+                          PropertiesOfT<Prof>::move_constructible_support ==
+                              move_constructible::maybe &&
+                          PropertiesOfT<Prof>::move_assignable_support ==
+                              move_assignable::maybe &&
+                          PropertiesOfT<Prof>::destructible_support !=
+                              destructible::maybe>::type>
+    : ArchetypeSpecialMembersBase<
+          PropertiesOfT<Prof>::default_constructible_support,
+          PropertiesOfT<Prof>::move_constructible_support,
+          PropertiesOfT<Prof>::copy_constructible_support,
+          PropertiesOfT<Prof>::move_assignable_support,
+          PropertiesOfT<Prof>::copy_assignable_support,
+          PropertiesOfT<Prof>::destructible_support> {
+ public:
+  Archetype() = default;
+  Archetype(Archetype&&) = delete;
+  Archetype(const Archetype&) = default;
+  Archetype& operator=(Archetype&&) = delete;
+  Archetype& operator=(const Archetype&) = default;
+
+  // Disallow moves when requested, and disallow implicit conversions.
+  template <class T, typename std::enable_if<
+                         ShouldDeleteConstructor<Prof, T>()>::type* = nullptr>
+  Archetype(T&&) = delete;
+
+  // Disallow moves when requested, and disallow implicit conversions.
+  template <class T, typename std::enable_if<
+                         ShouldDeleteAssign<Prof, T>()>::type* = nullptr>
+  Archetype& operator=(T&&) = delete;
+
+  using ArchetypeSpecialMembersBase<
+      PropertiesOfT<Prof>::default_constructible_support,
+      PropertiesOfT<Prof>::move_constructible_support,
+      PropertiesOfT<Prof>::copy_constructible_support,
+      PropertiesOfT<Prof>::move_assignable_support,
+      PropertiesOfT<Prof>::copy_assignable_support,
+      PropertiesOfT<Prof>::destructible_support>::archetype_state;
+
+ private:
+  explicit Archetype(MakeArchetypeState, ArchetypeState state) noexcept
+      : ArchetypeSpecialMembersBase<
+            PropertiesOfT<Prof>::default_constructible_support,
+            PropertiesOfT<Prof>::move_constructible_support,
+            PropertiesOfT<Prof>::copy_constructible_support,
+            PropertiesOfT<Prof>::move_assignable_support,
+            PropertiesOfT<Prof>::copy_assignable_support,
+            PropertiesOfT<Prof>::destructible_support>(MakeArchetypeState(),
+                                                       state) {}
+
+  friend Archetype MakeArchetype<Archetype>(ArchetypeState) noexcept;
+};
+
+template <class Prof>
+class Archetype<Prof, typename std::enable_if<
+                          PropertiesOfT<Prof>::move_constructible_support ==
+                              move_constructible::maybe &&
+                          PropertiesOfT<Prof>::move_assignable_support !=
+                              move_assignable::maybe &&
+                          PropertiesOfT<Prof>::destructible_support !=
+                              destructible::maybe>::type>
+    : ArchetypeSpecialMembersBase<
+          PropertiesOfT<Prof>::default_constructible_support,
+          PropertiesOfT<Prof>::move_constructible_support,
+          PropertiesOfT<Prof>::copy_constructible_support,
+          PropertiesOfT<Prof>::move_assignable_support,
+          PropertiesOfT<Prof>::copy_assignable_support,
+          PropertiesOfT<Prof>::destructible_support> {
+ public:
+  Archetype() = default;
+  Archetype(Archetype&&) = delete;
+  Archetype(const Archetype&) = default;
+  Archetype& operator=(Archetype&&) = default;
+  Archetype& operator=(const Archetype&) = default;
+
+  // Disallow moves when requested, and disallow implicit conversions.
+  template <class T, typename std::enable_if<
+                         ShouldDeleteConstructor<Prof, T>()>::type* = nullptr>
+  Archetype(T&&) = delete;
+
+  // Disallow moves when requested, and disallow implicit conversions.
+  template <class T, typename std::enable_if<
+                         ShouldDeleteAssign<Prof, T>()>::type* = nullptr>
+  Archetype& operator=(T&&) = delete;
+
+  using ArchetypeSpecialMembersBase<
+      PropertiesOfT<Prof>::default_constructible_support,
+      PropertiesOfT<Prof>::move_constructible_support,
+      PropertiesOfT<Prof>::copy_constructible_support,
+      PropertiesOfT<Prof>::move_assignable_support,
+      PropertiesOfT<Prof>::copy_assignable_support,
+      PropertiesOfT<Prof>::destructible_support>::archetype_state;
+
+ private:
+  explicit Archetype(MakeArchetypeState, ArchetypeState state) noexcept
+      : ArchetypeSpecialMembersBase<
+            PropertiesOfT<Prof>::default_constructible_support,
+            PropertiesOfT<Prof>::move_constructible_support,
+            PropertiesOfT<Prof>::copy_constructible_support,
+            PropertiesOfT<Prof>::move_assignable_support,
+            PropertiesOfT<Prof>::copy_assignable_support,
+            PropertiesOfT<Prof>::destructible_support>(MakeArchetypeState(),
+                                                       state) {}
+
+  friend Archetype MakeArchetype<Archetype>(ArchetypeState) noexcept;
+};
+
+template <class Prof>
+class Archetype<Prof, typename std::enable_if<
+                          PropertiesOfT<Prof>::move_constructible_support !=
+                              move_constructible::maybe &&
+                          PropertiesOfT<Prof>::move_assignable_support ==
+                              move_assignable::maybe &&
+                          PropertiesOfT<Prof>::destructible_support ==
+                              destructible::maybe>::type>
+    : ArchetypeSpecialMembersBase<
+          PropertiesOfT<Prof>::default_constructible_support,
+          PropertiesOfT<Prof>::move_constructible_support,
+          PropertiesOfT<Prof>::copy_constructible_support,
+          PropertiesOfT<Prof>::move_assignable_support,
+          PropertiesOfT<Prof>::copy_assignable_support,
+          PropertiesOfT<Prof>::destructible_support> {
+ public:
+  Archetype() = default;
+  Archetype(Archetype&&) = default;
+  Archetype(const Archetype&) = default;
+  Archetype& operator=(Archetype&&) = delete;
+  Archetype& operator=(const Archetype&) = default;
+  ~Archetype() = delete;
+
+  // Disallow moves when requested, and disallow implicit conversions.
+  template <class T, typename std::enable_if<
+                         ShouldDeleteConstructor<Prof, T>()>::type* = nullptr>
+  Archetype(T&&) = delete;
+
+  // Disallow moves when requested, and disallow implicit conversions.
+  template <class T, typename std::enable_if<
+                         ShouldDeleteAssign<Prof, T>()>::type* = nullptr>
+  Archetype& operator=(T&&) = delete;
+
+  using ArchetypeSpecialMembersBase<
+      PropertiesOfT<Prof>::default_constructible_support,
+      PropertiesOfT<Prof>::move_constructible_support,
+      PropertiesOfT<Prof>::copy_constructible_support,
+      PropertiesOfT<Prof>::move_assignable_support,
+      PropertiesOfT<Prof>::copy_assignable_support,
+      PropertiesOfT<Prof>::destructible_support>::archetype_state;
+
+ private:
+  explicit Archetype(MakeArchetypeState, ArchetypeState state) noexcept
+      : ArchetypeSpecialMembersBase<
+            PropertiesOfT<Prof>::default_constructible_support,
+            PropertiesOfT<Prof>::move_constructible_support,
+            PropertiesOfT<Prof>::copy_constructible_support,
+            PropertiesOfT<Prof>::move_assignable_support,
+            PropertiesOfT<Prof>::copy_assignable_support,
+            PropertiesOfT<Prof>::destructible_support>(MakeArchetypeState(),
+                                                       state) {}
+
+  friend Archetype MakeArchetype<Archetype>(ArchetypeState) noexcept;
+};
+
+template <class Prof>
+class Archetype<Prof, typename std::enable_if<
+                          PropertiesOfT<Prof>::move_constructible_support ==
+                              move_constructible::maybe &&
+                          PropertiesOfT<Prof>::move_assignable_support ==
+                              move_assignable::maybe &&
+                          PropertiesOfT<Prof>::destructible_support ==
+                              destructible::maybe>::type>
+    : ArchetypeSpecialMembersBase<
+          PropertiesOfT<Prof>::default_constructible_support,
+          PropertiesOfT<Prof>::move_constructible_support,
+          PropertiesOfT<Prof>::copy_constructible_support,
+          PropertiesOfT<Prof>::move_assignable_support,
+          PropertiesOfT<Prof>::copy_assignable_support,
+          PropertiesOfT<Prof>::destructible_support> {
+ public:
+  Archetype() = default;
+  Archetype(Archetype&&) = delete;
+  Archetype(const Archetype&) = default;
+  Archetype& operator=(Archetype&&) = delete;
+  Archetype& operator=(const Archetype&) = default;
+  ~Archetype() = delete;
+
+  // Disallow moves when requested, and disallow implicit conversions.
+  template <class T, typename std::enable_if<
+                         ShouldDeleteConstructor<Prof, T>()>::type* = nullptr>
+  Archetype(T&&) = delete;
+
+  // Disallow moves when requested, and disallow implicit conversions.
+  template <class T, typename std::enable_if<
+                         ShouldDeleteAssign<Prof, T>()>::type* = nullptr>
+  Archetype& operator=(T&&) = delete;
+
+  using ArchetypeSpecialMembersBase<
+      PropertiesOfT<Prof>::default_constructible_support,
+      PropertiesOfT<Prof>::move_constructible_support,
+      PropertiesOfT<Prof>::copy_constructible_support,
+      PropertiesOfT<Prof>::move_assignable_support,
+      PropertiesOfT<Prof>::copy_assignable_support,
+      PropertiesOfT<Prof>::destructible_support>::archetype_state;
+
+ private:
+  explicit Archetype(MakeArchetypeState, ArchetypeState state) noexcept
+      : ArchetypeSpecialMembersBase<
+            PropertiesOfT<Prof>::default_constructible_support,
+            PropertiesOfT<Prof>::move_constructible_support,
+            PropertiesOfT<Prof>::copy_constructible_support,
+            PropertiesOfT<Prof>::move_assignable_support,
+            PropertiesOfT<Prof>::copy_assignable_support,
+            PropertiesOfT<Prof>::destructible_support>(MakeArchetypeState(),
+                                                       state) {}
+
+  friend Archetype MakeArchetype<Archetype>(ArchetypeState) noexcept;
+};
+
+template <class Prof>
+class Archetype<Prof, typename std::enable_if<
+                          PropertiesOfT<Prof>::move_constructible_support ==
+                              move_constructible::maybe &&
+                          PropertiesOfT<Prof>::move_assignable_support !=
+                              move_assignable::maybe &&
+                          PropertiesOfT<Prof>::destructible_support ==
+                              destructible::maybe>::type>
+    : ArchetypeSpecialMembersBase<
+          PropertiesOfT<Prof>::default_constructible_support,
+          PropertiesOfT<Prof>::move_constructible_support,
+          PropertiesOfT<Prof>::copy_constructible_support,
+          PropertiesOfT<Prof>::move_assignable_support,
+          PropertiesOfT<Prof>::copy_assignable_support,
+          PropertiesOfT<Prof>::destructible_support> {
+ public:
+  Archetype() = default;
+  Archetype(Archetype&&) = delete;
+  Archetype(const Archetype&) = default;
+  Archetype& operator=(Archetype&&) = default;
+  Archetype& operator=(const Archetype&) = default;
+  ~Archetype() = delete;
+
+  // Disallow moves when requested, and disallow implicit conversions.
+  template <class T, typename std::enable_if<
+                         ShouldDeleteConstructor<Prof, T>()>::type* = nullptr>
+  Archetype(T&&) = delete;
+
+  // Disallow moves when requested, and disallow implicit conversions.
+  template <class T, typename std::enable_if<
+                         ShouldDeleteAssign<Prof, T>()>::type* = nullptr>
+  Archetype& operator=(T&&) = delete;
+
+  using ArchetypeSpecialMembersBase<
+      PropertiesOfT<Prof>::default_constructible_support,
+      PropertiesOfT<Prof>::move_constructible_support,
+      PropertiesOfT<Prof>::copy_constructible_support,
+      PropertiesOfT<Prof>::move_assignable_support,
+      PropertiesOfT<Prof>::copy_assignable_support,
+      PropertiesOfT<Prof>::destructible_support>::archetype_state;
+
+ private:
+  explicit Archetype(MakeArchetypeState, ArchetypeState state) noexcept
+      : ArchetypeSpecialMembersBase<
+            PropertiesOfT<Prof>::default_constructible_support,
+            PropertiesOfT<Prof>::move_constructible_support,
+            PropertiesOfT<Prof>::copy_constructible_support,
+            PropertiesOfT<Prof>::move_assignable_support,
+            PropertiesOfT<Prof>::copy_assignable_support,
+            PropertiesOfT<Prof>::destructible_support>(MakeArchetypeState(),
+                                                       state) {}
+
+  friend Archetype MakeArchetype<Archetype>(ArchetypeState) noexcept;
+};
+
+// Explicitly deleted swap for Archetype if the profile does not require swap.
+// It is important to delete it rather than simply leave it out so that the
+// "using std::swap;" idiom will result in this deleted overload being picked.
+template <class Prof,
+          absl::enable_if_t<!PropertiesOfT<Prof>::is_swappable, int> = 0>
+void swap(Archetype<Prof>&, Archetype<Prof>&) = delete;  // NOLINT
+
+// A conditionally-noexcept swap implementation for Archetype when the profile
+// supports swap.
+template <class Prof,
+          absl::enable_if_t<PropertiesOfT<Prof>::is_swappable, int> = 0>
+void swap(Archetype<Prof>& lhs, Archetype<Prof>& rhs)  // NOLINT
+    noexcept(PropertiesOfT<Prof>::swappable_support != swappable::yes) {
+  std::swap(lhs.archetype_state, rhs.archetype_state);
+}
+
+// A convertible-to-bool type that is used as the return type of comparison
+// operators since the standard doesn't always require exactly bool.
+struct NothrowBool {
+  explicit NothrowBool() = delete;
+  ~NothrowBool() = default;
+
+  // TODO(calabrese) Delete the copy constructor in C++17 mode since guaranteed
+  // elision makes it not required when returning from a function.
+  // NothrowBool(NothrowBool const&) = delete;
+
+  NothrowBool& operator=(NothrowBool const&) = delete;
+
+  explicit operator bool() const noexcept { return value; }
+
+  static NothrowBool make(bool const value) noexcept {
+    return NothrowBool(value);
+  }
+
+ private:
+  explicit NothrowBool(bool const value) noexcept : value(value) {}
+
+  bool value;
+};
+
+// A convertible-to-bool type that is used as the return type of comparison
+// operators since the standard doesn't always require exactly bool.
+// Note: ExceptionalBool has a conversion operator that is not noexcept, so
+// that even when a comparison operator is noexcept, that operation may still
+// potentially throw when converted to bool.
+struct ExceptionalBool {
+  explicit ExceptionalBool() = delete;
+  ~ExceptionalBool() = default;
+
+  // TODO(calabrese) Delete the copy constructor in C++17 mode since guaranteed
+  // elision makes it not required when returning from a function.
+  // ExceptionalBool(ExceptionalBool const&) = delete;
+
+  ExceptionalBool& operator=(ExceptionalBool const&) = delete;
+
+  explicit operator bool() const { return value; }  // NOLINT
+
+  static ExceptionalBool make(bool const value) noexcept {
+    return ExceptionalBool(value);
+  }
+
+ private:
+  explicit ExceptionalBool(bool const value) noexcept : value(value) {}
+
+  bool value;
+};
+
+// The following macro is only used as a helper in this file to stamp out
+// comparison operator definitions. It is undefined after usage.
+//
+// NOTE: Non-nothrow operators throw via their result's conversion to bool even
+// though the operation itself is noexcept.
+#define ABSL_TYPES_INTERNAL_OP(enum_name, op)                                \
+  template <class Prof>                                                      \
+  absl::enable_if_t<!PropertiesOfT<Prof>::is_##enum_name, bool> operator op( \
+      const Archetype<Prof>&, const Archetype<Prof>&) = delete;              \
+                                                                             \
+  template <class Prof>                                                      \
+  typename absl::enable_if_t<                                                \
+      PropertiesOfT<Prof>::is_##enum_name,                                   \
+      std::conditional<PropertiesOfT<Prof>::enum_name##_support ==           \
+                           enum_name::nothrow,                               \
+                       NothrowBool, ExceptionalBool>>::type                  \
+  operator op(const Archetype<Prof>& lhs,                                    \
+              const Archetype<Prof>& rhs) noexcept {                         \
+    return absl::conditional_t<                                              \
+        PropertiesOfT<Prof>::enum_name##_support == enum_name::nothrow,      \
+        NothrowBool, ExceptionalBool>::make(lhs.archetype_state op           \
+                                                rhs.archetype_state);        \
+  }
+
+ABSL_TYPES_INTERNAL_OP(equality_comparable, ==);
+ABSL_TYPES_INTERNAL_OP(inequality_comparable, !=);
+ABSL_TYPES_INTERNAL_OP(less_than_comparable, <);
+ABSL_TYPES_INTERNAL_OP(less_equal_comparable, <=);
+ABSL_TYPES_INTERNAL_OP(greater_equal_comparable, >=);
+ABSL_TYPES_INTERNAL_OP(greater_than_comparable, >);
+
+#undef ABSL_TYPES_INTERNAL_OP
+
+// Base class for std::hash specializations when an Archetype doesn't support
+// hashing.
+struct PoisonedHash {
+  PoisonedHash() = delete;
+  PoisonedHash(const PoisonedHash&) = delete;
+  PoisonedHash& operator=(const PoisonedHash&) = delete;
+};
+
+// Base class for std::hash specializations when an Archetype supports hashing.
+template <class Prof>
+struct EnabledHash {
+  using argument_type = Archetype<Prof>;
+  using result_type = std::size_t;
+  result_type operator()(const argument_type& arg) const {
+    return std::hash<ArchetypeState>()(arg.archetype_state);
+  }
+};
+
+}  // namespace types_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+namespace std {
+
+template <class Prof>  // NOLINT
+struct hash<::absl::types_internal::Archetype<Prof>>
+    : conditional<::absl::types_internal::PropertiesOfT<Prof>::is_hashable,
+                  ::absl::types_internal::EnabledHash<Prof>,
+                  ::absl::types_internal::PoisonedHash>::type {};
+
+}  // namespace std
+
+#endif  // ABSL_TYPES_INTERNAL_CONFORMANCE_ARCHETYPE_H_
diff --git a/src/absl/types/internal/conformance_profile.h b/src/absl/types/internal/conformance_profile.h
new file mode 100644 (file)
index 0000000..cf64ff4
--- /dev/null
@@ -0,0 +1,931 @@
+// Copyright 2019 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// -----------------------------------------------------------------------------
+// conformance_profiles.h
+// -----------------------------------------------------------------------------
+//
+// This file contains templates for representing "Regularity Profiles" and
+// concisely-named versions of commonly used Regularity Profiles.
+//
+// A Regularity Profile is a compile-time description of the types of operations
+// that a given type supports, along with properties of those operations when
+// they do exist. For instance, a Regularity Profile may describe a type that
+// has a move-constructor that is noexcept and a copy constructor that is not
+// noexcept. This description can then be examined and passed around to other
+// templates for the purposes of asserting expectations on user-defined types
+// via a series trait checks, or for determining what kinds of run-time tests
+// are able to be performed.
+//
+// Regularity Profiles are also used when creating "archetypes," which are
+// minimum-conforming types that meet all of the requirements of a given
+// Regularity Profile. For more information regarding archetypes, see
+// "conformance_archetypes.h".
+
+#ifndef ABSL_TYPES_INTERNAL_CONFORMANCE_PROFILE_H_
+#define ABSL_TYPES_INTERNAL_CONFORMANCE_PROFILE_H_
+
+#include <set>
+#include <type_traits>
+#include <utility>
+#include <vector>
+
+#include "gtest/gtest.h"
+#include "absl/algorithm/container.h"
+#include "absl/meta/type_traits.h"
+#include "absl/strings/ascii.h"
+#include "absl/strings/str_cat.h"
+#include "absl/strings/string_view.h"
+#include "absl/types/internal/conformance_testing_helpers.h"
+#include "absl/utility/utility.h"
+
+// TODO(calabrese) Add support for extending profiles.
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace types_internal {
+
+// Converts an enum to its underlying integral value.
+template <typename Enum>
+constexpr absl::underlying_type_t<Enum> UnderlyingValue(Enum value) {
+  return static_cast<absl::underlying_type_t<Enum>>(value);
+}
+
+// A tag type used in place of a matcher when checking that an assertion result
+// does not actually contain any errors.
+struct NoError {};
+
+// -----------------------------------------------------------------------------
+// ConformanceErrors
+// -----------------------------------------------------------------------------
+class ConformanceErrors {
+ public:
+  // Setup the error reporting mechanism by seeding it with the name of the type
+  // that is being tested.
+  explicit ConformanceErrors(std::string type_name)
+      : assertion_result_(false), type_name_(std::move(type_name)) {
+    assertion_result_ << "\n\n"
+                         "Assuming the following type alias:\n"
+                         "\n"
+                         "  using _T = "
+                      << type_name_ << ";\n\n";
+    outputDivider();
+  }
+
+  // Adds the test name to the list of successfully run tests iff it was not
+  // previously reported as failing. This behavior is useful for tests that
+  // have multiple parts, where failures and successes are reported individually
+  // with the same test name.
+  void addTestSuccess(absl::string_view test_name) {
+    auto normalized_test_name = absl::AsciiStrToLower(test_name);
+
+    // If the test is already reported as failing, do not add it to the list of
+    // successes.
+    if (test_failures_.find(normalized_test_name) == test_failures_.end()) {
+      test_successes_.insert(std::move(normalized_test_name));
+    }
+  }
+
+  // Streams a single error description into the internal buffer (a visual
+  // divider is automatically inserted after the error so that multiple errors
+  // are visibly distinct).
+  //
+  // This function increases the error count by 1.
+  //
+  // TODO(calabrese) Determine desired behavior when if this function throws.
+  template <class... P>
+  void addTestFailure(absl::string_view test_name, const P&... args) {
+    // Output a message related to the test failure.
+    assertion_result_ << "\n\n"
+                         "Failed test: "
+                      << test_name << "\n\n";
+    addTestFailureImpl(args...);
+    assertion_result_ << "\n\n";
+    outputDivider();
+
+    auto normalized_test_name = absl::AsciiStrToLower(test_name);
+
+    // If previous parts of this test succeeded, remove it from that set.
+    test_successes_.erase(normalized_test_name);
+
+    // Add the test name to the list of failed tests.
+    test_failures_.insert(std::move(normalized_test_name));
+
+    has_error_ = true;
+  }
+
+  // Convert this object into a testing::AssertionResult instance such that it
+  // can be used with gtest.
+  ::testing::AssertionResult assertionResult() const {
+    return has_error_ ? assertion_result_ : ::testing::AssertionSuccess();
+  }
+
+  // Convert this object into a testing::AssertionResult instance such that it
+  // can be used with gtest. This overload expects errors, using the specified
+  // matcher.
+  ::testing::AssertionResult expectFailedTests(
+      const std::set<std::string>& test_names) const {
+    // Since we are expecting nonconformance, output an error message when the
+    // type actually conformed to the specified profile.
+    if (!has_error_) {
+      return ::testing::AssertionFailure()
+             << "Unexpected conformance of type:\n"
+                "    "
+             << type_name_ << "\n\n";
+    }
+
+    // Get a list of all expected failures that did not actually fail
+    // (or that were not run).
+    std::vector<std::string> nonfailing_tests;
+    absl::c_set_difference(test_names, test_failures_,
+                           std::back_inserter(nonfailing_tests));
+
+    // Get a list of all "expected failures" that were never actually run.
+    std::vector<std::string> unrun_tests;
+    absl::c_set_difference(nonfailing_tests, test_successes_,
+                           std::back_inserter(unrun_tests));
+
+    // Report when the user specified tests that were not run.
+    if (!unrun_tests.empty()) {
+      const bool tests_were_run =
+          !(test_failures_.empty() && test_successes_.empty());
+
+      // Prepare an assertion result used in the case that tests pass that were
+      // expected to fail.
+      ::testing::AssertionResult result = ::testing::AssertionFailure();
+      result << "When testing type:\n    " << type_name_
+             << "\n\nThe following tests were expected to fail but were not "
+                "run";
+
+      if (tests_were_run) result << " (was the test name spelled correctly?)";
+
+      result << ":\n\n";
+
+      // List all of the tests that unexpectedly passed.
+      for (const auto& test_name : unrun_tests) {
+        result << "    " << test_name << "\n";
+      }
+
+      if (!tests_were_run) result << "\nNo tests were run.";
+
+      if (!test_failures_.empty()) {
+        // List test failures
+        result << "\nThe tests that were run and failed are:\n\n";
+        for (const auto& test_name : test_failures_) {
+          result << "    " << test_name << "\n";
+        }
+      }
+
+      if (!test_successes_.empty()) {
+        // List test successes
+        result << "\nThe tests that were run and succeeded are:\n\n";
+        for (const auto& test_name : test_successes_) {
+          result << "    " << test_name << "\n";
+        }
+      }
+
+      return result;
+    }
+
+    // If some tests passed when they were expected to fail, alert the caller.
+    if (nonfailing_tests.empty()) return ::testing::AssertionSuccess();
+
+    // Prepare an assertion result used in the case that tests pass that were
+    // expected to fail.
+    ::testing::AssertionResult unexpected_successes =
+        ::testing::AssertionFailure();
+    unexpected_successes << "When testing type:\n    " << type_name_
+                         << "\n\nThe following tests passed when they were "
+                            "expected to fail:\n\n";
+
+    // List all of the tests that unexpectedly passed.
+    for (const auto& test_name : nonfailing_tests) {
+      unexpected_successes << "    " << test_name << "\n";
+    }
+
+    return unexpected_successes;
+  }
+
+ private:
+  void outputDivider() {
+    assertion_result_ << "========================================";
+  }
+
+  void addTestFailureImpl() {}
+
+  template <class H, class... T>
+  void addTestFailureImpl(const H& head, const T&... tail) {
+    assertion_result_ << head;
+    addTestFailureImpl(tail...);
+  }
+
+  ::testing::AssertionResult assertion_result_;
+  std::set<std::string> test_failures_;
+  std::set<std::string> test_successes_;
+  std::string type_name_;
+  bool has_error_ = false;
+};
+
+template <class T, class /*Enabler*/ = void>
+struct PropertiesOfImpl {};
+
+template <class T>
+struct PropertiesOfImpl<T, absl::void_t<typename T::properties>> {
+  using type = typename T::properties;
+};
+
+template <class T>
+struct PropertiesOfImpl<T, absl::void_t<typename T::profile_alias_of>> {
+  using type = typename PropertiesOfImpl<typename T::profile_alias_of>::type;
+};
+
+template <class T>
+struct PropertiesOf : PropertiesOfImpl<T> {};
+
+template <class T>
+using PropertiesOfT = typename PropertiesOf<T>::type;
+
+// NOTE: These enums use this naming convention to be consistent with the
+// standard trait names, which is useful since it allows us to match up each
+// enum name with a corresponding trait name in macro definitions.
+
+// An enum that describes the various expectations on an operations existence.
+enum class function_support { maybe, yes, nothrow, trivial };
+
+constexpr const char* PessimisticPropertyDescription(function_support v) {
+  return v == function_support::maybe
+             ? "no"
+             : v == function_support::yes
+                   ? "yes, potentially throwing"
+                   : v == function_support::nothrow ? "yes, nothrow"
+                                                    : "yes, trivial";
+}
+
+// Return a string that describes the kind of property support that was
+// expected.
+inline std::string ExpectedFunctionKindList(function_support min,
+                                            function_support max) {
+  if (min == max) {
+    std::string result =
+        absl::StrCat("Expected:\n  ",
+                     PessimisticPropertyDescription(
+                         static_cast<function_support>(UnderlyingValue(min))),
+                     "\n");
+    return result;
+  }
+
+  std::string result = "Expected one of:\n";
+  for (auto curr_support = UnderlyingValue(min);
+       curr_support <= UnderlyingValue(max); ++curr_support) {
+    absl::StrAppend(&result, "  ",
+                    PessimisticPropertyDescription(
+                        static_cast<function_support>(curr_support)),
+                    "\n");
+  }
+
+  return result;
+}
+
+template <class Enum>
+void ExpectModelOfImpl(ConformanceErrors* errors, Enum min_support,
+                       Enum max_support, Enum kind) {
+  const auto kind_value = UnderlyingValue(kind);
+  const auto min_support_value = UnderlyingValue(min_support);
+  const auto max_support_value = UnderlyingValue(max_support);
+
+  if (!(kind_value >= min_support_value && kind_value <= max_support_value)) {
+    errors->addTestFailure(
+        PropertyName(kind), "**Failed property expectation**\n\n",
+        ExpectedFunctionKindList(
+            static_cast<function_support>(min_support_value),
+            static_cast<function_support>(max_support_value)),
+        '\n', "Actual:\n  ",
+        PessimisticPropertyDescription(
+            static_cast<function_support>(kind_value)));
+  } else {
+    errors->addTestSuccess(PropertyName(kind));
+  }
+}
+
+#define ABSL_INTERNAL_SPECIAL_MEMBER_FUNCTION_ENUM(description, name) \
+  enum class name { maybe, yes, nothrow, trivial };                   \
+                                                                      \
+  constexpr const char* PropertyName(name v) { return description; }  \
+  static_assert(true, "")  // Force a semicolon when using this macro.
+
+ABSL_INTERNAL_SPECIAL_MEMBER_FUNCTION_ENUM("support for default construction",
+                                           default_constructible);
+ABSL_INTERNAL_SPECIAL_MEMBER_FUNCTION_ENUM("support for move construction",
+                                           move_constructible);
+ABSL_INTERNAL_SPECIAL_MEMBER_FUNCTION_ENUM("support for copy construction",
+                                           copy_constructible);
+ABSL_INTERNAL_SPECIAL_MEMBER_FUNCTION_ENUM("support for move assignment",
+                                           move_assignable);
+ABSL_INTERNAL_SPECIAL_MEMBER_FUNCTION_ENUM("support for copy assignment",
+                                           copy_assignable);
+ABSL_INTERNAL_SPECIAL_MEMBER_FUNCTION_ENUM("support for destruction",
+                                           destructible);
+
+#undef ABSL_INTERNAL_SPECIAL_MEMBER_FUNCTION_ENUM
+
+#define ABSL_INTERNAL_INTRINSIC_FUNCTION_ENUM(description, name)     \
+  enum class name { maybe, yes, nothrow };                           \
+                                                                     \
+  constexpr const char* PropertyName(name v) { return description; } \
+  static_assert(true, "")  // Force a semicolon when using this macro.
+
+ABSL_INTERNAL_INTRINSIC_FUNCTION_ENUM("support for ==", equality_comparable);
+ABSL_INTERNAL_INTRINSIC_FUNCTION_ENUM("support for !=", inequality_comparable);
+ABSL_INTERNAL_INTRINSIC_FUNCTION_ENUM("support for <", less_than_comparable);
+ABSL_INTERNAL_INTRINSIC_FUNCTION_ENUM("support for <=", less_equal_comparable);
+ABSL_INTERNAL_INTRINSIC_FUNCTION_ENUM("support for >=",
+                                      greater_equal_comparable);
+ABSL_INTERNAL_INTRINSIC_FUNCTION_ENUM("support for >", greater_than_comparable);
+
+ABSL_INTERNAL_INTRINSIC_FUNCTION_ENUM("support for swap", swappable);
+
+#undef ABSL_INTERNAL_INTRINSIC_FUNCTION_ENUM
+
+enum class hashable { maybe, yes };
+
+constexpr const char* PropertyName(hashable v) {
+  return "support for std::hash";
+}
+
+template <class T>
+using AlwaysFalse = std::false_type;
+
+#define ABSL_INTERNAL_PESSIMISTIC_MODEL_OF_SPECIAL_MEMBER(name, property)   \
+  template <class T>                                                        \
+  constexpr property property##_support_of() {                              \
+    return std::is_##property<T>::value                                     \
+               ? std::is_nothrow_##property<T>::value                       \
+                     ? absl::is_trivially_##property<T>::value              \
+                           ? property::trivial                              \
+                           : property::nothrow                              \
+                     : property::yes                                        \
+               : property::maybe;                                           \
+  }                                                                         \
+                                                                            \
+  template <class T, class MinProf, class MaxProf>                          \
+  void ExpectModelOf##name(ConformanceErrors* errors) {                     \
+    (ExpectModelOfImpl)(errors, PropertiesOfT<MinProf>::property##_support, \
+                        PropertiesOfT<MaxProf>::property##_support,         \
+                        property##_support_of<T>());                        \
+  }
+
+ABSL_INTERNAL_PESSIMISTIC_MODEL_OF_SPECIAL_MEMBER(DefaultConstructible,
+                                                  default_constructible);
+
+ABSL_INTERNAL_PESSIMISTIC_MODEL_OF_SPECIAL_MEMBER(MoveConstructible,
+                                                  move_constructible);
+
+ABSL_INTERNAL_PESSIMISTIC_MODEL_OF_SPECIAL_MEMBER(CopyConstructible,
+                                                  copy_constructible);
+
+ABSL_INTERNAL_PESSIMISTIC_MODEL_OF_SPECIAL_MEMBER(MoveAssignable,
+                                                  move_assignable);
+
+ABSL_INTERNAL_PESSIMISTIC_MODEL_OF_SPECIAL_MEMBER(CopyAssignable,
+                                                  copy_assignable);
+
+ABSL_INTERNAL_PESSIMISTIC_MODEL_OF_SPECIAL_MEMBER(Destructible, destructible);
+
+#undef ABSL_INTERNAL_PESSIMISTIC_MODEL_OF_SPECIAL_MEMBER
+
+void BoolFunction(bool) noexcept;
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// A metafunction for checking if an operation exists through SFINAE.
+//
+// `T` is the type to test and Op is an alias containing the expression to test.
+template <class T, template <class...> class Op, class = void>
+struct IsOpableImpl : std::false_type {};
+
+template <class T, template <class...> class Op>
+struct IsOpableImpl<T, Op, absl::void_t<Op<T>>> : std::true_type {};
+
+template <template <class...> class Op>
+struct IsOpable {
+  template <class T>
+  using apply = typename IsOpableImpl<T, Op>::type;
+};
+//
+////////////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// A metafunction for checking if an operation exists and is also noexcept
+// through SFINAE and the noexcept operator.
+///
+// `T` is the type to test and Op is an alias containing the expression to test.
+template <class T, template <class...> class Op, class = void>
+struct IsNothrowOpableImpl : std::false_type {};
+
+template <class T, template <class...> class Op>
+struct IsNothrowOpableImpl<T, Op, absl::enable_if_t<Op<T>::value>>
+    : std::true_type {};
+
+template <template <class...> class Op>
+struct IsNothrowOpable {
+  template <class T>
+  using apply = typename IsNothrowOpableImpl<T, Op>::type;
+};
+//
+////////////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// A macro that produces the necessary function for reporting what kind of
+// support a specific comparison operation has and a function for reporting an
+// error if a given type's support for that operation does not meet the expected
+// requirements.
+#define ABSL_INTERNAL_PESSIMISTIC_MODEL_OF_COMPARISON(name, property, op)      \
+  template <class T,                                                           \
+            class Result = std::integral_constant<                             \
+                bool, noexcept((BoolFunction)(std::declval<const T&>() op      \
+                                                  std::declval<const T&>()))>> \
+  using name = Result;                                                         \
+                                                                               \
+  template <class T>                                                           \
+  constexpr property property##_support_of() {                                 \
+    return IsOpable<name>::apply<T>::value                                     \
+               ? IsNothrowOpable<name>::apply<T>::value ? property::nothrow    \
+                                                        : property::yes        \
+               : property::maybe;                                              \
+  }                                                                            \
+                                                                               \
+  template <class T, class MinProf, class MaxProf>                             \
+  void ExpectModelOf##name(ConformanceErrors* errors) {                        \
+    (ExpectModelOfImpl)(errors, PropertiesOfT<MinProf>::property##_support,    \
+                        PropertiesOfT<MaxProf>::property##_support,            \
+                        property##_support_of<T>());                           \
+  }
+//
+////////////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// Generate the necessary support-checking and error reporting functions for
+// each of the comparison operators.
+ABSL_INTERNAL_PESSIMISTIC_MODEL_OF_COMPARISON(EqualityComparable,
+                                              equality_comparable, ==);
+
+ABSL_INTERNAL_PESSIMISTIC_MODEL_OF_COMPARISON(InequalityComparable,
+                                              inequality_comparable, !=);
+
+ABSL_INTERNAL_PESSIMISTIC_MODEL_OF_COMPARISON(LessThanComparable,
+                                              less_than_comparable, <);
+
+ABSL_INTERNAL_PESSIMISTIC_MODEL_OF_COMPARISON(LessEqualComparable,
+                                              less_equal_comparable, <=);
+
+ABSL_INTERNAL_PESSIMISTIC_MODEL_OF_COMPARISON(GreaterEqualComparable,
+                                              greater_equal_comparable, >=);
+
+ABSL_INTERNAL_PESSIMISTIC_MODEL_OF_COMPARISON(GreaterThanComparable,
+                                              greater_than_comparable, >);
+
+#undef ABSL_INTERNAL_PESSIMISTIC_MODEL_OF_COMPARISON
+//
+////////////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// The necessary support-checking and error-reporting functions for swap.
+template <class T>
+constexpr swappable swappable_support_of() {
+  return type_traits_internal::IsSwappable<T>::value
+             ? type_traits_internal::IsNothrowSwappable<T>::value
+                   ? swappable::nothrow
+                   : swappable::yes
+             : swappable::maybe;
+}
+
+template <class T, class MinProf, class MaxProf>
+void ExpectModelOfSwappable(ConformanceErrors* errors) {
+  (ExpectModelOfImpl)(errors, PropertiesOfT<MinProf>::swappable_support,
+                      PropertiesOfT<MaxProf>::swappable_support,
+                      swappable_support_of<T>());
+}
+//
+////////////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// The necessary support-checking and error-reporting functions for std::hash.
+template <class T>
+constexpr hashable hashable_support_of() {
+  return type_traits_internal::IsHashable<T>::value ? hashable::yes
+                                                    : hashable::maybe;
+}
+
+template <class T, class MinProf, class MaxProf>
+void ExpectModelOfHashable(ConformanceErrors* errors) {
+  (ExpectModelOfImpl)(errors, PropertiesOfT<MinProf>::hashable_support,
+                      PropertiesOfT<MaxProf>::hashable_support,
+                      hashable_support_of<T>());
+}
+//
+////////////////////////////////////////////////////////////////////////////////
+
+template <
+    default_constructible DefaultConstructibleValue =
+        default_constructible::maybe,
+    move_constructible MoveConstructibleValue = move_constructible::maybe,
+    copy_constructible CopyConstructibleValue = copy_constructible::maybe,
+    move_assignable MoveAssignableValue = move_assignable::maybe,
+    copy_assignable CopyAssignableValue = copy_assignable::maybe,
+    destructible DestructibleValue = destructible::maybe,
+    equality_comparable EqualityComparableValue = equality_comparable::maybe,
+    inequality_comparable InequalityComparableValue =
+        inequality_comparable::maybe,
+    less_than_comparable LessThanComparableValue = less_than_comparable::maybe,
+    less_equal_comparable LessEqualComparableValue =
+        less_equal_comparable::maybe,
+    greater_equal_comparable GreaterEqualComparableValue =
+        greater_equal_comparable::maybe,
+    greater_than_comparable GreaterThanComparableValue =
+        greater_than_comparable::maybe,
+    swappable SwappableValue = swappable::maybe,
+    hashable HashableValue = hashable::maybe>
+struct ConformanceProfile {
+  using properties = ConformanceProfile;
+
+  static constexpr default_constructible
+      default_constructible_support =  // NOLINT
+      DefaultConstructibleValue;
+
+  static constexpr move_constructible move_constructible_support =  // NOLINT
+      MoveConstructibleValue;
+
+  static constexpr copy_constructible copy_constructible_support =  // NOLINT
+      CopyConstructibleValue;
+
+  static constexpr move_assignable move_assignable_support =  // NOLINT
+      MoveAssignableValue;
+
+  static constexpr copy_assignable copy_assignable_support =  // NOLINT
+      CopyAssignableValue;
+
+  static constexpr destructible destructible_support =  // NOLINT
+      DestructibleValue;
+
+  static constexpr equality_comparable equality_comparable_support =  // NOLINT
+      EqualityComparableValue;
+
+  static constexpr inequality_comparable
+      inequality_comparable_support =  // NOLINT
+      InequalityComparableValue;
+
+  static constexpr less_than_comparable
+      less_than_comparable_support =  // NOLINT
+      LessThanComparableValue;
+
+  static constexpr less_equal_comparable
+      less_equal_comparable_support =  // NOLINT
+      LessEqualComparableValue;
+
+  static constexpr greater_equal_comparable
+      greater_equal_comparable_support =  // NOLINT
+      GreaterEqualComparableValue;
+
+  static constexpr greater_than_comparable
+      greater_than_comparable_support =  // NOLINT
+      GreaterThanComparableValue;
+
+  static constexpr swappable swappable_support = SwappableValue;  // NOLINT
+
+  static constexpr hashable hashable_support = HashableValue;  // NOLINT
+
+  static constexpr bool is_default_constructible =  // NOLINT
+      DefaultConstructibleValue != default_constructible::maybe;
+
+  static constexpr bool is_move_constructible =  // NOLINT
+      MoveConstructibleValue != move_constructible::maybe;
+
+  static constexpr bool is_copy_constructible =  // NOLINT
+      CopyConstructibleValue != copy_constructible::maybe;
+
+  static constexpr bool is_move_assignable =  // NOLINT
+      MoveAssignableValue != move_assignable::maybe;
+
+  static constexpr bool is_copy_assignable =  // NOLINT
+      CopyAssignableValue != copy_assignable::maybe;
+
+  static constexpr bool is_destructible =  // NOLINT
+      DestructibleValue != destructible::maybe;
+
+  static constexpr bool is_equality_comparable =  // NOLINT
+      EqualityComparableValue != equality_comparable::maybe;
+
+  static constexpr bool is_inequality_comparable =  // NOLINT
+      InequalityComparableValue != inequality_comparable::maybe;
+
+  static constexpr bool is_less_than_comparable =  // NOLINT
+      LessThanComparableValue != less_than_comparable::maybe;
+
+  static constexpr bool is_less_equal_comparable =  // NOLINT
+      LessEqualComparableValue != less_equal_comparable::maybe;
+
+  static constexpr bool is_greater_equal_comparable =  // NOLINT
+      GreaterEqualComparableValue != greater_equal_comparable::maybe;
+
+  static constexpr bool is_greater_than_comparable =  // NOLINT
+      GreaterThanComparableValue != greater_than_comparable::maybe;
+
+  static constexpr bool is_swappable =  // NOLINT
+      SwappableValue != swappable::maybe;
+
+  static constexpr bool is_hashable =  // NOLINT
+      HashableValue != hashable::maybe;
+};
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// Compliant SFINAE-friendliness is not always present on the standard library
+// implementations that we support. This helper-struct (and associated enum) is
+// used as a means to conditionally check the hashability support of a type.
+enum class CheckHashability { no, yes };
+
+template <class T, CheckHashability ShouldCheckHashability>
+struct conservative_hashable_support_of;
+
+template <class T>
+struct conservative_hashable_support_of<T, CheckHashability::no> {
+  static constexpr hashable Invoke() { return hashable::maybe; }
+};
+
+template <class T>
+struct conservative_hashable_support_of<T, CheckHashability::yes> {
+  static constexpr hashable Invoke() { return hashable_support_of<T>(); }
+};
+//
+////////////////////////////////////////////////////////////////////////////////
+
+// The ConformanceProfile that is expected based on introspection into the type
+// by way of trait checks.
+template <class T, CheckHashability ShouldCheckHashability>
+struct SyntacticConformanceProfileOf {
+  using properties = ConformanceProfile<
+      default_constructible_support_of<T>(), move_constructible_support_of<T>(),
+      copy_constructible_support_of<T>(), move_assignable_support_of<T>(),
+      copy_assignable_support_of<T>(), destructible_support_of<T>(),
+      equality_comparable_support_of<T>(),
+      inequality_comparable_support_of<T>(),
+      less_than_comparable_support_of<T>(),
+      less_equal_comparable_support_of<T>(),
+      greater_equal_comparable_support_of<T>(),
+      greater_than_comparable_support_of<T>(), swappable_support_of<T>(),
+      conservative_hashable_support_of<T, ShouldCheckHashability>::Invoke()>;
+};
+
+#define ABSL_INTERNAL_CONFORMANCE_TESTING_DATA_MEMBER_DEF_IMPL(type, name)     \
+  template <default_constructible DefaultConstructibleValue,                   \
+            move_constructible MoveConstructibleValue,                         \
+            copy_constructible CopyConstructibleValue,                         \
+            move_assignable MoveAssignableValue,                               \
+            copy_assignable CopyAssignableValue,                               \
+            destructible DestructibleValue,                                    \
+            equality_comparable EqualityComparableValue,                       \
+            inequality_comparable InequalityComparableValue,                   \
+            less_than_comparable LessThanComparableValue,                      \
+            less_equal_comparable LessEqualComparableValue,                    \
+            greater_equal_comparable GreaterEqualComparableValue,              \
+            greater_than_comparable GreaterThanComparableValue,                \
+            swappable SwappableValue, hashable HashableValue>                  \
+  constexpr type ConformanceProfile<                                           \
+      DefaultConstructibleValue, MoveConstructibleValue,                       \
+      CopyConstructibleValue, MoveAssignableValue, CopyAssignableValue,        \
+      DestructibleValue, EqualityComparableValue, InequalityComparableValue,   \
+      LessThanComparableValue, LessEqualComparableValue,                       \
+      GreaterEqualComparableValue, GreaterThanComparableValue, SwappableValue, \
+      HashableValue>::name
+
+#define ABSL_INTERNAL_CONFORMANCE_TESTING_DATA_MEMBER_DEF(type)           \
+  ABSL_INTERNAL_CONFORMANCE_TESTING_DATA_MEMBER_DEF_IMPL(type,            \
+                                                         type##_support); \
+  ABSL_INTERNAL_CONFORMANCE_TESTING_DATA_MEMBER_DEF_IMPL(bool, is_##type)
+
+ABSL_INTERNAL_CONFORMANCE_TESTING_DATA_MEMBER_DEF(default_constructible);
+ABSL_INTERNAL_CONFORMANCE_TESTING_DATA_MEMBER_DEF(move_constructible);
+ABSL_INTERNAL_CONFORMANCE_TESTING_DATA_MEMBER_DEF(copy_constructible);
+ABSL_INTERNAL_CONFORMANCE_TESTING_DATA_MEMBER_DEF(move_assignable);
+ABSL_INTERNAL_CONFORMANCE_TESTING_DATA_MEMBER_DEF(copy_assignable);
+ABSL_INTERNAL_CONFORMANCE_TESTING_DATA_MEMBER_DEF(destructible);
+ABSL_INTERNAL_CONFORMANCE_TESTING_DATA_MEMBER_DEF(equality_comparable);
+ABSL_INTERNAL_CONFORMANCE_TESTING_DATA_MEMBER_DEF(inequality_comparable);
+ABSL_INTERNAL_CONFORMANCE_TESTING_DATA_MEMBER_DEF(less_than_comparable);
+ABSL_INTERNAL_CONFORMANCE_TESTING_DATA_MEMBER_DEF(less_equal_comparable);
+ABSL_INTERNAL_CONFORMANCE_TESTING_DATA_MEMBER_DEF(greater_equal_comparable);
+ABSL_INTERNAL_CONFORMANCE_TESTING_DATA_MEMBER_DEF(greater_than_comparable);
+ABSL_INTERNAL_CONFORMANCE_TESTING_DATA_MEMBER_DEF(swappable);
+ABSL_INTERNAL_CONFORMANCE_TESTING_DATA_MEMBER_DEF(hashable);
+
+#undef ABSL_INTERNAL_CONFORMANCE_TESTING_DATA_MEMBER_DEF
+#undef ABSL_INTERNAL_CONFORMANCE_TESTING_DATA_MEMBER_DEF_IMPL
+
+// Retrieve the enum with the minimum underlying value.
+// Note: std::min is not constexpr in C++11, which is why this is necessary.
+template <class H>
+constexpr H MinEnum(H head) {
+  return head;
+}
+
+template <class H, class N, class... T>
+constexpr H MinEnum(H head, N next, T... tail) {
+  return (UnderlyingValue)(head) < (UnderlyingValue)(next)
+             ? (MinEnum)(head, tail...)
+             : (MinEnum)(next, tail...);
+}
+
+template <class... Profs>
+struct MinimalProfiles {
+  static constexpr default_constructible
+      default_constructible_support =  // NOLINT
+      (MinEnum)(PropertiesOfT<Profs>::default_constructible_support...);
+
+  static constexpr move_constructible move_constructible_support =  // NOLINT
+      (MinEnum)(PropertiesOfT<Profs>::move_constructible_support...);
+
+  static constexpr copy_constructible copy_constructible_support =  // NOLINT
+      (MinEnum)(PropertiesOfT<Profs>::copy_constructible_support...);
+
+  static constexpr move_assignable move_assignable_support =  // NOLINT
+      (MinEnum)(PropertiesOfT<Profs>::move_assignable_support...);
+
+  static constexpr copy_assignable copy_assignable_support =  // NOLINT
+      (MinEnum)(PropertiesOfT<Profs>::copy_assignable_support...);
+
+  static constexpr destructible destructible_support =  // NOLINT
+      (MinEnum)(PropertiesOfT<Profs>::destructible_support...);
+
+  static constexpr equality_comparable equality_comparable_support =  // NOLINT
+      (MinEnum)(PropertiesOfT<Profs>::equality_comparable_support...);
+
+  static constexpr inequality_comparable
+      inequality_comparable_support =  // NOLINT
+      (MinEnum)(PropertiesOfT<Profs>::inequality_comparable_support...);
+
+  static constexpr less_than_comparable
+      less_than_comparable_support =  // NOLINT
+      (MinEnum)(PropertiesOfT<Profs>::less_than_comparable_support...);
+
+  static constexpr less_equal_comparable
+      less_equal_comparable_support =  // NOLINT
+      (MinEnum)(PropertiesOfT<Profs>::less_equal_comparable_support...);
+
+  static constexpr greater_equal_comparable
+      greater_equal_comparable_support =  // NOLINT
+      (MinEnum)(PropertiesOfT<Profs>::greater_equal_comparable_support...);
+
+  static constexpr greater_than_comparable
+      greater_than_comparable_support =  // NOLINT
+      (MinEnum)(PropertiesOfT<Profs>::greater_than_comparable_support...);
+
+  static constexpr swappable swappable_support =  // NOLINT
+      (MinEnum)(PropertiesOfT<Profs>::swappable_support...);
+
+  static constexpr hashable hashable_support =  // NOLINT
+      (MinEnum)(PropertiesOfT<Profs>::hashable_support...);
+
+  using properties = ConformanceProfile<
+      default_constructible_support, move_constructible_support,
+      copy_constructible_support, move_assignable_support,
+      copy_assignable_support, destructible_support,
+      equality_comparable_support, inequality_comparable_support,
+      less_than_comparable_support, less_equal_comparable_support,
+      greater_equal_comparable_support, greater_than_comparable_support,
+      swappable_support, hashable_support>;
+};
+
+// Retrieve the enum with the greatest underlying value.
+// Note: std::max is not constexpr in C++11, which is why this is necessary.
+template <class H>
+constexpr H MaxEnum(H head) {
+  return head;
+}
+
+template <class H, class N, class... T>
+constexpr H MaxEnum(H head, N next, T... tail) {
+  return (UnderlyingValue)(next) < (UnderlyingValue)(head)
+             ? (MaxEnum)(head, tail...)
+             : (MaxEnum)(next, tail...);
+}
+
+template <class... Profs>
+struct CombineProfilesImpl {
+  static constexpr default_constructible
+      default_constructible_support =  // NOLINT
+      (MaxEnum)(PropertiesOfT<Profs>::default_constructible_support...);
+
+  static constexpr move_constructible move_constructible_support =  // NOLINT
+      (MaxEnum)(PropertiesOfT<Profs>::move_constructible_support...);
+
+  static constexpr copy_constructible copy_constructible_support =  // NOLINT
+      (MaxEnum)(PropertiesOfT<Profs>::copy_constructible_support...);
+
+  static constexpr move_assignable move_assignable_support =  // NOLINT
+      (MaxEnum)(PropertiesOfT<Profs>::move_assignable_support...);
+
+  static constexpr copy_assignable copy_assignable_support =  // NOLINT
+      (MaxEnum)(PropertiesOfT<Profs>::copy_assignable_support...);
+
+  static constexpr destructible destructible_support =  // NOLINT
+      (MaxEnum)(PropertiesOfT<Profs>::destructible_support...);
+
+  static constexpr equality_comparable equality_comparable_support =  // NOLINT
+      (MaxEnum)(PropertiesOfT<Profs>::equality_comparable_support...);
+
+  static constexpr inequality_comparable
+      inequality_comparable_support =  // NOLINT
+      (MaxEnum)(PropertiesOfT<Profs>::inequality_comparable_support...);
+
+  static constexpr less_than_comparable
+      less_than_comparable_support =  // NOLINT
+      (MaxEnum)(PropertiesOfT<Profs>::less_than_comparable_support...);
+
+  static constexpr less_equal_comparable
+      less_equal_comparable_support =  // NOLINT
+      (MaxEnum)(PropertiesOfT<Profs>::less_equal_comparable_support...);
+
+  static constexpr greater_equal_comparable
+      greater_equal_comparable_support =  // NOLINT
+      (MaxEnum)(PropertiesOfT<Profs>::greater_equal_comparable_support...);
+
+  static constexpr greater_than_comparable
+      greater_than_comparable_support =  // NOLINT
+      (MaxEnum)(PropertiesOfT<Profs>::greater_than_comparable_support...);
+
+  static constexpr swappable swappable_support =  // NOLINT
+      (MaxEnum)(PropertiesOfT<Profs>::swappable_support...);
+
+  static constexpr hashable hashable_support =  // NOLINT
+      (MaxEnum)(PropertiesOfT<Profs>::hashable_support...);
+
+  using properties = ConformanceProfile<
+      default_constructible_support, move_constructible_support,
+      copy_constructible_support, move_assignable_support,
+      copy_assignable_support, destructible_support,
+      equality_comparable_support, inequality_comparable_support,
+      less_than_comparable_support, less_equal_comparable_support,
+      greater_equal_comparable_support, greater_than_comparable_support,
+      swappable_support, hashable_support>;
+};
+
+// NOTE: We use this as opposed to a direct alias of CombineProfilesImpl so that
+// when named aliases of CombineProfiles are created (such as in
+// conformance_aliases.h), we only pay for the combination algorithm on the
+// profiles that are actually used.
+template <class... Profs>
+struct CombineProfiles {
+  using profile_alias_of = CombineProfilesImpl<Profs...>;
+};
+
+template <>
+struct CombineProfiles<> {
+  using properties = ConformanceProfile<>;
+};
+
+template <class Profile, class Tag>
+struct StrongProfileTypedef {
+  using properties = PropertiesOfT<Profile>;
+};
+
+template <class T, class /*Enabler*/ = void>
+struct IsProfileImpl : std::false_type {};
+
+template <class T>
+struct IsProfileImpl<T, absl::void_t<PropertiesOfT<T>>> : std::true_type {};
+
+template <class T>
+struct IsProfile : IsProfileImpl<T>::type {};
+
+// A tag that describes which set of properties we will check when the user
+// requires a strict match in conformance (as opposed to a loose match which
+// allows more-refined support of any given operation).
+//
+// Currently only the RegularityDomain exists and it includes all operations
+// that the conformance testing suite knows about. The intent is that if the
+// suite is expanded to support extension, such as for checking conformance of
+// concepts like Iterators or Containers, additional corresponding domains can
+// be created.
+struct RegularityDomain {};
+
+}  // namespace types_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#endif  // ABSL_TYPES_INTERNAL_CONFORMANCE_PROFILE_H_
diff --git a/src/absl/types/internal/conformance_testing_helpers.h b/src/absl/types/internal/conformance_testing_helpers.h
new file mode 100644 (file)
index 0000000..00775f9
--- /dev/null
@@ -0,0 +1,391 @@
+// Copyright 2019 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef ABSL_TYPES_INTERNAL_CONFORMANCE_TESTING_HELPERS_H_
+#define ABSL_TYPES_INTERNAL_CONFORMANCE_TESTING_HELPERS_H_
+
+// Checks to determine whether or not we can use abi::__cxa_demangle
+#if (defined(__ANDROID__) || defined(ANDROID)) && !defined(OS_ANDROID)
+#define ABSL_INTERNAL_OS_ANDROID
+#endif
+
+// We support certain compilers only.  See demangle.h for details.
+#if defined(OS_ANDROID) && (defined(__i386__) || defined(__x86_64__))
+#define ABSL_TYPES_INTERNAL_HAS_CXA_DEMANGLE 0
+#elif (__GNUC__ >= 4 || (__GNUC__ >= 3 && __GNUC_MINOR__ >= 4)) && \
+    !defined(__mips__)
+#define ABSL_TYPES_INTERNAL_HAS_CXA_DEMANGLE 1
+#elif defined(__clang__) && !defined(_MSC_VER)
+#define ABSL_TYPES_INTERNAL_HAS_CXA_DEMANGLE 1
+#else
+#define ABSL_TYPES_INTERNAL_HAS_CXA_DEMANGLE 0
+#endif
+
+#include <tuple>
+#include <type_traits>
+#include <utility>
+
+#include "absl/meta/type_traits.h"
+#include "absl/strings/string_view.h"
+#include "absl/utility/utility.h"
+
+#if ABSL_TYPES_INTERNAL_HAS_CXA_DEMANGLE
+#include <cxxabi.h>
+
+#include <cstdlib>
+#endif
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace types_internal {
+
+// Return a readable name for type T.
+template <class T>
+absl::string_view NameOfImpl() {
+// TODO(calabrese) Investigate using debugging:internal_demangle as a fallback.
+#if ABSL_TYPES_INTERNAL_HAS_CXA_DEMANGLE
+  int status = 0;
+  char* demangled_name = nullptr;
+
+  demangled_name =
+      abi::__cxa_demangle(typeid(T).name(), nullptr, nullptr, &status);
+
+  if (status == 0 && demangled_name != nullptr) {
+    return demangled_name;
+  } else {
+    return typeid(T).name();
+  }
+#else
+  return typeid(T).name();
+#endif
+  // NOTE: We intentionally leak demangled_name so that it remains valid
+  // throughout the remainder of the program.
+}
+
+// Given a type, returns as nice of a type name as we can produce (demangled).
+//
+// Note: This currently strips cv-qualifiers and references, but that is okay
+// because we only use this internally with unqualified object types.
+template <class T>
+std::string NameOf() {
+  static const absl::string_view result = NameOfImpl<T>();
+  return std::string(result);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// Metafunction to check if a type is callable with no explicit arguments
+template <class Fun, class /*Enabler*/ = void>
+struct IsNullaryCallableImpl : std::false_type {};
+
+template <class Fun>
+struct IsNullaryCallableImpl<
+    Fun, absl::void_t<decltype(std::declval<const Fun&>()())>>
+    : std::true_type {
+  using result_type = decltype(std::declval<const Fun&>()());
+
+  template <class ValueType>
+  using for_type = std::is_same<ValueType, result_type>;
+
+  using void_if_true = void;
+};
+
+template <class Fun>
+struct IsNullaryCallable : IsNullaryCallableImpl<Fun> {};
+//
+////////////////////////////////////////////////////////////////////////////////
+
+// A type that contains a function object that returns an instance of a type
+// that is undergoing conformance testing. This function is required to always
+// return the same value upon invocation.
+template <class Fun>
+struct GeneratorType;
+
+// A type that contains a tuple of GeneratorType<Fun> where each Fun has the
+// same return type. The result of each of the different generators should all
+// be equal values, though the underlying object representation may differ (such
+// as if one returns 0.0 and another return -0.0, or if one returns an empty
+// vector and another returns an empty vector with a different capacity.
+template <class... Funs>
+struct EquivalenceClassType;
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// A metafunction to check if a type is a specialization of EquivalenceClassType
+template <class T>
+struct IsEquivalenceClass : std::false_type {};
+
+template <>
+struct IsEquivalenceClass<EquivalenceClassType<>> : std::true_type {
+  using self = IsEquivalenceClass;
+
+  // A metafunction to check if this EquivalenceClassType is a valid
+  // EquivalenceClassType for a type `ValueType` that is undergoing testing
+  template <class ValueType>
+  using for_type = std::true_type;
+};
+
+template <class Head, class... Tail>
+struct IsEquivalenceClass<EquivalenceClassType<Head, Tail...>>
+    : std::true_type {
+  using self = IsEquivalenceClass;
+
+  // The type undergoing conformance testing that this EquivalenceClass
+  // corresponds to
+  using result_type = typename IsNullaryCallable<Head>::result_type;
+
+  // A metafunction to check if this EquivalenceClassType is a valid
+  // EquivalenceClassType for a type `ValueType` that is undergoing testing
+  template <class ValueType>
+  using for_type = std::is_same<ValueType, result_type>;
+};
+//
+////////////////////////////////////////////////////////////////////////////////
+
+// A type that contains an ordered series of EquivalenceClassTypes, where the
+// the function object of each underlying GeneratorType has the same return type
+//
+// These equivalence classes are required to be in a logical ascending order
+// that is consistent with comparison operators that are defined for the return
+// type of each GeneratorType, if any.
+template <class... EqClasses>
+struct OrderedEquivalenceClasses;
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// A metafunction to determine the return type of the function object contained
+// in a GeneratorType specialization.
+template <class T>
+struct ResultOfGenerator {};
+
+template <class Fun>
+struct ResultOfGenerator<GeneratorType<Fun>> {
+  using type = decltype(std::declval<const Fun&>()());
+};
+
+template <class Fun>
+using ResultOfGeneratorT = typename ResultOfGenerator<GeneratorType<Fun>>::type;
+//
+////////////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// A metafunction that yields true iff each of Funs is a GeneratorType
+// specialization and they all contain functions with the same return type
+template <class /*Enabler*/, class... Funs>
+struct AreGeneratorsWithTheSameReturnTypeImpl : std::false_type {};
+
+template <>
+struct AreGeneratorsWithTheSameReturnTypeImpl<void> : std::true_type {};
+
+template <class Head, class... Tail>
+struct AreGeneratorsWithTheSameReturnTypeImpl<
+    typename std::enable_if<absl::conjunction<std::is_same<
+        ResultOfGeneratorT<Head>, ResultOfGeneratorT<Tail>>...>::value>::type,
+    Head, Tail...> : std::true_type {};
+
+template <class... Funs>
+struct AreGeneratorsWithTheSameReturnType
+    : AreGeneratorsWithTheSameReturnTypeImpl<void, Funs...>::type {};
+//
+////////////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// A metafunction that yields true iff each of Funs is an EquivalenceClassType
+// specialization and they all contain GeneratorType specializations that have
+// the same return type
+template <class... EqClasses>
+struct AreEquivalenceClassesOfTheSameType {
+  static_assert(sizeof...(EqClasses) != sizeof...(EqClasses), "");
+};
+
+template <>
+struct AreEquivalenceClassesOfTheSameType<> : std::true_type {
+  using self = AreEquivalenceClassesOfTheSameType;
+
+  // Metafunction to check that a type is the same as all of the equivalence
+  // classes, if any.
+  // Note: In this specialization there are no equivalence classes, so the
+  // value type is always compatible.
+  template <class /*ValueType*/>
+  using for_type = std::true_type;
+};
+
+template <class... Funs>
+struct AreEquivalenceClassesOfTheSameType<EquivalenceClassType<Funs...>>
+    : std::true_type {
+  using self = AreEquivalenceClassesOfTheSameType;
+
+  // Metafunction to check that a type is the same as all of the equivalence
+  // classes, if any.
+  template <class ValueType>
+  using for_type = typename IsEquivalenceClass<
+      EquivalenceClassType<Funs...>>::template for_type<ValueType>;
+};
+
+template <class... TailEqClasses>
+struct AreEquivalenceClassesOfTheSameType<
+    EquivalenceClassType<>, EquivalenceClassType<>, TailEqClasses...>
+    : AreEquivalenceClassesOfTheSameType<TailEqClasses...>::self {};
+
+template <class HeadNextFun, class... TailNextFuns, class... TailEqClasses>
+struct AreEquivalenceClassesOfTheSameType<
+    EquivalenceClassType<>, EquivalenceClassType<HeadNextFun, TailNextFuns...>,
+    TailEqClasses...>
+    : AreEquivalenceClassesOfTheSameType<
+          EquivalenceClassType<HeadNextFun, TailNextFuns...>,
+          TailEqClasses...>::self {};
+
+template <class HeadHeadFun, class... TailHeadFuns, class... TailEqClasses>
+struct AreEquivalenceClassesOfTheSameType<
+    EquivalenceClassType<HeadHeadFun, TailHeadFuns...>, EquivalenceClassType<>,
+    TailEqClasses...>
+    : AreEquivalenceClassesOfTheSameType<
+          EquivalenceClassType<HeadHeadFun, TailHeadFuns...>,
+          TailEqClasses...>::self {};
+
+template <class HeadHeadFun, class... TailHeadFuns, class HeadNextFun,
+          class... TailNextFuns, class... TailEqClasses>
+struct AreEquivalenceClassesOfTheSameType<
+    EquivalenceClassType<HeadHeadFun, TailHeadFuns...>,
+    EquivalenceClassType<HeadNextFun, TailNextFuns...>, TailEqClasses...>
+    : absl::conditional_t<
+          IsNullaryCallable<HeadNextFun>::template for_type<
+              typename IsNullaryCallable<HeadHeadFun>::result_type>::value,
+          AreEquivalenceClassesOfTheSameType<
+              EquivalenceClassType<HeadHeadFun, TailHeadFuns...>,
+              TailEqClasses...>,
+          std::false_type> {};
+//
+////////////////////////////////////////////////////////////////////////////////
+
+// Execute a function for each passed-in parameter.
+template <class Fun, class... Cases>
+void ForEachParameter(const Fun& fun, const Cases&... cases) {
+  const std::initializer_list<bool> results = {
+      (static_cast<void>(fun(cases)), true)...};
+
+  (void)results;
+}
+
+// Execute a function on each passed-in parameter (using a bound function).
+template <class Fun>
+struct ForEachParameterFun {
+  template <class... T>
+  void operator()(const T&... cases) const {
+    (ForEachParameter)(fun, cases...);
+  }
+
+  Fun fun;
+};
+
+// Execute a function on each element of a tuple.
+template <class Fun, class Tup>
+void ForEachTupleElement(const Fun& fun, const Tup& tup) {
+  absl::apply(ForEachParameterFun<Fun>{fun}, tup);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// Execute a function for each combination of two elements of a tuple, including
+// combinations of an element with itself.
+template <class Fun, class... T>
+struct ForEveryTwoImpl {
+  template <class Lhs>
+  struct WithBoundLhs {
+    template <class Rhs>
+    void operator()(const Rhs& rhs) const {
+      fun(lhs, rhs);
+    }
+
+    Fun fun;
+    Lhs lhs;
+  };
+
+  template <class Lhs>
+  void operator()(const Lhs& lhs) const {
+    (ForEachTupleElement)(WithBoundLhs<Lhs>{fun, lhs}, args);
+  }
+
+  Fun fun;
+  std::tuple<T...> args;
+};
+
+template <class Fun, class... T>
+void ForEveryTwo(const Fun& fun, std::tuple<T...> args) {
+  (ForEachTupleElement)(ForEveryTwoImpl<Fun, T...>{fun, args}, args);
+}
+//
+////////////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// Insert all values into an associative container
+template<class Container>
+void InsertEach(Container* cont) {
+}
+
+template<class Container, class H, class... T>
+void InsertEach(Container* cont, H&& head, T&&... tail) {
+  cont->insert(head);
+  (InsertEach)(cont, tail...);
+}
+//
+////////////////////////////////////////////////////////////////////////////////
+// A template with a nested "Invoke" static-member-function that executes a
+// passed-in Callable when `Condition` is true, otherwise it ignores the
+// Callable. This is useful for executing a function object with a condition
+// that corresponds to whether or not the Callable can be safely instantiated.
+// It has some overlapping uses with C++17 `if constexpr`.
+template <bool Condition>
+struct If;
+
+template <>
+struct If</*Condition =*/false> {
+  template <class Fun, class... P>
+  static void Invoke(const Fun& /*fun*/, P&&... /*args*/) {}
+};
+
+template <>
+struct If</*Condition =*/true> {
+  template <class Fun, class... P>
+  static void Invoke(const Fun& fun, P&&... args) {
+    // TODO(calabrese) Use std::invoke equivalent instead of function-call.
+    fun(absl::forward<P>(args)...);
+  }
+};
+
+//
+// ABSL_INTERNAL_STRINGIZE(...)
+//
+// This variadic macro transforms its arguments into a c-string literal after
+// expansion.
+//
+// Example:
+//
+//   ABSL_INTERNAL_STRINGIZE(std::array<int, 10>)
+//
+// Results in:
+//
+//   "std::array<int, 10>"
+#define ABSL_INTERNAL_STRINGIZE(...) ABSL_INTERNAL_STRINGIZE_IMPL((__VA_ARGS__))
+#define ABSL_INTERNAL_STRINGIZE_IMPL(arg) ABSL_INTERNAL_STRINGIZE_IMPL2 arg
+#define ABSL_INTERNAL_STRINGIZE_IMPL2(...) #__VA_ARGS__
+
+}  // namespace types_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#endif  // ABSL_TYPES_INTERNAL_CONFORMANCE_TESTING_HELPERS_H_
diff --git a/src/absl/types/internal/optional.h b/src/absl/types/internal/optional.h
new file mode 100644 (file)
index 0000000..92932b6
--- /dev/null
@@ -0,0 +1,396 @@
+// Copyright 2017 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+#ifndef ABSL_TYPES_INTERNAL_OPTIONAL_H_
+#define ABSL_TYPES_INTERNAL_OPTIONAL_H_
+
+#include <functional>
+#include <new>
+#include <type_traits>
+#include <utility>
+
+#include "absl/base/internal/inline_variable.h"
+#include "absl/memory/memory.h"
+#include "absl/meta/type_traits.h"
+#include "absl/utility/utility.h"
+
+// ABSL_OPTIONAL_USE_INHERITING_CONSTRUCTORS
+//
+// Inheriting constructors is supported in GCC 4.8+, Clang 3.3+ and MSVC 2015.
+// __cpp_inheriting_constructors is a predefined macro and a recommended way to
+// check for this language feature, but GCC doesn't support it until 5.0 and
+// Clang doesn't support it until 3.6.
+// Also, MSVC 2015 has a bug: it doesn't inherit the constexpr template
+// constructor. For example, the following code won't work on MSVC 2015 Update3:
+// struct Base {
+//   int t;
+//   template <typename T>
+//   constexpr Base(T t_) : t(t_) {}
+// };
+// struct Foo : Base {
+//   using Base::Base;
+// }
+// constexpr Foo foo(0);  // doesn't work on MSVC 2015
+#if defined(__clang__)
+#if __has_feature(cxx_inheriting_constructors)
+#define ABSL_OPTIONAL_USE_INHERITING_CONSTRUCTORS 1
+#endif
+#elif (defined(__GNUC__) &&                                       \
+       (__GNUC__ > 4 || __GNUC__ == 4 && __GNUC_MINOR__ >= 8)) || \
+    (__cpp_inheriting_constructors >= 200802) ||                  \
+    (defined(_MSC_VER) && _MSC_VER >= 1910)
+#define ABSL_OPTIONAL_USE_INHERITING_CONSTRUCTORS 1
+#endif
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+
+// Forward declaration
+template <typename T>
+class optional;
+
+namespace optional_internal {
+
+// This tag type is used as a constructor parameter type for `nullopt_t`.
+struct init_t {
+  explicit init_t() = default;
+};
+
+struct empty_struct {};
+
+// This class stores the data in optional<T>.
+// It is specialized based on whether T is trivially destructible.
+// This is the specialization for non trivially destructible type.
+template <typename T, bool unused = std::is_trivially_destructible<T>::value>
+class optional_data_dtor_base {
+  struct dummy_type {
+    static_assert(sizeof(T) % sizeof(empty_struct) == 0, "");
+    // Use an array to avoid GCC 6 placement-new warning.
+    empty_struct data[sizeof(T) / sizeof(empty_struct)];
+  };
+
+ protected:
+  // Whether there is data or not.
+  bool engaged_;
+  // Data storage
+  union {
+    T data_;
+    dummy_type dummy_;
+  };
+
+  void destruct() noexcept {
+    if (engaged_) {
+      data_.~T();
+      engaged_ = false;
+    }
+  }
+
+  // dummy_ must be initialized for constexpr constructor.
+  constexpr optional_data_dtor_base() noexcept : engaged_(false), dummy_{{}} {}
+
+  template <typename... Args>
+  constexpr explicit optional_data_dtor_base(in_place_t, Args&&... args)
+      : engaged_(true), data_(absl::forward<Args>(args)...) {}
+
+  ~optional_data_dtor_base() { destruct(); }
+};
+
+// Specialization for trivially destructible type.
+template <typename T>
+class optional_data_dtor_base<T, true> {
+  struct dummy_type {
+    static_assert(sizeof(T) % sizeof(empty_struct) == 0, "");
+    // Use array to avoid GCC 6 placement-new warning.
+    empty_struct data[sizeof(T) / sizeof(empty_struct)];
+  };
+
+ protected:
+  // Whether there is data or not.
+  bool engaged_;
+  // Data storage
+  union {
+    T data_;
+    dummy_type dummy_;
+  };
+  void destruct() noexcept { engaged_ = false; }
+
+  // dummy_ must be initialized for constexpr constructor.
+  constexpr optional_data_dtor_base() noexcept : engaged_(false), dummy_{{}} {}
+
+  template <typename... Args>
+  constexpr explicit optional_data_dtor_base(in_place_t, Args&&... args)
+      : engaged_(true), data_(absl::forward<Args>(args)...) {}
+};
+
+template <typename T>
+class optional_data_base : public optional_data_dtor_base<T> {
+ protected:
+  using base = optional_data_dtor_base<T>;
+#ifdef ABSL_OPTIONAL_USE_INHERITING_CONSTRUCTORS
+  using base::base;
+#else
+  optional_data_base() = default;
+
+  template <typename... Args>
+  constexpr explicit optional_data_base(in_place_t t, Args&&... args)
+      : base(t, absl::forward<Args>(args)...) {}
+#endif
+
+  template <typename... Args>
+  void construct(Args&&... args) {
+    // Use dummy_'s address to work around casting cv-qualified T* to void*.
+    ::new (static_cast<void*>(&this->dummy_)) T(std::forward<Args>(args)...);
+    this->engaged_ = true;
+  }
+
+  template <typename U>
+  void assign(U&& u) {
+    if (this->engaged_) {
+      this->data_ = std::forward<U>(u);
+    } else {
+      construct(std::forward<U>(u));
+    }
+  }
+};
+
+// TODO(absl-team): Add another class using
+// std::is_trivially_move_constructible trait when available to match
+// http://cplusplus.github.io/LWG/lwg-defects.html#2900, for types that
+// have trivial move but nontrivial copy.
+// Also, we should be checking is_trivially_copyable here, which is not
+// supported now, so we use is_trivially_* traits instead.
+template <typename T,
+          bool unused = absl::is_trivially_copy_constructible<T>::value&&
+              absl::is_trivially_copy_assignable<typename std::remove_cv<
+                  T>::type>::value&& std::is_trivially_destructible<T>::value>
+class optional_data;
+
+// Trivially copyable types
+template <typename T>
+class optional_data<T, true> : public optional_data_base<T> {
+ protected:
+#ifdef ABSL_OPTIONAL_USE_INHERITING_CONSTRUCTORS
+  using optional_data_base<T>::optional_data_base;
+#else
+  optional_data() = default;
+
+  template <typename... Args>
+  constexpr explicit optional_data(in_place_t t, Args&&... args)
+      : optional_data_base<T>(t, absl::forward<Args>(args)...) {}
+#endif
+};
+
+template <typename T>
+class optional_data<T, false> : public optional_data_base<T> {
+ protected:
+#ifdef ABSL_OPTIONAL_USE_INHERITING_CONSTRUCTORS
+  using optional_data_base<T>::optional_data_base;
+#else
+  template <typename... Args>
+  constexpr explicit optional_data(in_place_t t, Args&&... args)
+      : optional_data_base<T>(t, absl::forward<Args>(args)...) {}
+#endif
+
+  optional_data() = default;
+
+  optional_data(const optional_data& rhs) : optional_data_base<T>() {
+    if (rhs.engaged_) {
+      this->construct(rhs.data_);
+    }
+  }
+
+  optional_data(optional_data&& rhs) noexcept(
+      absl::default_allocator_is_nothrow::value ||
+      std::is_nothrow_move_constructible<T>::value)
+      : optional_data_base<T>() {
+    if (rhs.engaged_) {
+      this->construct(std::move(rhs.data_));
+    }
+  }
+
+  optional_data& operator=(const optional_data& rhs) {
+    if (rhs.engaged_) {
+      this->assign(rhs.data_);
+    } else {
+      this->destruct();
+    }
+    return *this;
+  }
+
+  optional_data& operator=(optional_data&& rhs) noexcept(
+      std::is_nothrow_move_assignable<T>::value&&
+          std::is_nothrow_move_constructible<T>::value) {
+    if (rhs.engaged_) {
+      this->assign(std::move(rhs.data_));
+    } else {
+      this->destruct();
+    }
+    return *this;
+  }
+};
+
+// Ordered by level of restriction, from low to high.
+// Copyable implies movable.
+enum class copy_traits { copyable = 0, movable = 1, non_movable = 2 };
+
+// Base class for enabling/disabling copy/move constructor.
+template <copy_traits>
+class optional_ctor_base;
+
+template <>
+class optional_ctor_base<copy_traits::copyable> {
+ public:
+  constexpr optional_ctor_base() = default;
+  optional_ctor_base(const optional_ctor_base&) = default;
+  optional_ctor_base(optional_ctor_base&&) = default;
+  optional_ctor_base& operator=(const optional_ctor_base&) = default;
+  optional_ctor_base& operator=(optional_ctor_base&&) = default;
+};
+
+template <>
+class optional_ctor_base<copy_traits::movable> {
+ public:
+  constexpr optional_ctor_base() = default;
+  optional_ctor_base(const optional_ctor_base&) = delete;
+  optional_ctor_base(optional_ctor_base&&) = default;
+  optional_ctor_base& operator=(const optional_ctor_base&) = default;
+  optional_ctor_base& operator=(optional_ctor_base&&) = default;
+};
+
+template <>
+class optional_ctor_base<copy_traits::non_movable> {
+ public:
+  constexpr optional_ctor_base() = default;
+  optional_ctor_base(const optional_ctor_base&) = delete;
+  optional_ctor_base(optional_ctor_base&&) = delete;
+  optional_ctor_base& operator=(const optional_ctor_base&) = default;
+  optional_ctor_base& operator=(optional_ctor_base&&) = default;
+};
+
+// Base class for enabling/disabling copy/move assignment.
+template <copy_traits>
+class optional_assign_base;
+
+template <>
+class optional_assign_base<copy_traits::copyable> {
+ public:
+  constexpr optional_assign_base() = default;
+  optional_assign_base(const optional_assign_base&) = default;
+  optional_assign_base(optional_assign_base&&) = default;
+  optional_assign_base& operator=(const optional_assign_base&) = default;
+  optional_assign_base& operator=(optional_assign_base&&) = default;
+};
+
+template <>
+class optional_assign_base<copy_traits::movable> {
+ public:
+  constexpr optional_assign_base() = default;
+  optional_assign_base(const optional_assign_base&) = default;
+  optional_assign_base(optional_assign_base&&) = default;
+  optional_assign_base& operator=(const optional_assign_base&) = delete;
+  optional_assign_base& operator=(optional_assign_base&&) = default;
+};
+
+template <>
+class optional_assign_base<copy_traits::non_movable> {
+ public:
+  constexpr optional_assign_base() = default;
+  optional_assign_base(const optional_assign_base&) = default;
+  optional_assign_base(optional_assign_base&&) = default;
+  optional_assign_base& operator=(const optional_assign_base&) = delete;
+  optional_assign_base& operator=(optional_assign_base&&) = delete;
+};
+
+template <typename T>
+struct ctor_copy_traits {
+  static constexpr copy_traits traits =
+      std::is_copy_constructible<T>::value
+          ? copy_traits::copyable
+          : std::is_move_constructible<T>::value ? copy_traits::movable
+                                                 : copy_traits::non_movable;
+};
+
+template <typename T>
+struct assign_copy_traits {
+  static constexpr copy_traits traits =
+      absl::is_copy_assignable<T>::value && std::is_copy_constructible<T>::value
+          ? copy_traits::copyable
+          : absl::is_move_assignable<T>::value &&
+                    std::is_move_constructible<T>::value
+                ? copy_traits::movable
+                : copy_traits::non_movable;
+};
+
+// Whether T is constructible or convertible from optional<U>.
+template <typename T, typename U>
+struct is_constructible_convertible_from_optional
+    : std::integral_constant<
+          bool, std::is_constructible<T, optional<U>&>::value ||
+                    std::is_constructible<T, optional<U>&&>::value ||
+                    std::is_constructible<T, const optional<U>&>::value ||
+                    std::is_constructible<T, const optional<U>&&>::value ||
+                    std::is_convertible<optional<U>&, T>::value ||
+                    std::is_convertible<optional<U>&&, T>::value ||
+                    std::is_convertible<const optional<U>&, T>::value ||
+                    std::is_convertible<const optional<U>&&, T>::value> {};
+
+// Whether T is constructible or convertible or assignable from optional<U>.
+template <typename T, typename U>
+struct is_constructible_convertible_assignable_from_optional
+    : std::integral_constant<
+          bool, is_constructible_convertible_from_optional<T, U>::value ||
+                    std::is_assignable<T&, optional<U>&>::value ||
+                    std::is_assignable<T&, optional<U>&&>::value ||
+                    std::is_assignable<T&, const optional<U>&>::value ||
+                    std::is_assignable<T&, const optional<U>&&>::value> {};
+
+// Helper function used by [optional.relops], [optional.comp_with_t],
+// for checking whether an expression is convertible to bool.
+bool convertible_to_bool(bool);
+
+// Base class for std::hash<absl::optional<T>>:
+// If std::hash<std::remove_const_t<T>> is enabled, it provides operator() to
+// compute the hash; Otherwise, it is disabled.
+// Reference N4659 23.14.15 [unord.hash].
+template <typename T, typename = size_t>
+struct optional_hash_base {
+  optional_hash_base() = delete;
+  optional_hash_base(const optional_hash_base&) = delete;
+  optional_hash_base(optional_hash_base&&) = delete;
+  optional_hash_base& operator=(const optional_hash_base&) = delete;
+  optional_hash_base& operator=(optional_hash_base&&) = delete;
+};
+
+template <typename T>
+struct optional_hash_base<T, decltype(std::hash<absl::remove_const_t<T> >()(
+                                 std::declval<absl::remove_const_t<T> >()))> {
+  using argument_type = absl::optional<T>;
+  using result_type = size_t;
+  size_t operator()(const absl::optional<T>& opt) const {
+    absl::type_traits_internal::AssertHashEnabled<absl::remove_const_t<T>>();
+    if (opt) {
+      return std::hash<absl::remove_const_t<T> >()(*opt);
+    } else {
+      return static_cast<size_t>(0x297814aaad196e6dULL);
+    }
+  }
+};
+
+}  // namespace optional_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#undef ABSL_OPTIONAL_USE_INHERITING_CONSTRUCTORS
+
+#endif  // ABSL_TYPES_INTERNAL_OPTIONAL_H_
diff --git a/src/absl/types/internal/parentheses.h b/src/absl/types/internal/parentheses.h
new file mode 100644 (file)
index 0000000..5aebee8
--- /dev/null
@@ -0,0 +1,34 @@
+// Copyright 2019 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// -----------------------------------------------------------------------------
+// parentheses.h
+// -----------------------------------------------------------------------------
+//
+// This file contains macros that expand to a left parenthesis and a right
+// parenthesis. These are in their own file and are generated from macros
+// because otherwise clang-format gets confused and clang-format off directives
+// do not help.
+//
+// The parentheses macros are used when wanting to require a rescan before
+// expansion of parenthesized text appearing after a function-style macro name.
+
+#ifndef ABSL_TYPES_INTERNAL_PARENTHESES_H_
+#define ABSL_TYPES_INTERNAL_PARENTHESES_H_
+
+#define ABSL_INTERNAL_LPAREN (
+
+#define ABSL_INTERNAL_RPAREN )
+
+#endif  // ABSL_TYPES_INTERNAL_PARENTHESES_H_
diff --git a/src/absl/types/internal/span.h b/src/absl/types/internal/span.h
new file mode 100644 (file)
index 0000000..112612f
--- /dev/null
@@ -0,0 +1,128 @@
+//
+// Copyright 2019 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+#ifndef ABSL_TYPES_INTERNAL_SPAN_H_
+#define ABSL_TYPES_INTERNAL_SPAN_H_
+
+#include <algorithm>
+#include <cstddef>
+#include <string>
+#include <type_traits>
+
+#include "absl/algorithm/algorithm.h"
+#include "absl/base/internal/throw_delegate.h"
+#include "absl/meta/type_traits.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+
+namespace span_internal {
+// A constexpr min function
+constexpr size_t Min(size_t a, size_t b) noexcept { return a < b ? a : b; }
+
+// Wrappers for access to container data pointers.
+template <typename C>
+constexpr auto GetDataImpl(C& c, char) noexcept  // NOLINT(runtime/references)
+    -> decltype(c.data()) {
+  return c.data();
+}
+
+// Before C++17, std::string::data returns a const char* in all cases.
+inline char* GetDataImpl(std::string& s,  // NOLINT(runtime/references)
+                         int) noexcept {
+  return &s[0];
+}
+
+template <typename C>
+constexpr auto GetData(C& c) noexcept  // NOLINT(runtime/references)
+    -> decltype(GetDataImpl(c, 0)) {
+  return GetDataImpl(c, 0);
+}
+
+// Detection idioms for size() and data().
+template <typename C>
+using HasSize =
+    std::is_integral<absl::decay_t<decltype(std::declval<C&>().size())>>;
+
+// We want to enable conversion from vector<T*> to Span<const T* const> but
+// disable conversion from vector<Derived> to Span<Base>. Here we use
+// the fact that U** is convertible to Q* const* if and only if Q is the same
+// type or a more cv-qualified version of U.  We also decay the result type of
+// data() to avoid problems with classes which have a member function data()
+// which returns a reference.
+template <typename T, typename C>
+using HasData =
+    std::is_convertible<absl::decay_t<decltype(GetData(std::declval<C&>()))>*,
+                        T* const*>;
+
+// Extracts value type from a Container
+template <typename C>
+struct ElementType {
+  using type = typename absl::remove_reference_t<C>::value_type;
+};
+
+template <typename T, size_t N>
+struct ElementType<T (&)[N]> {
+  using type = T;
+};
+
+template <typename C>
+using ElementT = typename ElementType<C>::type;
+
+template <typename T>
+using EnableIfMutable =
+    typename std::enable_if<!std::is_const<T>::value, int>::type;
+
+template <template <typename> class SpanT, typename T>
+bool EqualImpl(SpanT<T> a, SpanT<T> b) {
+  static_assert(std::is_const<T>::value, "");
+  return absl::equal(a.begin(), a.end(), b.begin(), b.end());
+}
+
+template <template <typename> class SpanT, typename T>
+bool LessThanImpl(SpanT<T> a, SpanT<T> b) {
+  // We can't use value_type since that is remove_cv_t<T>, so we go the long way
+  // around.
+  static_assert(std::is_const<T>::value, "");
+  return std::lexicographical_compare(a.begin(), a.end(), b.begin(), b.end());
+}
+
+// The `IsConvertible` classes here are needed because of the
+// `std::is_convertible` bug in libcxx when compiled with GCC. This build
+// configuration is used by Android NDK toolchain. Reference link:
+// https://bugs.llvm.org/show_bug.cgi?id=27538.
+template <typename From, typename To>
+struct IsConvertibleHelper {
+ private:
+  static std::true_type testval(To);
+  static std::false_type testval(...);
+
+ public:
+  using type = decltype(testval(std::declval<From>()));
+};
+
+template <typename From, typename To>
+struct IsConvertible : IsConvertibleHelper<From, To>::type {};
+
+// TODO(zhangxy): replace `IsConvertible` with `std::is_convertible` once the
+// older version of libcxx is not supported.
+template <typename From, typename To>
+using EnableIfConvertibleTo =
+    typename std::enable_if<IsConvertible<From, To>::value>::type;
+}  // namespace span_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#endif  // ABSL_TYPES_INTERNAL_SPAN_H_
diff --git a/src/absl/types/internal/transform_args.h b/src/absl/types/internal/transform_args.h
new file mode 100644 (file)
index 0000000..4a0ab42
--- /dev/null
@@ -0,0 +1,246 @@
+// Copyright 2019 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// -----------------------------------------------------------------------------
+// transform_args.h
+// -----------------------------------------------------------------------------
+//
+// This file contains a higher-order macro that "transforms" each element of a
+// a variadic argument by a provided secondary macro.
+
+#ifndef ABSL_TYPES_INTERNAL_TRANSFORM_ARGS_H_
+#define ABSL_TYPES_INTERNAL_TRANSFORM_ARGS_H_
+
+//
+// ABSL_INTERNAL_CAT(a, b)
+//
+// This macro takes two arguments and concatenates them together via ## after
+// expansion.
+//
+// Example:
+//
+//   ABSL_INTERNAL_CAT(foo_, bar)
+//
+// Results in:
+//
+//   foo_bar
+#define ABSL_INTERNAL_CAT(a, b) ABSL_INTERNAL_CAT_IMPL(a, b)
+#define ABSL_INTERNAL_CAT_IMPL(a, b) a##b
+
+//
+// ABSL_INTERNAL_TRANSFORM_ARGS(m, ...)
+//
+// This macro takes another macro as an argument followed by a trailing series
+// of additional parameters (up to 32 additional arguments). It invokes the
+// passed-in macro once for each of the additional arguments, with the
+// expansions separated by commas.
+//
+// Example:
+//
+//   ABSL_INTERNAL_TRANSFORM_ARGS(MY_MACRO, a, b, c)
+//
+// Results in:
+//
+//   MY_MACRO(a), MY_MACRO(b), MY_MACRO(c)
+//
+// TODO(calabrese) Handle no arguments as a special case.
+#define ABSL_INTERNAL_TRANSFORM_ARGS(m, ...)             \
+  ABSL_INTERNAL_CAT(ABSL_INTERNAL_TRANSFORM_ARGS,        \
+                    ABSL_INTERNAL_NUM_ARGS(__VA_ARGS__)) \
+  (m, __VA_ARGS__)
+
+#define ABSL_INTERNAL_TRANSFORM_ARGS1(m, a0) m(a0)
+
+#define ABSL_INTERNAL_TRANSFORM_ARGS2(m, a0, a1) m(a0), m(a1)
+
+#define ABSL_INTERNAL_TRANSFORM_ARGS3(m, a0, a1, a2) m(a0), m(a1), m(a2)
+
+#define ABSL_INTERNAL_TRANSFORM_ARGS4(m, a0, a1, a2, a3) \
+  m(a0), m(a1), m(a2), m(a3)
+
+#define ABSL_INTERNAL_TRANSFORM_ARGS5(m, a0, a1, a2, a3, a4) \
+  m(a0), m(a1), m(a2), m(a3), m(a4)
+
+#define ABSL_INTERNAL_TRANSFORM_ARGS6(m, a0, a1, a2, a3, a4, a5) \
+  m(a0), m(a1), m(a2), m(a3), m(a4), m(a5)
+
+#define ABSL_INTERNAL_TRANSFORM_ARGS7(m, a0, a1, a2, a3, a4, a5, a6) \
+  m(a0), m(a1), m(a2), m(a3), m(a4), m(a5), m(a6)
+
+#define ABSL_INTERNAL_TRANSFORM_ARGS8(m, a0, a1, a2, a3, a4, a5, a6, a7) \
+  m(a0), m(a1), m(a2), m(a3), m(a4), m(a5), m(a6), m(a7)
+
+#define ABSL_INTERNAL_TRANSFORM_ARGS9(m, a0, a1, a2, a3, a4, a5, a6, a7, a8) \
+  m(a0), m(a1), m(a2), m(a3), m(a4), m(a5), m(a6), m(a7), m(a8)
+
+#define ABSL_INTERNAL_TRANSFORM_ARGS10(m, a0, a1, a2, a3, a4, a5, a6, a7, a8, \
+                                       a9)                                    \
+  m(a0), m(a1), m(a2), m(a3), m(a4), m(a5), m(a6), m(a7), m(a8), m(a9)
+
+#define ABSL_INTERNAL_TRANSFORM_ARGS11(m, a0, a1, a2, a3, a4, a5, a6, a7, a8, \
+                                       a9, a10)                               \
+  m(a0), m(a1), m(a2), m(a3), m(a4), m(a5), m(a6), m(a7), m(a8), m(a9), m(a10)
+
+#define ABSL_INTERNAL_TRANSFORM_ARGS12(m, a0, a1, a2, a3, a4, a5, a6, a7, a8, \
+                                       a9, a10, a11)                          \
+  m(a0), m(a1), m(a2), m(a3), m(a4), m(a5), m(a6), m(a7), m(a8), m(a9),       \
+      m(a10), m(a11)
+
+#define ABSL_INTERNAL_TRANSFORM_ARGS13(m, a0, a1, a2, a3, a4, a5, a6, a7, a8, \
+                                       a9, a10, a11, a12)                     \
+  m(a0), m(a1), m(a2), m(a3), m(a4), m(a5), m(a6), m(a7), m(a8), m(a9),       \
+      m(a10), m(a11), m(a12)
+
+#define ABSL_INTERNAL_TRANSFORM_ARGS14(m, a0, a1, a2, a3, a4, a5, a6, a7, a8, \
+                                       a9, a10, a11, a12, a13)                \
+  m(a0), m(a1), m(a2), m(a3), m(a4), m(a5), m(a6), m(a7), m(a8), m(a9),       \
+      m(a10), m(a11), m(a12), m(a13)
+
+#define ABSL_INTERNAL_TRANSFORM_ARGS15(m, a0, a1, a2, a3, a4, a5, a6, a7, a8, \
+                                       a9, a10, a11, a12, a13, a14)           \
+  m(a0), m(a1), m(a2), m(a3), m(a4), m(a5), m(a6), m(a7), m(a8), m(a9),       \
+      m(a10), m(a11), m(a12), m(a13), m(a14)
+
+#define ABSL_INTERNAL_TRANSFORM_ARGS16(m, a0, a1, a2, a3, a4, a5, a6, a7, a8, \
+                                       a9, a10, a11, a12, a13, a14, a15)      \
+  m(a0), m(a1), m(a2), m(a3), m(a4), m(a5), m(a6), m(a7), m(a8), m(a9),       \
+      m(a10), m(a11), m(a12), m(a13), m(a14), m(a15)
+
+#define ABSL_INTERNAL_TRANSFORM_ARGS17(m, a0, a1, a2, a3, a4, a5, a6, a7, a8, \
+                                       a9, a10, a11, a12, a13, a14, a15, a16) \
+  m(a0), m(a1), m(a2), m(a3), m(a4), m(a5), m(a6), m(a7), m(a8), m(a9),       \
+      m(a10), m(a11), m(a12), m(a13), m(a14), m(a15), m(a16)
+
+#define ABSL_INTERNAL_TRANSFORM_ARGS18(m, a0, a1, a2, a3, a4, a5, a6, a7, a8, \
+                                       a9, a10, a11, a12, a13, a14, a15, a16, \
+                                       a17)                                   \
+  m(a0), m(a1), m(a2), m(a3), m(a4), m(a5), m(a6), m(a7), m(a8), m(a9),       \
+      m(a10), m(a11), m(a12), m(a13), m(a14), m(a15), m(a16), m(a17)
+
+#define ABSL_INTERNAL_TRANSFORM_ARGS19(m, a0, a1, a2, a3, a4, a5, a6, a7, a8, \
+                                       a9, a10, a11, a12, a13, a14, a15, a16, \
+                                       a17, a18)                              \
+  m(a0), m(a1), m(a2), m(a3), m(a4), m(a5), m(a6), m(a7), m(a8), m(a9),       \
+      m(a10), m(a11), m(a12), m(a13), m(a14), m(a15), m(a16), m(a17), m(a18)
+
+#define ABSL_INTERNAL_TRANSFORM_ARGS20(m, a0, a1, a2, a3, a4, a5, a6, a7, a8, \
+                                       a9, a10, a11, a12, a13, a14, a15, a16, \
+                                       a17, a18, a19)                         \
+  m(a0), m(a1), m(a2), m(a3), m(a4), m(a5), m(a6), m(a7), m(a8), m(a9),       \
+      m(a10), m(a11), m(a12), m(a13), m(a14), m(a15), m(a16), m(a17), m(a18), \
+      m(a19)
+
+#define ABSL_INTERNAL_TRANSFORM_ARGS21(m, a0, a1, a2, a3, a4, a5, a6, a7, a8, \
+                                       a9, a10, a11, a12, a13, a14, a15, a16, \
+                                       a17, a18, a19, a20)                    \
+  m(a0), m(a1), m(a2), m(a3), m(a4), m(a5), m(a6), m(a7), m(a8), m(a9),       \
+      m(a10), m(a11), m(a12), m(a13), m(a14), m(a15), m(a16), m(a17), m(a18), \
+      m(a19), m(a20)
+
+#define ABSL_INTERNAL_TRANSFORM_ARGS22(m, a0, a1, a2, a3, a4, a5, a6, a7, a8, \
+                                       a9, a10, a11, a12, a13, a14, a15, a16, \
+                                       a17, a18, a19, a20, a21)               \
+  m(a0), m(a1), m(a2), m(a3), m(a4), m(a5), m(a6), m(a7), m(a8), m(a9),       \
+      m(a10), m(a11), m(a12), m(a13), m(a14), m(a15), m(a16), m(a17), m(a18), \
+      m(a19), m(a20), m(a21)
+
+#define ABSL_INTERNAL_TRANSFORM_ARGS23(m, a0, a1, a2, a3, a4, a5, a6, a7, a8, \
+                                       a9, a10, a11, a12, a13, a14, a15, a16, \
+                                       a17, a18, a19, a20, a21, a22)          \
+  m(a0), m(a1), m(a2), m(a3), m(a4), m(a5), m(a6), m(a7), m(a8), m(a9),       \
+      m(a10), m(a11), m(a12), m(a13), m(a14), m(a15), m(a16), m(a17), m(a18), \
+      m(a19), m(a20), m(a21), m(a22)
+
+#define ABSL_INTERNAL_TRANSFORM_ARGS24(m, a0, a1, a2, a3, a4, a5, a6, a7, a8, \
+                                       a9, a10, a11, a12, a13, a14, a15, a16, \
+                                       a17, a18, a19, a20, a21, a22, a23)     \
+  m(a0), m(a1), m(a2), m(a3), m(a4), m(a5), m(a6), m(a7), m(a8), m(a9),       \
+      m(a10), m(a11), m(a12), m(a13), m(a14), m(a15), m(a16), m(a17), m(a18), \
+      m(a19), m(a20), m(a21), m(a22), m(a23)
+
+#define ABSL_INTERNAL_TRANSFORM_ARGS25(m, a0, a1, a2, a3, a4, a5, a6, a7, a8,  \
+                                       a9, a10, a11, a12, a13, a14, a15, a16,  \
+                                       a17, a18, a19, a20, a21, a22, a23, a24) \
+  m(a0), m(a1), m(a2), m(a3), m(a4), m(a5), m(a6), m(a7), m(a8), m(a9),        \
+      m(a10), m(a11), m(a12), m(a13), m(a14), m(a15), m(a16), m(a17), m(a18),  \
+      m(a19), m(a20), m(a21), m(a22), m(a23), m(a24)
+
+#define ABSL_INTERNAL_TRANSFORM_ARGS26(                                       \
+    m, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15,  \
+    a16, a17, a18, a19, a20, a21, a22, a23, a24, a25)                         \
+  m(a0), m(a1), m(a2), m(a3), m(a4), m(a5), m(a6), m(a7), m(a8), m(a9),       \
+      m(a10), m(a11), m(a12), m(a13), m(a14), m(a15), m(a16), m(a17), m(a18), \
+      m(a19), m(a20), m(a21), m(a22), m(a23), m(a24), m(a25)
+
+#define ABSL_INTERNAL_TRANSFORM_ARGS27(                                       \
+    m, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15,  \
+    a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26)                    \
+  m(a0), m(a1), m(a2), m(a3), m(a4), m(a5), m(a6), m(a7), m(a8), m(a9),       \
+      m(a10), m(a11), m(a12), m(a13), m(a14), m(a15), m(a16), m(a17), m(a18), \
+      m(a19), m(a20), m(a21), m(a22), m(a23), m(a24), m(a25), m(a26)
+
+#define ABSL_INTERNAL_TRANSFORM_ARGS28(                                       \
+    m, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15,  \
+    a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27)               \
+  m(a0), m(a1), m(a2), m(a3), m(a4), m(a5), m(a6), m(a7), m(a8), m(a9),       \
+      m(a10), m(a11), m(a12), m(a13), m(a14), m(a15), m(a16), m(a17), m(a18), \
+      m(a19), m(a20), m(a21), m(a22), m(a23), m(a24), m(a25), m(a26), m(a27)
+
+#define ABSL_INTERNAL_TRANSFORM_ARGS29(                                       \
+    m, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15,  \
+    a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28)          \
+  m(a0), m(a1), m(a2), m(a3), m(a4), m(a5), m(a6), m(a7), m(a8), m(a9),       \
+      m(a10), m(a11), m(a12), m(a13), m(a14), m(a15), m(a16), m(a17), m(a18), \
+      m(a19), m(a20), m(a21), m(a22), m(a23), m(a24), m(a25), m(a26), m(a27), \
+      m(a28)
+
+#define ABSL_INTERNAL_TRANSFORM_ARGS30(                                       \
+    m, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15,  \
+    a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, a29)     \
+  m(a0), m(a1), m(a2), m(a3), m(a4), m(a5), m(a6), m(a7), m(a8), m(a9),       \
+      m(a10), m(a11), m(a12), m(a13), m(a14), m(a15), m(a16), m(a17), m(a18), \
+      m(a19), m(a20), m(a21), m(a22), m(a23), m(a24), m(a25), m(a26), m(a27), \
+      m(a28), m(a29)
+
+#define ABSL_INTERNAL_TRANSFORM_ARGS31(                                        \
+    m, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15,   \
+    a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, a29, a30) \
+  m(a0), m(a1), m(a2), m(a3), m(a4), m(a5), m(a6), m(a7), m(a8), m(a9),        \
+      m(a10), m(a11), m(a12), m(a13), m(a14), m(a15), m(a16), m(a17), m(a18),  \
+      m(a19), m(a20), m(a21), m(a22), m(a23), m(a24), m(a25), m(a26), m(a27),  \
+      m(a28), m(a29), m(a30)
+
+#define ABSL_INTERNAL_TRANSFORM_ARGS32(m, a0, a1, a2, a3, a4, a5, a6, a7, a8,  \
+                                       a9, a10, a11, a12, a13, a14, a15, a16,  \
+                                       a17, a18, a19, a20, a21, a22, a23, a24, \
+                                       a25, a26, a27, a28, a29, a30, a31)      \
+  m(a0), m(a1), m(a2), m(a3), m(a4), m(a5), m(a6), m(a7), m(a8), m(a9),        \
+      m(a10), m(a11), m(a12), m(a13), m(a14), m(a15), m(a16), m(a17), m(a18),  \
+      m(a19), m(a20), m(a21), m(a22), m(a23), m(a24), m(a25), m(a26), m(a27),  \
+      m(a28), m(a29), m(a30), m(a31)
+
+#define ABSL_INTERNAL_NUM_ARGS_IMPL(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9,    \
+                                    a10, a11, a12, a13, a14, a15, a16, a17,    \
+                                    a18, a19, a20, a21, a22, a23, a24, a25,    \
+                                    a26, a27, a28, a29, a30, a31, result, ...) \
+  result
+
+#define ABSL_INTERNAL_FORCE_EXPANSION(...) __VA_ARGS__
+
+#define ABSL_INTERNAL_NUM_ARGS(...)                                            \
+  ABSL_INTERNAL_FORCE_EXPANSION(ABSL_INTERNAL_NUM_ARGS_IMPL(                   \
+      __VA_ARGS__, 32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, \
+      17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, ))
+
+#endif  // ABSL_TYPES_INTERNAL_TRANSFORM_ARGS_H_
diff --git a/src/absl/types/internal/variant.h b/src/absl/types/internal/variant.h
new file mode 100644 (file)
index 0000000..772008c
--- /dev/null
@@ -0,0 +1,1646 @@
+// Copyright 2018 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// Implementation details of absl/types/variant.h, pulled into a
+// separate file to avoid cluttering the top of the API header with
+// implementation details.
+
+#ifndef ABSL_TYPES_variant_internal_H_
+#define ABSL_TYPES_variant_internal_H_
+
+#include <cassert>
+#include <cstddef>
+#include <cstdlib>
+#include <memory>
+#include <stdexcept>
+#include <tuple>
+#include <type_traits>
+
+#include "absl/base/config.h"
+#include "absl/base/internal/identity.h"
+#include "absl/base/internal/inline_variable.h"
+#include "absl/base/internal/invoke.h"
+#include "absl/base/macros.h"
+#include "absl/base/optimization.h"
+#include "absl/meta/type_traits.h"
+#include "absl/types/bad_variant_access.h"
+#include "absl/utility/utility.h"
+
+#if !defined(ABSL_USES_STD_VARIANT)
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+
+template <class... Types>
+class variant;
+
+ABSL_INTERNAL_INLINE_CONSTEXPR(size_t, variant_npos, static_cast<size_t>(-1));
+
+template <class T>
+struct variant_size;
+
+template <std::size_t I, class T>
+struct variant_alternative;
+
+namespace variant_internal {
+
+// NOTE: See specializations below for details.
+template <std::size_t I, class T>
+struct VariantAlternativeSfinae {};
+
+// Requires: I < variant_size_v<T>.
+//
+// Value: The Ith type of Types...
+template <std::size_t I, class T0, class... Tn>
+struct VariantAlternativeSfinae<I, variant<T0, Tn...>>
+    : VariantAlternativeSfinae<I - 1, variant<Tn...>> {};
+
+// Value: T0
+template <class T0, class... Ts>
+struct VariantAlternativeSfinae<0, variant<T0, Ts...>> {
+  using type = T0;
+};
+
+template <std::size_t I, class T>
+using VariantAlternativeSfinaeT = typename VariantAlternativeSfinae<I, T>::type;
+
+// NOTE: Requires T to be a reference type.
+template <class T, class U>
+struct GiveQualsTo;
+
+template <class T, class U>
+struct GiveQualsTo<T&, U> {
+  using type = U&;
+};
+
+template <class T, class U>
+struct GiveQualsTo<T&&, U> {
+  using type = U&&;
+};
+
+template <class T, class U>
+struct GiveQualsTo<const T&, U> {
+  using type = const U&;
+};
+
+template <class T, class U>
+struct GiveQualsTo<const T&&, U> {
+  using type = const U&&;
+};
+
+template <class T, class U>
+struct GiveQualsTo<volatile T&, U> {
+  using type = volatile U&;
+};
+
+template <class T, class U>
+struct GiveQualsTo<volatile T&&, U> {
+  using type = volatile U&&;
+};
+
+template <class T, class U>
+struct GiveQualsTo<volatile const T&, U> {
+  using type = volatile const U&;
+};
+
+template <class T, class U>
+struct GiveQualsTo<volatile const T&&, U> {
+  using type = volatile const U&&;
+};
+
+template <class T, class U>
+using GiveQualsToT = typename GiveQualsTo<T, U>::type;
+
+// Convenience alias, since size_t integral_constant is used a lot in this file.
+template <std::size_t I>
+using SizeT = std::integral_constant<std::size_t, I>;
+
+using NPos = SizeT<variant_npos>;
+
+template <class Variant, class T, class = void>
+struct IndexOfConstructedType {};
+
+template <std::size_t I, class Variant>
+struct VariantAccessResultImpl;
+
+template <std::size_t I, template <class...> class Variantemplate, class... T>
+struct VariantAccessResultImpl<I, Variantemplate<T...>&> {
+  using type = typename absl::variant_alternative<I, variant<T...>>::type&;
+};
+
+template <std::size_t I, template <class...> class Variantemplate, class... T>
+struct VariantAccessResultImpl<I, const Variantemplate<T...>&> {
+  using type =
+      const typename absl::variant_alternative<I, variant<T...>>::type&;
+};
+
+template <std::size_t I, template <class...> class Variantemplate, class... T>
+struct VariantAccessResultImpl<I, Variantemplate<T...>&&> {
+  using type = typename absl::variant_alternative<I, variant<T...>>::type&&;
+};
+
+template <std::size_t I, template <class...> class Variantemplate, class... T>
+struct VariantAccessResultImpl<I, const Variantemplate<T...>&&> {
+  using type =
+      const typename absl::variant_alternative<I, variant<T...>>::type&&;
+};
+
+template <std::size_t I, class Variant>
+using VariantAccessResult =
+    typename VariantAccessResultImpl<I, Variant&&>::type;
+
+// NOTE: This is used instead of std::array to reduce instantiation overhead.
+template <class T, std::size_t Size>
+struct SimpleArray {
+  static_assert(Size != 0, "");
+  T value[Size];
+};
+
+template <class T>
+struct AccessedType {
+  using type = T;
+};
+
+template <class T>
+using AccessedTypeT = typename AccessedType<T>::type;
+
+template <class T, std::size_t Size>
+struct AccessedType<SimpleArray<T, Size>> {
+  using type = AccessedTypeT<T>;
+};
+
+template <class T>
+constexpr T AccessSimpleArray(const T& value) {
+  return value;
+}
+
+template <class T, std::size_t Size, class... SizeT>
+constexpr AccessedTypeT<T> AccessSimpleArray(const SimpleArray<T, Size>& table,
+                                             std::size_t head_index,
+                                             SizeT... tail_indices) {
+  return AccessSimpleArray(table.value[head_index], tail_indices...);
+}
+
+// Note: Intentionally is an alias.
+template <class T>
+using AlwaysZero = SizeT<0>;
+
+template <class Op, class... Vs>
+struct VisitIndicesResultImpl {
+  using type = absl::result_of_t<Op(AlwaysZero<Vs>...)>;
+};
+
+template <class Op, class... Vs>
+using VisitIndicesResultT = typename VisitIndicesResultImpl<Op, Vs...>::type;
+
+template <class ReturnType, class FunctionObject, class EndIndices,
+          class BoundIndices>
+struct MakeVisitationMatrix;
+
+template <class ReturnType, class FunctionObject, std::size_t... Indices>
+constexpr ReturnType call_with_indices(FunctionObject&& function) {
+  static_assert(
+      std::is_same<ReturnType, decltype(std::declval<FunctionObject>()(
+                                   SizeT<Indices>()...))>::value,
+      "Not all visitation overloads have the same return type.");
+  return absl::forward<FunctionObject>(function)(SizeT<Indices>()...);
+}
+
+template <class ReturnType, class FunctionObject, std::size_t... BoundIndices>
+struct MakeVisitationMatrix<ReturnType, FunctionObject, index_sequence<>,
+                            index_sequence<BoundIndices...>> {
+  using ResultType = ReturnType (*)(FunctionObject&&);
+  static constexpr ResultType Run() {
+    return &call_with_indices<ReturnType, FunctionObject,
+                              (BoundIndices - 1)...>;
+  }
+};
+
+template <typename Is, std::size_t J>
+struct AppendToIndexSequence;
+
+template <typename Is, std::size_t J>
+using AppendToIndexSequenceT = typename AppendToIndexSequence<Is, J>::type;
+
+template <std::size_t... Is, std::size_t J>
+struct AppendToIndexSequence<index_sequence<Is...>, J> {
+  using type = index_sequence<Is..., J>;
+};
+
+template <class ReturnType, class FunctionObject, class EndIndices,
+          class CurrIndices, class BoundIndices>
+struct MakeVisitationMatrixImpl;
+
+template <class ReturnType, class FunctionObject, class EndIndices,
+          std::size_t... CurrIndices, class BoundIndices>
+struct MakeVisitationMatrixImpl<ReturnType, FunctionObject, EndIndices,
+                                index_sequence<CurrIndices...>, BoundIndices> {
+  using ResultType = SimpleArray<
+      typename MakeVisitationMatrix<ReturnType, FunctionObject, EndIndices,
+                                    index_sequence<>>::ResultType,
+      sizeof...(CurrIndices)>;
+
+  static constexpr ResultType Run() {
+    return {{MakeVisitationMatrix<
+        ReturnType, FunctionObject, EndIndices,
+        AppendToIndexSequenceT<BoundIndices, CurrIndices>>::Run()...}};
+  }
+};
+
+template <class ReturnType, class FunctionObject, std::size_t HeadEndIndex,
+          std::size_t... TailEndIndices, std::size_t... BoundIndices>
+struct MakeVisitationMatrix<ReturnType, FunctionObject,
+                            index_sequence<HeadEndIndex, TailEndIndices...>,
+                            index_sequence<BoundIndices...>>
+    : MakeVisitationMatrixImpl<ReturnType, FunctionObject,
+                               index_sequence<TailEndIndices...>,
+                               absl::make_index_sequence<HeadEndIndex>,
+                               index_sequence<BoundIndices...>> {};
+
+struct UnreachableSwitchCase {
+  template <class Op>
+  [[noreturn]] static VisitIndicesResultT<Op, std::size_t> Run(
+      Op&& /*ignored*/) {
+#if ABSL_HAVE_BUILTIN(__builtin_unreachable) || \
+    (defined(__GNUC__) && !defined(__clang__))
+    __builtin_unreachable();
+#elif defined(_MSC_VER)
+    __assume(false);
+#else
+    // Try to use assert of false being identified as an unreachable intrinsic.
+    // NOTE: We use assert directly to increase chances of exploiting an assume
+    //       intrinsic.
+    assert(false);  // NOLINT
+
+    // Hack to silence potential no return warning -- cause an infinite loop.
+    return Run(absl::forward<Op>(op));
+#endif  // Checks for __builtin_unreachable
+  }
+};
+
+template <class Op, std::size_t I>
+struct ReachableSwitchCase {
+  static VisitIndicesResultT<Op, std::size_t> Run(Op&& op) {
+    return absl::base_internal::invoke(absl::forward<Op>(op), SizeT<I>());
+  }
+};
+
+// The number 33 is just a guess at a reasonable maximum to our switch. It is
+// not based on any analysis. The reason it is a power of 2 plus 1 instead of a
+// power of 2 is because the number was picked to correspond to a power of 2
+// amount of "normal" alternatives, plus one for the possibility of the user
+// providing "monostate" in addition to the more natural alternatives.
+ABSL_INTERNAL_INLINE_CONSTEXPR(std::size_t, MaxUnrolledVisitCases, 33);
+
+// Note: The default-definition is for unreachable cases.
+template <bool IsReachable>
+struct PickCaseImpl {
+  template <class Op, std::size_t I>
+  using Apply = UnreachableSwitchCase;
+};
+
+template <>
+struct PickCaseImpl</*IsReachable =*/true> {
+  template <class Op, std::size_t I>
+  using Apply = ReachableSwitchCase<Op, I>;
+};
+
+// Note: This form of dance with template aliases is to make sure that we
+//       instantiate a number of templates proportional to the number of variant
+//       alternatives rather than a number of templates proportional to our
+//       maximum unrolled amount of visitation cases (aliases are effectively
+//       "free" whereas other template instantiations are costly).
+template <class Op, std::size_t I, std::size_t EndIndex>
+using PickCase = typename PickCaseImpl<(I < EndIndex)>::template Apply<Op, I>;
+
+template <class ReturnType>
+[[noreturn]] ReturnType TypedThrowBadVariantAccess() {
+  absl::variant_internal::ThrowBadVariantAccess();
+}
+
+// Given N variant sizes, determine the number of cases there would need to be
+// in a single switch-statement that would cover every possibility in the
+// corresponding N-ary visit operation.
+template <std::size_t... NumAlternatives>
+struct NumCasesOfSwitch;
+
+template <std::size_t HeadNumAlternatives, std::size_t... TailNumAlternatives>
+struct NumCasesOfSwitch<HeadNumAlternatives, TailNumAlternatives...> {
+  static constexpr std::size_t value =
+      (HeadNumAlternatives + 1) *
+      NumCasesOfSwitch<TailNumAlternatives...>::value;
+};
+
+template <>
+struct NumCasesOfSwitch<> {
+  static constexpr std::size_t value = 1;
+};
+
+// A switch statement optimizes better than the table of function pointers.
+template <std::size_t EndIndex>
+struct VisitIndicesSwitch {
+  static_assert(EndIndex <= MaxUnrolledVisitCases,
+                "Maximum unrolled switch size exceeded.");
+
+  template <class Op>
+  static VisitIndicesResultT<Op, std::size_t> Run(Op&& op, std::size_t i) {
+    switch (i) {
+      case 0:
+        return PickCase<Op, 0, EndIndex>::Run(absl::forward<Op>(op));
+      case 1:
+        return PickCase<Op, 1, EndIndex>::Run(absl::forward<Op>(op));
+      case 2:
+        return PickCase<Op, 2, EndIndex>::Run(absl::forward<Op>(op));
+      case 3:
+        return PickCase<Op, 3, EndIndex>::Run(absl::forward<Op>(op));
+      case 4:
+        return PickCase<Op, 4, EndIndex>::Run(absl::forward<Op>(op));
+      case 5:
+        return PickCase<Op, 5, EndIndex>::Run(absl::forward<Op>(op));
+      case 6:
+        return PickCase<Op, 6, EndIndex>::Run(absl::forward<Op>(op));
+      case 7:
+        return PickCase<Op, 7, EndIndex>::Run(absl::forward<Op>(op));
+      case 8:
+        return PickCase<Op, 8, EndIndex>::Run(absl::forward<Op>(op));
+      case 9:
+        return PickCase<Op, 9, EndIndex>::Run(absl::forward<Op>(op));
+      case 10:
+        return PickCase<Op, 10, EndIndex>::Run(absl::forward<Op>(op));
+      case 11:
+        return PickCase<Op, 11, EndIndex>::Run(absl::forward<Op>(op));
+      case 12:
+        return PickCase<Op, 12, EndIndex>::Run(absl::forward<Op>(op));
+      case 13:
+        return PickCase<Op, 13, EndIndex>::Run(absl::forward<Op>(op));
+      case 14:
+        return PickCase<Op, 14, EndIndex>::Run(absl::forward<Op>(op));
+      case 15:
+        return PickCase<Op, 15, EndIndex>::Run(absl::forward<Op>(op));
+      case 16:
+        return PickCase<Op, 16, EndIndex>::Run(absl::forward<Op>(op));
+      case 17:
+        return PickCase<Op, 17, EndIndex>::Run(absl::forward<Op>(op));
+      case 18:
+        return PickCase<Op, 18, EndIndex>::Run(absl::forward<Op>(op));
+      case 19:
+        return PickCase<Op, 19, EndIndex>::Run(absl::forward<Op>(op));
+      case 20:
+        return PickCase<Op, 20, EndIndex>::Run(absl::forward<Op>(op));
+      case 21:
+        return PickCase<Op, 21, EndIndex>::Run(absl::forward<Op>(op));
+      case 22:
+        return PickCase<Op, 22, EndIndex>::Run(absl::forward<Op>(op));
+      case 23:
+        return PickCase<Op, 23, EndIndex>::Run(absl::forward<Op>(op));
+      case 24:
+        return PickCase<Op, 24, EndIndex>::Run(absl::forward<Op>(op));
+      case 25:
+        return PickCase<Op, 25, EndIndex>::Run(absl::forward<Op>(op));
+      case 26:
+        return PickCase<Op, 26, EndIndex>::Run(absl::forward<Op>(op));
+      case 27:
+        return PickCase<Op, 27, EndIndex>::Run(absl::forward<Op>(op));
+      case 28:
+        return PickCase<Op, 28, EndIndex>::Run(absl::forward<Op>(op));
+      case 29:
+        return PickCase<Op, 29, EndIndex>::Run(absl::forward<Op>(op));
+      case 30:
+        return PickCase<Op, 30, EndIndex>::Run(absl::forward<Op>(op));
+      case 31:
+        return PickCase<Op, 31, EndIndex>::Run(absl::forward<Op>(op));
+      case 32:
+        return PickCase<Op, 32, EndIndex>::Run(absl::forward<Op>(op));
+      default:
+        ABSL_ASSERT(i == variant_npos);
+        return absl::base_internal::invoke(absl::forward<Op>(op), NPos());
+    }
+  }
+};
+
+template <std::size_t... EndIndices>
+struct VisitIndicesFallback {
+  template <class Op, class... SizeT>
+  static VisitIndicesResultT<Op, SizeT...> Run(Op&& op, SizeT... indices) {
+    return AccessSimpleArray(
+        MakeVisitationMatrix<VisitIndicesResultT<Op, SizeT...>, Op,
+                             index_sequence<(EndIndices + 1)...>,
+                             index_sequence<>>::Run(),
+        (indices + 1)...)(absl::forward<Op>(op));
+  }
+};
+
+// Take an N-dimensional series of indices and convert them into a single index
+// without loss of information. The purpose of this is to be able to convert an
+// N-ary visit operation into a single switch statement.
+template <std::size_t...>
+struct FlattenIndices;
+
+template <std::size_t HeadSize, std::size_t... TailSize>
+struct FlattenIndices<HeadSize, TailSize...> {
+  template<class... SizeType>
+  static constexpr std::size_t Run(std::size_t head, SizeType... tail) {
+    return head + HeadSize * FlattenIndices<TailSize...>::Run(tail...);
+  }
+};
+
+template <>
+struct FlattenIndices<> {
+  static constexpr std::size_t Run() { return 0; }
+};
+
+// Take a single "flattened" index (flattened by FlattenIndices) and determine
+// the value of the index of one of the logically represented dimensions.
+template <std::size_t I, std::size_t IndexToGet, std::size_t HeadSize,
+          std::size_t... TailSize>
+struct UnflattenIndex {
+  static constexpr std::size_t value =
+      UnflattenIndex<I / HeadSize, IndexToGet - 1, TailSize...>::value;
+};
+
+template <std::size_t I, std::size_t HeadSize, std::size_t... TailSize>
+struct UnflattenIndex<I, 0, HeadSize, TailSize...> {
+  static constexpr std::size_t value = (I % HeadSize);
+};
+
+// The backend for converting an N-ary visit operation into a unary visit.
+template <class IndexSequence, std::size_t... EndIndices>
+struct VisitIndicesVariadicImpl;
+
+template <std::size_t... N, std::size_t... EndIndices>
+struct VisitIndicesVariadicImpl<absl::index_sequence<N...>, EndIndices...> {
+  // A type that can take an N-ary function object and converts it to a unary
+  // function object that takes a single, flattened index, and "unflattens" it
+  // into its individual dimensions when forwarding to the wrapped object.
+  template <class Op>
+  struct FlattenedOp {
+    template <std::size_t I>
+    VisitIndicesResultT<Op, decltype(EndIndices)...> operator()(
+        SizeT<I> /*index*/) && {
+      return base_internal::invoke(
+          absl::forward<Op>(op),
+          SizeT<UnflattenIndex<I, N, (EndIndices + 1)...>::value -
+                std::size_t{1}>()...);
+    }
+
+    Op&& op;
+  };
+
+  template <class Op, class... SizeType>
+  static VisitIndicesResultT<Op, decltype(EndIndices)...> Run(
+      Op&& op, SizeType... i) {
+    return VisitIndicesSwitch<NumCasesOfSwitch<EndIndices...>::value>::Run(
+        FlattenedOp<Op>{absl::forward<Op>(op)},
+        FlattenIndices<(EndIndices + std::size_t{1})...>::Run(
+            (i + std::size_t{1})...));
+  }
+};
+
+template <std::size_t... EndIndices>
+struct VisitIndicesVariadic
+    : VisitIndicesVariadicImpl<absl::make_index_sequence<sizeof...(EndIndices)>,
+                               EndIndices...> {};
+
+// This implementation will flatten N-ary visit operations into a single switch
+// statement when the number of cases would be less than our maximum specified
+// switch-statement size.
+// TODO(calabrese)
+//   Based on benchmarks, determine whether the function table approach actually
+//   does optimize better than a chain of switch statements and possibly update
+//   the implementation accordingly. Also consider increasing the maximum switch
+//   size.
+template <std::size_t... EndIndices>
+struct VisitIndices
+    : absl::conditional_t<(NumCasesOfSwitch<EndIndices...>::value <=
+                           MaxUnrolledVisitCases),
+                          VisitIndicesVariadic<EndIndices...>,
+                          VisitIndicesFallback<EndIndices...>> {};
+
+template <std::size_t EndIndex>
+struct VisitIndices<EndIndex>
+    : absl::conditional_t<(EndIndex <= MaxUnrolledVisitCases),
+                          VisitIndicesSwitch<EndIndex>,
+                          VisitIndicesFallback<EndIndex>> {};
+
+// Suppress bogus warning on MSVC: MSVC complains that the `reinterpret_cast`
+// below is returning the address of a temporary or local object.
+#ifdef _MSC_VER
+#pragma warning(push)
+#pragma warning(disable : 4172)
+#endif  // _MSC_VER
+
+// TODO(calabrese) std::launder
+// TODO(calabrese) constexpr
+// NOTE: DO NOT REMOVE the `inline` keyword as it is necessary to work around a
+// MSVC bug. See https://github.com/abseil/abseil-cpp/issues/129 for details.
+template <class Self, std::size_t I>
+inline VariantAccessResult<I, Self> AccessUnion(Self&& self, SizeT<I> /*i*/) {
+  return reinterpret_cast<VariantAccessResult<I, Self>>(self);
+}
+
+#ifdef _MSC_VER
+#pragma warning(pop)
+#endif  // _MSC_VER
+
+template <class T>
+void DeducedDestroy(T& self) {  // NOLINT
+  self.~T();
+}
+
+// NOTE: This type exists as a single entity for variant and its bases to
+// befriend. It contains helper functionality that manipulates the state of the
+// variant, such as the implementation of things like assignment and emplace
+// operations.
+struct VariantCoreAccess {
+  template <class VariantType>
+  static typename VariantType::Variant& Derived(VariantType& self) {  // NOLINT
+    return static_cast<typename VariantType::Variant&>(self);
+  }
+
+  template <class VariantType>
+  static const typename VariantType::Variant& Derived(
+      const VariantType& self) {  // NOLINT
+    return static_cast<const typename VariantType::Variant&>(self);
+  }
+
+  template <class VariantType>
+  static void Destroy(VariantType& self) {  // NOLINT
+    Derived(self).destroy();
+    self.index_ = absl::variant_npos;
+  }
+
+  template <class Variant>
+  static void SetIndex(Variant& self, std::size_t i) {  // NOLINT
+    self.index_ = i;
+  }
+
+  template <class Variant>
+  static void InitFrom(Variant& self, Variant&& other) {  // NOLINT
+    VisitIndices<absl::variant_size<Variant>::value>::Run(
+        InitFromVisitor<Variant, Variant&&>{&self,
+                                            std::forward<Variant>(other)},
+        other.index());
+    self.index_ = other.index();
+  }
+
+  // Access a variant alternative, assuming the index is correct.
+  template <std::size_t I, class Variant>
+  static VariantAccessResult<I, Variant> Access(Variant&& self) {
+    // This cast instead of invocation of AccessUnion with an rvalue is a
+    // workaround for msvc. Without this there is a runtime failure when dealing
+    // with rvalues.
+    // TODO(calabrese) Reduce test case and find a simpler workaround.
+    return static_cast<VariantAccessResult<I, Variant>>(
+        variant_internal::AccessUnion(self.state_, SizeT<I>()));
+  }
+
+  // Access a variant alternative, throwing if the index is incorrect.
+  template <std::size_t I, class Variant>
+  static VariantAccessResult<I, Variant> CheckedAccess(Variant&& self) {
+    if (ABSL_PREDICT_FALSE(self.index_ != I)) {
+      TypedThrowBadVariantAccess<VariantAccessResult<I, Variant>>();
+    }
+
+    return Access<I>(absl::forward<Variant>(self));
+  }
+
+  // The implementation of the move-assignment operation for a variant.
+  template <class VType>
+  struct MoveAssignVisitor {
+    using DerivedType = typename VType::Variant;
+    template <std::size_t NewIndex>
+    void operator()(SizeT<NewIndex> /*new_i*/) const {
+      if (left->index_ == NewIndex) {
+        Access<NewIndex>(*left) = std::move(Access<NewIndex>(*right));
+      } else {
+        Derived(*left).template emplace<NewIndex>(
+            std::move(Access<NewIndex>(*right)));
+      }
+    }
+
+    void operator()(SizeT<absl::variant_npos> /*new_i*/) const {
+      Destroy(*left);
+    }
+
+    VType* left;
+    VType* right;
+  };
+
+  template <class VType>
+  static MoveAssignVisitor<VType> MakeMoveAssignVisitor(VType* left,
+                                                        VType* other) {
+    return {left, other};
+  }
+
+  // The implementation of the assignment operation for a variant.
+  template <class VType>
+  struct CopyAssignVisitor {
+    using DerivedType = typename VType::Variant;
+    template <std::size_t NewIndex>
+    void operator()(SizeT<NewIndex> /*new_i*/) const {
+      using New =
+          typename absl::variant_alternative<NewIndex, DerivedType>::type;
+
+      if (left->index_ == NewIndex) {
+        Access<NewIndex>(*left) = Access<NewIndex>(*right);
+      } else if (std::is_nothrow_copy_constructible<New>::value ||
+                 !std::is_nothrow_move_constructible<New>::value) {
+        Derived(*left).template emplace<NewIndex>(Access<NewIndex>(*right));
+      } else {
+        Derived(*left) = DerivedType(Derived(*right));
+      }
+    }
+
+    void operator()(SizeT<absl::variant_npos> /*new_i*/) const {
+      Destroy(*left);
+    }
+
+    VType* left;
+    const VType* right;
+  };
+
+  template <class VType>
+  static CopyAssignVisitor<VType> MakeCopyAssignVisitor(VType* left,
+                                                        const VType& other) {
+    return {left, &other};
+  }
+
+  // The implementation of conversion-assignment operations for variant.
+  template <class Left, class QualifiedNew>
+  struct ConversionAssignVisitor {
+    using NewIndex =
+        variant_internal::IndexOfConstructedType<Left, QualifiedNew>;
+
+    void operator()(SizeT<NewIndex::value> /*old_i*/
+                    ) const {
+      Access<NewIndex::value>(*left) = absl::forward<QualifiedNew>(other);
+    }
+
+    template <std::size_t OldIndex>
+    void operator()(SizeT<OldIndex> /*old_i*/
+                    ) const {
+      using New =
+          typename absl::variant_alternative<NewIndex::value, Left>::type;
+      if (std::is_nothrow_constructible<New, QualifiedNew>::value ||
+          !std::is_nothrow_move_constructible<New>::value) {
+        left->template emplace<NewIndex::value>(
+            absl::forward<QualifiedNew>(other));
+      } else {
+        // the standard says "equivalent to
+        // operator=(variant(std::forward<T>(t)))", but we use `emplace` here
+        // because the variant's move assignment operator could be deleted.
+        left->template emplace<NewIndex::value>(
+            New(absl::forward<QualifiedNew>(other)));
+      }
+    }
+
+    Left* left;
+    QualifiedNew&& other;
+  };
+
+  template <class Left, class QualifiedNew>
+  static ConversionAssignVisitor<Left, QualifiedNew>
+  MakeConversionAssignVisitor(Left* left, QualifiedNew&& qual) {
+    return {left, absl::forward<QualifiedNew>(qual)};
+  }
+
+  // Backend for operations for `emplace()` which destructs `*self` then
+  // construct a new alternative with `Args...`.
+  template <std::size_t NewIndex, class Self, class... Args>
+  static typename absl::variant_alternative<NewIndex, Self>::type& Replace(
+      Self* self, Args&&... args) {
+    Destroy(*self);
+    using New = typename absl::variant_alternative<NewIndex, Self>::type;
+    New* const result = ::new (static_cast<void*>(&self->state_))
+        New(absl::forward<Args>(args)...);
+    self->index_ = NewIndex;
+    return *result;
+  }
+
+  template <class LeftVariant, class QualifiedRightVariant>
+  struct InitFromVisitor {
+    template <std::size_t NewIndex>
+    void operator()(SizeT<NewIndex> /*new_i*/) const {
+      using Alternative =
+          typename variant_alternative<NewIndex, LeftVariant>::type;
+      ::new (static_cast<void*>(&left->state_)) Alternative(
+          Access<NewIndex>(std::forward<QualifiedRightVariant>(right)));
+    }
+
+    void operator()(SizeT<absl::variant_npos> /*new_i*/) const {
+      // This space intentionally left blank.
+    }
+    LeftVariant* left;
+    QualifiedRightVariant&& right;
+  };
+};
+
+template <class Expected, class... T>
+struct IndexOfImpl;
+
+template <class Expected>
+struct IndexOfImpl<Expected> {
+  using IndexFromEnd = SizeT<0>;
+  using MatchedIndexFromEnd = IndexFromEnd;
+  using MultipleMatches = std::false_type;
+};
+
+template <class Expected, class Head, class... Tail>
+struct IndexOfImpl<Expected, Head, Tail...> : IndexOfImpl<Expected, Tail...> {
+  using IndexFromEnd =
+      SizeT<IndexOfImpl<Expected, Tail...>::IndexFromEnd::value + 1>;
+};
+
+template <class Expected, class... Tail>
+struct IndexOfImpl<Expected, Expected, Tail...>
+    : IndexOfImpl<Expected, Tail...> {
+  using IndexFromEnd =
+      SizeT<IndexOfImpl<Expected, Tail...>::IndexFromEnd::value + 1>;
+  using MatchedIndexFromEnd = IndexFromEnd;
+  using MultipleMatches = std::integral_constant<
+      bool, IndexOfImpl<Expected, Tail...>::MatchedIndexFromEnd::value != 0>;
+};
+
+template <class Expected, class... Types>
+struct IndexOfMeta {
+  using Results = IndexOfImpl<Expected, Types...>;
+  static_assert(!Results::MultipleMatches::value,
+                "Attempted to access a variant by specifying a type that "
+                "matches more than one alternative.");
+  static_assert(Results::MatchedIndexFromEnd::value != 0,
+                "Attempted to access a variant by specifying a type that does "
+                "not match any alternative.");
+  using type = SizeT<sizeof...(Types) - Results::MatchedIndexFromEnd::value>;
+};
+
+template <class Expected, class... Types>
+using IndexOf = typename IndexOfMeta<Expected, Types...>::type;
+
+template <class Variant, class T, std::size_t CurrIndex>
+struct UnambiguousIndexOfImpl;
+
+// Terminating case encountered once we've checked all of the alternatives
+template <class T, std::size_t CurrIndex>
+struct UnambiguousIndexOfImpl<variant<>, T, CurrIndex> : SizeT<CurrIndex> {};
+
+// Case where T is not Head
+template <class Head, class... Tail, class T, std::size_t CurrIndex>
+struct UnambiguousIndexOfImpl<variant<Head, Tail...>, T, CurrIndex>
+    : UnambiguousIndexOfImpl<variant<Tail...>, T, CurrIndex + 1>::type {};
+
+// Case where T is Head
+template <class Head, class... Tail, std::size_t CurrIndex>
+struct UnambiguousIndexOfImpl<variant<Head, Tail...>, Head, CurrIndex>
+    : SizeT<UnambiguousIndexOfImpl<variant<Tail...>, Head, 0>::value ==
+                    sizeof...(Tail)
+                ? CurrIndex
+                : CurrIndex + sizeof...(Tail) + 1> {};
+
+template <class Variant, class T>
+struct UnambiguousIndexOf;
+
+struct NoMatch {
+  struct type {};
+};
+
+template <class... Alts, class T>
+struct UnambiguousIndexOf<variant<Alts...>, T>
+    : std::conditional<UnambiguousIndexOfImpl<variant<Alts...>, T, 0>::value !=
+                           sizeof...(Alts),
+                       UnambiguousIndexOfImpl<variant<Alts...>, T, 0>,
+                       NoMatch>::type::type {};
+
+template <class T, std::size_t /*Dummy*/>
+using UnambiguousTypeOfImpl = T;
+
+template <class Variant, class T>
+using UnambiguousTypeOfT =
+    UnambiguousTypeOfImpl<T, UnambiguousIndexOf<Variant, T>::value>;
+
+template <class H, class... T>
+class VariantStateBase;
+
+// This is an implementation of the "imaginary function" that is described in
+// [variant.ctor]
+// It is used in order to determine which alternative to construct during
+// initialization from some type T.
+template <class Variant, std::size_t I = 0>
+struct ImaginaryFun;
+
+template <std::size_t I>
+struct ImaginaryFun<variant<>, I> {
+  static void Run() = delete;
+};
+
+template <class H, class... T, std::size_t I>
+struct ImaginaryFun<variant<H, T...>, I> : ImaginaryFun<variant<T...>, I + 1> {
+  using ImaginaryFun<variant<T...>, I + 1>::Run;
+
+  // NOTE: const& and && are used instead of by-value due to lack of guaranteed
+  // move elision of C++17. This may have other minor differences, but tests
+  // pass.
+  static SizeT<I> Run(const H&, SizeT<I>);
+  static SizeT<I> Run(H&&, SizeT<I>);
+};
+
+// The following metafunctions are used in constructor and assignment
+// constraints.
+template <class Self, class T>
+struct IsNeitherSelfNorInPlace : std::true_type {};
+
+template <class Self>
+struct IsNeitherSelfNorInPlace<Self, Self> : std::false_type {};
+
+template <class Self, class T>
+struct IsNeitherSelfNorInPlace<Self, in_place_type_t<T>> : std::false_type {};
+
+template <class Self, std::size_t I>
+struct IsNeitherSelfNorInPlace<Self, in_place_index_t<I>> : std::false_type {};
+
+template <class Variant, class T, class = void>
+struct ConversionIsPossibleImpl : std::false_type {};
+
+template <class Variant, class T>
+struct ConversionIsPossibleImpl<
+    Variant, T,
+    void_t<decltype(ImaginaryFun<Variant>::Run(std::declval<T>(), {}))>>
+    : std::true_type {};
+
+template <class Variant, class T>
+struct ConversionIsPossible : ConversionIsPossibleImpl<Variant, T>::type {};
+
+template <class Variant, class T>
+struct IndexOfConstructedType<
+    Variant, T,
+    void_t<decltype(ImaginaryFun<Variant>::Run(std::declval<T>(), {}))>>
+    : decltype(ImaginaryFun<Variant>::Run(std::declval<T>(), {})) {};
+
+template <std::size_t... Is>
+struct ContainsVariantNPos
+    : absl::negation<std::is_same<  // NOLINT
+          absl::integer_sequence<bool, 0 <= Is...>,
+          absl::integer_sequence<bool, Is != absl::variant_npos...>>> {};
+
+template <class Op, class... QualifiedVariants>
+using RawVisitResult =
+    absl::result_of_t<Op(VariantAccessResult<0, QualifiedVariants>...)>;
+
+// NOTE: The spec requires that all return-paths yield the same type and is not
+// SFINAE-friendly, so we can deduce the return type by examining the first
+// result. If it's not callable, then we get an error, but are compliant and
+// fast to compile.
+// TODO(calabrese) Possibly rewrite in a way that yields better compile errors
+// at the cost of longer compile-times.
+template <class Op, class... QualifiedVariants>
+struct VisitResultImpl {
+  using type =
+      absl::result_of_t<Op(VariantAccessResult<0, QualifiedVariants>...)>;
+};
+
+// Done in two steps intentionally so that we don't cause substitution to fail.
+template <class Op, class... QualifiedVariants>
+using VisitResult = typename VisitResultImpl<Op, QualifiedVariants...>::type;
+
+template <class Op, class... QualifiedVariants>
+struct PerformVisitation {
+  using ReturnType = VisitResult<Op, QualifiedVariants...>;
+
+  template <std::size_t... Is>
+  constexpr ReturnType operator()(SizeT<Is>... indices) const {
+    return Run(typename ContainsVariantNPos<Is...>::type{},
+               absl::index_sequence_for<QualifiedVariants...>(), indices...);
+  }
+
+  template <std::size_t... TupIs, std::size_t... Is>
+  constexpr ReturnType Run(std::false_type /*has_valueless*/,
+                           index_sequence<TupIs...>, SizeT<Is>...) const {
+    static_assert(
+        std::is_same<ReturnType,
+                     absl::result_of_t<Op(VariantAccessResult<
+                                          Is, QualifiedVariants>...)>>::value,
+        "All visitation overloads must have the same return type.");
+    return absl::base_internal::invoke(
+        absl::forward<Op>(op),
+        VariantCoreAccess::Access<Is>(
+            absl::forward<QualifiedVariants>(std::get<TupIs>(variant_tup)))...);
+  }
+
+  template <std::size_t... TupIs, std::size_t... Is>
+  [[noreturn]] ReturnType Run(std::true_type /*has_valueless*/,
+                              index_sequence<TupIs...>, SizeT<Is>...) const {
+    absl::variant_internal::ThrowBadVariantAccess();
+  }
+
+  // TODO(calabrese) Avoid using a tuple, which causes lots of instantiations
+  // Attempts using lambda variadic captures fail on current GCC.
+  std::tuple<QualifiedVariants&&...> variant_tup;
+  Op&& op;
+};
+
+template <class... T>
+union Union;
+
+// We want to allow for variant<> to be trivial. For that, we need the default
+// constructor to be trivial, which means we can't define it ourselves.
+// Instead, we use a non-default constructor that takes NoopConstructorTag
+// that doesn't affect the triviality of the types.
+struct NoopConstructorTag {};
+
+template <std::size_t I>
+struct EmplaceTag {};
+
+template <>
+union Union<> {
+  constexpr explicit Union(NoopConstructorTag) noexcept {}
+};
+
+// Suppress bogus warning on MSVC: MSVC complains that Union<T...> has a defined
+// deleted destructor from the `std::is_destructible` check below.
+#ifdef _MSC_VER
+#pragma warning(push)
+#pragma warning(disable : 4624)
+#endif  // _MSC_VER
+
+template <class Head, class... Tail>
+union Union<Head, Tail...> {
+  using TailUnion = Union<Tail...>;
+
+  explicit constexpr Union(NoopConstructorTag /*tag*/) noexcept
+      : tail(NoopConstructorTag()) {}
+
+  template <class... P>
+  explicit constexpr Union(EmplaceTag<0>, P&&... args)
+      : head(absl::forward<P>(args)...) {}
+
+  template <std::size_t I, class... P>
+  explicit constexpr Union(EmplaceTag<I>, P&&... args)
+      : tail(EmplaceTag<I - 1>{}, absl::forward<P>(args)...) {}
+
+  Head head;
+  TailUnion tail;
+};
+
+#ifdef _MSC_VER
+#pragma warning(pop)
+#endif  // _MSC_VER
+
+// TODO(calabrese) Just contain a Union in this union (certain configs fail).
+template <class... T>
+union DestructibleUnionImpl;
+
+template <>
+union DestructibleUnionImpl<> {
+  constexpr explicit DestructibleUnionImpl(NoopConstructorTag) noexcept {}
+};
+
+template <class Head, class... Tail>
+union DestructibleUnionImpl<Head, Tail...> {
+  using TailUnion = DestructibleUnionImpl<Tail...>;
+
+  explicit constexpr DestructibleUnionImpl(NoopConstructorTag /*tag*/) noexcept
+      : tail(NoopConstructorTag()) {}
+
+  template <class... P>
+  explicit constexpr DestructibleUnionImpl(EmplaceTag<0>, P&&... args)
+      : head(absl::forward<P>(args)...) {}
+
+  template <std::size_t I, class... P>
+  explicit constexpr DestructibleUnionImpl(EmplaceTag<I>, P&&... args)
+      : tail(EmplaceTag<I - 1>{}, absl::forward<P>(args)...) {}
+
+  ~DestructibleUnionImpl() {}
+
+  Head head;
+  TailUnion tail;
+};
+
+// This union type is destructible even if one or more T are not trivially
+// destructible. In the case that all T are trivially destructible, then so is
+// this resultant type.
+template <class... T>
+using DestructibleUnion =
+    absl::conditional_t<std::is_destructible<Union<T...>>::value, Union<T...>,
+                        DestructibleUnionImpl<T...>>;
+
+// Deepest base, containing the actual union and the discriminator
+template <class H, class... T>
+class VariantStateBase {
+ protected:
+  using Variant = variant<H, T...>;
+
+  template <class LazyH = H,
+            class ConstructibleH = absl::enable_if_t<
+                std::is_default_constructible<LazyH>::value, LazyH>>
+  constexpr VariantStateBase() noexcept(
+      std::is_nothrow_default_constructible<ConstructibleH>::value)
+      : state_(EmplaceTag<0>()), index_(0) {}
+
+  template <std::size_t I, class... P>
+  explicit constexpr VariantStateBase(EmplaceTag<I> tag, P&&... args)
+      : state_(tag, absl::forward<P>(args)...), index_(I) {}
+
+  explicit constexpr VariantStateBase(NoopConstructorTag)
+      : state_(NoopConstructorTag()), index_(variant_npos) {}
+
+  void destroy() {}  // Does nothing (shadowed in child if non-trivial)
+
+  DestructibleUnion<H, T...> state_;
+  std::size_t index_;
+};
+
+using absl::internal::identity;
+
+// OverloadSet::Overload() is a unary function which is overloaded to
+// take any of the element types of the variant, by reference-to-const.
+// The return type of the overload on T is identity<T>, so that you
+// can statically determine which overload was called.
+//
+// Overload() is not defined, so it can only be called in unevaluated
+// contexts.
+template <typename... Ts>
+struct OverloadSet;
+
+template <typename T, typename... Ts>
+struct OverloadSet<T, Ts...> : OverloadSet<Ts...> {
+  using Base = OverloadSet<Ts...>;
+  static identity<T> Overload(const T&);
+  using Base::Overload;
+};
+
+template <>
+struct OverloadSet<> {
+  // For any case not handled above.
+  static void Overload(...);
+};
+
+template <class T>
+using LessThanResult = decltype(std::declval<T>() < std::declval<T>());
+
+template <class T>
+using GreaterThanResult = decltype(std::declval<T>() > std::declval<T>());
+
+template <class T>
+using LessThanOrEqualResult = decltype(std::declval<T>() <= std::declval<T>());
+
+template <class T>
+using GreaterThanOrEqualResult =
+    decltype(std::declval<T>() >= std::declval<T>());
+
+template <class T>
+using EqualResult = decltype(std::declval<T>() == std::declval<T>());
+
+template <class T>
+using NotEqualResult = decltype(std::declval<T>() != std::declval<T>());
+
+using type_traits_internal::is_detected_convertible;
+
+template <class... T>
+using RequireAllHaveEqualT = absl::enable_if_t<
+    absl::conjunction<is_detected_convertible<bool, EqualResult, T>...>::value,
+    bool>;
+
+template <class... T>
+using RequireAllHaveNotEqualT =
+    absl::enable_if_t<absl::conjunction<is_detected_convertible<
+                          bool, NotEqualResult, T>...>::value,
+                      bool>;
+
+template <class... T>
+using RequireAllHaveLessThanT =
+    absl::enable_if_t<absl::conjunction<is_detected_convertible<
+                          bool, LessThanResult, T>...>::value,
+                      bool>;
+
+template <class... T>
+using RequireAllHaveLessThanOrEqualT =
+    absl::enable_if_t<absl::conjunction<is_detected_convertible<
+                          bool, LessThanOrEqualResult, T>...>::value,
+                      bool>;
+
+template <class... T>
+using RequireAllHaveGreaterThanOrEqualT =
+    absl::enable_if_t<absl::conjunction<is_detected_convertible<
+                          bool, GreaterThanOrEqualResult, T>...>::value,
+                      bool>;
+
+template <class... T>
+using RequireAllHaveGreaterThanT =
+    absl::enable_if_t<absl::conjunction<is_detected_convertible<
+                          bool, GreaterThanResult, T>...>::value,
+                      bool>;
+
+// Helper template containing implementations details of variant that can't go
+// in the private section. For convenience, this takes the variant type as a
+// single template parameter.
+template <typename T>
+struct VariantHelper;
+
+template <typename... Ts>
+struct VariantHelper<variant<Ts...>> {
+  // Type metafunction which returns the element type selected if
+  // OverloadSet::Overload() is well-formed when called with argument type U.
+  template <typename U>
+  using BestMatch = decltype(
+      variant_internal::OverloadSet<Ts...>::Overload(std::declval<U>()));
+
+  // Type metafunction which returns true if OverloadSet::Overload() is
+  // well-formed when called with argument type U.
+  // CanAccept can't be just an alias because there is a MSVC bug on parameter
+  // pack expansion involving decltype.
+  template <typename U>
+  struct CanAccept :
+      std::integral_constant<bool, !std::is_void<BestMatch<U>>::value> {};
+
+  // Type metafunction which returns true if Other is an instantiation of
+  // variant, and variants's converting constructor from Other will be
+  // well-formed. We will use this to remove constructors that would be
+  // ill-formed from the overload set.
+  template <typename Other>
+  struct CanConvertFrom;
+
+  template <typename... Us>
+  struct CanConvertFrom<variant<Us...>>
+      : public absl::conjunction<CanAccept<Us>...> {};
+};
+
+// A type with nontrivial copy ctor and trivial move ctor.
+struct TrivialMoveOnly {
+  TrivialMoveOnly(TrivialMoveOnly&&) = default;
+};
+
+// Trait class to detect whether a type is trivially move constructible.
+// A union's defaulted copy/move constructor is deleted if any variant member's
+// copy/move constructor is nontrivial.
+template <typename T>
+struct IsTriviallyMoveConstructible:
+  std::is_move_constructible<Union<T, TrivialMoveOnly>> {};
+
+// To guarantee triviality of all special-member functions that can be trivial,
+// we use a chain of conditional bases for each one.
+// The order of inheritance of bases from child to base are logically:
+//
+// variant
+// VariantCopyAssignBase
+// VariantMoveAssignBase
+// VariantCopyBase
+// VariantMoveBase
+// VariantStateBaseDestructor
+// VariantStateBase
+//
+// Note that there is a separate branch at each base that is dependent on
+// whether or not that corresponding special-member-function can be trivial in
+// the resultant variant type.
+
+template <class... T>
+class VariantStateBaseDestructorNontrivial;
+
+template <class... T>
+class VariantMoveBaseNontrivial;
+
+template <class... T>
+class VariantCopyBaseNontrivial;
+
+template <class... T>
+class VariantMoveAssignBaseNontrivial;
+
+template <class... T>
+class VariantCopyAssignBaseNontrivial;
+
+// Base that is dependent on whether or not the destructor can be trivial.
+template <class... T>
+using VariantStateBaseDestructor =
+    absl::conditional_t<std::is_destructible<Union<T...>>::value,
+                        VariantStateBase<T...>,
+                        VariantStateBaseDestructorNontrivial<T...>>;
+
+// Base that is dependent on whether or not the move-constructor can be
+// implicitly generated by the compiler (trivial or deleted).
+// Previously we were using `std::is_move_constructible<Union<T...>>` to check
+// whether all Ts have trivial move constructor, but it ran into a GCC bug:
+// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=84866
+// So we have to use a different approach (i.e. `HasTrivialMoveConstructor`) to
+// work around the bug.
+template <class... T>
+using VariantMoveBase = absl::conditional_t<
+    absl::disjunction<
+        absl::negation<absl::conjunction<std::is_move_constructible<T>...>>,
+        absl::conjunction<IsTriviallyMoveConstructible<T>...>>::value,
+    VariantStateBaseDestructor<T...>, VariantMoveBaseNontrivial<T...>>;
+
+// Base that is dependent on whether or not the copy-constructor can be trivial.
+template <class... T>
+using VariantCopyBase = absl::conditional_t<
+    absl::disjunction<
+        absl::negation<absl::conjunction<std::is_copy_constructible<T>...>>,
+        std::is_copy_constructible<Union<T...>>>::value,
+    VariantMoveBase<T...>, VariantCopyBaseNontrivial<T...>>;
+
+// Base that is dependent on whether or not the move-assign can be trivial.
+template <class... T>
+using VariantMoveAssignBase = absl::conditional_t<
+    absl::disjunction<
+        absl::conjunction<absl::is_move_assignable<Union<T...>>,
+                          std::is_move_constructible<Union<T...>>,
+                          std::is_destructible<Union<T...>>>,
+        absl::negation<absl::conjunction<std::is_move_constructible<T>...,
+                                         // Note: We're not qualifying this with
+                                         // absl:: because it doesn't compile
+                                         // under MSVC.
+                                         is_move_assignable<T>...>>>::value,
+    VariantCopyBase<T...>, VariantMoveAssignBaseNontrivial<T...>>;
+
+// Base that is dependent on whether or not the copy-assign can be trivial.
+template <class... T>
+using VariantCopyAssignBase = absl::conditional_t<
+    absl::disjunction<
+        absl::conjunction<absl::is_copy_assignable<Union<T...>>,
+                          std::is_copy_constructible<Union<T...>>,
+                          std::is_destructible<Union<T...>>>,
+        absl::negation<absl::conjunction<std::is_copy_constructible<T>...,
+                                         // Note: We're not qualifying this with
+                                         // absl:: because it doesn't compile
+                                         // under MSVC.
+                                         is_copy_assignable<T>...>>>::value,
+    VariantMoveAssignBase<T...>, VariantCopyAssignBaseNontrivial<T...>>;
+
+template <class... T>
+using VariantBase = VariantCopyAssignBase<T...>;
+
+template <class... T>
+class VariantStateBaseDestructorNontrivial : protected VariantStateBase<T...> {
+ private:
+  using Base = VariantStateBase<T...>;
+
+ protected:
+  using Base::Base;
+
+  VariantStateBaseDestructorNontrivial() = default;
+  VariantStateBaseDestructorNontrivial(VariantStateBaseDestructorNontrivial&&) =
+      default;
+  VariantStateBaseDestructorNontrivial(
+      const VariantStateBaseDestructorNontrivial&) = default;
+  VariantStateBaseDestructorNontrivial& operator=(
+      VariantStateBaseDestructorNontrivial&&) = default;
+  VariantStateBaseDestructorNontrivial& operator=(
+      const VariantStateBaseDestructorNontrivial&) = default;
+
+  struct Destroyer {
+    template <std::size_t I>
+    void operator()(SizeT<I> i) const {
+      using Alternative =
+          typename absl::variant_alternative<I, variant<T...>>::type;
+      variant_internal::AccessUnion(self->state_, i).~Alternative();
+    }
+
+    void operator()(SizeT<absl::variant_npos> /*i*/) const {
+      // This space intentionally left blank
+    }
+
+    VariantStateBaseDestructorNontrivial* self;
+  };
+
+  void destroy() { VisitIndices<sizeof...(T)>::Run(Destroyer{this}, index_); }
+
+  ~VariantStateBaseDestructorNontrivial() { destroy(); }
+
+ protected:
+  using Base::index_;
+  using Base::state_;
+};
+
+template <class... T>
+class VariantMoveBaseNontrivial : protected VariantStateBaseDestructor<T...> {
+ private:
+  using Base = VariantStateBaseDestructor<T...>;
+
+ protected:
+  using Base::Base;
+
+  struct Construct {
+    template <std::size_t I>
+    void operator()(SizeT<I> i) const {
+      using Alternative =
+          typename absl::variant_alternative<I, variant<T...>>::type;
+      ::new (static_cast<void*>(&self->state_)) Alternative(
+          variant_internal::AccessUnion(absl::move(other->state_), i));
+    }
+
+    void operator()(SizeT<absl::variant_npos> /*i*/) const {}
+
+    VariantMoveBaseNontrivial* self;
+    VariantMoveBaseNontrivial* other;
+  };
+
+  VariantMoveBaseNontrivial() = default;
+  VariantMoveBaseNontrivial(VariantMoveBaseNontrivial&& other) noexcept(
+      absl::conjunction<std::is_nothrow_move_constructible<T>...>::value)
+      : Base(NoopConstructorTag()) {
+    VisitIndices<sizeof...(T)>::Run(Construct{this, &other}, other.index_);
+    index_ = other.index_;
+  }
+
+  VariantMoveBaseNontrivial(VariantMoveBaseNontrivial const&) = default;
+
+  VariantMoveBaseNontrivial& operator=(VariantMoveBaseNontrivial&&) = default;
+  VariantMoveBaseNontrivial& operator=(VariantMoveBaseNontrivial const&) =
+      default;
+
+ protected:
+  using Base::index_;
+  using Base::state_;
+};
+
+template <class... T>
+class VariantCopyBaseNontrivial : protected VariantMoveBase<T...> {
+ private:
+  using Base = VariantMoveBase<T...>;
+
+ protected:
+  using Base::Base;
+
+  VariantCopyBaseNontrivial() = default;
+  VariantCopyBaseNontrivial(VariantCopyBaseNontrivial&&) = default;
+
+  struct Construct {
+    template <std::size_t I>
+    void operator()(SizeT<I> i) const {
+      using Alternative =
+          typename absl::variant_alternative<I, variant<T...>>::type;
+      ::new (static_cast<void*>(&self->state_))
+          Alternative(variant_internal::AccessUnion(other->state_, i));
+    }
+
+    void operator()(SizeT<absl::variant_npos> /*i*/) const {}
+
+    VariantCopyBaseNontrivial* self;
+    const VariantCopyBaseNontrivial* other;
+  };
+
+  VariantCopyBaseNontrivial(VariantCopyBaseNontrivial const& other)
+      : Base(NoopConstructorTag()) {
+    VisitIndices<sizeof...(T)>::Run(Construct{this, &other}, other.index_);
+    index_ = other.index_;
+  }
+
+  VariantCopyBaseNontrivial& operator=(VariantCopyBaseNontrivial&&) = default;
+  VariantCopyBaseNontrivial& operator=(VariantCopyBaseNontrivial const&) =
+      default;
+
+ protected:
+  using Base::index_;
+  using Base::state_;
+};
+
+template <class... T>
+class VariantMoveAssignBaseNontrivial : protected VariantCopyBase<T...> {
+  friend struct VariantCoreAccess;
+
+ private:
+  using Base = VariantCopyBase<T...>;
+
+ protected:
+  using Base::Base;
+
+  VariantMoveAssignBaseNontrivial() = default;
+  VariantMoveAssignBaseNontrivial(VariantMoveAssignBaseNontrivial&&) = default;
+  VariantMoveAssignBaseNontrivial(const VariantMoveAssignBaseNontrivial&) =
+      default;
+  VariantMoveAssignBaseNontrivial& operator=(
+      VariantMoveAssignBaseNontrivial const&) = default;
+
+    VariantMoveAssignBaseNontrivial&
+    operator=(VariantMoveAssignBaseNontrivial&& other) noexcept(
+        absl::conjunction<std::is_nothrow_move_constructible<T>...,
+                          std::is_nothrow_move_assignable<T>...>::value) {
+      VisitIndices<sizeof...(T)>::Run(
+          VariantCoreAccess::MakeMoveAssignVisitor(this, &other), other.index_);
+      return *this;
+    }
+
+ protected:
+  using Base::index_;
+  using Base::state_;
+};
+
+template <class... T>
+class VariantCopyAssignBaseNontrivial : protected VariantMoveAssignBase<T...> {
+  friend struct VariantCoreAccess;
+
+ private:
+  using Base = VariantMoveAssignBase<T...>;
+
+ protected:
+  using Base::Base;
+
+  VariantCopyAssignBaseNontrivial() = default;
+  VariantCopyAssignBaseNontrivial(VariantCopyAssignBaseNontrivial&&) = default;
+  VariantCopyAssignBaseNontrivial(const VariantCopyAssignBaseNontrivial&) =
+      default;
+  VariantCopyAssignBaseNontrivial& operator=(
+      VariantCopyAssignBaseNontrivial&&) = default;
+
+    VariantCopyAssignBaseNontrivial& operator=(
+        const VariantCopyAssignBaseNontrivial& other) {
+      VisitIndices<sizeof...(T)>::Run(
+          VariantCoreAccess::MakeCopyAssignVisitor(this, other), other.index_);
+      return *this;
+    }
+
+ protected:
+  using Base::index_;
+  using Base::state_;
+};
+
+////////////////////////////////////////
+// Visitors for Comparison Operations //
+////////////////////////////////////////
+
+template <class... Types>
+struct EqualsOp {
+  const variant<Types...>* v;
+  const variant<Types...>* w;
+
+  constexpr bool operator()(SizeT<absl::variant_npos> /*v_i*/) const {
+    return true;
+  }
+
+  template <std::size_t I>
+  constexpr bool operator()(SizeT<I> /*v_i*/) const {
+    return VariantCoreAccess::Access<I>(*v) == VariantCoreAccess::Access<I>(*w);
+  }
+};
+
+template <class... Types>
+struct NotEqualsOp {
+  const variant<Types...>* v;
+  const variant<Types...>* w;
+
+  constexpr bool operator()(SizeT<absl::variant_npos> /*v_i*/) const {
+    return false;
+  }
+
+  template <std::size_t I>
+  constexpr bool operator()(SizeT<I> /*v_i*/) const {
+    return VariantCoreAccess::Access<I>(*v) != VariantCoreAccess::Access<I>(*w);
+  }
+};
+
+template <class... Types>
+struct LessThanOp {
+  const variant<Types...>* v;
+  const variant<Types...>* w;
+
+  constexpr bool operator()(SizeT<absl::variant_npos> /*v_i*/) const {
+    return false;
+  }
+
+  template <std::size_t I>
+  constexpr bool operator()(SizeT<I> /*v_i*/) const {
+    return VariantCoreAccess::Access<I>(*v) < VariantCoreAccess::Access<I>(*w);
+  }
+};
+
+template <class... Types>
+struct GreaterThanOp {
+  const variant<Types...>* v;
+  const variant<Types...>* w;
+
+  constexpr bool operator()(SizeT<absl::variant_npos> /*v_i*/) const {
+    return false;
+  }
+
+  template <std::size_t I>
+  constexpr bool operator()(SizeT<I> /*v_i*/) const {
+    return VariantCoreAccess::Access<I>(*v) > VariantCoreAccess::Access<I>(*w);
+  }
+};
+
+template <class... Types>
+struct LessThanOrEqualsOp {
+  const variant<Types...>* v;
+  const variant<Types...>* w;
+
+  constexpr bool operator()(SizeT<absl::variant_npos> /*v_i*/) const {
+    return true;
+  }
+
+  template <std::size_t I>
+  constexpr bool operator()(SizeT<I> /*v_i*/) const {
+    return VariantCoreAccess::Access<I>(*v) <= VariantCoreAccess::Access<I>(*w);
+  }
+};
+
+template <class... Types>
+struct GreaterThanOrEqualsOp {
+  const variant<Types...>* v;
+  const variant<Types...>* w;
+
+  constexpr bool operator()(SizeT<absl::variant_npos> /*v_i*/) const {
+    return true;
+  }
+
+  template <std::size_t I>
+  constexpr bool operator()(SizeT<I> /*v_i*/) const {
+    return VariantCoreAccess::Access<I>(*v) >= VariantCoreAccess::Access<I>(*w);
+  }
+};
+
+// Precondition: v.index() == w.index();
+template <class... Types>
+struct SwapSameIndex {
+  variant<Types...>* v;
+  variant<Types...>* w;
+  template <std::size_t I>
+  void operator()(SizeT<I>) const {
+    type_traits_internal::Swap(VariantCoreAccess::Access<I>(*v),
+                               VariantCoreAccess::Access<I>(*w));
+  }
+
+  void operator()(SizeT<variant_npos>) const {}
+};
+
+// TODO(calabrese) do this from a different namespace for proper adl usage
+template <class... Types>
+struct Swap {
+  variant<Types...>* v;
+  variant<Types...>* w;
+
+  void generic_swap() const {
+    variant<Types...> tmp(std::move(*w));
+    VariantCoreAccess::Destroy(*w);
+    VariantCoreAccess::InitFrom(*w, std::move(*v));
+    VariantCoreAccess::Destroy(*v);
+    VariantCoreAccess::InitFrom(*v, std::move(tmp));
+  }
+
+  void operator()(SizeT<absl::variant_npos> /*w_i*/) const {
+    if (!v->valueless_by_exception()) {
+      generic_swap();
+    }
+  }
+
+  template <std::size_t Wi>
+  void operator()(SizeT<Wi> /*w_i*/) {
+    if (v->index() == Wi) {
+      VisitIndices<sizeof...(Types)>::Run(SwapSameIndex<Types...>{v, w}, Wi);
+    } else {
+      generic_swap();
+    }
+  }
+};
+
+template <typename Variant, typename = void, typename... Ts>
+struct VariantHashBase {
+  VariantHashBase() = delete;
+  VariantHashBase(const VariantHashBase&) = delete;
+  VariantHashBase(VariantHashBase&&) = delete;
+  VariantHashBase& operator=(const VariantHashBase&) = delete;
+  VariantHashBase& operator=(VariantHashBase&&) = delete;
+};
+
+struct VariantHashVisitor {
+  template <typename T>
+  size_t operator()(const T& t) {
+    return std::hash<T>{}(t);
+  }
+};
+
+template <typename Variant, typename... Ts>
+struct VariantHashBase<Variant,
+                       absl::enable_if_t<absl::conjunction<
+                           type_traits_internal::IsHashable<Ts>...>::value>,
+                       Ts...> {
+  using argument_type = Variant;
+  using result_type = size_t;
+  size_t operator()(const Variant& var) const {
+    type_traits_internal::AssertHashEnabled<Ts...>();
+    if (var.valueless_by_exception()) {
+      return 239799884;
+    }
+    size_t result = VisitIndices<variant_size<Variant>::value>::Run(
+        PerformVisitation<VariantHashVisitor, const Variant&>{
+            std::forward_as_tuple(var), VariantHashVisitor{}},
+        var.index());
+    // Combine the index and the hash result in order to distinguish
+    // std::variant<int, int> holding the same value as different alternative.
+    return result ^ var.index();
+  }
+};
+
+}  // namespace variant_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#endif  // !defined(ABSL_USES_STD_VARIANT)
+#endif  // ABSL_TYPES_variant_internal_H_
diff --git a/src/absl/types/optional.h b/src/absl/types/optional.h
new file mode 100644 (file)
index 0000000..61540cf
--- /dev/null
@@ -0,0 +1,776 @@
+// Copyright 2017 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// -----------------------------------------------------------------------------
+// optional.h
+// -----------------------------------------------------------------------------
+//
+// This header file defines the `absl::optional` type for holding a value which
+// may or may not be present. This type is useful for providing value semantics
+// for operations that may either wish to return or hold "something-or-nothing".
+//
+// Example:
+//
+//   // A common way to signal operation failure is to provide an output
+//   // parameter and a bool return type:
+//   bool AcquireResource(const Input&, Resource * out);
+//
+//   // Providing an absl::optional return type provides a cleaner API:
+//   absl::optional<Resource> AcquireResource(const Input&);
+//
+// `absl::optional` is a C++11 compatible version of the C++17 `std::optional`
+// abstraction and is designed to be a drop-in replacement for code compliant
+// with C++17.
+#ifndef ABSL_TYPES_OPTIONAL_H_
+#define ABSL_TYPES_OPTIONAL_H_
+
+#include "absl/base/config.h"   // TODO(calabrese) IWYU removal?
+#include "absl/utility/utility.h"
+
+#ifdef ABSL_USES_STD_OPTIONAL
+
+#include <optional>  // IWYU pragma: export
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+using std::bad_optional_access;
+using std::optional;
+using std::make_optional;
+using std::nullopt_t;
+using std::nullopt;
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#else  // ABSL_USES_STD_OPTIONAL
+
+#include <cassert>
+#include <functional>
+#include <initializer_list>
+#include <type_traits>
+#include <utility>
+
+#include "absl/base/attributes.h"
+#include "absl/base/internal/inline_variable.h"
+#include "absl/meta/type_traits.h"
+#include "absl/types/bad_optional_access.h"
+#include "absl/types/internal/optional.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+
+// nullopt_t
+//
+// Class type for `absl::nullopt` used to indicate an `absl::optional<T>` type
+// that does not contain a value.
+struct nullopt_t {
+  // It must not be default-constructible to avoid ambiguity for opt = {}.
+  explicit constexpr nullopt_t(optional_internal::init_t) noexcept {}
+};
+
+// nullopt
+//
+// A tag constant of type `absl::nullopt_t` used to indicate an empty
+// `absl::optional` in certain functions, such as construction or assignment.
+ABSL_INTERNAL_INLINE_CONSTEXPR(nullopt_t, nullopt,
+                               nullopt_t(optional_internal::init_t()));
+
+// -----------------------------------------------------------------------------
+// absl::optional
+// -----------------------------------------------------------------------------
+//
+// A value of type `absl::optional<T>` holds either a value of `T` or an
+// "empty" value.  When it holds a value of `T`, it stores it as a direct
+// sub-object, so `sizeof(optional<T>)` is approximately
+// `sizeof(T) + sizeof(bool)`.
+//
+// This implementation is based on the specification in the latest draft of the
+// C++17 `std::optional` specification as of May 2017, section 20.6.
+//
+// Differences between `absl::optional<T>` and `std::optional<T>` include:
+//
+//    * `constexpr` is not used for non-const member functions.
+//      (dependency on some differences between C++11 and C++14.)
+//    * `absl::nullopt` and `absl::in_place` are not declared `constexpr`. We
+//      need the inline variable support in C++17 for external linkage.
+//    * Throws `absl::bad_optional_access` instead of
+//      `std::bad_optional_access`.
+//    * `make_optional()` cannot be declared `constexpr` due to the absence of
+//      guaranteed copy elision.
+//    * The move constructor's `noexcept` specification is stronger, i.e. if the
+//      default allocator is non-throwing (via setting
+//      `ABSL_ALLOCATOR_NOTHROW`), it evaluates to `noexcept(true)`, because
+//      we assume
+//       a) move constructors should only throw due to allocation failure and
+//       b) if T's move constructor allocates, it uses the same allocation
+//          function as the default allocator.
+//
+template <typename T>
+class optional : private optional_internal::optional_data<T>,
+                 private optional_internal::optional_ctor_base<
+                     optional_internal::ctor_copy_traits<T>::traits>,
+                 private optional_internal::optional_assign_base<
+                     optional_internal::assign_copy_traits<T>::traits> {
+  using data_base = optional_internal::optional_data<T>;
+
+ public:
+  typedef T value_type;
+
+  // Constructors
+
+  // Constructs an `optional` holding an empty value, NOT a default constructed
+  // `T`.
+  constexpr optional() noexcept {}
+
+  // Constructs an `optional` initialized with `nullopt` to hold an empty value.
+  constexpr optional(nullopt_t) noexcept {}  // NOLINT(runtime/explicit)
+
+  // Copy constructor, standard semantics
+  optional(const optional&) = default;
+
+  // Move constructor, standard semantics
+  optional(optional&&) = default;
+
+  // Constructs a non-empty `optional` direct-initialized value of type `T` from
+  // the arguments `std::forward<Args>(args)...`  within the `optional`.
+  // (The `in_place_t` is a tag used to indicate that the contained object
+  // should be constructed in-place.)
+  template <typename InPlaceT, typename... Args,
+            absl::enable_if_t<absl::conjunction<
+                std::is_same<InPlaceT, in_place_t>,
+                std::is_constructible<T, Args&&...> >::value>* = nullptr>
+  constexpr explicit optional(InPlaceT, Args&&... args)
+      : data_base(in_place_t(), absl::forward<Args>(args)...) {}
+
+  // Constructs a non-empty `optional` direct-initialized value of type `T` from
+  // the arguments of an initializer_list and `std::forward<Args>(args)...`.
+  // (The `in_place_t` is a tag used to indicate that the contained object
+  // should be constructed in-place.)
+  template <typename U, typename... Args,
+            typename = typename std::enable_if<std::is_constructible<
+                T, std::initializer_list<U>&, Args&&...>::value>::type>
+  constexpr explicit optional(in_place_t, std::initializer_list<U> il,
+                              Args&&... args)
+      : data_base(in_place_t(), il, absl::forward<Args>(args)...) {
+  }
+
+  // Value constructor (implicit)
+  template <
+      typename U = T,
+      typename std::enable_if<
+          absl::conjunction<absl::negation<std::is_same<
+                                in_place_t, typename std::decay<U>::type> >,
+                            absl::negation<std::is_same<
+                                optional<T>, typename std::decay<U>::type> >,
+                            std::is_convertible<U&&, T>,
+                            std::is_constructible<T, U&&> >::value,
+          bool>::type = false>
+  constexpr optional(U&& v) : data_base(in_place_t(), absl::forward<U>(v)) {}
+
+  // Value constructor (explicit)
+  template <
+      typename U = T,
+      typename std::enable_if<
+          absl::conjunction<absl::negation<std::is_same<
+                                in_place_t, typename std::decay<U>::type>>,
+                            absl::negation<std::is_same<
+                                optional<T>, typename std::decay<U>::type>>,
+                            absl::negation<std::is_convertible<U&&, T>>,
+                            std::is_constructible<T, U&&>>::value,
+          bool>::type = false>
+  explicit constexpr optional(U&& v)
+      : data_base(in_place_t(), absl::forward<U>(v)) {}
+
+  // Converting copy constructor (implicit)
+  template <typename U,
+            typename std::enable_if<
+                absl::conjunction<
+                    absl::negation<std::is_same<T, U> >,
+                    std::is_constructible<T, const U&>,
+                    absl::negation<
+                        optional_internal::
+                            is_constructible_convertible_from_optional<T, U> >,
+                    std::is_convertible<const U&, T> >::value,
+                bool>::type = false>
+  optional(const optional<U>& rhs) {
+    if (rhs) {
+      this->construct(*rhs);
+    }
+  }
+
+  // Converting copy constructor (explicit)
+  template <typename U,
+            typename std::enable_if<
+                absl::conjunction<
+                    absl::negation<std::is_same<T, U>>,
+                    std::is_constructible<T, const U&>,
+                    absl::negation<
+                        optional_internal::
+                            is_constructible_convertible_from_optional<T, U>>,
+                    absl::negation<std::is_convertible<const U&, T>>>::value,
+                bool>::type = false>
+  explicit optional(const optional<U>& rhs) {
+    if (rhs) {
+      this->construct(*rhs);
+    }
+  }
+
+  // Converting move constructor (implicit)
+  template <typename U,
+            typename std::enable_if<
+                absl::conjunction<
+                    absl::negation<std::is_same<T, U> >,
+                    std::is_constructible<T, U&&>,
+                    absl::negation<
+                        optional_internal::
+                            is_constructible_convertible_from_optional<T, U> >,
+                    std::is_convertible<U&&, T> >::value,
+                bool>::type = false>
+  optional(optional<U>&& rhs) {
+    if (rhs) {
+      this->construct(std::move(*rhs));
+    }
+  }
+
+  // Converting move constructor (explicit)
+  template <
+      typename U,
+      typename std::enable_if<
+          absl::conjunction<
+              absl::negation<std::is_same<T, U>>, std::is_constructible<T, U&&>,
+              absl::negation<
+                  optional_internal::is_constructible_convertible_from_optional<
+                      T, U>>,
+              absl::negation<std::is_convertible<U&&, T>>>::value,
+          bool>::type = false>
+  explicit optional(optional<U>&& rhs) {
+    if (rhs) {
+      this->construct(std::move(*rhs));
+    }
+  }
+
+  // Destructor. Trivial if `T` is trivially destructible.
+  ~optional() = default;
+
+  // Assignment Operators
+
+  // Assignment from `nullopt`
+  //
+  // Example:
+  //
+  //   struct S { int value; };
+  //   optional<S> opt = absl::nullopt;  // Could also use opt = { };
+  optional& operator=(nullopt_t) noexcept {
+    this->destruct();
+    return *this;
+  }
+
+  // Copy assignment operator, standard semantics
+  optional& operator=(const optional& src) = default;
+
+  // Move assignment operator, standard semantics
+  optional& operator=(optional&& src) = default;
+
+  // Value assignment operators
+  template <
+      typename U = T,
+      typename = typename std::enable_if<absl::conjunction<
+          absl::negation<
+              std::is_same<optional<T>, typename std::decay<U>::type>>,
+          absl::negation<
+              absl::conjunction<std::is_scalar<T>,
+                                std::is_same<T, typename std::decay<U>::type>>>,
+          std::is_constructible<T, U>, std::is_assignable<T&, U>>::value>::type>
+  optional& operator=(U&& v) {
+    this->assign(std::forward<U>(v));
+    return *this;
+  }
+
+  template <
+      typename U,
+      typename = typename std::enable_if<absl::conjunction<
+          absl::negation<std::is_same<T, U>>,
+          std::is_constructible<T, const U&>, std::is_assignable<T&, const U&>,
+          absl::negation<
+              optional_internal::
+                  is_constructible_convertible_assignable_from_optional<
+                      T, U>>>::value>::type>
+  optional& operator=(const optional<U>& rhs) {
+    if (rhs) {
+      this->assign(*rhs);
+    } else {
+      this->destruct();
+    }
+    return *this;
+  }
+
+  template <typename U,
+            typename = typename std::enable_if<absl::conjunction<
+                absl::negation<std::is_same<T, U>>, std::is_constructible<T, U>,
+                std::is_assignable<T&, U>,
+                absl::negation<
+                    optional_internal::
+                        is_constructible_convertible_assignable_from_optional<
+                            T, U>>>::value>::type>
+  optional& operator=(optional<U>&& rhs) {
+    if (rhs) {
+      this->assign(std::move(*rhs));
+    } else {
+      this->destruct();
+    }
+    return *this;
+  }
+
+  // Modifiers
+
+  // optional::reset()
+  //
+  // Destroys the inner `T` value of an `absl::optional` if one is present.
+  ABSL_ATTRIBUTE_REINITIALIZES void reset() noexcept { this->destruct(); }
+
+  // optional::emplace()
+  //
+  // (Re)constructs the underlying `T` in-place with the given forwarded
+  // arguments.
+  //
+  // Example:
+  //
+  //   optional<Foo> opt;
+  //   opt.emplace(arg1,arg2,arg3);  // Constructs Foo(arg1,arg2,arg3)
+  //
+  // If the optional is non-empty, and the `args` refer to subobjects of the
+  // current object, then behaviour is undefined, because the current object
+  // will be destructed before the new object is constructed with `args`.
+  template <typename... Args,
+            typename = typename std::enable_if<
+                std::is_constructible<T, Args&&...>::value>::type>
+  T& emplace(Args&&... args) {
+    this->destruct();
+    this->construct(std::forward<Args>(args)...);
+    return reference();
+  }
+
+  // Emplace reconstruction overload for an initializer list and the given
+  // forwarded arguments.
+  //
+  // Example:
+  //
+  //   struct Foo {
+  //     Foo(std::initializer_list<int>);
+  //   };
+  //
+  //   optional<Foo> opt;
+  //   opt.emplace({1,2,3});  // Constructs Foo({1,2,3})
+  template <typename U, typename... Args,
+            typename = typename std::enable_if<std::is_constructible<
+                T, std::initializer_list<U>&, Args&&...>::value>::type>
+  T& emplace(std::initializer_list<U> il, Args&&... args) {
+    this->destruct();
+    this->construct(il, std::forward<Args>(args)...);
+    return reference();
+  }
+
+  // Swaps
+
+  // Swap, standard semantics
+  void swap(optional& rhs) noexcept(
+      std::is_nothrow_move_constructible<T>::value&&
+          type_traits_internal::IsNothrowSwappable<T>::value) {
+    if (*this) {
+      if (rhs) {
+        type_traits_internal::Swap(**this, *rhs);
+      } else {
+        rhs.construct(std::move(**this));
+        this->destruct();
+      }
+    } else {
+      if (rhs) {
+        this->construct(std::move(*rhs));
+        rhs.destruct();
+      } else {
+        // No effect (swap(disengaged, disengaged)).
+      }
+    }
+  }
+
+  // Observers
+
+  // optional::operator->()
+  //
+  // Accesses the underlying `T` value's member `m` of an `optional`. If the
+  // `optional` is empty, behavior is undefined.
+  //
+  // If you need myOpt->foo in constexpr, use (*myOpt).foo instead.
+  const T* operator->() const {
+    ABSL_HARDENING_ASSERT(this->engaged_);
+    return std::addressof(this->data_);
+  }
+  T* operator->() {
+    ABSL_HARDENING_ASSERT(this->engaged_);
+    return std::addressof(this->data_);
+  }
+
+  // optional::operator*()
+  //
+  // Accesses the underlying `T` value of an `optional`. If the `optional` is
+  // empty, behavior is undefined.
+  constexpr const T& operator*() const& {
+    return ABSL_HARDENING_ASSERT(this->engaged_), reference();
+  }
+  T& operator*() & {
+    ABSL_HARDENING_ASSERT(this->engaged_);
+    return reference();
+  }
+  constexpr const T&& operator*() const && {
+    return ABSL_HARDENING_ASSERT(this->engaged_), absl::move(reference());
+  }
+  T&& operator*() && {
+    ABSL_HARDENING_ASSERT(this->engaged_);
+    return std::move(reference());
+  }
+
+  // optional::operator bool()
+  //
+  // Returns false if and only if the `optional` is empty.
+  //
+  //   if (opt) {
+  //     // do something with *opt or opt->;
+  //   } else {
+  //     // opt is empty.
+  //   }
+  //
+  constexpr explicit operator bool() const noexcept { return this->engaged_; }
+
+  // optional::has_value()
+  //
+  // Determines whether the `optional` contains a value. Returns `false` if and
+  // only if `*this` is empty.
+  constexpr bool has_value() const noexcept { return this->engaged_; }
+
+// Suppress bogus warning on MSVC: MSVC complains call to reference() after
+// throw_bad_optional_access() is unreachable.
+#ifdef _MSC_VER
+#pragma warning(push)
+#pragma warning(disable : 4702)
+#endif  // _MSC_VER
+  // optional::value()
+  //
+  // Returns a reference to an `optional`s underlying value. The constness
+  // and lvalue/rvalue-ness of the `optional` is preserved to the view of
+  // the `T` sub-object. Throws `absl::bad_optional_access` when the `optional`
+  // is empty.
+  constexpr const T& value() const & {
+    return static_cast<bool>(*this)
+               ? reference()
+               : (optional_internal::throw_bad_optional_access(), reference());
+  }
+  T& value() & {
+    return static_cast<bool>(*this)
+               ? reference()
+               : (optional_internal::throw_bad_optional_access(), reference());
+  }
+  T&& value() && {  // NOLINT(build/c++11)
+    return std::move(
+        static_cast<bool>(*this)
+            ? reference()
+            : (optional_internal::throw_bad_optional_access(), reference()));
+  }
+  constexpr const T&& value() const && {  // NOLINT(build/c++11)
+    return absl::move(
+        static_cast<bool>(*this)
+            ? reference()
+            : (optional_internal::throw_bad_optional_access(), reference()));
+  }
+#ifdef _MSC_VER
+#pragma warning(pop)
+#endif  // _MSC_VER
+
+  // optional::value_or()
+  //
+  // Returns either the value of `T` or a passed default `v` if the `optional`
+  // is empty.
+  template <typename U>
+  constexpr T value_or(U&& v) const& {
+    static_assert(std::is_copy_constructible<value_type>::value,
+                  "optional<T>::value_or: T must be copy constructible");
+    static_assert(std::is_convertible<U&&, value_type>::value,
+                  "optional<T>::value_or: U must be convertible to T");
+    return static_cast<bool>(*this)
+               ? **this
+               : static_cast<T>(absl::forward<U>(v));
+  }
+  template <typename U>
+  T value_or(U&& v) && {  // NOLINT(build/c++11)
+    static_assert(std::is_move_constructible<value_type>::value,
+                  "optional<T>::value_or: T must be move constructible");
+    static_assert(std::is_convertible<U&&, value_type>::value,
+                  "optional<T>::value_or: U must be convertible to T");
+    return static_cast<bool>(*this) ? std::move(**this)
+                                    : static_cast<T>(std::forward<U>(v));
+  }
+
+ private:
+  // Private accessors for internal storage viewed as reference to T.
+  constexpr const T& reference() const { return this->data_; }
+  T& reference() { return this->data_; }
+
+  // T constraint checks.  You can't have an optional of nullopt_t, in_place_t
+  // or a reference.
+  static_assert(
+      !std::is_same<nullopt_t, typename std::remove_cv<T>::type>::value,
+      "optional<nullopt_t> is not allowed.");
+  static_assert(
+      !std::is_same<in_place_t, typename std::remove_cv<T>::type>::value,
+      "optional<in_place_t> is not allowed.");
+  static_assert(!std::is_reference<T>::value,
+                "optional<reference> is not allowed.");
+};
+
+// Non-member functions
+
+// swap()
+//
+// Performs a swap between two `absl::optional` objects, using standard
+// semantics.
+template <typename T, typename std::enable_if<
+                          std::is_move_constructible<T>::value &&
+                              type_traits_internal::IsSwappable<T>::value,
+                          bool>::type = false>
+void swap(optional<T>& a, optional<T>& b) noexcept(noexcept(a.swap(b))) {
+  a.swap(b);
+}
+
+// make_optional()
+//
+// Creates a non-empty `optional<T>` where the type of `T` is deduced. An
+// `absl::optional` can also be explicitly instantiated with
+// `make_optional<T>(v)`.
+//
+// Note: `make_optional()` constructions may be declared `constexpr` for
+// trivially copyable types `T`. Non-trivial types require copy elision
+// support in C++17 for `make_optional` to support `constexpr` on such
+// non-trivial types.
+//
+// Example:
+//
+//   constexpr absl::optional<int> opt = absl::make_optional(1);
+//   static_assert(opt.value() == 1, "");
+template <typename T>
+constexpr optional<typename std::decay<T>::type> make_optional(T&& v) {
+  return optional<typename std::decay<T>::type>(absl::forward<T>(v));
+}
+
+template <typename T, typename... Args>
+constexpr optional<T> make_optional(Args&&... args) {
+  return optional<T>(in_place_t(), absl::forward<Args>(args)...);
+}
+
+template <typename T, typename U, typename... Args>
+constexpr optional<T> make_optional(std::initializer_list<U> il,
+                                    Args&&... args) {
+  return optional<T>(in_place_t(), il,
+                     absl::forward<Args>(args)...);
+}
+
+// Relational operators [optional.relops]
+
+// Empty optionals are considered equal to each other and less than non-empty
+// optionals. Supports relations between optional<T> and optional<U>, between
+// optional<T> and U, and between optional<T> and nullopt.
+//
+// Note: We're careful to support T having non-bool relationals.
+
+// Requires: The expression, e.g. "*x == *y" shall be well-formed and its result
+// shall be convertible to bool.
+// The C++17 (N4606) "Returns:" statements are translated into
+// code in an obvious way here, and the original text retained as function docs.
+// Returns: If bool(x) != bool(y), false; otherwise if bool(x) == false, true;
+// otherwise *x == *y.
+template <typename T, typename U>
+constexpr auto operator==(const optional<T>& x, const optional<U>& y)
+    -> decltype(optional_internal::convertible_to_bool(*x == *y)) {
+  return static_cast<bool>(x) != static_cast<bool>(y)
+             ? false
+             : static_cast<bool>(x) == false ? true
+                                             : static_cast<bool>(*x == *y);
+}
+
+// Returns: If bool(x) != bool(y), true; otherwise, if bool(x) == false, false;
+// otherwise *x != *y.
+template <typename T, typename U>
+constexpr auto operator!=(const optional<T>& x, const optional<U>& y)
+    -> decltype(optional_internal::convertible_to_bool(*x != *y)) {
+  return static_cast<bool>(x) != static_cast<bool>(y)
+             ? true
+             : static_cast<bool>(x) == false ? false
+                                             : static_cast<bool>(*x != *y);
+}
+// Returns: If !y, false; otherwise, if !x, true; otherwise *x < *y.
+template <typename T, typename U>
+constexpr auto operator<(const optional<T>& x, const optional<U>& y)
+    -> decltype(optional_internal::convertible_to_bool(*x < *y)) {
+  return !y ? false : !x ? true : static_cast<bool>(*x < *y);
+}
+// Returns: If !x, false; otherwise, if !y, true; otherwise *x > *y.
+template <typename T, typename U>
+constexpr auto operator>(const optional<T>& x, const optional<U>& y)
+    -> decltype(optional_internal::convertible_to_bool(*x > *y)) {
+  return !x ? false : !y ? true : static_cast<bool>(*x > *y);
+}
+// Returns: If !x, true; otherwise, if !y, false; otherwise *x <= *y.
+template <typename T, typename U>
+constexpr auto operator<=(const optional<T>& x, const optional<U>& y)
+    -> decltype(optional_internal::convertible_to_bool(*x <= *y)) {
+  return !x ? true : !y ? false : static_cast<bool>(*x <= *y);
+}
+// Returns: If !y, true; otherwise, if !x, false; otherwise *x >= *y.
+template <typename T, typename U>
+constexpr auto operator>=(const optional<T>& x, const optional<U>& y)
+    -> decltype(optional_internal::convertible_to_bool(*x >= *y)) {
+  return !y ? true : !x ? false : static_cast<bool>(*x >= *y);
+}
+
+// Comparison with nullopt [optional.nullops]
+// The C++17 (N4606) "Returns:" statements are used directly here.
+template <typename T>
+constexpr bool operator==(const optional<T>& x, nullopt_t) noexcept {
+  return !x;
+}
+template <typename T>
+constexpr bool operator==(nullopt_t, const optional<T>& x) noexcept {
+  return !x;
+}
+template <typename T>
+constexpr bool operator!=(const optional<T>& x, nullopt_t) noexcept {
+  return static_cast<bool>(x);
+}
+template <typename T>
+constexpr bool operator!=(nullopt_t, const optional<T>& x) noexcept {
+  return static_cast<bool>(x);
+}
+template <typename T>
+constexpr bool operator<(const optional<T>&, nullopt_t) noexcept {
+  return false;
+}
+template <typename T>
+constexpr bool operator<(nullopt_t, const optional<T>& x) noexcept {
+  return static_cast<bool>(x);
+}
+template <typename T>
+constexpr bool operator<=(const optional<T>& x, nullopt_t) noexcept {
+  return !x;
+}
+template <typename T>
+constexpr bool operator<=(nullopt_t, const optional<T>&) noexcept {
+  return true;
+}
+template <typename T>
+constexpr bool operator>(const optional<T>& x, nullopt_t) noexcept {
+  return static_cast<bool>(x);
+}
+template <typename T>
+constexpr bool operator>(nullopt_t, const optional<T>&) noexcept {
+  return false;
+}
+template <typename T>
+constexpr bool operator>=(const optional<T>&, nullopt_t) noexcept {
+  return true;
+}
+template <typename T>
+constexpr bool operator>=(nullopt_t, const optional<T>& x) noexcept {
+  return !x;
+}
+
+// Comparison with T [optional.comp_with_t]
+
+// Requires: The expression, e.g. "*x == v" shall be well-formed and its result
+// shall be convertible to bool.
+// The C++17 (N4606) "Equivalent to:" statements are used directly here.
+template <typename T, typename U>
+constexpr auto operator==(const optional<T>& x, const U& v)
+    -> decltype(optional_internal::convertible_to_bool(*x == v)) {
+  return static_cast<bool>(x) ? static_cast<bool>(*x == v) : false;
+}
+template <typename T, typename U>
+constexpr auto operator==(const U& v, const optional<T>& x)
+    -> decltype(optional_internal::convertible_to_bool(v == *x)) {
+  return static_cast<bool>(x) ? static_cast<bool>(v == *x) : false;
+}
+template <typename T, typename U>
+constexpr auto operator!=(const optional<T>& x, const U& v)
+    -> decltype(optional_internal::convertible_to_bool(*x != v)) {
+  return static_cast<bool>(x) ? static_cast<bool>(*x != v) : true;
+}
+template <typename T, typename U>
+constexpr auto operator!=(const U& v, const optional<T>& x)
+    -> decltype(optional_internal::convertible_to_bool(v != *x)) {
+  return static_cast<bool>(x) ? static_cast<bool>(v != *x) : true;
+}
+template <typename T, typename U>
+constexpr auto operator<(const optional<T>& x, const U& v)
+    -> decltype(optional_internal::convertible_to_bool(*x < v)) {
+  return static_cast<bool>(x) ? static_cast<bool>(*x < v) : true;
+}
+template <typename T, typename U>
+constexpr auto operator<(const U& v, const optional<T>& x)
+    -> decltype(optional_internal::convertible_to_bool(v < *x)) {
+  return static_cast<bool>(x) ? static_cast<bool>(v < *x) : false;
+}
+template <typename T, typename U>
+constexpr auto operator<=(const optional<T>& x, const U& v)
+    -> decltype(optional_internal::convertible_to_bool(*x <= v)) {
+  return static_cast<bool>(x) ? static_cast<bool>(*x <= v) : true;
+}
+template <typename T, typename U>
+constexpr auto operator<=(const U& v, const optional<T>& x)
+    -> decltype(optional_internal::convertible_to_bool(v <= *x)) {
+  return static_cast<bool>(x) ? static_cast<bool>(v <= *x) : false;
+}
+template <typename T, typename U>
+constexpr auto operator>(const optional<T>& x, const U& v)
+    -> decltype(optional_internal::convertible_to_bool(*x > v)) {
+  return static_cast<bool>(x) ? static_cast<bool>(*x > v) : false;
+}
+template <typename T, typename U>
+constexpr auto operator>(const U& v, const optional<T>& x)
+    -> decltype(optional_internal::convertible_to_bool(v > *x)) {
+  return static_cast<bool>(x) ? static_cast<bool>(v > *x) : true;
+}
+template <typename T, typename U>
+constexpr auto operator>=(const optional<T>& x, const U& v)
+    -> decltype(optional_internal::convertible_to_bool(*x >= v)) {
+  return static_cast<bool>(x) ? static_cast<bool>(*x >= v) : false;
+}
+template <typename T, typename U>
+constexpr auto operator>=(const U& v, const optional<T>& x)
+    -> decltype(optional_internal::convertible_to_bool(v >= *x)) {
+  return static_cast<bool>(x) ? static_cast<bool>(v >= *x) : true;
+}
+
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+namespace std {
+
+// std::hash specialization for absl::optional.
+template <typename T>
+struct hash<absl::optional<T> >
+    : absl::optional_internal::optional_hash_base<T> {};
+
+}  // namespace std
+
+#undef ABSL_MSVC_CONSTEXPR_BUG_IN_UNION_LIKE_CLASS
+
+#endif  // ABSL_USES_STD_OPTIONAL
+
+#endif  // ABSL_TYPES_OPTIONAL_H_
diff --git a/src/absl/types/span.h b/src/absl/types/span.h
new file mode 100644 (file)
index 0000000..95fe792
--- /dev/null
@@ -0,0 +1,726 @@
+//
+// Copyright 2017 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// -----------------------------------------------------------------------------
+// span.h
+// -----------------------------------------------------------------------------
+//
+// This header file defines a `Span<T>` type for holding a reference to existing
+// array data. The `Span` object, much like the `absl::string_view` object,
+// does not own such data itself, and the data being referenced by the span must
+// outlive the span itself. Unlike `view` type references, a span can hold a
+// reference to mutable data (and can mutate it for underlying types of
+// non-const T.) A span provides a lightweight way to pass a reference to such
+// data.
+//
+// Additionally, this header file defines `MakeSpan()` and `MakeConstSpan()`
+// factory functions, for clearly creating spans of type `Span<T>` or read-only
+// `Span<const T>` when such types may be difficult to identify due to issues
+// with implicit conversion.
+//
+// The C++20 draft standard includes a `std::span` type. As of June 2020, the
+// differences between `absl::Span` and `std::span` are:
+//    * `absl::Span` has `operator==` (which is likely a design bug,
+//       per https://abseil.io/blog/20180531-regular-types)
+//    * `absl::Span` has the factory functions `MakeSpan()` and
+//      `MakeConstSpan()`
+//    * bounds-checked access to `absl::Span` is accomplished with `at()`
+//    * `absl::Span` has compiler-provided move and copy constructors and
+//      assignment. This is due to them being specified as `constexpr`, but that
+//      implies const in C++11.
+//    * `absl::Span` has no `element_type` typedef
+//    * A read-only `absl::Span<const T>` can be implicitly constructed from an
+//      initializer list.
+//    * `absl::Span` has no `bytes()`, `size_bytes()`, `as_bytes()`, or
+//      `as_mutable_bytes()` methods
+//    * `absl::Span` has no static extent template parameter, nor constructors
+//      which exist only because of the static extent parameter.
+//    * `absl::Span` has an explicit mutable-reference constructor
+//
+// For more information, see the class comments below.
+#ifndef ABSL_TYPES_SPAN_H_
+#define ABSL_TYPES_SPAN_H_
+
+#include <algorithm>
+#include <cassert>
+#include <cstddef>
+#include <initializer_list>
+#include <iterator>
+#include <type_traits>
+#include <utility>
+
+#include "absl/base/internal/throw_delegate.h"
+#include "absl/base/macros.h"
+#include "absl/base/optimization.h"
+#include "absl/base/port.h"    // TODO(strel): remove this include
+#include "absl/meta/type_traits.h"
+#include "absl/types/internal/span.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+
+//------------------------------------------------------------------------------
+// Span
+//------------------------------------------------------------------------------
+//
+// A `Span` is an "array reference" type for holding a reference of contiguous
+// array data; the `Span` object does not and cannot own such data itself. A
+// span provides an easy way to provide overloads for anything operating on
+// contiguous sequences without needing to manage pointers and array lengths
+// manually.
+
+// A span is conceptually a pointer (ptr) and a length (size) into an already
+// existing array of contiguous memory; the array it represents references the
+// elements "ptr[0] .. ptr[size-1]". Passing a properly-constructed `Span`
+// instead of raw pointers avoids many issues related to index out of bounds
+// errors.
+//
+// Spans may also be constructed from containers holding contiguous sequences.
+// Such containers must supply `data()` and `size() const` methods (e.g
+// `std::vector<T>`, `absl::InlinedVector<T, N>`). All implicit conversions to
+// `absl::Span` from such containers will create spans of type `const T`;
+// spans which can mutate their values (of type `T`) must use explicit
+// constructors.
+//
+// A `Span<T>` is somewhat analogous to an `absl::string_view`, but for an array
+// of elements of type `T`, and unlike an `absl::string_view`, a span can hold a
+// reference to mutable data. A user of `Span` must ensure that the data being
+// pointed to outlives the `Span` itself.
+//
+// You can construct a `Span<T>` in several ways:
+//
+//   * Explicitly from a reference to a container type
+//   * Explicitly from a pointer and size
+//   * Implicitly from a container type (but only for spans of type `const T`)
+//   * Using the `MakeSpan()` or `MakeConstSpan()` factory functions.
+//
+// Examples:
+//
+//   // Construct a Span explicitly from a container:
+//   std::vector<int> v = {1, 2, 3, 4, 5};
+//   auto span = absl::Span<const int>(v);
+//
+//   // Construct a Span explicitly from a C-style array:
+//   int a[5] =  {1, 2, 3, 4, 5};
+//   auto span = absl::Span<const int>(a);
+//
+//   // Construct a Span implicitly from a container
+//   void MyRoutine(absl::Span<const int> a) {
+//     ...
+//   }
+//   std::vector v = {1,2,3,4,5};
+//   MyRoutine(v)                     // convert to Span<const T>
+//
+// Note that `Span` objects, in addition to requiring that the memory they
+// point to remains alive, must also ensure that such memory does not get
+// reallocated. Therefore, to avoid undefined behavior, containers with
+// associated spans should not invoke operations that may reallocate memory
+// (such as resizing) or invalidate iterators into the container.
+//
+// One common use for a `Span` is when passing arguments to a routine that can
+// accept a variety of array types (e.g. a `std::vector`, `absl::InlinedVector`,
+// a C-style array, etc.). Instead of creating overloads for each case, you
+// can simply specify a `Span` as the argument to such a routine.
+//
+// Example:
+//
+//   void MyRoutine(absl::Span<const int> a) {
+//     ...
+//   }
+//
+//   std::vector v = {1,2,3,4,5};
+//   MyRoutine(v);
+//
+//   absl::InlinedVector<int, 4> my_inline_vector;
+//   MyRoutine(my_inline_vector);
+//
+//   // Explicit constructor from pointer,size
+//   int* my_array = new int[10];
+//   MyRoutine(absl::Span<const int>(my_array, 10));
+template <typename T>
+class Span {
+ private:
+  // Used to determine whether a Span can be constructed from a container of
+  // type C.
+  template <typename C>
+  using EnableIfConvertibleFrom =
+      typename std::enable_if<span_internal::HasData<T, C>::value &&
+                              span_internal::HasSize<C>::value>::type;
+
+  // Used to SFINAE-enable a function when the slice elements are const.
+  template <typename U>
+  using EnableIfConstView =
+      typename std::enable_if<std::is_const<T>::value, U>::type;
+
+  // Used to SFINAE-enable a function when the slice elements are mutable.
+  template <typename U>
+  using EnableIfMutableView =
+      typename std::enable_if<!std::is_const<T>::value, U>::type;
+
+ public:
+  using value_type = absl::remove_cv_t<T>;
+  using pointer = T*;
+  using const_pointer = const T*;
+  using reference = T&;
+  using const_reference = const T&;
+  using iterator = pointer;
+  using const_iterator = const_pointer;
+  using reverse_iterator = std::reverse_iterator<iterator>;
+  using const_reverse_iterator = std::reverse_iterator<const_iterator>;
+  using size_type = size_t;
+  using difference_type = ptrdiff_t;
+
+  static const size_type npos = ~(size_type(0));
+
+  constexpr Span() noexcept : Span(nullptr, 0) {}
+  constexpr Span(pointer array, size_type length) noexcept
+      : ptr_(array), len_(length) {}
+
+  // Implicit conversion constructors
+  template <size_t N>
+  constexpr Span(T (&a)[N]) noexcept  // NOLINT(runtime/explicit)
+      : Span(a, N) {}
+
+  // Explicit reference constructor for a mutable `Span<T>` type. Can be
+  // replaced with MakeSpan() to infer the type parameter.
+  template <typename V, typename = EnableIfConvertibleFrom<V>,
+            typename = EnableIfMutableView<V>>
+  explicit Span(V& v) noexcept  // NOLINT(runtime/references)
+      : Span(span_internal::GetData(v), v.size()) {}
+
+  // Implicit reference constructor for a read-only `Span<const T>` type
+  template <typename V, typename = EnableIfConvertibleFrom<V>,
+            typename = EnableIfConstView<V>>
+  constexpr Span(const V& v) noexcept  // NOLINT(runtime/explicit)
+      : Span(span_internal::GetData(v), v.size()) {}
+
+  // Implicit constructor from an initializer list, making it possible to pass a
+  // brace-enclosed initializer list to a function expecting a `Span`. Such
+  // spans constructed from an initializer list must be of type `Span<const T>`.
+  //
+  //   void Process(absl::Span<const int> x);
+  //   Process({1, 2, 3});
+  //
+  // Note that as always the array referenced by the span must outlive the span.
+  // Since an initializer list constructor acts as if it is fed a temporary
+  // array (cf. C++ standard [dcl.init.list]/5), it's safe to use this
+  // constructor only when the `std::initializer_list` itself outlives the span.
+  // In order to meet this requirement it's sufficient to ensure that neither
+  // the span nor a copy of it is used outside of the expression in which it's
+  // created:
+  //
+  //   // Assume that this function uses the array directly, not retaining any
+  //   // copy of the span or pointer to any of its elements.
+  //   void Process(absl::Span<const int> ints);
+  //
+  //   // Okay: the std::initializer_list<int> will reference a temporary array
+  //   // that isn't destroyed until after the call to Process returns.
+  //   Process({ 17, 19 });
+  //
+  //   // Not okay: the storage used by the std::initializer_list<int> is not
+  //   // allowed to be referenced after the first line.
+  //   absl::Span<const int> ints = { 17, 19 };
+  //   Process(ints);
+  //
+  //   // Not okay for the same reason as above: even when the elements of the
+  //   // initializer list expression are not temporaries the underlying array
+  //   // is, so the initializer list must still outlive the span.
+  //   const int foo = 17;
+  //   absl::Span<const int> ints = { foo };
+  //   Process(ints);
+  //
+  template <typename LazyT = T,
+            typename = EnableIfConstView<LazyT>>
+  Span(
+      std::initializer_list<value_type> v) noexcept  // NOLINT(runtime/explicit)
+      : Span(v.begin(), v.size()) {}
+
+  // Accessors
+
+  // Span::data()
+  //
+  // Returns a pointer to the span's underlying array of data (which is held
+  // outside the span).
+  constexpr pointer data() const noexcept { return ptr_; }
+
+  // Span::size()
+  //
+  // Returns the size of this span.
+  constexpr size_type size() const noexcept { return len_; }
+
+  // Span::length()
+  //
+  // Returns the length (size) of this span.
+  constexpr size_type length() const noexcept { return size(); }
+
+  // Span::empty()
+  //
+  // Returns a boolean indicating whether or not this span is considered empty.
+  constexpr bool empty() const noexcept { return size() == 0; }
+
+  // Span::operator[]
+  //
+  // Returns a reference to the i'th element of this span.
+  constexpr reference operator[](size_type i) const noexcept {
+    // MSVC 2015 accepts this as constexpr, but not ptr_[i]
+    return ABSL_HARDENING_ASSERT(i < size()), *(data() + i);
+  }
+
+  // Span::at()
+  //
+  // Returns a reference to the i'th element of this span.
+  constexpr reference at(size_type i) const {
+    return ABSL_PREDICT_TRUE(i < size())  //
+               ? *(data() + i)
+               : (base_internal::ThrowStdOutOfRange(
+                      "Span::at failed bounds check"),
+                  *(data() + i));
+  }
+
+  // Span::front()
+  //
+  // Returns a reference to the first element of this span. The span must not
+  // be empty.
+  constexpr reference front() const noexcept {
+    return ABSL_HARDENING_ASSERT(size() > 0), *data();
+  }
+
+  // Span::back()
+  //
+  // Returns a reference to the last element of this span. The span must not
+  // be empty.
+  constexpr reference back() const noexcept {
+    return ABSL_HARDENING_ASSERT(size() > 0), *(data() + size() - 1);
+  }
+
+  // Span::begin()
+  //
+  // Returns an iterator pointing to the first element of this span, or `end()`
+  // if the span is empty.
+  constexpr iterator begin() const noexcept { return data(); }
+
+  // Span::cbegin()
+  //
+  // Returns a const iterator pointing to the first element of this span, or
+  // `end()` if the span is empty.
+  constexpr const_iterator cbegin() const noexcept { return begin(); }
+
+  // Span::end()
+  //
+  // Returns an iterator pointing just beyond the last element at the
+  // end of this span. This iterator acts as a placeholder; attempting to
+  // access it results in undefined behavior.
+  constexpr iterator end() const noexcept { return data() + size(); }
+
+  // Span::cend()
+  //
+  // Returns a const iterator pointing just beyond the last element at the
+  // end of this span. This iterator acts as a placeholder; attempting to
+  // access it results in undefined behavior.
+  constexpr const_iterator cend() const noexcept { return end(); }
+
+  // Span::rbegin()
+  //
+  // Returns a reverse iterator pointing to the last element at the end of this
+  // span, or `rend()` if the span is empty.
+  constexpr reverse_iterator rbegin() const noexcept {
+    return reverse_iterator(end());
+  }
+
+  // Span::crbegin()
+  //
+  // Returns a const reverse iterator pointing to the last element at the end of
+  // this span, or `crend()` if the span is empty.
+  constexpr const_reverse_iterator crbegin() const noexcept { return rbegin(); }
+
+  // Span::rend()
+  //
+  // Returns a reverse iterator pointing just before the first element
+  // at the beginning of this span. This pointer acts as a placeholder;
+  // attempting to access its element results in undefined behavior.
+  constexpr reverse_iterator rend() const noexcept {
+    return reverse_iterator(begin());
+  }
+
+  // Span::crend()
+  //
+  // Returns a reverse const iterator pointing just before the first element
+  // at the beginning of this span. This pointer acts as a placeholder;
+  // attempting to access its element results in undefined behavior.
+  constexpr const_reverse_iterator crend() const noexcept { return rend(); }
+
+  // Span mutations
+
+  // Span::remove_prefix()
+  //
+  // Removes the first `n` elements from the span.
+  void remove_prefix(size_type n) noexcept {
+    ABSL_HARDENING_ASSERT(size() >= n);
+    ptr_ += n;
+    len_ -= n;
+  }
+
+  // Span::remove_suffix()
+  //
+  // Removes the last `n` elements from the span.
+  void remove_suffix(size_type n) noexcept {
+    ABSL_HARDENING_ASSERT(size() >= n);
+    len_ -= n;
+  }
+
+  // Span::subspan()
+  //
+  // Returns a `Span` starting at element `pos` and of length `len`. Both `pos`
+  // and `len` are of type `size_type` and thus non-negative. Parameter `pos`
+  // must be <= size(). Any `len` value that points past the end of the span
+  // will be trimmed to at most size() - `pos`. A default `len` value of `npos`
+  // ensures the returned subspan continues until the end of the span.
+  //
+  // Examples:
+  //
+  //   std::vector<int> vec = {10, 11, 12, 13};
+  //   absl::MakeSpan(vec).subspan(1, 2);  // {11, 12}
+  //   absl::MakeSpan(vec).subspan(2, 8);  // {12, 13}
+  //   absl::MakeSpan(vec).subspan(1);     // {11, 12, 13}
+  //   absl::MakeSpan(vec).subspan(4);     // {}
+  //   absl::MakeSpan(vec).subspan(5);     // throws std::out_of_range
+  constexpr Span subspan(size_type pos = 0, size_type len = npos) const {
+    return (pos <= size())
+               ? Span(data() + pos, span_internal::Min(size() - pos, len))
+               : (base_internal::ThrowStdOutOfRange("pos > size()"), Span());
+  }
+
+  // Span::first()
+  //
+  // Returns a `Span` containing first `len` elements. Parameter `len` is of
+  // type `size_type` and thus non-negative. `len` value must be <= size().
+  //
+  // Examples:
+  //
+  //   std::vector<int> vec = {10, 11, 12, 13};
+  //   absl::MakeSpan(vec).first(1);  // {10}
+  //   absl::MakeSpan(vec).first(3);  // {10, 11, 12}
+  //   absl::MakeSpan(vec).first(5);  // throws std::out_of_range
+  constexpr Span first(size_type len) const {
+    return (len <= size())
+               ? Span(data(), len)
+               : (base_internal::ThrowStdOutOfRange("len > size()"), Span());
+  }
+
+  // Span::last()
+  //
+  // Returns a `Span` containing last `len` elements. Parameter `len` is of
+  // type `size_type` and thus non-negative. `len` value must be <= size().
+  //
+  // Examples:
+  //
+  //   std::vector<int> vec = {10, 11, 12, 13};
+  //   absl::MakeSpan(vec).last(1);  // {13}
+  //   absl::MakeSpan(vec).last(3);  // {11, 12, 13}
+  //   absl::MakeSpan(vec).last(5);  // throws std::out_of_range
+  constexpr Span last(size_type len) const {
+    return (len <= size())
+               ? Span(size() - len + data(), len)
+               : (base_internal::ThrowStdOutOfRange("len > size()"), Span());
+  }
+
+  // Support for absl::Hash.
+  template <typename H>
+  friend H AbslHashValue(H h, Span v) {
+    return H::combine(H::combine_contiguous(std::move(h), v.data(), v.size()),
+                      v.size());
+  }
+
+ private:
+  pointer ptr_;
+  size_type len_;
+};
+
+template <typename T>
+const typename Span<T>::size_type Span<T>::npos;
+
+// Span relationals
+
+// Equality is compared element-by-element, while ordering is lexicographical.
+// We provide three overloads for each operator to cover any combination on the
+// left or right hand side of mutable Span<T>, read-only Span<const T>, and
+// convertible-to-read-only Span<T>.
+// TODO(zhangxy): Due to MSVC overload resolution bug with partial ordering
+// template functions, 5 overloads per operator is needed as a workaround. We
+// should update them to 3 overloads per operator using non-deduced context like
+// string_view, i.e.
+// - (Span<T>, Span<T>)
+// - (Span<T>, non_deduced<Span<const T>>)
+// - (non_deduced<Span<const T>>, Span<T>)
+
+// operator==
+template <typename T>
+bool operator==(Span<T> a, Span<T> b) {
+  return span_internal::EqualImpl<Span, const T>(a, b);
+}
+template <typename T>
+bool operator==(Span<const T> a, Span<T> b) {
+  return span_internal::EqualImpl<Span, const T>(a, b);
+}
+template <typename T>
+bool operator==(Span<T> a, Span<const T> b) {
+  return span_internal::EqualImpl<Span, const T>(a, b);
+}
+template <
+    typename T, typename U,
+    typename = span_internal::EnableIfConvertibleTo<U, absl::Span<const T>>>
+bool operator==(const U& a, Span<T> b) {
+  return span_internal::EqualImpl<Span, const T>(a, b);
+}
+template <
+    typename T, typename U,
+    typename = span_internal::EnableIfConvertibleTo<U, absl::Span<const T>>>
+bool operator==(Span<T> a, const U& b) {
+  return span_internal::EqualImpl<Span, const T>(a, b);
+}
+
+// operator!=
+template <typename T>
+bool operator!=(Span<T> a, Span<T> b) {
+  return !(a == b);
+}
+template <typename T>
+bool operator!=(Span<const T> a, Span<T> b) {
+  return !(a == b);
+}
+template <typename T>
+bool operator!=(Span<T> a, Span<const T> b) {
+  return !(a == b);
+}
+template <
+    typename T, typename U,
+    typename = span_internal::EnableIfConvertibleTo<U, absl::Span<const T>>>
+bool operator!=(const U& a, Span<T> b) {
+  return !(a == b);
+}
+template <
+    typename T, typename U,
+    typename = span_internal::EnableIfConvertibleTo<U, absl::Span<const T>>>
+bool operator!=(Span<T> a, const U& b) {
+  return !(a == b);
+}
+
+// operator<
+template <typename T>
+bool operator<(Span<T> a, Span<T> b) {
+  return span_internal::LessThanImpl<Span, const T>(a, b);
+}
+template <typename T>
+bool operator<(Span<const T> a, Span<T> b) {
+  return span_internal::LessThanImpl<Span, const T>(a, b);
+}
+template <typename T>
+bool operator<(Span<T> a, Span<const T> b) {
+  return span_internal::LessThanImpl<Span, const T>(a, b);
+}
+template <
+    typename T, typename U,
+    typename = span_internal::EnableIfConvertibleTo<U, absl::Span<const T>>>
+bool operator<(const U& a, Span<T> b) {
+  return span_internal::LessThanImpl<Span, const T>(a, b);
+}
+template <
+    typename T, typename U,
+    typename = span_internal::EnableIfConvertibleTo<U, absl::Span<const T>>>
+bool operator<(Span<T> a, const U& b) {
+  return span_internal::LessThanImpl<Span, const T>(a, b);
+}
+
+// operator>
+template <typename T>
+bool operator>(Span<T> a, Span<T> b) {
+  return b < a;
+}
+template <typename T>
+bool operator>(Span<const T> a, Span<T> b) {
+  return b < a;
+}
+template <typename T>
+bool operator>(Span<T> a, Span<const T> b) {
+  return b < a;
+}
+template <
+    typename T, typename U,
+    typename = span_internal::EnableIfConvertibleTo<U, absl::Span<const T>>>
+bool operator>(const U& a, Span<T> b) {
+  return b < a;
+}
+template <
+    typename T, typename U,
+    typename = span_internal::EnableIfConvertibleTo<U, absl::Span<const T>>>
+bool operator>(Span<T> a, const U& b) {
+  return b < a;
+}
+
+// operator<=
+template <typename T>
+bool operator<=(Span<T> a, Span<T> b) {
+  return !(b < a);
+}
+template <typename T>
+bool operator<=(Span<const T> a, Span<T> b) {
+  return !(b < a);
+}
+template <typename T>
+bool operator<=(Span<T> a, Span<const T> b) {
+  return !(b < a);
+}
+template <
+    typename T, typename U,
+    typename = span_internal::EnableIfConvertibleTo<U, absl::Span<const T>>>
+bool operator<=(const U& a, Span<T> b) {
+  return !(b < a);
+}
+template <
+    typename T, typename U,
+    typename = span_internal::EnableIfConvertibleTo<U, absl::Span<const T>>>
+bool operator<=(Span<T> a, const U& b) {
+  return !(b < a);
+}
+
+// operator>=
+template <typename T>
+bool operator>=(Span<T> a, Span<T> b) {
+  return !(a < b);
+}
+template <typename T>
+bool operator>=(Span<const T> a, Span<T> b) {
+  return !(a < b);
+}
+template <typename T>
+bool operator>=(Span<T> a, Span<const T> b) {
+  return !(a < b);
+}
+template <
+    typename T, typename U,
+    typename = span_internal::EnableIfConvertibleTo<U, absl::Span<const T>>>
+bool operator>=(const U& a, Span<T> b) {
+  return !(a < b);
+}
+template <
+    typename T, typename U,
+    typename = span_internal::EnableIfConvertibleTo<U, absl::Span<const T>>>
+bool operator>=(Span<T> a, const U& b) {
+  return !(a < b);
+}
+
+// MakeSpan()
+//
+// Constructs a mutable `Span<T>`, deducing `T` automatically from either a
+// container or pointer+size.
+//
+// Because a read-only `Span<const T>` is implicitly constructed from container
+// types regardless of whether the container itself is a const container,
+// constructing mutable spans of type `Span<T>` from containers requires
+// explicit constructors. The container-accepting version of `MakeSpan()`
+// deduces the type of `T` by the constness of the pointer received from the
+// container's `data()` member. Similarly, the pointer-accepting version returns
+// a `Span<const T>` if `T` is `const`, and a `Span<T>` otherwise.
+//
+// Examples:
+//
+//   void MyRoutine(absl::Span<MyComplicatedType> a) {
+//     ...
+//   };
+//   // my_vector is a container of non-const types
+//   std::vector<MyComplicatedType> my_vector;
+//
+//   // Constructing a Span implicitly attempts to create a Span of type
+//   // `Span<const T>`
+//   MyRoutine(my_vector);                // error, type mismatch
+//
+//   // Explicitly constructing the Span is verbose
+//   MyRoutine(absl::Span<MyComplicatedType>(my_vector));
+//
+//   // Use MakeSpan() to make an absl::Span<T>
+//   MyRoutine(absl::MakeSpan(my_vector));
+//
+//   // Construct a span from an array ptr+size
+//   absl::Span<T> my_span() {
+//     return absl::MakeSpan(&array[0], num_elements_);
+//   }
+//
+template <int&... ExplicitArgumentBarrier, typename T>
+constexpr Span<T> MakeSpan(T* ptr, size_t size) noexcept {
+  return Span<T>(ptr, size);
+}
+
+template <int&... ExplicitArgumentBarrier, typename T>
+Span<T> MakeSpan(T* begin, T* end) noexcept {
+  return ABSL_HARDENING_ASSERT(begin <= end), Span<T>(begin, end - begin);
+}
+
+template <int&... ExplicitArgumentBarrier, typename C>
+constexpr auto MakeSpan(C& c) noexcept  // NOLINT(runtime/references)
+    -> decltype(absl::MakeSpan(span_internal::GetData(c), c.size())) {
+  return MakeSpan(span_internal::GetData(c), c.size());
+}
+
+template <int&... ExplicitArgumentBarrier, typename T, size_t N>
+constexpr Span<T> MakeSpan(T (&array)[N]) noexcept {
+  return Span<T>(array, N);
+}
+
+// MakeConstSpan()
+//
+// Constructs a `Span<const T>` as with `MakeSpan`, deducing `T` automatically,
+// but always returning a `Span<const T>`.
+//
+// Examples:
+//
+//   void ProcessInts(absl::Span<const int> some_ints);
+//
+//   // Call with a pointer and size.
+//   int array[3] = { 0, 0, 0 };
+//   ProcessInts(absl::MakeConstSpan(&array[0], 3));
+//
+//   // Call with a [begin, end) pair.
+//   ProcessInts(absl::MakeConstSpan(&array[0], &array[3]));
+//
+//   // Call directly with an array.
+//   ProcessInts(absl::MakeConstSpan(array));
+//
+//   // Call with a contiguous container.
+//   std::vector<int> some_ints = ...;
+//   ProcessInts(absl::MakeConstSpan(some_ints));
+//   ProcessInts(absl::MakeConstSpan(std::vector<int>{ 0, 0, 0 }));
+//
+template <int&... ExplicitArgumentBarrier, typename T>
+constexpr Span<const T> MakeConstSpan(T* ptr, size_t size) noexcept {
+  return Span<const T>(ptr, size);
+}
+
+template <int&... ExplicitArgumentBarrier, typename T>
+Span<const T> MakeConstSpan(T* begin, T* end) noexcept {
+  return ABSL_HARDENING_ASSERT(begin <= end), Span<const T>(begin, end - begin);
+}
+
+template <int&... ExplicitArgumentBarrier, typename C>
+constexpr auto MakeConstSpan(const C& c) noexcept -> decltype(MakeSpan(c)) {
+  return MakeSpan(c);
+}
+
+template <int&... ExplicitArgumentBarrier, typename T, size_t N>
+constexpr Span<const T> MakeConstSpan(const T (&array)[N]) noexcept {
+  return Span<const T>(array, N);
+}
+ABSL_NAMESPACE_END
+}  // namespace absl
+#endif  // ABSL_TYPES_SPAN_H_
diff --git a/src/absl/types/variant.h b/src/absl/types/variant.h
new file mode 100644 (file)
index 0000000..ac93464
--- /dev/null
@@ -0,0 +1,866 @@
+// Copyright 2018 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// -----------------------------------------------------------------------------
+// variant.h
+// -----------------------------------------------------------------------------
+//
+// This header file defines an `absl::variant` type for holding a type-safe
+// value of some prescribed set of types (noted as alternative types), and
+// associated functions for managing variants.
+//
+// The `absl::variant` type is a form of type-safe union. An `absl::variant`
+// should always hold a value of one of its alternative types (except in the
+// "valueless by exception state" -- see below). A default-constructed
+// `absl::variant` will hold the value of its first alternative type, provided
+// it is default-constructible.
+//
+// In exceptional cases due to error, an `absl::variant` can hold no
+// value (known as a "valueless by exception" state), though this is not the
+// norm.
+//
+// As with `absl::optional`, an `absl::variant` -- when it holds a value --
+// allocates a value of that type directly within the `variant` itself; it
+// cannot hold a reference, array, or the type `void`; it can, however, hold a
+// pointer to externally managed memory.
+//
+// `absl::variant` is a C++11 compatible version of the C++17 `std::variant`
+// abstraction and is designed to be a drop-in replacement for code compliant
+// with C++17.
+
+#ifndef ABSL_TYPES_VARIANT_H_
+#define ABSL_TYPES_VARIANT_H_
+
+#include "absl/base/config.h"
+#include "absl/utility/utility.h"
+
+#ifdef ABSL_USES_STD_VARIANT
+
+#include <variant>  // IWYU pragma: export
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+using std::bad_variant_access;
+using std::get;
+using std::get_if;
+using std::holds_alternative;
+using std::monostate;
+using std::variant;
+using std::variant_alternative;
+using std::variant_alternative_t;
+using std::variant_npos;
+using std::variant_size;
+using std::variant_size_v;
+using std::visit;
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#else  // ABSL_USES_STD_VARIANT
+
+#include <functional>
+#include <new>
+#include <type_traits>
+#include <utility>
+
+#include "absl/base/macros.h"
+#include "absl/base/port.h"
+#include "absl/meta/type_traits.h"
+#include "absl/types/internal/variant.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+
+// -----------------------------------------------------------------------------
+// absl::variant
+// -----------------------------------------------------------------------------
+//
+// An `absl::variant` type is a form of type-safe union. An `absl::variant` --
+// except in exceptional cases -- always holds a value of one of its alternative
+// types.
+//
+// Example:
+//
+//   // Construct a variant that holds either an integer or a std::string and
+//   // assign it to a std::string.
+//   absl::variant<int, std::string> v = std::string("abc");
+//
+//   // A default-constructed variant will hold a value-initialized value of
+//   // the first alternative type.
+//   auto a = absl::variant<int, std::string>();   // Holds an int of value '0'.
+//
+//   // variants are assignable.
+//
+//   // copy assignment
+//   auto v1 = absl::variant<int, std::string>("abc");
+//   auto v2 = absl::variant<int, std::string>(10);
+//   v2 = v1;  // copy assign
+//
+//   // move assignment
+//   auto v1 = absl::variant<int, std::string>("abc");
+//   v1 = absl::variant<int, std::string>(10);
+//
+//   // assignment through type conversion
+//   a = 128;         // variant contains int
+//   a = "128";       // variant contains std::string
+//
+// An `absl::variant` holding a value of one of its alternative types `T` holds
+// an allocation of `T` directly within the variant itself. An `absl::variant`
+// is not allowed to allocate additional storage, such as dynamic memory, to
+// allocate the contained value. The contained value shall be allocated in a
+// region of the variant storage suitably aligned for all alternative types.
+template <typename... Ts>
+class variant;
+
+// swap()
+//
+// Swaps two `absl::variant` values. This function is equivalent to `v.swap(w)`
+// where `v` and `w` are `absl::variant` types.
+//
+// Note that this function requires all alternative types to be both swappable
+// and move-constructible, because any two variants may refer to either the same
+// type (in which case, they will be swapped) or to two different types (in
+// which case the values will need to be moved).
+//
+template <
+    typename... Ts,
+    absl::enable_if_t<
+        absl::conjunction<std::is_move_constructible<Ts>...,
+                          type_traits_internal::IsSwappable<Ts>...>::value,
+        int> = 0>
+void swap(variant<Ts...>& v, variant<Ts...>& w) noexcept(noexcept(v.swap(w))) {
+  v.swap(w);
+}
+
+// variant_size
+//
+// Returns the number of alternative types available for a given `absl::variant`
+// type as a compile-time constant expression. As this is a class template, it
+// is not generally useful for accessing the number of alternative types of
+// any given `absl::variant` instance.
+//
+// Example:
+//
+//   auto a = absl::variant<int, std::string>;
+//   constexpr int num_types =
+//       absl::variant_size<absl::variant<int, std::string>>();
+//
+//   // You can also use the member constant `value`.
+//   constexpr int num_types =
+//       absl::variant_size<absl::variant<int, std::string>>::value;
+//
+//   // `absl::variant_size` is more valuable for use in generic code:
+//   template <typename Variant>
+//   constexpr bool IsVariantMultivalue() {
+//       return absl::variant_size<Variant>() > 1;
+//   }
+//
+// Note that the set of cv-qualified specializations of `variant_size` are
+// provided to ensure that those specializations compile (especially when passed
+// within template logic).
+template <class T>
+struct variant_size;
+
+template <class... Ts>
+struct variant_size<variant<Ts...>>
+    : std::integral_constant<std::size_t, sizeof...(Ts)> {};
+
+// Specialization of `variant_size` for const qualified variants.
+template <class T>
+struct variant_size<const T> : variant_size<T>::type {};
+
+// Specialization of `variant_size` for volatile qualified variants.
+template <class T>
+struct variant_size<volatile T> : variant_size<T>::type {};
+
+// Specialization of `variant_size` for const volatile qualified variants.
+template <class T>
+struct variant_size<const volatile T> : variant_size<T>::type {};
+
+// variant_alternative
+//
+// Returns the alternative type for a given `absl::variant` at the passed
+// index value as a compile-time constant expression. As this is a class
+// template resulting in a type, it is not useful for access of the run-time
+// value of any given `absl::variant` variable.
+//
+// Example:
+//
+//   // The type of the 0th alternative is "int".
+//   using alternative_type_0
+//     = absl::variant_alternative<0, absl::variant<int, std::string>>::type;
+//
+//   static_assert(std::is_same<alternative_type_0, int>::value, "");
+//
+//   // `absl::variant_alternative` is more valuable for use in generic code:
+//   template <typename Variant>
+//   constexpr bool IsFirstElementTrivial() {
+//       return std::is_trivial_v<variant_alternative<0, Variant>::type>;
+//   }
+//
+// Note that the set of cv-qualified specializations of `variant_alternative`
+// are provided to ensure that those specializations compile (especially when
+// passed within template logic).
+template <std::size_t I, class T>
+struct variant_alternative;
+
+template <std::size_t I, class... Types>
+struct variant_alternative<I, variant<Types...>> {
+  using type =
+      variant_internal::VariantAlternativeSfinaeT<I, variant<Types...>>;
+};
+
+// Specialization of `variant_alternative` for const qualified variants.
+template <std::size_t I, class T>
+struct variant_alternative<I, const T> {
+  using type = const typename variant_alternative<I, T>::type;
+};
+
+// Specialization of `variant_alternative` for volatile qualified variants.
+template <std::size_t I, class T>
+struct variant_alternative<I, volatile T> {
+  using type = volatile typename variant_alternative<I, T>::type;
+};
+
+// Specialization of `variant_alternative` for const volatile qualified
+// variants.
+template <std::size_t I, class T>
+struct variant_alternative<I, const volatile T> {
+  using type = const volatile typename variant_alternative<I, T>::type;
+};
+
+// Template type alias for variant_alternative<I, T>::type.
+//
+// Example:
+//
+//   using alternative_type_0
+//     = absl::variant_alternative_t<0, absl::variant<int, std::string>>;
+//   static_assert(std::is_same<alternative_type_0, int>::value, "");
+template <std::size_t I, class T>
+using variant_alternative_t = typename variant_alternative<I, T>::type;
+
+// holds_alternative()
+//
+// Checks whether the given variant currently holds a given alternative type,
+// returning `true` if so.
+//
+// Example:
+//
+//   absl::variant<int, std::string> foo = 42;
+//   if (absl::holds_alternative<int>(foo)) {
+//       std::cout << "The variant holds an integer";
+//   }
+template <class T, class... Types>
+constexpr bool holds_alternative(const variant<Types...>& v) noexcept {
+  static_assert(
+      variant_internal::UnambiguousIndexOfImpl<variant<Types...>, T,
+                                               0>::value != sizeof...(Types),
+      "The type T must occur exactly once in Types...");
+  return v.index() ==
+         variant_internal::UnambiguousIndexOf<variant<Types...>, T>::value;
+}
+
+// get()
+//
+// Returns a reference to the value currently within a given variant, using
+// either a unique alternative type amongst the variant's set of alternative
+// types, or the variant's index value. Attempting to get a variant's value
+// using a type that is not unique within the variant's set of alternative types
+// is a compile-time error. If the index of the alternative being specified is
+// different from the index of the alternative that is currently stored, throws
+// `absl::bad_variant_access`.
+//
+// Example:
+//
+//   auto a = absl::variant<int, std::string>;
+//
+//   // Get the value by type (if unique).
+//   int i = absl::get<int>(a);
+//
+//   auto b = absl::variant<int, int>;
+//
+//   // Getting the value by a type that is not unique is ill-formed.
+//   int j = absl::get<int>(b);     // Compile Error!
+//
+//   // Getting value by index not ambiguous and allowed.
+//   int k = absl::get<1>(b);
+
+// Overload for getting a variant's lvalue by type.
+template <class T, class... Types>
+constexpr T& get(variant<Types...>& v) {  // NOLINT
+  return variant_internal::VariantCoreAccess::CheckedAccess<
+      variant_internal::IndexOf<T, Types...>::value>(v);
+}
+
+// Overload for getting a variant's rvalue by type.
+// Note: `absl::move()` is required to allow use of constexpr in C++11.
+template <class T, class... Types>
+constexpr T&& get(variant<Types...>&& v) {
+  return variant_internal::VariantCoreAccess::CheckedAccess<
+      variant_internal::IndexOf<T, Types...>::value>(absl::move(v));
+}
+
+// Overload for getting a variant's const lvalue by type.
+template <class T, class... Types>
+constexpr const T& get(const variant<Types...>& v) {
+  return variant_internal::VariantCoreAccess::CheckedAccess<
+      variant_internal::IndexOf<T, Types...>::value>(v);
+}
+
+// Overload for getting a variant's const rvalue by type.
+// Note: `absl::move()` is required to allow use of constexpr in C++11.
+template <class T, class... Types>
+constexpr const T&& get(const variant<Types...>&& v) {
+  return variant_internal::VariantCoreAccess::CheckedAccess<
+      variant_internal::IndexOf<T, Types...>::value>(absl::move(v));
+}
+
+// Overload for getting a variant's lvalue by index.
+template <std::size_t I, class... Types>
+constexpr variant_alternative_t<I, variant<Types...>>& get(
+    variant<Types...>& v) {  // NOLINT
+  return variant_internal::VariantCoreAccess::CheckedAccess<I>(v);
+}
+
+// Overload for getting a variant's rvalue by index.
+// Note: `absl::move()` is required to allow use of constexpr in C++11.
+template <std::size_t I, class... Types>
+constexpr variant_alternative_t<I, variant<Types...>>&& get(
+    variant<Types...>&& v) {
+  return variant_internal::VariantCoreAccess::CheckedAccess<I>(absl::move(v));
+}
+
+// Overload for getting a variant's const lvalue by index.
+template <std::size_t I, class... Types>
+constexpr const variant_alternative_t<I, variant<Types...>>& get(
+    const variant<Types...>& v) {
+  return variant_internal::VariantCoreAccess::CheckedAccess<I>(v);
+}
+
+// Overload for getting a variant's const rvalue by index.
+// Note: `absl::move()` is required to allow use of constexpr in C++11.
+template <std::size_t I, class... Types>
+constexpr const variant_alternative_t<I, variant<Types...>>&& get(
+    const variant<Types...>&& v) {
+  return variant_internal::VariantCoreAccess::CheckedAccess<I>(absl::move(v));
+}
+
+// get_if()
+//
+// Returns a pointer to the value currently stored within a given variant, if
+// present, using either a unique alternative type amongst the variant's set of
+// alternative types, or the variant's index value. If such a value does not
+// exist, returns `nullptr`.
+//
+// As with `get`, attempting to get a variant's value using a type that is not
+// unique within the variant's set of alternative types is a compile-time error.
+
+// Overload for getting a pointer to the value stored in the given variant by
+// index.
+template <std::size_t I, class... Types>
+constexpr absl::add_pointer_t<variant_alternative_t<I, variant<Types...>>>
+get_if(variant<Types...>* v) noexcept {
+  return (v != nullptr && v->index() == I)
+             ? std::addressof(
+                   variant_internal::VariantCoreAccess::Access<I>(*v))
+             : nullptr;
+}
+
+// Overload for getting a pointer to the const value stored in the given
+// variant by index.
+template <std::size_t I, class... Types>
+constexpr absl::add_pointer_t<const variant_alternative_t<I, variant<Types...>>>
+get_if(const variant<Types...>* v) noexcept {
+  return (v != nullptr && v->index() == I)
+             ? std::addressof(
+                   variant_internal::VariantCoreAccess::Access<I>(*v))
+             : nullptr;
+}
+
+// Overload for getting a pointer to the value stored in the given variant by
+// type.
+template <class T, class... Types>
+constexpr absl::add_pointer_t<T> get_if(variant<Types...>* v) noexcept {
+  return absl::get_if<variant_internal::IndexOf<T, Types...>::value>(v);
+}
+
+// Overload for getting a pointer to the const value stored in the given variant
+// by type.
+template <class T, class... Types>
+constexpr absl::add_pointer_t<const T> get_if(
+    const variant<Types...>* v) noexcept {
+  return absl::get_if<variant_internal::IndexOf<T, Types...>::value>(v);
+}
+
+// visit()
+//
+// Calls a provided functor on a given set of variants. `absl::visit()` is
+// commonly used to conditionally inspect the state of a given variant (or set
+// of variants).
+//
+// The functor must return the same type when called with any of the variants'
+// alternatives.
+//
+// Example:
+//
+//   // Define a visitor functor
+//   struct GetVariant {
+//       template<typename T>
+//       void operator()(const T& i) const {
+//         std::cout << "The variant's value is: " << i;
+//       }
+//   };
+//
+//   // Declare our variant, and call `absl::visit()` on it.
+//   // Note that `GetVariant()` returns void in either case.
+//   absl::variant<int, std::string> foo = std::string("foo");
+//   GetVariant visitor;
+//   absl::visit(visitor, foo);  // Prints `The variant's value is: foo'
+template <typename Visitor, typename... Variants>
+variant_internal::VisitResult<Visitor, Variants...> visit(Visitor&& vis,
+                                                          Variants&&... vars) {
+  return variant_internal::
+      VisitIndices<variant_size<absl::decay_t<Variants> >::value...>::Run(
+          variant_internal::PerformVisitation<Visitor, Variants...>{
+              std::forward_as_tuple(absl::forward<Variants>(vars)...),
+              absl::forward<Visitor>(vis)},
+          vars.index()...);
+}
+
+// monostate
+//
+// The monostate class serves as a first alternative type for a variant for
+// which the first variant type is otherwise not default-constructible.
+struct monostate {};
+
+// `absl::monostate` Relational Operators
+
+constexpr bool operator<(monostate, monostate) noexcept { return false; }
+constexpr bool operator>(monostate, monostate) noexcept { return false; }
+constexpr bool operator<=(monostate, monostate) noexcept { return true; }
+constexpr bool operator>=(monostate, monostate) noexcept { return true; }
+constexpr bool operator==(monostate, monostate) noexcept { return true; }
+constexpr bool operator!=(monostate, monostate) noexcept { return false; }
+
+
+//------------------------------------------------------------------------------
+// `absl::variant` Template Definition
+//------------------------------------------------------------------------------
+template <typename T0, typename... Tn>
+class variant<T0, Tn...> : private variant_internal::VariantBase<T0, Tn...> {
+  static_assert(absl::conjunction<std::is_object<T0>,
+                                  std::is_object<Tn>...>::value,
+                "Attempted to instantiate a variant containing a non-object "
+                "type.");
+  // Intentionally not qualifying `negation` with `absl::` to work around a bug
+  // in MSVC 2015 with inline namespace and variadic template.
+  static_assert(absl::conjunction<negation<std::is_array<T0> >,
+                                  negation<std::is_array<Tn> >...>::value,
+                "Attempted to instantiate a variant containing an array type.");
+  static_assert(absl::conjunction<std::is_nothrow_destructible<T0>,
+                                  std::is_nothrow_destructible<Tn>...>::value,
+                "Attempted to instantiate a variant containing a non-nothrow "
+                "destructible type.");
+
+  friend struct variant_internal::VariantCoreAccess;
+
+ private:
+  using Base = variant_internal::VariantBase<T0, Tn...>;
+
+ public:
+  // Constructors
+
+  // Constructs a variant holding a default-initialized value of the first
+  // alternative type.
+  constexpr variant() /*noexcept(see 111above)*/ = default;
+
+  // Copy constructor, standard semantics
+  variant(const variant& other) = default;
+
+  // Move constructor, standard semantics
+  variant(variant&& other) /*noexcept(see above)*/ = default;
+
+  // Constructs a variant of an alternative type specified by overload
+  // resolution of the provided forwarding arguments through
+  // direct-initialization.
+  //
+  // Note: If the selected constructor is a constexpr constructor, this
+  // constructor shall be a constexpr constructor.
+  //
+  // NOTE: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p0608r1.html
+  // has been voted passed the design phase in the C++ standard meeting in Mar
+  // 2018. It will be implemented and integrated into `absl::variant`.
+  template <
+      class T,
+      std::size_t I = std::enable_if<
+          variant_internal::IsNeitherSelfNorInPlace<variant,
+                                                    absl::decay_t<T>>::value,
+          variant_internal::IndexOfConstructedType<variant, T>>::type::value,
+      class Tj = absl::variant_alternative_t<I, variant>,
+      absl::enable_if_t<std::is_constructible<Tj, T>::value>* =
+          nullptr>
+  constexpr variant(T&& t) noexcept(std::is_nothrow_constructible<Tj, T>::value)
+      : Base(variant_internal::EmplaceTag<I>(), absl::forward<T>(t)) {}
+
+  // Constructs a variant of an alternative type from the arguments through
+  // direct-initialization.
+  //
+  // Note: If the selected constructor is a constexpr constructor, this
+  // constructor shall be a constexpr constructor.
+  template <class T, class... Args,
+            typename std::enable_if<std::is_constructible<
+                variant_internal::UnambiguousTypeOfT<variant, T>,
+                Args...>::value>::type* = nullptr>
+  constexpr explicit variant(in_place_type_t<T>, Args&&... args)
+      : Base(variant_internal::EmplaceTag<
+                 variant_internal::UnambiguousIndexOf<variant, T>::value>(),
+             absl::forward<Args>(args)...) {}
+
+  // Constructs a variant of an alternative type from an initializer list
+  // and other arguments through direct-initialization.
+  //
+  // Note: If the selected constructor is a constexpr constructor, this
+  // constructor shall be a constexpr constructor.
+  template <class T, class U, class... Args,
+            typename std::enable_if<std::is_constructible<
+                variant_internal::UnambiguousTypeOfT<variant, T>,
+                std::initializer_list<U>&, Args...>::value>::type* = nullptr>
+  constexpr explicit variant(in_place_type_t<T>, std::initializer_list<U> il,
+                             Args&&... args)
+      : Base(variant_internal::EmplaceTag<
+                 variant_internal::UnambiguousIndexOf<variant, T>::value>(),
+             il, absl::forward<Args>(args)...) {}
+
+  // Constructs a variant of an alternative type from a provided index,
+  // through value-initialization using the provided forwarded arguments.
+  template <std::size_t I, class... Args,
+            typename std::enable_if<std::is_constructible<
+                variant_internal::VariantAlternativeSfinaeT<I, variant>,
+                Args...>::value>::type* = nullptr>
+  constexpr explicit variant(in_place_index_t<I>, Args&&... args)
+      : Base(variant_internal::EmplaceTag<I>(), absl::forward<Args>(args)...) {}
+
+  // Constructs a variant of an alternative type from a provided index,
+  // through value-initialization of an initializer list and the provided
+  // forwarded arguments.
+  template <std::size_t I, class U, class... Args,
+            typename std::enable_if<std::is_constructible<
+                variant_internal::VariantAlternativeSfinaeT<I, variant>,
+                std::initializer_list<U>&, Args...>::value>::type* = nullptr>
+  constexpr explicit variant(in_place_index_t<I>, std::initializer_list<U> il,
+                             Args&&... args)
+      : Base(variant_internal::EmplaceTag<I>(), il,
+             absl::forward<Args>(args)...) {}
+
+  // Destructors
+
+  // Destroys the variant's currently contained value, provided that
+  // `absl::valueless_by_exception()` is false.
+  ~variant() = default;
+
+  // Assignment Operators
+
+  // Copy assignment operator
+  variant& operator=(const variant& other) = default;
+
+  // Move assignment operator
+  variant& operator=(variant&& other) /*noexcept(see above)*/ = default;
+
+  // Converting assignment operator
+  //
+  // NOTE: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p0608r1.html
+  // has been voted passed the design phase in the C++ standard meeting in Mar
+  // 2018. It will be implemented and integrated into `absl::variant`.
+  template <
+      class T,
+      std::size_t I = std::enable_if<
+          !std::is_same<absl::decay_t<T>, variant>::value,
+          variant_internal::IndexOfConstructedType<variant, T>>::type::value,
+      class Tj = absl::variant_alternative_t<I, variant>,
+      typename std::enable_if<std::is_assignable<Tj&, T>::value &&
+                              std::is_constructible<Tj, T>::value>::type* =
+          nullptr>
+  variant& operator=(T&& t) noexcept(
+      std::is_nothrow_assignable<Tj&, T>::value&&
+          std::is_nothrow_constructible<Tj, T>::value) {
+    variant_internal::VisitIndices<sizeof...(Tn) + 1>::Run(
+        variant_internal::VariantCoreAccess::MakeConversionAssignVisitor(
+            this, absl::forward<T>(t)),
+        index());
+
+    return *this;
+  }
+
+
+  // emplace() Functions
+
+  // Constructs a value of the given alternative type T within the variant. The
+  // existing value of the variant is destroyed first (provided that
+  // `absl::valueless_by_exception()` is false). Requires that T is unambiguous
+  // in the variant.
+  //
+  // Example:
+  //
+  //   absl::variant<std::vector<int>, int, std::string> v;
+  //   v.emplace<int>(99);
+  //   v.emplace<std::string>("abc");
+  template <
+      class T, class... Args,
+      typename std::enable_if<std::is_constructible<
+          absl::variant_alternative_t<
+              variant_internal::UnambiguousIndexOf<variant, T>::value, variant>,
+          Args...>::value>::type* = nullptr>
+  T& emplace(Args&&... args) {
+    return variant_internal::VariantCoreAccess::Replace<
+        variant_internal::UnambiguousIndexOf<variant, T>::value>(
+        this, absl::forward<Args>(args)...);
+  }
+
+  // Constructs a value of the given alternative type T within the variant using
+  // an initializer list. The existing value of the variant is destroyed first
+  // (provided that `absl::valueless_by_exception()` is false). Requires that T
+  // is unambiguous in the variant.
+  //
+  // Example:
+  //
+  //   absl::variant<std::vector<int>, int, std::string> v;
+  //   v.emplace<std::vector<int>>({0, 1, 2});
+  template <
+      class T, class U, class... Args,
+      typename std::enable_if<std::is_constructible<
+          absl::variant_alternative_t<
+              variant_internal::UnambiguousIndexOf<variant, T>::value, variant>,
+          std::initializer_list<U>&, Args...>::value>::type* = nullptr>
+  T& emplace(std::initializer_list<U> il, Args&&... args) {
+    return variant_internal::VariantCoreAccess::Replace<
+        variant_internal::UnambiguousIndexOf<variant, T>::value>(
+        this, il, absl::forward<Args>(args)...);
+  }
+
+  // Destroys the current value of the variant (provided that
+  // `absl::valueless_by_exception()` is false) and constructs a new value at
+  // the given index.
+  //
+  // Example:
+  //
+  //   absl::variant<std::vector<int>, int, int> v;
+  //   v.emplace<1>(99);
+  //   v.emplace<2>(98);
+  //   v.emplace<int>(99);  // Won't compile. 'int' isn't a unique type.
+  template <std::size_t I, class... Args,
+            typename std::enable_if<
+                std::is_constructible<absl::variant_alternative_t<I, variant>,
+                                      Args...>::value>::type* = nullptr>
+  absl::variant_alternative_t<I, variant>& emplace(Args&&... args) {
+    return variant_internal::VariantCoreAccess::Replace<I>(
+        this, absl::forward<Args>(args)...);
+  }
+
+  // Destroys the current value of the variant (provided that
+  // `absl::valueless_by_exception()` is false) and constructs a new value at
+  // the given index using an initializer list and the provided arguments.
+  //
+  // Example:
+  //
+  //   absl::variant<std::vector<int>, int, int> v;
+  //   v.emplace<0>({0, 1, 2});
+  template <std::size_t I, class U, class... Args,
+            typename std::enable_if<std::is_constructible<
+                absl::variant_alternative_t<I, variant>,
+                std::initializer_list<U>&, Args...>::value>::type* = nullptr>
+  absl::variant_alternative_t<I, variant>& emplace(std::initializer_list<U> il,
+                                                   Args&&... args) {
+    return variant_internal::VariantCoreAccess::Replace<I>(
+        this, il, absl::forward<Args>(args)...);
+  }
+
+  // variant::valueless_by_exception()
+  //
+  // Returns false if and only if the variant currently holds a valid value.
+  constexpr bool valueless_by_exception() const noexcept {
+    return this->index_ == absl::variant_npos;
+  }
+
+  // variant::index()
+  //
+  // Returns the index value of the variant's currently selected alternative
+  // type.
+  constexpr std::size_t index() const noexcept { return this->index_; }
+
+  // variant::swap()
+  //
+  // Swaps the values of two variant objects.
+  //
+  void swap(variant& rhs) noexcept(
+      absl::conjunction<
+          std::is_nothrow_move_constructible<T0>,
+          std::is_nothrow_move_constructible<Tn>...,
+          type_traits_internal::IsNothrowSwappable<T0>,
+          type_traits_internal::IsNothrowSwappable<Tn>...>::value) {
+    return variant_internal::VisitIndices<sizeof...(Tn) + 1>::Run(
+        variant_internal::Swap<T0, Tn...>{this, &rhs}, rhs.index());
+  }
+};
+
+// We need a valid declaration of variant<> for SFINAE and overload resolution
+// to work properly above, but we don't need a full declaration since this type
+// will never be constructed. This declaration, though incomplete, suffices.
+template <>
+class variant<>;
+
+//------------------------------------------------------------------------------
+// Relational Operators
+//------------------------------------------------------------------------------
+//
+// If neither operand is in the `variant::valueless_by_exception` state:
+//
+//   * If the index of both variants is the same, the relational operator
+//     returns the result of the corresponding relational operator for the
+//     corresponding alternative type.
+//   * If the index of both variants is not the same, the relational operator
+//     returns the result of that operation applied to the value of the left
+//     operand's index and the value of the right operand's index.
+//   * If at least one operand is in the valueless_by_exception state:
+//     - A variant in the valueless_by_exception state is only considered equal
+//       to another variant in the valueless_by_exception state.
+//     - If exactly one operand is in the valueless_by_exception state, the
+//       variant in the valueless_by_exception state is less than the variant
+//       that is not in the valueless_by_exception state.
+//
+// Note: The value 1 is added to each index in the relational comparisons such
+// that the index corresponding to the valueless_by_exception state wraps around
+// to 0 (the lowest value for the index type), and the remaining indices stay in
+// the same relative order.
+
+// Equal-to operator
+template <typename... Types>
+constexpr variant_internal::RequireAllHaveEqualT<Types...> operator==(
+    const variant<Types...>& a, const variant<Types...>& b) {
+  return (a.index() == b.index()) &&
+         variant_internal::VisitIndices<sizeof...(Types)>::Run(
+             variant_internal::EqualsOp<Types...>{&a, &b}, a.index());
+}
+
+// Not equal operator
+template <typename... Types>
+constexpr variant_internal::RequireAllHaveNotEqualT<Types...> operator!=(
+    const variant<Types...>& a, const variant<Types...>& b) {
+  return (a.index() != b.index()) ||
+         variant_internal::VisitIndices<sizeof...(Types)>::Run(
+             variant_internal::NotEqualsOp<Types...>{&a, &b}, a.index());
+}
+
+// Less-than operator
+template <typename... Types>
+constexpr variant_internal::RequireAllHaveLessThanT<Types...> operator<(
+    const variant<Types...>& a, const variant<Types...>& b) {
+  return (a.index() != b.index())
+             ? (a.index() + 1) < (b.index() + 1)
+             : variant_internal::VisitIndices<sizeof...(Types)>::Run(
+                   variant_internal::LessThanOp<Types...>{&a, &b}, a.index());
+}
+
+// Greater-than operator
+template <typename... Types>
+constexpr variant_internal::RequireAllHaveGreaterThanT<Types...> operator>(
+    const variant<Types...>& a, const variant<Types...>& b) {
+  return (a.index() != b.index())
+             ? (a.index() + 1) > (b.index() + 1)
+             : variant_internal::VisitIndices<sizeof...(Types)>::Run(
+                   variant_internal::GreaterThanOp<Types...>{&a, &b},
+                   a.index());
+}
+
+// Less-than or equal-to operator
+template <typename... Types>
+constexpr variant_internal::RequireAllHaveLessThanOrEqualT<Types...> operator<=(
+    const variant<Types...>& a, const variant<Types...>& b) {
+  return (a.index() != b.index())
+             ? (a.index() + 1) < (b.index() + 1)
+             : variant_internal::VisitIndices<sizeof...(Types)>::Run(
+                   variant_internal::LessThanOrEqualsOp<Types...>{&a, &b},
+                   a.index());
+}
+
+// Greater-than or equal-to operator
+template <typename... Types>
+constexpr variant_internal::RequireAllHaveGreaterThanOrEqualT<Types...>
+operator>=(const variant<Types...>& a, const variant<Types...>& b) {
+  return (a.index() != b.index())
+             ? (a.index() + 1) > (b.index() + 1)
+             : variant_internal::VisitIndices<sizeof...(Types)>::Run(
+                   variant_internal::GreaterThanOrEqualsOp<Types...>{&a, &b},
+                   a.index());
+}
+
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+namespace std {
+
+// hash()
+template <>  // NOLINT
+struct hash<absl::monostate> {
+  std::size_t operator()(absl::monostate) const { return 0; }
+};
+
+template <class... T>  // NOLINT
+struct hash<absl::variant<T...>>
+    : absl::variant_internal::VariantHashBase<absl::variant<T...>, void,
+                                              absl::remove_const_t<T>...> {};
+
+}  // namespace std
+
+#endif  // ABSL_USES_STD_VARIANT
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace variant_internal {
+
+// Helper visitor for converting a variant<Ts...>` into another type (mostly
+// variant) that can be constructed from any type.
+template <typename To>
+struct ConversionVisitor {
+  template <typename T>
+  To operator()(T&& v) const {
+    return To(std::forward<T>(v));
+  }
+};
+
+}  // namespace variant_internal
+
+// ConvertVariantTo()
+//
+// Helper functions to convert an `absl::variant` to a variant of another set of
+// types, provided that the alternative type of the new variant type can be
+// converted from any type in the source variant.
+//
+// Example:
+//
+//   absl::variant<name1, name2, float> InternalReq(const Req&);
+//
+//   // name1 and name2 are convertible to name
+//   absl::variant<name, float> ExternalReq(const Req& req) {
+//     return absl::ConvertVariantTo<absl::variant<name, float>>(
+//              InternalReq(req));
+//   }
+template <typename To, typename Variant>
+To ConvertVariantTo(Variant&& variant) {
+  return absl::visit(variant_internal::ConversionVisitor<To>{},
+                     std::forward<Variant>(variant));
+}
+
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#endif  // ABSL_TYPES_VARIANT_H_
diff --git a/src/absl/utility/utility.h b/src/absl/utility/utility.h
new file mode 100644 (file)
index 0000000..bf92322
--- /dev/null
@@ -0,0 +1,350 @@
+// Copyright 2017 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// This header file contains C++11 versions of standard <utility> header
+// abstractions available within C++14 and C++17, and are designed to be drop-in
+// replacement for code compliant with C++14 and C++17.
+//
+// The following abstractions are defined:
+//
+//   * integer_sequence<T, Ints...>  == std::integer_sequence<T, Ints...>
+//   * index_sequence<Ints...>       == std::index_sequence<Ints...>
+//   * make_integer_sequence<T, N>   == std::make_integer_sequence<T, N>
+//   * make_index_sequence<N>        == std::make_index_sequence<N>
+//   * index_sequence_for<Ts...>     == std::index_sequence_for<Ts...>
+//   * apply<Functor, Tuple>         == std::apply<Functor, Tuple>
+//   * exchange<T>                   == std::exchange<T>
+//   * make_from_tuple<T>            == std::make_from_tuple<T>
+//
+// This header file also provides the tag types `in_place_t`, `in_place_type_t`,
+// and `in_place_index_t`, as well as the constant `in_place`, and
+// `constexpr` `std::move()` and `std::forward()` implementations in C++11.
+//
+// References:
+//
+//  https://en.cppreference.com/w/cpp/utility/integer_sequence
+//  https://en.cppreference.com/w/cpp/utility/apply
+//  http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3658.html
+
+#ifndef ABSL_UTILITY_UTILITY_H_
+#define ABSL_UTILITY_UTILITY_H_
+
+#include <cstddef>
+#include <cstdlib>
+#include <tuple>
+#include <utility>
+
+#include "absl/base/config.h"
+#include "absl/base/internal/inline_variable.h"
+#include "absl/base/internal/invoke.h"
+#include "absl/meta/type_traits.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+
+// integer_sequence
+//
+// Class template representing a compile-time integer sequence. An instantiation
+// of `integer_sequence<T, Ints...>` has a sequence of integers encoded in its
+// type through its template arguments (which is a common need when
+// working with C++11 variadic templates). `absl::integer_sequence` is designed
+// to be a drop-in replacement for C++14's `std::integer_sequence`.
+//
+// Example:
+//
+//   template< class T, T... Ints >
+//   void user_function(integer_sequence<T, Ints...>);
+//
+//   int main()
+//   {
+//     // user_function's `T` will be deduced to `int` and `Ints...`
+//     // will be deduced to `0, 1, 2, 3, 4`.
+//     user_function(make_integer_sequence<int, 5>());
+//   }
+template <typename T, T... Ints>
+struct integer_sequence {
+  using value_type = T;
+  static constexpr size_t size() noexcept { return sizeof...(Ints); }
+};
+
+// index_sequence
+//
+// A helper template for an `integer_sequence` of `size_t`,
+// `absl::index_sequence` is designed to be a drop-in replacement for C++14's
+// `std::index_sequence`.
+template <size_t... Ints>
+using index_sequence = integer_sequence<size_t, Ints...>;
+
+namespace utility_internal {
+
+template <typename Seq, size_t SeqSize, size_t Rem>
+struct Extend;
+
+// Note that SeqSize == sizeof...(Ints). It's passed explicitly for efficiency.
+template <typename T, T... Ints, size_t SeqSize>
+struct Extend<integer_sequence<T, Ints...>, SeqSize, 0> {
+  using type = integer_sequence<T, Ints..., (Ints + SeqSize)...>;
+};
+
+template <typename T, T... Ints, size_t SeqSize>
+struct Extend<integer_sequence<T, Ints...>, SeqSize, 1> {
+  using type = integer_sequence<T, Ints..., (Ints + SeqSize)..., 2 * SeqSize>;
+};
+
+// Recursion helper for 'make_integer_sequence<T, N>'.
+// 'Gen<T, N>::type' is an alias for 'integer_sequence<T, 0, 1, ... N-1>'.
+template <typename T, size_t N>
+struct Gen {
+  using type =
+      typename Extend<typename Gen<T, N / 2>::type, N / 2, N % 2>::type;
+};
+
+template <typename T>
+struct Gen<T, 0> {
+  using type = integer_sequence<T>;
+};
+
+template <typename T>
+struct InPlaceTypeTag {
+  explicit InPlaceTypeTag() = delete;
+  InPlaceTypeTag(const InPlaceTypeTag&) = delete;
+  InPlaceTypeTag& operator=(const InPlaceTypeTag&) = delete;
+};
+
+template <size_t I>
+struct InPlaceIndexTag {
+  explicit InPlaceIndexTag() = delete;
+  InPlaceIndexTag(const InPlaceIndexTag&) = delete;
+  InPlaceIndexTag& operator=(const InPlaceIndexTag&) = delete;
+};
+
+}  // namespace utility_internal
+
+// Compile-time sequences of integers
+
+// make_integer_sequence
+//
+// This template alias is equivalent to
+// `integer_sequence<int, 0, 1, ..., N-1>`, and is designed to be a drop-in
+// replacement for C++14's `std::make_integer_sequence`.
+template <typename T, T N>
+using make_integer_sequence = typename utility_internal::Gen<T, N>::type;
+
+// make_index_sequence
+//
+// This template alias is equivalent to `index_sequence<0, 1, ..., N-1>`,
+// and is designed to be a drop-in replacement for C++14's
+// `std::make_index_sequence`.
+template <size_t N>
+using make_index_sequence = make_integer_sequence<size_t, N>;
+
+// index_sequence_for
+//
+// Converts a typename pack into an index sequence of the same length, and
+// is designed to be a drop-in replacement for C++14's
+// `std::index_sequence_for()`
+template <typename... Ts>
+using index_sequence_for = make_index_sequence<sizeof...(Ts)>;
+
+// Tag types
+
+#ifdef ABSL_USES_STD_OPTIONAL
+
+using std::in_place_t;
+using std::in_place;
+
+#else  // ABSL_USES_STD_OPTIONAL
+
+// in_place_t
+//
+// Tag type used to specify in-place construction, such as with
+// `absl::optional`, designed to be a drop-in replacement for C++17's
+// `std::in_place_t`.
+struct in_place_t {};
+
+ABSL_INTERNAL_INLINE_CONSTEXPR(in_place_t, in_place, {});
+
+#endif  // ABSL_USES_STD_OPTIONAL
+
+#if defined(ABSL_USES_STD_ANY) || defined(ABSL_USES_STD_VARIANT)
+using std::in_place_type;
+using std::in_place_type_t;
+#else
+
+// in_place_type_t
+//
+// Tag type used for in-place construction when the type to construct needs to
+// be specified, such as with `absl::any`, designed to be a drop-in replacement
+// for C++17's `std::in_place_type_t`.
+template <typename T>
+using in_place_type_t = void (*)(utility_internal::InPlaceTypeTag<T>);
+
+template <typename T>
+void in_place_type(utility_internal::InPlaceTypeTag<T>) {}
+#endif  // ABSL_USES_STD_ANY || ABSL_USES_STD_VARIANT
+
+#ifdef ABSL_USES_STD_VARIANT
+using std::in_place_index;
+using std::in_place_index_t;
+#else
+
+// in_place_index_t
+//
+// Tag type used for in-place construction when the type to construct needs to
+// be specified, such as with `absl::any`, designed to be a drop-in replacement
+// for C++17's `std::in_place_index_t`.
+template <size_t I>
+using in_place_index_t = void (*)(utility_internal::InPlaceIndexTag<I>);
+
+template <size_t I>
+void in_place_index(utility_internal::InPlaceIndexTag<I>) {}
+#endif  // ABSL_USES_STD_VARIANT
+
+// Constexpr move and forward
+
+// move()
+//
+// A constexpr version of `std::move()`, designed to be a drop-in replacement
+// for C++14's `std::move()`.
+template <typename T>
+constexpr absl::remove_reference_t<T>&& move(T&& t) noexcept {
+  return static_cast<absl::remove_reference_t<T>&&>(t);
+}
+
+// forward()
+//
+// A constexpr version of `std::forward()`, designed to be a drop-in replacement
+// for C++14's `std::forward()`.
+template <typename T>
+constexpr T&& forward(
+    absl::remove_reference_t<T>& t) noexcept {  // NOLINT(runtime/references)
+  return static_cast<T&&>(t);
+}
+
+namespace utility_internal {
+// Helper method for expanding tuple into a called method.
+template <typename Functor, typename Tuple, std::size_t... Indexes>
+auto apply_helper(Functor&& functor, Tuple&& t, index_sequence<Indexes...>)
+    -> decltype(absl::base_internal::invoke(
+        absl::forward<Functor>(functor),
+        std::get<Indexes>(absl::forward<Tuple>(t))...)) {
+  return absl::base_internal::invoke(
+      absl::forward<Functor>(functor),
+      std::get<Indexes>(absl::forward<Tuple>(t))...);
+}
+
+}  // namespace utility_internal
+
+// apply
+//
+// Invokes a Callable using elements of a tuple as its arguments.
+// Each element of the tuple corresponds to an argument of the call (in order).
+// Both the Callable argument and the tuple argument are perfect-forwarded.
+// For member-function Callables, the first tuple element acts as the `this`
+// pointer. `absl::apply` is designed to be a drop-in replacement for C++17's
+// `std::apply`. Unlike C++17's `std::apply`, this is not currently `constexpr`.
+//
+// Example:
+//
+//   class Foo {
+//    public:
+//     void Bar(int);
+//   };
+//   void user_function1(int, std::string);
+//   void user_function2(std::unique_ptr<Foo>);
+//   auto user_lambda = [](int, int) {};
+//
+//   int main()
+//   {
+//       std::tuple<int, std::string> tuple1(42, "bar");
+//       // Invokes the first user function on int, std::string.
+//       absl::apply(&user_function1, tuple1);
+//
+//       std::tuple<std::unique_ptr<Foo>> tuple2(absl::make_unique<Foo>());
+//       // Invokes the user function that takes ownership of the unique
+//       // pointer.
+//       absl::apply(&user_function2, std::move(tuple2));
+//
+//       auto foo = absl::make_unique<Foo>();
+//       std::tuple<Foo*, int> tuple3(foo.get(), 42);
+//       // Invokes the method Bar on foo with one argument, 42.
+//       absl::apply(&Foo::Bar, tuple3);
+//
+//       std::tuple<int, int> tuple4(8, 9);
+//       // Invokes a lambda.
+//       absl::apply(user_lambda, tuple4);
+//   }
+template <typename Functor, typename Tuple>
+auto apply(Functor&& functor, Tuple&& t)
+    -> decltype(utility_internal::apply_helper(
+        absl::forward<Functor>(functor), absl::forward<Tuple>(t),
+        absl::make_index_sequence<std::tuple_size<
+            typename std::remove_reference<Tuple>::type>::value>{})) {
+  return utility_internal::apply_helper(
+      absl::forward<Functor>(functor), absl::forward<Tuple>(t),
+      absl::make_index_sequence<std::tuple_size<
+          typename std::remove_reference<Tuple>::type>::value>{});
+}
+
+// exchange
+//
+// Replaces the value of `obj` with `new_value` and returns the old value of
+// `obj`.  `absl::exchange` is designed to be a drop-in replacement for C++14's
+// `std::exchange`.
+//
+// Example:
+//
+//   Foo& operator=(Foo&& other) {
+//     ptr1_ = absl::exchange(other.ptr1_, nullptr);
+//     int1_ = absl::exchange(other.int1_, -1);
+//     return *this;
+//   }
+template <typename T, typename U = T>
+T exchange(T& obj, U&& new_value) {
+  T old_value = absl::move(obj);
+  obj = absl::forward<U>(new_value);
+  return old_value;
+}
+
+namespace utility_internal {
+template <typename T, typename Tuple, size_t... I>
+T make_from_tuple_impl(Tuple&& tup, absl::index_sequence<I...>) {
+  return T(std::get<I>(std::forward<Tuple>(tup))...);
+}
+}  // namespace utility_internal
+
+// make_from_tuple
+//
+// Given the template parameter type `T` and a tuple of arguments
+// `std::tuple(arg0, arg1, ..., argN)` constructs an object of type `T` as if by
+// calling `T(arg0, arg1, ..., argN)`.
+//
+// Example:
+//
+//   std::tuple<const char*, size_t> args("hello world", 5);
+//   auto s = absl::make_from_tuple<std::string>(args);
+//   assert(s == "hello");
+//
+template <typename T, typename Tuple>
+constexpr T make_from_tuple(Tuple&& tup) {
+  return utility_internal::make_from_tuple_impl<T>(
+      std::forward<Tuple>(tup),
+      absl::make_index_sequence<
+          std::tuple_size<absl::decay_t<Tuple>>::value>{});
+}
+
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#endif  // ABSL_UTILITY_UTILITY_H_
diff --git a/src/cpp-compat.cpp b/src/cpp-compat.cpp
new file mode 100644 (file)
index 0000000..3a00b2e
--- /dev/null
@@ -0,0 +1,40 @@
+
+#include "cpp-compat.h"
+#include <Rcpp.h>
+#include <Rmath.h>
+using namespace Rcpp;
+
+#include <stdarg.h> // va_ stuff
+
+void cpp_compat_printf(const char* fmt, ...) {
+  va_list args;
+  va_start(args, fmt);
+  Rprintf(fmt, args);
+  va_end(args);
+}
+
+void cpp_compat_abort() {
+  throw std::runtime_error("abort() called");
+}
+
+void cpp_compat_exit(int code) {
+  throw std::runtime_error("exit() called");
+}
+
+int cpp_compat_random() {
+  // trying to match what random() would return
+  // www.gnu.org/software/libc/manual/html_node/BSD-Random.html#BSD-Random
+  // the RNG state is correctly managed for functions that use
+  // Rcpp::export...other functions will require management of the RNGScope
+  return unif_rand() * INT_MAX;
+}
+
+void cpp_compat_srandom(int seed) {
+  // pretty sure this should not have any effect
+  // it gets called on load here with the initiation
+  // of the Random class in s2testing, so it can't
+  // error out
+}
+
+std::ostream& cpp_compat_cerr = Rcerr;
+std::ostream& cpp_compat_cout = Rcout;
diff --git a/src/cpp-compat.h b/src/cpp-compat.h
new file mode 100644 (file)
index 0000000..7e18796
--- /dev/null
@@ -0,0 +1,16 @@
+
+#ifndef CPP_COMPAT_H
+#define CPP_COMPAT_H
+
+#include <streambuf>
+
+void cpp_compat_printf(const char* fmt, ...);
+[[ noreturn ]] void cpp_compat_abort();
+[[ noreturn ]] void cpp_compat_exit(int code);
+int cpp_compat_random();
+void cpp_compat_srandom(int seed);
+
+extern std::ostream& cpp_compat_cerr;
+extern std::ostream& cpp_compat_cout;
+
+#endif
diff --git a/src/geography-collection.h b/src/geography-collection.h
new file mode 100644 (file)
index 0000000..364be84
--- /dev/null
@@ -0,0 +1,241 @@
+
+#ifndef GEOGRAPHY_COLLECTION_H
+#define GEOGRAPHY_COLLECTION_H
+
+#include <algorithm>
+#include "geography.h"
+
+// This class handles collections of other Geography
+// objects.
+class GeographyCollection: public Geography {
+public:
+  GeographyCollection(): features(0) {}
+  GeographyCollection(std::vector<std::unique_ptr<Geography>> features):
+    features(std::move(features)) {}
+
+  Geography::Type GeographyType() {
+    return Geography::Type::GEOGRAPHY_COLLECTION;
+  }
+
+  bool FindValidationError(S2Error* error) {
+    bool result;
+    error->Clear();
+    for (size_t i = 0; i < this->features.size(); i++) {
+      result = this->features[i]->FindValidationError(error);
+      if (result) {
+        return result;
+      }
+    }
+
+    return false;
+  }
+
+  bool IsCollection() {
+    return this->features.size() > 0;
+  }
+
+  int Dimension() {
+    int dimension = -1;
+    for (size_t i = 0; i < this->features.size(); i++) {
+      dimension = std::max<int>(this->features[i]->Dimension(), dimension);
+    }
+
+    return dimension;
+  }
+
+  int NumPoints() {
+    int numPoints = 0;
+    for (size_t i = 0; i < this->features.size(); i++) {
+      numPoints += this->features[i]->NumPoints();
+    }
+    return numPoints;
+  }
+
+  bool IsEmpty() {
+    // could also loop and test all(!IsEmpty()), but
+    // that is inconsistent with what gets printed
+    return this->features.size() == 0;
+  }
+
+  double Area() {
+    double area = 0;
+    for (size_t i = 0; i < this->features.size(); i++) {
+      area += this->features[i]->Area();
+    }
+    return area;
+  }
+
+  double Length() {
+    double length = 0;
+    for (size_t i = 0; i < this->features.size(); i++) {
+      length += this->features[i]->Length();
+    }
+    return length;
+  }
+
+  double Perimeter() {
+    double perimeter = 0;
+    for (size_t i = 0; i < this->features.size(); i++) {
+      perimeter += this->features[i]->Perimeter();
+    }
+    return perimeter;
+  }
+
+  double X() {
+    Rcpp::stop("Can't compute X value of a non-point geography");
+  }
+
+  double Y() {
+    Rcpp::stop("Can't compute Y value of a non-point geography");
+  }
+
+  S2Point Centroid() {
+    S2Point cumCentroid(0, 0, 0);
+    for (size_t i = 0; i < this->features.size(); i++) {
+      S2Point centroid = this->features[i]->Centroid();
+      if (centroid.Norm2() > 0) {
+        cumCentroid += centroid.Normalize();
+      }
+    }
+
+    return cumCentroid;
+  }
+
+  std::unique_ptr<Geography> Boundary() {
+    std::vector<std::unique_ptr<Geography>> featureBoundaries(this->features.size());
+    for (size_t i = 0; i < this->features.size(); i++) {
+      featureBoundaries[i] = this->features[i]->Boundary();
+    }
+
+    return absl::make_unique<GeographyCollection>(std::move(featureBoundaries));
+  }
+
+  std::vector<int> BuildShapeIndex(MutableS2ShapeIndex* index) {
+    std::vector<int> shapeIds;
+    for (size_t i = 0; i < this->features.size(); i++) {
+      std::vector<int> newShapeIds = this->features[i]->BuildShapeIndex(index);
+      for (size_t j = 0; j < newShapeIds.size(); j++) {
+        shapeIds.push_back(newShapeIds[j]);
+      }
+    }
+    return shapeIds;
+  }
+
+  void Export(WKGeometryHandler* handler, uint32_t partId) {
+    WKGeometryMeta meta(WKGeometryType::GeometryCollection, false, false, false);
+    meta.hasSize = true;
+    meta.size = this->features.size();
+
+    handler->nextGeometryStart(meta, partId);
+    for (size_t i = 0; i < this->features.size(); i++) {
+      this->features[i]->Export(handler, i);
+    }
+    handler->nextGeometryEnd(meta, partId);
+  }
+
+  class Builder: public GeographyBuilder {
+  public:
+
+    Builder(bool oriented, bool check):
+      metaPtr(nullptr), builderPtr(nullptr), builderMetaPtr(nullptr),
+      oriented(oriented), check(check) {}
+
+    virtual void nextGeometryStart(const WKGeometryMeta& meta, uint32_t partId) {
+      // if this is the first call, store the meta reference associated with this geometry
+      if (this->metaPtr == nullptr) {
+        this->metaPtr = (WKGeometryMeta*) &meta;
+        return;
+      }
+
+      if (!this->builderPtr) {
+        // store a reference to the meta associated with this
+        // builder so that we know when the corresponding nextGeometryEnd()
+        // is called
+        this->builderMetaPtr = (WKGeometryMeta*) &meta;
+
+        switch (meta.geometryType) {
+        case WKGeometryType::Point:
+        case WKGeometryType::MultiPoint:
+          this->builderPtr = absl::make_unique<PointGeography::Builder>();
+          break;
+        case WKGeometryType::LineString:
+        case WKGeometryType::MultiLineString:
+          this->builderPtr = absl::make_unique<PolylineGeography::Builder>();
+          break;
+        case WKGeometryType::Polygon:
+        case WKGeometryType::MultiPolygon:
+          this->builderPtr = absl::make_unique<PolygonGeography::Builder>(
+            this->oriented,
+            this->check
+          );
+          break;
+        case WKGeometryType::GeometryCollection:
+          this->builderPtr = absl::make_unique<GeographyCollection::Builder>(
+            this->oriented,
+            this->check
+          );
+          break;
+        default:
+          std::stringstream err;
+          err << "Unknown geometry type in geography builder: " << meta.geometryType;
+          Rcpp::stop(err.str());
+        }
+      }
+
+      this->builder()->nextGeometryStart(meta, partId);
+    }
+
+    virtual void nextLinearRingStart(const WKGeometryMeta& meta, uint32_t size, uint32_t ringId) {
+      this->builder()->nextLinearRingStart(meta, size, ringId);
+    }
+
+    virtual void nextCoordinate(const WKGeometryMeta& meta, const WKCoord& coord, uint32_t coordId) {
+      this->builder()->nextCoordinate(meta, coord, coordId);
+    }
+
+    virtual void nextLinearRingEnd(const WKGeometryMeta& meta, uint32_t size, uint32_t ringId) {
+      this->builder()->nextLinearRingEnd(meta, size, ringId);
+    }
+
+    virtual void nextGeometryEnd(const WKGeometryMeta& meta, uint32_t partId) {
+      // the end of this GEOMETRYCOLLECTION
+      if (&meta == this->metaPtr) {
+        return;
+      }
+
+      this->builder()->nextGeometryEnd(meta, partId);
+
+      if (&meta == this->builderMetaPtr) {
+        std::unique_ptr<Geography> feature = this->builder()->build();
+        features.push_back(std::move(feature));
+        this->builderPtr = std::unique_ptr<GeographyBuilder>(nullptr);
+        this->builderMetaPtr = nullptr;
+      }
+    }
+
+    std::unique_ptr<Geography> build() {
+      return absl::make_unique<GeographyCollection>(std::move(this->features));
+    }
+
+  private:
+    std::vector<std::unique_ptr<Geography>> features;
+    WKGeometryMeta* metaPtr;
+    std::unique_ptr<GeographyBuilder> builderPtr;
+    WKGeometryMeta* builderMetaPtr;
+    bool oriented;
+    bool check;
+
+    GeographyBuilder* builder() {
+      if (this->builderPtr) {
+        return this->builderPtr.get();
+      } else {
+        Rcpp::stop("Invalid nesting in geometrycollection (can't find nested builder)");
+      }
+    }
+  };
+
+private:
+  std::vector<std::unique_ptr<Geography>> features;
+};
+
+#endif
diff --git a/src/geography-operator.h b/src/geography-operator.h
new file mode 100644 (file)
index 0000000..5150d20
--- /dev/null
@@ -0,0 +1,108 @@
+
+#ifndef GEOGRAPHY_OPERATOR_H
+#define GEOGRAPHY_OPERATOR_H
+
+#include <stdexcept>
+
+#include "geography.h"
+#include <Rcpp.h>
+
+class GeographyOperatorException: public std::runtime_error {
+public:
+  GeographyOperatorException(std::string msg): std::runtime_error(msg.c_str()) {}
+};
+
+template<class VectorType, class ScalarType>
+class UnaryGeographyOperator {
+public:
+  VectorType processVector(Rcpp::List geog) {
+    VectorType output(geog.size());
+
+    Rcpp::IntegerVector problemId;
+    Rcpp::CharacterVector problems;
+
+    SEXP item;
+    for (R_xlen_t i = 0; i < geog.size(); i++) {
+      Rcpp::checkUserInterrupt();
+
+      item = geog[i];
+      if (item == R_NilValue) {
+        output[i] = VectorType::get_na();
+      } else {
+        Rcpp::XPtr<Geography> feature(item);
+
+        try {
+          output[i] = this->processFeature(feature, i);
+        } catch (GeographyOperatorException& e) {
+          output[i] = VectorType::get_na();
+          problemId.push_back(i);
+          problems.push_back(e.what());
+        }
+      }
+    }
+
+    if (problemId.size() > 0) {
+      Rcpp::Environment s2NS = Rcpp::Environment::namespace_env("s2");
+      Rcpp::Function stopProblems = s2NS["stop_problems_process"];
+      stopProblems(problemId, problems);
+    }
+
+    return output;
+  }
+
+  virtual ScalarType processFeature(Rcpp::XPtr<Geography> feature, R_xlen_t i) = 0;
+};
+
+
+template<class VectorType, class ScalarType>
+class BinaryGeographyOperator {
+public:
+  VectorType processVector(Rcpp::List geog1, Rcpp::List geog2) {
+    if (geog2.size() != geog1.size()) {
+      Rcpp::stop("Incompatible lengths");
+    }
+
+    VectorType output(geog1.size());
+
+    Rcpp::IntegerVector problemId;
+    Rcpp::CharacterVector problems;
+
+    SEXP item1;
+    SEXP item2;
+
+    for (R_xlen_t i = 0; i < geog1.size(); i++) {
+      Rcpp::checkUserInterrupt();
+      
+      item1 = geog1[i];
+      item2 = geog2[i];
+      if (item1 ==  R_NilValue || item2 == R_NilValue) {
+        output[i] = VectorType::get_na();
+      } else {
+        Rcpp::XPtr<Geography> feature1(item1);
+        Rcpp::XPtr<Geography> feature2(item2);
+
+        try {
+          output[i] = processFeature(feature1, feature2, i);
+        } catch (GeographyOperatorException& e) {
+          output[i] = VectorType::get_na();
+          problemId.push_back(i);
+          problems.push_back(e.what());
+        }
+      }
+    }
+
+    if (problemId.size() > 0) {
+      Rcpp::Environment s2NS = Rcpp::Environment::namespace_env("s2");
+      Rcpp::Function stopProblems = s2NS["stop_problems_process"];
+      stopProblems(problemId, problems);
+    }
+
+    return output;
+  }
+
+  virtual ScalarType processFeature(Rcpp::XPtr<Geography> feature1,
+                                    Rcpp::XPtr<Geography> feature2,
+                                    R_xlen_t i) = 0;
+};
+
+#endif
diff --git a/src/geography.h b/src/geography.h
new file mode 100644 (file)
index 0000000..714ef82
--- /dev/null
@@ -0,0 +1,116 @@
+
+#ifndef GEOGRAPHY_H
+#define GEOGRAPHY_H
+
+#include <memory>
+#include "s2/s2latlng.h"
+#include "s2/s2polyline.h"
+#include "s2/s2polygon.h"
+#include "s2/s2shape_index.h"
+#include "s2/s2shape_index_region.h"
+#include "s2/mutable_s2shape_index.h"
+#include "s2/s2point_vector_shape.h"
+#include "s2/s2cap.h"
+#include "wk/geometry-handler.hpp"
+#include <Rcpp.h>
+
+class Geography {
+public:
+
+  enum class Type {
+    GEOGRAPHY_EMPTY,
+    GEOGRAPHY_POINT,
+    GEOGRAPHY_POLYLINE,
+    GEOGRAPHY_POLYGON,
+    GEOGRAPHY_COLLECTION
+  };
+
+  Geography(): hasIndex(false) {}
+
+  // accessors need to be methods, since their calculation
+  // depends on the geometry type
+  virtual Type GeographyType() {
+    return Type::GEOGRAPHY_EMPTY;
+  }
+
+  virtual bool FindValidationError(S2Error* error) = 0;
+
+  // returns true for a multi-
+  // or geometrycollection type
+  virtual bool IsCollection() = 0;
+  // Returns 0 for point, 1 for line, 2 for polygon
+  virtual int Dimension() = 0;
+  // Returns the number of points in the input
+  virtual int NumPoints() = 0;
+  virtual bool IsEmpty() = 0;
+  virtual double Area() = 0;
+  virtual double Length() = 0;
+  virtual double Perimeter() = 0;
+  virtual double X() = 0;
+  virtual double Y() = 0;
+  virtual S2Point Centroid() = 0;
+  virtual std::unique_ptr<Geography> Boundary() = 0;
+
+  // every type will build the index differently based on
+  // the underlying data, and this can (should?) be done
+  // lazily. Returns a vector of shape IDs so the caller
+  // can keep track of which shape came from which feature.
+  virtual std::vector<int> BuildShapeIndex(MutableS2ShapeIndex* index) = 0;
+
+  // the factory handler is responsible for building these objects
+  // but exporting can be done here
+  virtual void Export(WKGeometryHandler* handler, uint32_t partId) = 0;
+
+  virtual ~Geography() {}
+
+  // Most calculations will use the ShapeIndex, but sometimes access to the
+  // underlying point, line, or polygon is useful to keep this class from
+  // becoming bloated with the entire s2 API.
+  virtual const std::vector<S2Point>* Point() {
+    return nullptr;
+  }
+
+  virtual const std::vector<std::unique_ptr<S2Polyline>>* Polyline() {
+    return nullptr;
+  }
+
+  virtual const S2Polygon* Polygon() {
+    return nullptr;
+  }
+
+  // other calculations use ShapeIndex
+  virtual S2ShapeIndex* ShapeIndex() {
+    if (!this->hasIndex) {
+      this->BuildShapeIndex(&this->shape_index_);
+      this->hasIndex = true;
+    }
+
+    return &this->shape_index_;
+  }
+
+  virtual S2ShapeIndexRegion<S2ShapeIndex> ShapeIndexRegion() {
+         S2ShapeIndex *ix = this->ShapeIndex();
+         return MakeS2ShapeIndexRegion(ix);
+  }
+
+  virtual S2Cap GetCapBound() {
+         return this->ShapeIndexRegion().GetCapBound();
+  }
+
+  virtual S2LatLngRect GetRectBound() {
+         return this->ShapeIndexRegion().GetRectBound();
+  }
+
+protected:
+  MutableS2ShapeIndex shape_index_;
+  bool hasIndex;
+};
+
+
+class GeographyBuilder: public WKGeometryHandler {
+public:
+  virtual std::unique_ptr<Geography> build() = 0;
+  virtual ~GeographyBuilder() {}
+};
+
+#endif
diff --git a/src/init.cpp b/src/init.cpp
new file mode 100644 (file)
index 0000000..eaed686
--- /dev/null
@@ -0,0 +1,14 @@
+
+#include "s2/s2debug.h"
+#include <Rcpp.h>
+using namespace Rcpp;
+
+// [[Rcpp::export]]
+void cpp_s2_init() {
+  // It's important to set this flag, as users might have "debug" flags
+  // for their build environment, and there are some checks that will terminate
+  // R instead of throw an exception if this value is set to true.
+  // When possible, we also disable debug checks on a per-operation basis
+  // if there is another way to do so (e.g., constructing S2Loop and S2Polygon objects).
+  FLAGS_s2debug = false; // # nocov
+}
diff --git a/src/point-geography.h b/src/point-geography.h
new file mode 100644 (file)
index 0000000..c4f16f0
--- /dev/null
@@ -0,0 +1,181 @@
+
+#ifndef POINT_GEOGRAPHY_H
+#define POINT_GEOGRAPHY_H
+
+#include <cmath>
+
+#include "s2/s2latlng_rect.h"
+
+#include "geography.h"
+
+// This class handles both points and multipoints, as this is how
+// points are generally returned/required in S2 (vector of S2Point)
+// This is similar to an S2PointVectorLayer
+class PointGeography: public Geography {
+public:
+  PointGeography(): points(0) {}
+  PointGeography(S2Point point): points(1) {
+    this->points[0] = point;
+  }
+  PointGeography(std::vector<S2Point> points): points(points) {}
+
+  Geography::Type GeographyType() {
+    return Geography::Type::GEOGRAPHY_POINT;
+  }
+
+  bool FindValidationError(S2Error* error) {
+    return false;
+  }
+
+  const std::vector<S2Point>* Point() {
+    return &(this->points);
+  }
+
+  bool IsCollection() {
+    return this->points.size() > 1;
+  }
+
+  int Dimension() {
+    return 0;
+  }
+
+  int NumPoints() {
+    return this->points.size();
+  }
+
+  bool IsEmpty() {
+    return this->points.size() == 0;
+  }
+
+  double Area() {
+    return 0;
+  }
+
+  double Length() {
+    return 0;
+  }
+
+  double Perimeter() {
+    return 0;
+  }
+
+  double X() {
+    if (this->points.size() != 1) {
+      return NA_REAL;
+    } else {
+      S2LatLng latLng(this->points[0]);
+      return latLng.lng().degrees();
+    }
+  }
+
+  double Y() {
+    if (this->points.size() != 1) {
+      return NA_REAL;
+    } else {
+      S2LatLng latLng(this->points[0]);
+      return latLng.lat().degrees();
+    }
+  }
+
+  S2Point Centroid() {
+    S2Point output(0, 0, 0);
+    for (size_t i = 0; i < this->points.size(); i++) {
+        output += this->points[i];
+    }
+
+    return output;
+  }
+
+  S2LatLngRect GetRectBound() {
+       S2LatLngRect rect; 
+    for (size_t i = 0; i < this->points.size(); i++) {
+        rect.AddPoint(this->points[i]); // depends on order
+    }
+       return rect;
+  }
+
+  std::unique_ptr<Geography> Boundary() {
+    return absl::make_unique<PointGeography>();
+  }
+
+  std::vector<int> BuildShapeIndex(MutableS2ShapeIndex* index) {
+    std::vector<int> shapeIds(1);
+    std::vector<S2Point> pointsCopy(this->points);
+
+    shapeIds[0] = index->Add(std::unique_ptr<S2PointVectorShape>(
+      new S2PointVectorShape(std::move(pointsCopy)))
+    );
+    return shapeIds;
+  }
+
+  void Export(WKGeometryHandler* handler, uint32_t partId) {
+    S2LatLng point;
+
+    if (this->points.size() > 1) {
+      // export multipoint
+      WKGeometryMeta meta(WKGeometryType::MultiPoint, false, false, false);
+      meta.hasSize = true;
+      meta.size = this->points.size();
+
+      WKGeometryMeta childMeta(WKGeometryType::Point, false, false, false);
+      childMeta.hasSize = true;
+      childMeta.size = 1;
+
+      handler->nextGeometryStart(meta, partId);
+
+      for (size_t i = 0; i < this->points.size(); i++) {
+        point = S2LatLng(this->points[i]);
+
+        handler->nextGeometryStart(childMeta, i);
+        handler->nextCoordinate(meta, WKCoord::xy(point.lng().degrees(), point.lat().degrees()), 0);
+        handler->nextGeometryEnd(childMeta, i);
+      }
+
+      handler->nextGeometryEnd(meta, partId);
+
+    } else if (this->points.size() > 0) {
+      // export point
+      WKGeometryMeta meta(WKGeometryType::Point, false, false, false);
+      meta.hasSize = true;
+      meta.size = this->points.size();
+
+      handler->nextGeometryStart(meta, partId);
+
+      point = S2LatLng(this->points[0]);
+      handler->nextCoordinate(meta, WKCoord::xy(point.lng().degrees(), point.lat().degrees()), 0);
+
+      handler->nextGeometryEnd(meta, partId);
+    } else {
+      // export empty point
+      // export point
+      WKGeometryMeta meta(WKGeometryType::Point, false, false, false);
+      meta.hasSize = true;
+      meta.size = 0;
+      handler->nextGeometryStart(meta, partId);
+      handler->nextGeometryEnd(meta, partId);
+    }
+  }
+
+  class Builder: public GeographyBuilder {
+  public:
+    void nextCoordinate(const WKGeometryMeta& meta, const WKCoord& coord, uint32_t coordId) {
+      // Coordinates with nan in S2 are unpredictable; censor to EMPTY. Empty
+      // points coming from WKB are always nan, nan.
+      if (!std::isnan(coord.x) && !std::isnan(coord.y)) {
+        points.push_back(S2LatLng::FromDegrees(coord.y, coord.x).Normalized().ToPoint());
+      }
+    }
+
+    std::unique_ptr<Geography> build() {
+      return absl::make_unique<PointGeography>(std::move(this->points));
+    }
+
+    private:
+      std::vector<S2Point> points;
+  };
+
+private:
+  std::vector<S2Point> points;
+};
+
+#endif
diff --git a/src/polygon-geography.h b/src/polygon-geography.h
new file mode 100644 (file)
index 0000000..db28771
--- /dev/null
@@ -0,0 +1,334 @@
+
+#ifndef POLYGON_GEOGRAPHY_H
+#define POLYGON_GEOGRAPHY_H
+
+#include "wk/reader.hpp"
+
+#include "geography.h"
+#include "point-geography.h"
+#include "polyline-geography.h"
+
+// This class handles polygons (POLYGON and MULTIPOLYGON)
+// This is similar to an S2PolygonLayer
+class PolygonGeography: public Geography {
+public:
+  PolygonGeography() {}
+  PolygonGeography(std::unique_ptr<S2Polygon> polygon):
+    polygon(std::move(polygon)) {}
+
+  Geography::Type GeographyType() {
+    return Geography::Type::GEOGRAPHY_POLYGON;
+  }
+
+  bool FindValidationError(S2Error* error) {
+    return this->polygon->FindValidationError(error);
+  }
+
+  const S2Polygon* Polygon() {
+    return this->polygon.get();
+  }
+
+  bool IsCollection() {
+    return this->outerLoopIndices().size() > 1;
+  }
+
+  int Dimension() {
+    return 2;
+  }
+
+  int NumPoints() {
+    return this->polygon->num_vertices();
+  }
+
+  bool IsEmpty() {
+    return this->polygon->is_empty();
+  }
+
+  double Area() {
+    return this->polygon->GetArea();
+  }
+
+  double Length() {
+    return 0;
+  }
+
+  double Perimeter() {
+    std::unique_ptr<Geography> boundary = this->Boundary();
+    return boundary->Length();
+  }
+
+  double X() {
+    Rcpp::stop("Can't compute X value of a non-point geography");
+  }
+
+  double Y() {
+    Rcpp::stop("Can't compute Y value of a non-point geography");
+  }
+
+  S2Point Centroid() {
+    return this->polygon->GetCentroid();
+  }
+
+  S2Cap GetCapBound() {
+         return this->polygon->GetCapBound();
+  }
+
+  S2LatLngRect GetRectBound() {
+         return this->polygon->GetRectBound();
+  }
+
+  std::unique_ptr<Geography> Boundary() {
+    PolylineGeography::Builder builder;
+    std::vector<std::vector<int>> flatIndices = this->flatLoopIndices();
+
+    // export multilinestring
+    WKGeometryMeta meta(WKGeometryType::MultiLineString, false, false, false);
+    meta.hasSize = true;
+    meta.size = this->polygon->num_loops();
+
+    builder.nextGeometryStart(meta, WKReader::PART_ID_NONE);
+    int loopId = 0;
+    for (size_t i = 0; i < flatIndices.size(); i++) {
+      this->exportLoops(&builder, meta, flatIndices[i], loopId);
+      loopId += flatIndices[i].size();
+    }
+    builder.nextGeometryEnd(meta, WKReader::PART_ID_NONE);
+
+    return builder.build();
+  }
+
+  std::vector<int> BuildShapeIndex(MutableS2ShapeIndex* index) {
+    std::vector<int> shapeIds(1);
+    std::unique_ptr<S2Polygon::Shape> shape = absl::make_unique<S2Polygon::Shape>();
+    shape->Init(this->polygon.get());
+    shapeIds[0] = index->Add(std::move(shape));
+    return shapeIds;
+  }
+
+  void Export(WKGeometryHandler* handler, uint32_t partId) {
+    std::vector<std::vector<int>> flatIndices = this->flatLoopIndices();
+
+    if (flatIndices.size() > 1) {
+      // export multipolygon
+      WKGeometryMeta meta(WKGeometryType::MultiPolygon, false, false, false);
+      meta.hasSize = true;
+      meta.size = flatIndices.size();
+
+      WKGeometryMeta childMeta(WKGeometryType::Polygon, false, false, false);
+      childMeta.hasSize = true;
+
+      handler->nextGeometryStart(meta, partId);
+      for (size_t i = 0; i < flatIndices.size(); i++) {
+        childMeta.size = flatIndices[i].size();
+        handler->nextGeometryStart(childMeta, i);
+        this->exportLoops(handler, childMeta, flatIndices[i]);
+        handler->nextGeometryEnd(childMeta, i);
+      }
+
+      handler->nextGeometryEnd(meta, partId);
+
+    } else if (flatIndices.size() > 0) {
+      // export polygon
+      WKGeometryMeta meta(WKGeometryType::Polygon, false, false, false);
+      meta.hasSize = true;
+      meta.size = flatIndices[0].size();
+      handler->nextGeometryStart(meta, partId);
+      this->exportLoops(handler, meta, flatIndices[0]);
+      handler->nextGeometryEnd(meta, partId);
+
+    } else {
+      // export empty polygon
+      WKGeometryMeta meta(WKGeometryType::Polygon, false, false, false);
+      meta.hasSize = true;
+      meta.size = 0;
+      handler->nextGeometryStart(meta, partId);
+      handler->nextGeometryEnd(meta, partId);
+    }
+  }
+
+  class Builder: public GeographyBuilder {
+  public:
+    Builder(bool oriented, bool check):
+      oriented(oriented), check(check) {}
+
+    void nextLinearRingStart(const WKGeometryMeta& meta, uint32_t size, uint32_t ringId) {
+      // skip the last vertex (WKB rings are theoretically closed)
+      if (size > 0) {
+        this->vertices = std::vector<S2Point>(size - 1);
+      } else {
+        this->vertices = std::vector<S2Point>();
+      }
+    }
+
+    void nextCoordinate(const WKGeometryMeta& meta, const WKCoord& coord, uint32_t coordId) {
+      if (coordId < this->vertices.size()) {
+        vertices[coordId] = S2LatLng::FromDegrees(coord.y, coord.x).Normalized().ToPoint();
+      }
+    }
+
+    void nextLinearRingEnd(const WKGeometryMeta& meta, uint32_t size, uint32_t ringId) {
+      std::unique_ptr<S2Loop> loop = absl::make_unique<S2Loop>();
+      loop->set_s2debug_override(S2Debug::DISABLE);
+      loop->Init(vertices);
+
+      if (!oriented) {
+        loop->Normalize();
+      }
+
+      if (this->check && !loop->IsValid()) {
+        std::stringstream err;
+        err << "Loop " << (this->loops.size()) << " is not valid: ";
+        S2Error error;
+        loop->FindValidationError(&error);
+        err << error.text();
+        throw WKParseException(err.str());
+      }
+
+      this->loops.push_back(std::move(loop));
+    }
+
+    std::unique_ptr<Geography> build() {
+      std::unique_ptr<S2Polygon> polygon = absl::make_unique<S2Polygon>();
+      polygon->set_s2debug_override(S2Debug::DISABLE);
+      if (this->loops.size() > 0 && oriented) {
+        polygon->InitOriented(std::move(this->loops));
+      } else if (this->loops.size() > 0) {
+        polygon->InitNested(std::move(this->loops));
+      }
+
+      // make sure polygon is valid
+      if (this->check && !polygon->IsValid()) {
+        S2Error error;
+        polygon->FindValidationError(&error);
+        throw WKParseException(error.text());
+      }
+
+      return absl::make_unique<PolygonGeography>(std::move(polygon));
+    }
+
+  private:
+    bool oriented;
+    bool check;
+    std::vector<S2Point> vertices;
+    std::vector<std::unique_ptr<S2Loop>> loops;
+  };
+
+private:
+  std::unique_ptr<S2Polygon> polygon;
+
+  // Calculate which loops in the polygon are outer loops (loop->depth() == 0)
+  std::vector<int> outerLoopIndices() {
+    std::vector<int> indices;
+    for (int i = 0; i < this->polygon->num_loops(); i++) {
+      if (this->polygon->loop(i)->depth() == 0) {
+        indices.push_back(i);
+      }
+    }
+
+    return indices;
+  }
+
+  // Calculate the arrangement of loops in the form of a multipolygon
+  // (list(list(shell, !!! holes)))
+  std::vector<std::vector<int>> flatLoopIndices() {
+    std::vector<int> outerLoops = this->outerLoopIndices();
+
+    std::vector<std::vector<int>> flatIndices(outerLoops.size());
+    for (size_t i = 0; i < outerLoops.size(); i++) {
+      int k = outerLoops[i];
+      flatIndices[i] = std::vector<int>();
+
+      // the first loop here is the shell (depth == 0)
+      flatIndices[i].push_back(k);
+
+      // loops in the S2Polygon are arranged such that child loops are
+      // directly after the outer loop, so add all loop indices before
+      // the next parent loop (or end of polygon). This is similar to
+      // S2Polygon::GetLastDescendant() but is slightly easier to understand.
+      while (++k < this->polygon->num_loops() && this->polygon->loop(k)->depth() > 0) {
+        flatIndices[i].push_back(k);
+      }
+    }
+
+    return flatIndices;
+  }
+
+  void exportLoops(WKGeometryHandler* handler, WKGeometryMeta meta,
+                   const std::vector<int>& loopIndices, int loopIdOffset = 0) {
+    S2LatLng point;
+
+    for (size_t i = 0; i < loopIndices.size(); i++) {
+      int loopId = loopIndices[i];
+      S2Loop* loop = this->polygon->loop(loopId);
+      if (loop->num_vertices() == 0) {
+        continue;
+      }
+
+      // this is a slightly ugly way to make it possible to export either the
+      // boundaries or the loops using the same code
+      WKGeometryMeta childMeta(WKGeometryType::LineString, false, false, false);
+      childMeta.hasSize = true;
+      childMeta.size = loop->num_vertices() + 1;
+
+      WKGeometryMeta coordMeta;
+
+      if (meta.geometryType == WKGeometryType::Polygon) {
+        handler->nextLinearRingStart(meta, loop->num_vertices() + 1, i + loopIdOffset);
+        coordMeta = meta;
+      } else if (meta.geometryType == WKGeometryType::MultiLineString) {
+        handler->nextGeometryStart(childMeta, i + loopIdOffset);
+        coordMeta = childMeta;
+      } else {
+        std::stringstream err;
+        err << "Can't export S2Loop with parent geometry type " << meta.geometryType;
+        Rcpp::stop(err.str());
+      }
+
+      if ((loop->depth() % 2) == 0) {
+        // if this is the first ring, use the internal vertex order
+        for (int j = 0; j < loop->num_vertices(); j++) {
+          point = S2LatLng(loop->vertex(j));
+          handler->nextCoordinate(
+            coordMeta,
+            WKCoord::xy(point.lng().degrees(), point.lat().degrees()),
+            j
+          );
+        }
+
+        // close the loop!
+        point = S2LatLng(loop->vertex(0));
+        handler->nextCoordinate(
+          coordMeta,
+          WKCoord::xy(point.lng().degrees(), point.lat().degrees()),
+          loop->num_vertices()
+        );
+      } else {
+        // if an interior ring, reverse the vertex order
+        for (int j = 0; j < loop->num_vertices(); j++) {
+          point = S2LatLng(loop->vertex(loop->num_vertices() - 1 - j));
+          handler->nextCoordinate(
+            coordMeta,
+            WKCoord::xy(point.lng().degrees(), point.lat().degrees()),
+            j
+          );
+        }
+
+        // close the loop!
+        point = S2LatLng(loop->vertex(loop->num_vertices() - 1));
+        handler->nextCoordinate(
+          coordMeta,
+          WKCoord::xy(point.lng().degrees(), point.lat().degrees()),
+          loop->num_vertices()
+        );
+      }
+
+      if (meta.geometryType == WKGeometryType::Polygon) {
+        handler->nextLinearRingEnd(meta, loop->num_vertices() + 1, i + loopIdOffset);
+      } else if (meta.geometryType == WKGeometryType::MultiLineString) {
+        handler->nextGeometryEnd(childMeta, i + loopIdOffset);
+      }
+    }
+  }
+};
+
+#endif
diff --git a/src/polyline-geography.h b/src/polyline-geography.h
new file mode 100644 (file)
index 0000000..32ffef1
--- /dev/null
@@ -0,0 +1,215 @@
+
+#ifndef POLYLINE_GEOGRAPHY_H
+#define POLYLINE_GEOGRAPHY_H
+
+#include "s2/s2latlng_rect.h"
+
+#include "geography.h"
+
+// This class handles (vectors of) polylines (LINESTRING and MULTILINESTRING)
+// This is similar to an S2PolylineVectorLayer
+class PolylineGeography: public Geography {
+public:
+  PolylineGeography(): polylines(0) {}
+  PolylineGeography(std::vector<std::unique_ptr<S2Polyline>> polylines):
+    polylines(std::move(polylines)) {}
+
+  Geography::Type GeographyType() {
+    return Geography::Type::GEOGRAPHY_POLYLINE;
+  }
+
+  bool FindValidationError(S2Error* error) {
+    bool result;
+    error->Clear();
+    for (size_t i = 0; i < this->polylines.size(); i++) {
+      result = this->polylines[i]->FindValidationError(error);
+      if (result) {
+        return result;
+      }
+    }
+
+    return false;
+  }
+
+  const std::vector<std::unique_ptr<S2Polyline>>* Polyline() {
+    return &(this->polylines);
+  }
+
+  bool IsCollection() {
+    return this->polylines.size() > 1;
+  }
+
+  int Dimension() {
+    return 1;
+  }
+
+  int NumPoints() {
+    int numPoints = 0;
+    for (size_t i = 0; i < this->polylines.size(); i++) {
+      numPoints += this->polylines[i]->num_vertices();
+    }
+
+    return numPoints;
+  }
+
+  bool IsEmpty() {
+    for (size_t i = 0; i < this->polylines.size(); i++) {
+      if (this->polylines[i]->num_vertices() > 0) {
+        return false;
+      }
+    }
+
+    return true;
+  }
+
+  double Area() {
+    return 0;
+  }
+
+  double Length() {
+    double length  = 0;
+    for (size_t i = 0; i < this->polylines.size(); i++) {
+      length += this->polylines[i]->GetLength().radians();
+    }
+
+    return length;
+  }
+
+  double Perimeter() {
+    return 0;
+  }
+
+  double X() {
+    Rcpp::stop("Can't compute X value of a non-point geography");
+  }
+
+  double Y() {
+    Rcpp::stop("Can't compute Y value of a non-point geography");
+  }
+
+  S2Point Centroid() {
+    S2Point output(0, 0, 0);
+    for (size_t i = 0; i < this->polylines.size(); i++) {
+      output += this->polylines[i]->GetCentroid();
+    }
+
+    return output;
+  }
+
+  S2LatLngRect GetRectBound() {
+       S2LatLngRect rect; 
+       if (this->polylines.size())
+               rect = this->polylines[0]->GetRectBound();
+    for (size_t i = 1; i < this->polylines.size(); i++) {
+        rect.Union(this->polylines[i]->GetRectBound()); // depends on order
+    }
+       return rect;
+  }
+
+  std::unique_ptr<Geography> Boundary() {
+    std::vector<S2Point> endpoints;
+    for (size_t i = 0; i < this->polylines.size(); i++) {
+      if (this->polylines[i]->num_vertices() >= 2) {
+        endpoints.push_back(this->polylines[i]->vertex(0));
+        endpoints.push_back(this->polylines[i]->vertex(1));
+      }
+    }
+
+    return absl::make_unique<PointGeography>(endpoints);
+  }
+
+  std::vector<int> BuildShapeIndex(MutableS2ShapeIndex* index) {
+    std::vector<int> shapeIds(this->polylines.size());
+    for (size_t i = 0; i < this->polylines.size(); i++) {
+      std::unique_ptr<S2Polyline::Shape> shape = absl::make_unique<S2Polyline::Shape>();
+      shape->Init(this->polylines[i].get());
+      shapeIds[i] = index->Add(std::move(shape));
+    }
+    return shapeIds;
+  }
+
+  void Export(WKGeometryHandler* handler, uint32_t partId) {
+    S2LatLng point;
+
+    if (this->polylines.size() > 1) {
+      // export multilinestring
+      WKGeometryMeta meta(WKGeometryType::MultiLineString, false, false, false);
+      meta.hasSize = true;
+      meta.size = this->polylines.size();
+
+      handler->nextGeometryStart(meta, partId);
+
+      for (size_t i = 0; i < this->polylines.size(); i++) {
+        WKGeometryMeta childMeta(WKGeometryType::LineString, false, false, false);
+        childMeta.hasSize = true;
+        childMeta.size = this->polylines[i]->num_vertices();
+
+        handler->nextGeometryStart(childMeta, i);
+
+        for (size_t j = 0; j < childMeta.size; j++) {
+          point = S2LatLng(this->polylines[i]->vertex(j));
+          handler->nextCoordinate(meta, WKCoord::xy(point.lng().degrees(), point.lat().degrees()), j);
+        }
+
+        handler->nextGeometryEnd(childMeta, i);
+      }
+
+      handler->nextGeometryEnd(meta, partId);
+
+    } else if (this->polylines.size() > 0) {
+      // export linestring
+      WKGeometryMeta meta(WKGeometryType::LineString, false, false, false);
+      meta.hasSize = true;
+      meta.size = this->polylines[0]->num_vertices();
+
+      handler->nextGeometryStart(meta, partId);
+
+      for (size_t i = 0; i < meta.size; i++) {
+        point = S2LatLng(this->polylines[0]->vertex(i));
+        handler->nextCoordinate(meta, WKCoord::xy(point.lng().degrees(), point.lat().degrees()), i);
+      }
+
+      handler->nextGeometryEnd(meta, partId);
+
+    } else {
+      // export empty linestring
+      WKGeometryMeta meta(WKGeometryType::LineString, false, false, false);
+      meta.hasSize = true;
+      meta.size = this->polylines[0]->num_vertices();
+      handler->nextGeometryStart(meta, partId);
+      handler->nextGeometryEnd(meta, partId);
+    }
+  }
+
+  class Builder: public GeographyBuilder {
+  public:
+    void nextGeometryStart(const WKGeometryMeta& meta, uint32_t partId) {
+      if (meta.geometryType == WKGeometryType::LineString) {
+        points = std::vector<S2Point>(meta.size);
+      }
+    }
+
+    void nextCoordinate(const WKGeometryMeta& meta, const WKCoord& coord, uint32_t coordId) {
+      points[coordId] = S2LatLng::FromDegrees(coord.y, coord.x).Normalized().ToPoint();
+    }
+
+    void nextGeometryEnd(const WKGeometryMeta& meta, uint32_t partId) {
+      if (meta.geometryType == WKGeometryType::LineString) {
+        polylines.push_back(absl::make_unique<S2Polyline>(std::move(points)));
+      }
+    }
+
+    std::unique_ptr<Geography> build() {
+      return absl::make_unique<PolylineGeography>(std::move(this->polylines));
+    }
+
+    private:
+      std::vector<S2Point> points;
+      std::vector<std::unique_ptr<S2Polyline>> polylines;
+  };
+
+private:
+  std::vector<std::unique_ptr<S2Polyline>> polylines;
+};
+
+#endif
diff --git a/src/s2-accessors.cpp b/src/s2-accessors.cpp
new file mode 100644 (file)
index 0000000..0cb9d45
--- /dev/null
@@ -0,0 +1,237 @@
+
+#include "geography-operator.h"
+#include "s2/s2closest_edge_query.h"
+#include "s2/s2furthest_edge_query.h"
+#include <Rcpp.h>
+using namespace Rcpp;
+
+// [[Rcpp::export]]
+LogicalVector cpp_s2_is_collection(List geog) {
+  class Op: public UnaryGeographyOperator<LogicalVector, int> {
+    int processFeature(XPtr<Geography> feature, R_xlen_t i) {
+      return feature->IsCollection();
+    }
+  };
+
+  Op op;
+  return op.processVector(geog);
+}
+
+// [[Rcpp::export]]
+LogicalVector cpp_s2_is_valid(List geog) {
+  class Op: public UnaryGeographyOperator<LogicalVector, int> {
+    int processFeature(XPtr<Geography> feature, R_xlen_t i) {
+      return !(feature->FindValidationError(&(this->error)));
+    }
+
+    S2Error error;
+  };
+
+  Op op;
+  return op.processVector(geog);
+}
+
+// [[Rcpp::export]]
+CharacterVector cpp_s2_is_valid_reason(List geog) {
+  class Op: public UnaryGeographyOperator<CharacterVector, String> {
+    String processFeature(XPtr<Geography> feature, R_xlen_t i) {
+      if (feature->FindValidationError(&(this->error))) {
+        return this->error.text();
+      } else {
+        return NA_STRING;
+      }
+    }
+
+    S2Error error;
+  };
+
+  Op op;
+  return op.processVector(geog);
+}
+
+// [[Rcpp::export]]
+IntegerVector cpp_s2_dimension(List geog) {
+  class Op: public UnaryGeographyOperator<IntegerVector, int> {
+    int processFeature(XPtr<Geography> feature, R_xlen_t i) {
+      return feature->Dimension();
+    }
+  };
+
+  Op op;
+  return op.processVector(geog);
+}
+
+// [[Rcpp::export]]
+IntegerVector cpp_s2_num_points(List geog) {
+  class Op: public UnaryGeographyOperator<IntegerVector, int> {
+    int processFeature(XPtr<Geography> feature, R_xlen_t i) {
+      return feature->NumPoints();
+    }
+  };
+
+  Op op;
+  return op.processVector(geog);
+}
+
+// [[Rcpp::export]]
+LogicalVector cpp_s2_is_empty(List geog) {
+  class Op: public UnaryGeographyOperator<LogicalVector, int> {
+    int processFeature(XPtr<Geography> feature, R_xlen_t i) {
+      return feature->IsEmpty();
+    }
+  };
+
+  Op op;
+  return op.processVector(geog);
+}
+
+// [[Rcpp::export]]
+NumericVector cpp_s2_area(List geog) {
+  class Op: public UnaryGeographyOperator<NumericVector, double> {
+    double processFeature(XPtr<Geography> feature, R_xlen_t i) {
+      return feature->Area();
+    }
+  };
+
+  Op op;
+  return op.processVector(geog);
+}
+
+// [[Rcpp::export]]
+NumericVector cpp_s2_length(List geog) {
+  class Op: public UnaryGeographyOperator<NumericVector, double> {
+    double processFeature(XPtr<Geography> feature, R_xlen_t i) {
+      return feature->Length();
+    }
+  };
+
+  Op op;
+  return op.processVector(geog);
+}
+
+// [[Rcpp::export]]
+NumericVector cpp_s2_perimeter(List geog) {
+  class Op: public UnaryGeographyOperator<NumericVector, double> {
+    double processFeature(XPtr<Geography> feature, R_xlen_t i) {
+      return feature->Perimeter();
+    }
+  };
+
+  Op op;
+  return op.processVector(geog);
+}
+
+// [[Rcpp::export]]
+NumericVector cpp_s2_x(List geog) {
+  class Op: public UnaryGeographyOperator<NumericVector, double> {
+    double processFeature(XPtr<Geography> feature, R_xlen_t i) {
+      return feature->X();
+    }
+  };
+
+  Op op;
+  return op.processVector(geog);
+}
+
+// [[Rcpp::export]]
+NumericVector cpp_s2_y(List geog) {
+  class Op: public UnaryGeographyOperator<NumericVector, double> {
+    double processFeature(XPtr<Geography> feature, R_xlen_t i) {
+      return feature->Y();
+    }
+  };
+
+  Op op;
+  return op.processVector(geog);
+}
+
+// [[Rcpp::export]]
+NumericVector cpp_s2_project_normalized(List geog1, List geog2) {
+  class Op: public BinaryGeographyOperator<NumericVector, double> {
+    double processFeature(XPtr<Geography> feature1,
+                          XPtr<Geography> feature2,
+                          R_xlen_t i) {
+      if (feature1->IsCollection() || feature2->IsCollection()) {
+        throw GeographyOperatorException("`x` and `y` must both be simple geographies");
+      }
+
+      if (feature1->IsEmpty() || feature2->IsEmpty()) {
+        return NA_REAL;
+      }
+
+      if (feature1->GeographyType() == Geography::Type::GEOGRAPHY_POLYLINE) {
+        if (feature2->GeographyType() == Geography::Type::GEOGRAPHY_POINT) {
+          S2Point point = feature2->Point()->at(0);
+          int next_vertex;
+          S2Point point_on_line = feature1->Polyline()->at(0)->Project(point, &next_vertex);
+          return feature1->Polyline()->at(0)->UnInterpolate(point_on_line, next_vertex);
+        } else {
+          throw GeographyOperatorException("`y` must be a point geography");
+        }
+      } else {
+        throw GeographyOperatorException("`x` must be a polyline geography");
+      }
+      return NA_REAL;
+    }
+  };
+
+  Op op;
+  return op.processVector(geog1, geog2);
+}
+
+// [[Rcpp::export]]
+NumericVector cpp_s2_distance(List geog1, List geog2) {
+  class Op: public BinaryGeographyOperator<NumericVector, double> {
+
+    double processFeature(XPtr<Geography> feature1,
+                          XPtr<Geography> feature2,
+                          R_xlen_t i) {
+      S2ClosestEdgeQuery query(feature1->ShapeIndex());
+      S2ClosestEdgeQuery::ShapeIndexTarget target(feature2->ShapeIndex());
+
+      const auto& result = query.FindClosestEdge(&target);
+
+      S1ChordAngle angle = result.distance();
+      double distance = angle.ToAngle().radians();
+
+      if (distance == R_PosInf) {
+        return NA_REAL;
+      } else {
+        return distance;
+      }
+    }
+  };
+
+  Op op;
+  return op.processVector(geog1, geog2);
+}
+
+// [[Rcpp::export]]
+NumericVector cpp_s2_max_distance(List geog1, List geog2) {
+  class Op: public BinaryGeographyOperator<NumericVector, double> {
+
+    double processFeature(XPtr<Geography> feature1,
+                          XPtr<Geography> feature2,
+                          R_xlen_t i) {
+      S2FurthestEdgeQuery query(feature1->ShapeIndex());
+      S2FurthestEdgeQuery::ShapeIndexTarget target(feature2->ShapeIndex());
+
+      const auto& result = query.FindFurthestEdge(&target);
+
+      S1ChordAngle angle = result.distance();
+      double distance = angle.ToAngle().radians();
+
+      // returns -1 if one of the indexes is empty
+      // NA is more consistent with the BigQuery
+      // function, and makes way more sense
+      if (distance < 0) {
+        return NA_REAL;
+      } else {
+        return distance;
+      }
+    }
+  };
+
+  Op op;
+  return op.processVector(geog1, geog2);
+}
diff --git a/src/s2-bounds.cpp b/src/s2-bounds.cpp
new file mode 100644 (file)
index 0000000..5e12198
--- /dev/null
@@ -0,0 +1,68 @@
+
+#include "s2/s2latlng_rect.h"
+#include "s2/s2cap.h"
+
+#include "s2-options.h"
+#include "geography-operator.h"
+#include "point-geography.h"
+#include "polyline-geography.h"
+#include "polygon-geography.h"
+#include "geography-collection.h"
+
+#include <Rcpp.h>
+using namespace Rcpp;
+
+// [[Rcpp::export]]
+DataFrame cpp_s2_bounds_cap(List geog) {
+  SEXP item;
+  NumericVector lng(geog.size()), lat(geog.size()), angle(geog.size());
+
+  for (R_xlen_t i = 0; i < geog.size(); i++) {
+    Rcpp::checkUserInterrupt();
+    item = geog[i];
+    if (item == R_NilValue) {
+      lat[i] = lng[i] = angle[i] = NA_REAL;
+    } else {
+      Rcpp::XPtr<Geography> feature(item);
+      S2Cap cap = feature->GetCapBound();
+      S2LatLng center(cap.center());
+      lng[i] = center.lng().degrees();
+      lat[i] = center.lat().degrees();
+      angle[i] = cap.GetRadius().degrees();
+    }
+  }
+
+  return DataFrame::create(
+    _["lng"] = lng,
+    _["lat"] = lat,
+    _["angle"] = angle
+  );
+}
+
+// [[Rcpp::export]]
+DataFrame cpp_s2_bounds_rect(List geog) {
+  SEXP item;
+  NumericVector lng_lo(geog.size()), lat_lo(geog.size()), lng_hi(geog.size()), lat_hi(geog.size());
+
+  for (R_xlen_t i = 0; i < geog.size(); i++) {
+    Rcpp::checkUserInterrupt();
+    item = geog[i];
+    if (item == R_NilValue) {
+      lng_lo[i] = lat_lo[i] = lng_hi[i] = lat_hi[i] = NA_REAL;
+    } else {
+      Rcpp::XPtr<Geography> feature(item);
+      S2LatLngRect rect = feature->GetRectBound();
+      lng_lo[i] = rect.lng_lo().degrees();
+      lat_lo[i] = rect.lat_lo().degrees();
+      lng_hi[i] = rect.lng_hi().degrees();
+      lat_hi[i] = rect.lat_hi().degrees();
+    }
+  }
+
+  return DataFrame::create(
+    _["lng_lo"] = lng_lo,
+    _["lat_lo"] = lat_lo,
+    _["lng_hi"] = lng_hi,
+    _["lat_hi"] = lat_hi
+  );
+}
diff --git a/src/s2-c-api.cpp b/src/s2-c-api.cpp
new file mode 100644 (file)
index 0000000..28d55e8
--- /dev/null
@@ -0,0 +1,170 @@
+
+#include <vector>
+
+#include "s2/s2projections.h"
+#include "s2/s2edge_tessellator.h"
+
+typedef struct s2_projection_t s2_projection_t;
+typedef struct s2_tessellator_t s2_tessellator_t;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+s2_projection_t* s2_projection_create_plate_carree(double scale);
+s2_projection_t* s2_projection_create_mercator(double max_x);
+void s2_projection_destroy(s2_projection_t* projection);
+int s2_projection_project(s2_projection_t* projection, const double* coord_in, double* coord_out);
+int s2_projection_unproject(s2_projection_t* projection, const double* coord_in, double* coord_out);
+
+s2_tessellator_t* s2_tessellator_create(s2_projection_t* projection, double tolerance_radians);
+void s2_tessellator_destroy(s2_tessellator_t* tessellator);
+int s2_tessellator_reset(s2_tessellator_t* tessellator);
+int s2_tessellator_add_r2_point(s2_tessellator_t* tessellator, const double* coord);
+int s2_tessellator_add_s2_point(s2_tessellator_t* tessellator, const double* coord);
+int s2_tessellator_r2_points_size(s2_tessellator_t* tessellator);
+int s2_tessellator_s2_points_size(s2_tessellator_t* tessellator);
+int s2_tessellator_r2_point(s2_tessellator_t* tessellator, int i, double* coord);
+int s2_tessellator_s2_point(s2_tessellator_t* tessellator, int i, double* coord);
+
+#ifdef __cplusplus
+}
+#endif
+
+s2_projection_t* s2_projection_create_plate_carree(double scale) {
+    return (s2_projection_t*) new S2::PlateCarreeProjection(scale);
+}
+
+s2_projection_t* s2_projection_create_mercator(double max_x) {
+    return (s2_projection_t*) new S2::MercatorProjection(max_x);
+}
+
+void s2_projection_destroy(s2_projection_t* projection) {
+    if (projection != nullptr) {
+        delete ((S2::Projection*) projection);
+    }
+}
+
+int s2_projection_project(s2_projection_t* projection, const double* coord_in, double* coord_out) {
+    S2Point p(coord_in[0], coord_in[1], coord_in[2]);
+    R2Point result = ((S2::Projection*) projection)->Project(p);
+    coord_out[0] = result.x();
+    coord_out[1] = result.y();
+    return true;
+}
+
+int s2_projection_unproject(s2_projection_t* projection, const double* coord_in, double* coord_out) {
+    R2Point p(coord_in[0], coord_in[1]);
+    S2Point result = ((S2::Projection*) projection)->Unproject(p);
+    coord_out[0] = result.x();
+    coord_out[1] = result.y();
+    coord_out[2] = result.z();
+    return true;
+}
+
+// Wrapper class around a tessellator that also keeps coordinate buffers
+// and methods to iterate through them.
+class TessellatorWrapper {
+public:
+    TessellatorWrapper(s2_projection_t* projection, double tolerance_radians):
+        tessellator((S2::Projection*) projection, S1Angle::Radians(tolerance_radians)),
+        has_r2_last(false), has_s2_last(false) {}
+    
+    void reset() {
+        s2points.clear();
+        r2points.clear();
+        has_r2_last = false;
+        has_s2_last = false;
+    }
+
+    void add_r2_point(const double* coord) {
+        R2Point pt(coord[0], coord[1]);
+        if (has_r2_last) {
+            this->tessellator.AppendUnprojected(r2last, pt, &(this->s2points));
+        }
+        this->r2last = pt;
+        this->has_r2_last = true;
+    }
+
+    void add_s2_point(const double* coord) {
+        S2Point pt(coord[0], coord[1], coord[2]);
+        if (has_s2_last) {
+            this->tessellator.AppendProjected(s2last, pt, &(this->r2points));
+        }
+        this->s2last = pt;
+        this->has_s2_last = true;
+    }
+
+    int r2_points_size() {
+        return this->r2points.size();
+    }
+
+    void r2_point(int i, double* coord) {
+        const R2Point& pt = r2points[i];
+        coord[0] = pt.x();
+        coord[1] = pt.y();
+    }
+
+    int s2_points_size() {
+        return this->s2points.size();
+    }
+
+    void s2_point(int i, double* coord) {
+        const S2Point& pt = s2points[i];
+        coord[0] = pt.x();
+        coord[1] = pt.y();
+        coord[2] = pt.z();
+    }
+
+private:
+    S2EdgeTessellator tessellator;
+    std::vector<S2Point> s2points;
+    std::vector<R2Point> r2points;
+    R2Point r2last;
+    S2Point s2last;
+    bool has_r2_last;
+    bool has_s2_last;
+};
+
+s2_tessellator_t* s2_tessellator_create(s2_projection_t* projection, double tolerance_radians) {
+    return (s2_tessellator_t*) new TessellatorWrapper(projection, tolerance_radians);
+}
+
+void s2_tessellator_destroy(s2_tessellator_t* tessellator) {
+    if (tessellator != nullptr) {
+        delete ((TessellatorWrapper*) tessellator);
+    }
+}
+
+int s2_tessellator_reset(s2_tessellator_t* tessellator) {
+    ((TessellatorWrapper*) tessellator)->reset();
+    return true;
+}
+
+int s2_tessellator_add_r2_point(s2_tessellator_t* tessellator, const double* coord) {
+    ((TessellatorWrapper*) tessellator)->add_r2_point(coord);
+    return true;
+}
+
+int s2_tessellator_add_s2_point(s2_tessellator_t* tessellator, const double* coord) {
+    ((TessellatorWrapper*) tessellator)->add_s2_point(coord);
+    return true;
+}
+
+int s2_tessellator_r2_points_size(s2_tessellator_t* tessellator) {
+    return ((TessellatorWrapper*) tessellator)->r2_points_size();
+}
+
+int s2_tessellator_s2_points_size(s2_tessellator_t* tessellator) {
+    return ((TessellatorWrapper*) tessellator)->s2_points_size();
+}
+
+int s2_tessellator_r2_point(s2_tessellator_t* tessellator, int i, double* coord) {
+    ((TessellatorWrapper*) tessellator)->r2_point(i, coord);
+    return true;
+}
+
+int s2_tessellator_s2_point(s2_tessellator_t* tessellator, int i, double* coord) {
+    ((TessellatorWrapper*) tessellator)->s2_point(i, coord);
+    return true;
+}
diff --git a/src/s2-cell.cpp b/src/s2-cell.cpp
new file mode 100644 (file)
index 0000000..3d36ace
--- /dev/null
@@ -0,0 +1,744 @@
+
+#include <cstdint>
+#include <vector>
+#include <sstream>
+#include <algorithm>
+#include <set>
+
+#include "s2/s2cell_id.h"
+#include "s2/s2cell.h"
+#include "s2/s2latlng.h"
+
+#include "point-geography.h"
+#include "polyline-geography.h"
+#include "polygon-geography.h"
+
+#include <Rcpp.h>
+using namespace Rcpp;
+
+static inline double reinterpret_double(uint64_t id) {
+  double doppelganger;
+  memcpy(&doppelganger, &id, sizeof(double));
+  return doppelganger;
+}
+
+class S2CellOperatorException: public std::runtime_error {
+public:
+  S2CellOperatorException(std::string msg): std::runtime_error(msg.c_str()) {}
+};
+
+template<class VectorType, class ScalarType>
+class UnaryS2CellOperator {
+public:
+  VectorType processVector(Rcpp::NumericVector cellIdVector) {
+    VectorType output(cellIdVector.size());
+
+    for (R_xlen_t i = 0; i < cellIdVector.size(); i++) {
+      if ((i % 1000) == 0) {
+        Rcpp::checkUserInterrupt();
+      }
+
+      S2CellId cell(*((uint64_t*) &(cellIdVector[i])));
+      output[i] = this->processCell(cell, i);
+    }
+
+    return output;
+  }
+
+  virtual ScalarType processCell(S2CellId cellId, R_xlen_t i) = 0;
+};
+
+// For speed, take care of recycling here (only works if there is no
+// additional parameter). Most binary ops don't have a parameter and some
+// (like Ops, and Math) make recycling harder to incorporate at the R level
+template<class VectorType, class ScalarType>
+class BinaryS2CellOperator {
+public:
+  VectorType processVector(Rcpp::NumericVector cellIdVector1,
+                           Rcpp::NumericVector cellIdVector2) {
+
+    if (cellIdVector1.size() == cellIdVector2.size()) {
+      VectorType output(cellIdVector1.size());
+
+      for (R_xlen_t i = 0; i < cellIdVector1.size(); i++) {
+        if ((i % 1000) == 0) {
+          Rcpp::checkUserInterrupt();
+        }
+
+        S2CellId cell1(*((uint64_t*) &(cellIdVector1[i])));
+        S2CellId cell2(*((uint64_t*) &(cellIdVector2[i])));
+        output[i] = this->processCell(cell1, cell2, i);
+      }
+
+      return output;
+    } else if (cellIdVector1.size() == 1) {
+      VectorType output(cellIdVector2.size());
+
+      for (R_xlen_t i = 0; i < cellIdVector2.size(); i++) {
+        if ((i % 1000) == 0) {
+          Rcpp::checkUserInterrupt();
+        }
+
+        S2CellId cell1(*((uint64_t*) &(cellIdVector1[0])));
+        S2CellId cell2(*((uint64_t*) &(cellIdVector2[i])));
+        output[i] = this->processCell(cell1, cell2, i);
+      }
+
+      return output;
+    } else if (cellIdVector2.size() == 1) {
+      VectorType output(cellIdVector1.size());
+
+      for (R_xlen_t i = 0; i < cellIdVector1.size(); i++) {
+        if ((i % 1000) == 0) {
+          Rcpp::checkUserInterrupt();
+        }
+
+        S2CellId cell1(*((uint64_t*) &(cellIdVector1[i])));
+        S2CellId cell2(*((uint64_t*) &(cellIdVector2[0])));
+        output[i] = this->processCell(cell1, cell2, i);
+      }
+
+      return output;
+    } else {
+      std::stringstream err;
+      err << 
+        "Can't recycle vectors of size " << cellIdVector1.size() << 
+        " and " << cellIdVector2.size() <<
+        " to a common length.";
+      stop(err.str());
+    }
+  }
+
+  virtual ScalarType processCell(S2CellId cellId1, S2CellId cellId2, R_xlen_t i) = 0;
+};
+
+// [[Rcpp::export]]
+NumericVector cpp_s2_cell_sentinel() {
+  NumericVector result = NumericVector::create(reinterpret_double(S2CellId::Sentinel().id()));
+  result.attr("class") = CharacterVector::create("s2_cell", "wk_vctr");
+  return result;
+}
+
+// [[Rcpp::export]]
+NumericVector cpp_s2_cell_from_string(CharacterVector cellString) {
+  R_xlen_t size = cellString.size();
+  NumericVector cellId(size);
+  double* ptrDouble = REAL(cellId);
+  uint64_t* ptrCellId = (uint64_t*) ptrDouble;
+
+  for (R_xlen_t i = 0; i < size; i++) {
+    if ((i % 1000) == 0) {
+      Rcpp::checkUserInterrupt();
+    }
+
+    if (CharacterVector::is_na(cellString[i])) {
+      ptrDouble[i] = NA_REAL;
+    } else {
+      ptrCellId[i] = S2CellId::FromToken(as<std::string>(cellString[i])).id();
+    }
+  }
+  
+  cellId.attr("class") = CharacterVector::create("s2_cell", "wk_vctr");
+  return cellId;
+}
+
+// [[Rcpp::export]]
+NumericVector cpp_s2_cell_from_lnglat(List lnglat) {
+    NumericVector lng = lnglat[0];
+    NumericVector lat = lnglat[1];
+    R_xlen_t size = lng.size();
+    NumericVector cellId(size);
+    double* ptrDouble = REAL(cellId);
+    uint64_t* ptrCellId = (uint64_t*) ptrDouble;
+
+    for (R_xlen_t i = 0; i < size; i++) {
+      if ((i % 1000) == 0) {
+        Rcpp::checkUserInterrupt();
+      }
+
+      if (R_IsNA(lng[i]) || R_IsNA(lat[i])) {
+          ptrDouble[i] = NA_REAL;
+      } else {
+          S2LatLng ll = S2LatLng::FromDegrees(lat[i], lng[i]).Normalized();
+          ptrCellId[i] = S2CellId(ll).id();
+      }
+    }
+
+    cellId.attr("class") = CharacterVector::create("s2_cell", "wk_vctr");
+    return cellId;
+}
+
+// [[Rcpp::export]]
+List cpp_s2_cell_to_lnglat(NumericVector cellId) {
+    R_xlen_t size = cellId.size();
+    double* ptrDouble = REAL(cellId);
+    uint64_t* ptrCellId = (uint64_t*) ptrDouble;
+
+    NumericVector lng(size);
+    NumericVector lat(size);
+
+    for (R_xlen_t i = 0; i < size; i++) {
+      if ((i % 1000) == 0) {
+        Rcpp::checkUserInterrupt();
+      }
+
+      if (R_IsNA(ptrDouble[i])) {
+          lng[i] = NA_REAL;
+          lat[i] = NA_REAL;
+      } else {
+          S2CellId cell(ptrCellId[i]);
+          if (!cell.is_valid()) {
+            lng[i] = NA_REAL;
+            lat[i] = NA_REAL;
+          } else {
+            S2LatLng ll = S2CellId(ptrCellId[i]).ToLatLng();
+            lng[i] = ll.lng().degrees();
+            lat[i] = ll.lat().degrees();
+          }
+      }
+    }
+
+    return List::create(_["x"] = lng, _["y"] = lat);
+}
+
+// [[Rcpp::export]]
+LogicalVector cpp_s2_cell_is_na(NumericVector cellIdVector) {
+  LogicalVector out(cellIdVector.size());
+  for (R_xlen_t i = 0; i < cellIdVector.size(); i++) {
+    out = R_IsNA(cellIdVector[i]);
+  }
+  return out;
+}
+
+// [[Rcpp::export]]
+NumericVector cpp_s2_cell_sort(NumericVector cellIdVector, bool decreasing) {
+  NumericVector out = clone(cellIdVector);
+  uint64_t* data = (uint64_t*) REAL(out);
+
+  if (decreasing) {
+    std::sort(data, data + out.size(), std::greater<uint64_t>());
+  } else {
+    std::sort(data, data + out.size());
+  }
+
+  out.attr("class") = CharacterVector::create("s2_cell", "wk_vctr");
+  return out;
+}
+
+// [[Rcpp::export]]
+NumericVector cpp_s2_cell_range(NumericVector cellIdVector, bool naRm) {
+  uint64_t* data = (uint64_t*) REAL(cellIdVector);
+  uint64_t zero = 0;
+  uint64_t big = ~zero;
+  auto dataRange = std::pair<uint64_t, uint64_t>(big, zero);
+  // without NA handling this is just
+  // dataRange = std::minmax_element(data, data + cellIdVector.size());
+
+  for (R_xlen_t i = 0; i < cellIdVector.size(); i++) {
+    if (R_IsNA(cellIdVector[i]) && !naRm) {
+      dataRange.first = data[i];
+      dataRange.second = data[i];
+      break;
+    }
+    
+    if (!R_IsNA(cellIdVector[i]) && (data[i] < dataRange.first)) {
+      dataRange.first = data[i];
+    }
+    
+    if (!R_IsNA(cellIdVector[i]) && (data[i] > dataRange.second)) {
+      dataRange.second = data[i];
+    }
+  }
+
+  if (dataRange.first > dataRange.second) {
+    NumericVector out = NumericVector::create(NA_REAL, NA_REAL);
+    out.attr("class") = CharacterVector::create("s2_cell", "wk_vctr");
+    return out;
+  } else {
+    NumericVector out = NumericVector::create(
+      reinterpret_double(dataRange.first),
+      reinterpret_double(dataRange.second)
+    );
+    out.attr("class") = CharacterVector::create("s2_cell", "wk_vctr");
+    return out;
+  }
+}
+
+// [[Rcpp::export]]
+NumericVector cpp_s2_cell_unique(NumericVector cellIdVector) {
+  std::set<uint64_t> uniqueValues;
+  uint64_t value;
+  for (R_xlen_t i = 0; i < cellIdVector.size(); i++) {
+    memcpy(&value, &(cellIdVector[i]), sizeof(uint64_t));
+    uniqueValues.insert(value);
+  }
+
+  NumericVector out(uniqueValues.size());
+  R_xlen_t i = 0;
+  for (uint64_t value : uniqueValues) {
+    out[i++] = reinterpret_double(value);
+  }
+
+  out.attr("class") = CharacterVector::create("s2_cell", "wk_vctr");
+  return out;
+}
+
+// [[Rcpp::export]]
+CharacterVector cpp_s2_cell_to_string(NumericVector cellIdVector) {
+  class Op: public UnaryS2CellOperator<CharacterVector, String> {
+    String processCell(S2CellId cellId, R_xlen_t i) {
+      if (R_IsNA(reinterpret_double(cellId.id()))) {
+        return NA_STRING;
+      } else {
+        return cellId.ToToken();
+      }
+    }
+  };
+
+  Op op;
+  return op.processVector(cellIdVector);
+}
+
+// [[Rcpp::export]]
+CharacterVector cpp_s2_cell_debug_string(NumericVector cellIdVector) {
+  class Op: public UnaryS2CellOperator<CharacterVector, String> {
+    String processCell(S2CellId cellId, R_xlen_t i) {
+      if (R_IsNA(reinterpret_double(cellId.id()))) {
+        return NA_STRING;
+      } else {
+        return cellId.ToString();
+      }
+    }
+  };
+
+  Op op;
+  return op.processVector(cellIdVector);
+}
+
+// [[Rcpp::export]]
+LogicalVector cpp_s2_cell_is_valid(NumericVector cellIdVector) {
+  class Op: public UnaryS2CellOperator<LogicalVector, int> {
+    int processCell(S2CellId cellId, R_xlen_t i) {
+      return cellId.is_valid();
+    }
+  };
+
+  Op op;
+  return op.processVector(cellIdVector);
+}
+
+// [[Rcpp::export]]
+List cpp_s2_cell_center(NumericVector cellIdVector) {
+  class Op: public UnaryS2CellOperator<List, SEXP> {
+    SEXP processCell(S2CellId cellId, R_xlen_t i) {
+      if (cellId.is_valid()) {
+        return XPtr<PointGeography>(new PointGeography(cellId.ToPoint()));
+      } else {
+        return R_NilValue;
+      }
+    }
+  };
+
+  Op op;
+  List result = op.processVector(cellIdVector);
+  result.attr("class") = CharacterVector::create("s2_geography", "s2_xptr");
+  return result;
+}
+
+// [[Rcpp::export]]
+List cpp_s2_cell_polygon(NumericVector cellIdVector) {
+  class Op: public UnaryS2CellOperator<List, SEXP> {
+    SEXP processCell(S2CellId cellId, R_xlen_t i) {
+      if (cellId.is_valid()) {
+        return XPtr<PolygonGeography>(new PolygonGeography(absl::make_unique<S2Polygon>(S2Cell(cellId))));
+      } else {
+        return R_NilValue;
+      }
+    }
+  };
+
+  Op op;
+  List result = op.processVector(cellIdVector);
+  result.attr("class") = CharacterVector::create("s2_geography", "s2_xptr");
+  return result;
+}
+
+// [[Rcpp::export]]
+List cpp_s2_cell_vertex(NumericVector cellIdVector, IntegerVector k) {
+  class Op: public UnaryS2CellOperator<List, SEXP> {
+    SEXP processCell(S2CellId cellId, R_xlen_t i) {
+      if (cellId.is_valid() && (this->k[i] >= 0)) {
+        return XPtr<PointGeography>(new PointGeography(S2Cell(cellId).GetVertex(this->k[i])));
+      } else {
+        return R_NilValue;
+      }
+    }
+
+  public:
+    IntegerVector k;
+  };
+
+  Op op;
+  op.k = k;
+  List result = op.processVector(cellIdVector);
+  result.attr("class") = CharacterVector::create("s2_geography", "s2_xptr");
+  return result;
+}
+
+// [[Rcpp::export]]
+IntegerVector cpp_s2_cell_level(NumericVector cellIdVector) {
+  class Op: public UnaryS2CellOperator<IntegerVector, int> {
+    int processCell(S2CellId cellId, R_xlen_t i) {
+      if (cellId.is_valid()) {
+        return cellId.level();
+      } else {
+        return NA_INTEGER;
+      }
+    }
+  };
+
+  Op op;
+  return op.processVector(cellIdVector);
+}
+
+// [[Rcpp::export]]
+NumericVector cpp_s2_cell_area(NumericVector cellIdVector) {
+  class Op: public UnaryS2CellOperator<NumericVector, double> {
+    double processCell(S2CellId cellId, R_xlen_t i) {
+      if (cellId.is_valid()) {
+        return S2Cell(cellId).ExactArea();
+      } else {
+        return NA_REAL;
+      }
+    }
+  };
+
+  Op op;
+  return op.processVector(cellIdVector);
+}
+
+// [[Rcpp::export]]
+NumericVector cpp_s2_cell_area_approx(NumericVector cellIdVector) {
+  class Op: public UnaryS2CellOperator<NumericVector, double> {
+    double processCell(S2CellId cellId, R_xlen_t i) {
+      if (cellId.is_valid()) {
+        return S2Cell(cellId).ApproxArea();
+      } else {
+        return NA_REAL;
+      }
+    }
+  };
+
+  Op op;
+  return op.processVector(cellIdVector);
+}
+
+// [[Rcpp::export]]
+NumericVector cpp_s2_cell_parent(NumericVector cellIdVector, IntegerVector level) {
+  class Op: public UnaryS2CellOperator<NumericVector, double> {
+    double processCell(S2CellId cellId, R_xlen_t i) {
+      int leveli = this->level[i];
+
+      // allow negative numbers to relate to current level
+      if (leveli < 0) {
+        leveli = cellId.level() + leveli;
+      }
+
+      if (cellId.is_valid() && (leveli >= 0) && (leveli <= cellId.level())) {
+        return reinterpret_double(cellId.parent(leveli).id());
+      } else {
+        return NA_REAL;
+      }
+    }
+
+  public:
+    IntegerVector level;
+  };
+
+  Op op;
+  op.level = level;
+  NumericVector result = op.processVector(cellIdVector);
+  result.attr("class") = CharacterVector::create("s2_cell", "wk_vctr");
+  return result;
+}
+
+// [[Rcpp::export]]
+NumericVector cpp_s2_cell_child(NumericVector cellIdVector, IntegerVector k) {
+  class Op: public UnaryS2CellOperator<NumericVector, double> {
+    double processCell(S2CellId cellId, R_xlen_t i) {
+      int ki = this->k[i];
+      if (cellId.is_valid() && (ki >=0) && (ki <= 3)) {
+        return reinterpret_double(cellId.child(ki).id());
+      } else {
+        return NA_REAL;
+      }
+    }
+
+  public:
+    IntegerVector k;
+  };
+
+  Op op;
+  op.k = k;
+  NumericVector result = op.processVector(cellIdVector);
+  result.attr("class") = CharacterVector::create("s2_cell", "wk_vctr");
+  return result;
+}
+
+// [[Rcpp::export]]
+NumericVector cpp_s2_cell_edge_neighbour(NumericVector cellIdVector, IntegerVector k) {
+  class Op: public UnaryS2CellOperator<NumericVector, double> {
+    double processCell(S2CellId cellId, R_xlen_t i) {
+      int ki = this->k[i];
+      if (cellId.is_valid() && (ki >=0) && (ki <= 3)) {
+        S2CellId neighbours[4];
+        cellId.GetEdgeNeighbors(neighbours);
+        return reinterpret_double(neighbours[ki].id());
+      } else {
+        return NA_REAL;
+      }
+    }
+
+  public:
+    IntegerVector k;
+  };
+
+  Op op;
+  op.k = k;
+  NumericVector result = op.processVector(cellIdVector);
+  result.attr("class") = CharacterVector::create("s2_cell", "wk_vctr");
+  return result;
+}
+
+// Ops for Ops, Math, Summary generics
+
+// [[Rcpp::export]]
+NumericVector cpp_s2_cell_cummax(NumericVector cellIdVector) {
+  class Op: public UnaryS2CellOperator<NumericVector, double> {
+  public:
+    Op(): current(reinterpret_double(0)), currentId(0) {}
+
+    double processCell(S2CellId cellId, R_xlen_t i) {
+      double doubleVal = reinterpret_double(cellId.id());
+      if (R_IsNA(this->current) || R_IsNA(doubleVal)) {
+        this->current = NA_REAL;
+        this->currentId = cellId.id();
+        return NA_REAL;
+      } else if (cellId.id() > this->currentId) {
+        this->currentId = cellId.id();
+        this->current = doubleVal;
+        return doubleVal;
+      } else {
+        return this->current;
+      }
+    }
+
+    double current;
+    uint64_t currentId;
+  };
+
+  Op op;
+  NumericVector result = op.processVector(cellIdVector);
+  result.attr("class") = CharacterVector::create("s2_cell", "wk_vctr");
+  return result;
+}
+
+// [[Rcpp::export]]
+NumericVector cpp_s2_cell_cummin(NumericVector cellIdVector) {
+  class Op: public UnaryS2CellOperator<NumericVector, double> {
+  public:
+    Op(): current(reinterpret_double(UINT64_MAX)), currentId(UINT64_MAX) {}
+
+    double processCell(S2CellId cellId, R_xlen_t i) {
+      double doubleVal = reinterpret_double(cellId.id());
+      if (R_IsNA(this->current) || R_IsNA(doubleVal)) {
+        this->current = NA_REAL;
+        this->currentId = cellId.id();
+        return NA_REAL;
+      } else if (cellId.id() < this->currentId) {
+        this->currentId = cellId.id();
+        this->current = doubleVal;
+        return doubleVal;
+      } else {
+        return this->current;
+      }
+    }
+
+    double current;
+    uint64_t currentId;
+  };
+
+  Op op;
+  NumericVector result = op.processVector(cellIdVector);
+  result.attr("class") = CharacterVector::create("s2_cell", "wk_vctr");
+  return result;
+}
+
+// These are unique in that invalid cells (e.g., Sentinel)
+// should not return NA; but NA_real_ should
+
+// [[Rcpp::export]]
+LogicalVector cpp_s2_cell_eq(NumericVector cellIdVector1, NumericVector cellIdVector2) {
+  class Op: public BinaryS2CellOperator<LogicalVector, int> {
+    int processCell(S2CellId cellId1, S2CellId cellId2, R_xlen_t i) {
+      if (R_IsNA(reinterpret_double(cellId1.id())) || 
+            R_IsNA(reinterpret_double(cellId2.id()))) {
+        return NA_LOGICAL;
+      } else {
+        return cellId1.id() == cellId2.id();
+      }
+    }
+  };
+
+  Op op;
+  return op.processVector(cellIdVector1, cellIdVector2);
+}
+
+// [[Rcpp::export]]
+LogicalVector cpp_s2_cell_neq(NumericVector cellIdVector1, NumericVector cellIdVector2) {
+  class Op: public BinaryS2CellOperator<LogicalVector, int> {
+    int processCell(S2CellId cellId1, S2CellId cellId2, R_xlen_t i) {
+      if (R_IsNA(reinterpret_double(cellId1.id())) || 
+            R_IsNA(reinterpret_double(cellId2.id()))) {
+        return NA_LOGICAL;
+      } else {
+        return cellId1.id() != cellId2.id();
+      }
+    }
+  };
+
+  Op op;
+  return op.processVector(cellIdVector1, cellIdVector2);
+}
+
+// [[Rcpp::export]]
+LogicalVector cpp_s2_cell_lt(NumericVector cellIdVector1, NumericVector cellIdVector2) {
+  class Op: public BinaryS2CellOperator<LogicalVector, int> {
+    int processCell(S2CellId cellId1, S2CellId cellId2, R_xlen_t i) {
+      if (R_IsNA(reinterpret_double(cellId1.id())) || 
+            R_IsNA(reinterpret_double(cellId2.id()))) {
+        return NA_LOGICAL;
+      } else {
+        return cellId1.id() < cellId2.id();
+      }
+    }
+  };
+
+  Op op;
+  return op.processVector(cellIdVector1, cellIdVector2);
+}
+
+// [[Rcpp::export]]
+LogicalVector cpp_s2_cell_lte(NumericVector cellIdVector1, NumericVector cellIdVector2) {
+  class Op: public BinaryS2CellOperator<LogicalVector, int> {
+    int processCell(S2CellId cellId1, S2CellId cellId2, R_xlen_t i) {
+      if (R_IsNA(reinterpret_double(cellId1.id())) || 
+            R_IsNA(reinterpret_double(cellId2.id()))) {
+        return NA_LOGICAL;
+      } else {
+        return cellId1.id() <= cellId2.id();
+      }
+    }
+  };
+
+  Op op;
+  return op.processVector(cellIdVector1, cellIdVector2);
+}
+
+// [[Rcpp::export]]
+LogicalVector cpp_s2_cell_gte(NumericVector cellIdVector1, NumericVector cellIdVector2) {
+  class Op: public BinaryS2CellOperator<LogicalVector, int> {
+    int processCell(S2CellId cellId1, S2CellId cellId2, R_xlen_t i) {
+      if (R_IsNA(reinterpret_double(cellId1.id())) || 
+            R_IsNA(reinterpret_double(cellId2.id()))) {
+        return NA_LOGICAL;
+      } else {
+        return cellId1.id() >= cellId2.id();
+      }
+    }
+  };
+
+  Op op;
+  return op.processVector(cellIdVector1, cellIdVector2);
+}
+
+// [[Rcpp::export]]
+LogicalVector cpp_s2_cell_gt(NumericVector cellIdVector1, NumericVector cellIdVector2) {
+  class Op: public BinaryS2CellOperator<LogicalVector, int> {
+    int processCell(S2CellId cellId1, S2CellId cellId2, R_xlen_t i) {
+      if (R_IsNA(reinterpret_double(cellId1.id())) || 
+            R_IsNA(reinterpret_double(cellId2.id()))) {
+        return NA_LOGICAL;
+      } else {
+        return cellId1.id() > cellId2.id();
+      }
+    }
+  };
+
+  Op op;
+  return op.processVector(cellIdVector1, cellIdVector2);
+}
+
+// [[Rcpp::export]]
+LogicalVector cpp_s2_cell_contains(NumericVector cellIdVector1, NumericVector cellIdVector2) {
+  class Op: public BinaryS2CellOperator<LogicalVector, int> {
+    int processCell(S2CellId cellId1, S2CellId cellId2, R_xlen_t i) {
+      if (cellId1.is_valid() && cellId2.is_valid()) {
+        return cellId1.contains(cellId2);
+      } else {
+        return NA_LOGICAL;
+      }
+    }
+  };
+
+  Op op;
+  return op.processVector(cellIdVector1, cellIdVector2);
+}
+
+// [[Rcpp::export]]
+LogicalVector cpp_s2_cell_may_intersect(NumericVector cellIdVector1, NumericVector cellIdVector2) {
+  class Op: public BinaryS2CellOperator<LogicalVector, int> {
+    int processCell(S2CellId cellId1, S2CellId cellId2, R_xlen_t i) {
+      if (cellId1.is_valid() && cellId2.is_valid()) {
+        return S2Cell(cellId1).MayIntersect(S2Cell(cellId2));
+      } else {
+        return NA_LOGICAL;
+      }
+    }
+  };
+
+  Op op;
+  return op.processVector(cellIdVector1, cellIdVector2);
+}
+
+// [[Rcpp::export]]
+NumericVector cpp_s2_cell_distance(NumericVector cellIdVector1, NumericVector cellIdVector2) {
+  class Op: public BinaryS2CellOperator<NumericVector, double> {
+    double processCell(S2CellId cellId1, S2CellId cellId2, R_xlen_t i) {
+      if (cellId1.is_valid() && cellId2.is_valid()) {
+        return S2Cell(cellId1).GetDistance(S2Cell(cellId2)).radians();
+      } else {
+        return NA_REAL;
+      }
+    }
+  };
+
+  Op op;
+  return op.processVector(cellIdVector1, cellIdVector2);
+}
+
+// [[Rcpp::export]]
+NumericVector cpp_s2_cell_max_distance(NumericVector cellIdVector1, NumericVector cellIdVector2) {
+  class Op: public BinaryS2CellOperator<NumericVector, double> {
+    double processCell(S2CellId cellId1, S2CellId cellId2, R_xlen_t i) {
+      if (cellId1.is_valid() && cellId2.is_valid()) {
+        return S2Cell(cellId1).GetMaxDistance(S2Cell(cellId2)).radians();
+      } else {
+        return NA_REAL;
+      }
+    }
+  };
+
+  Op op;
+  return op.processVector(cellIdVector1, cellIdVector2);
+}
diff --git a/src/s2-constructors-formatters.cpp b/src/s2-constructors-formatters.cpp
new file mode 100644 (file)
index 0000000..7741e4d
--- /dev/null
@@ -0,0 +1,82 @@
+
+#include <Rcpp.h>
+#include "wk/rcpp-translate.hpp"
+#include "wk/rcpp-coord-reader.hpp"
+
+#include "wk-geography.h"
+
+using namespace Rcpp;
+
+// [[Rcpp::export]]
+List cpp_s2_geog_point(NumericVector x, NumericVector y) {
+  NumericVector z(x.size());
+  z.fill(NA_REAL);
+  NumericVector m(x.size());
+  m.fill(NA_REAL);
+
+  WKRcppPointCoordProvider provider(x, y, z, m);
+  WKRcppPointCoordReader reader(provider);
+
+  WKGeographyWriter writer(provider.nFeatures());
+  reader.setHandler(&writer);
+
+  while (reader.hasNextFeature()) {
+    checkUserInterrupt();
+    reader.iterateFeature();
+  }
+
+  return writer.output;
+}
+
+// [[Rcpp::export]]
+List cpp_s2_make_line(NumericVector x, NumericVector y, IntegerVector featureId) {
+  NumericVector z(x.size());
+  z.fill(NA_REAL);
+  NumericVector m(x.size());
+  m.fill(NA_REAL);
+
+  WKRcppLinestringCoordProvider provider(x, y, z, m, featureId);
+  WKRcppLinestringCoordReader reader(provider);
+
+  WKGeographyWriter writer(provider.nFeatures());
+  reader.setHandler(&writer);
+
+  while (reader.hasNextFeature()) {
+    checkUserInterrupt();
+    reader.iterateFeature();
+  }
+
+  return writer.output;
+}
+
+// [[Rcpp::export]]
+List cpp_s2_make_polygon(NumericVector x, NumericVector y,
+                         IntegerVector featureId, IntegerVector ringId,
+                         bool oriented, bool check) {
+  NumericVector z(x.size());
+  z.fill(NA_REAL);
+  NumericVector m(x.size());
+  m.fill(NA_REAL);
+
+  WKRcppPolygonCoordProvider provider(x, y, z, m, featureId, ringId);
+  WKRcppPolygonCoordReader reader(provider);
+
+  WKGeographyWriter writer(provider.nFeatures());
+  writer.setOriented(oriented);
+  writer.setCheck(check);
+
+  reader.setHandler(&writer);
+
+  while (reader.hasNextFeature()) {
+    checkUserInterrupt();
+    reader.iterateFeature();
+  }
+
+  if (writer.problemId.size() > 0) {
+    Environment s2NS = Environment::namespace_env("s2");
+    Function stopProblems = s2NS["stop_problems_create"];
+    stopProblems(writer.problemId, writer.problems);
+  }
+
+  return writer.output;
+}
diff --git a/src/s2-geography.cpp b/src/s2-geography.cpp
new file mode 100644 (file)
index 0000000..88eb386
--- /dev/null
@@ -0,0 +1,135 @@
+
+#include "s2/s2latlng.h"
+#include "s2/s2polyline.h"
+#include "s2/s2polygon.h"
+
+#include "wk/wkb-reader.hpp"
+#include "wk/wkt-reader.hpp"
+#include "wk/wkb-writer.hpp"
+#include "wk/wkt-writer.hpp"
+#include "wk/geometry-formatter.hpp"
+
+#include "geography.h"
+#include "wk-geography.h"
+#include "point-geography.h"
+#include "polyline-geography.h"
+#include "polygon-geography.h"
+#include "geography-collection.h"
+
+#include <Rcpp.h>
+using namespace Rcpp;
+
+
+// [[Rcpp::export]]
+List s2_geography_from_wkb(List wkb, bool oriented, bool check) {
+  WKRawVectorListProvider provider(wkb);
+  WKGeographyWriter writer(wkb.size());
+  writer.setOriented(oriented);
+  writer.setCheck(check);
+
+  WKBReader reader(provider);
+  reader.setHandler(&writer);
+
+  while (reader.hasNextFeature()) {
+    checkUserInterrupt();
+    reader.iterateFeature();
+  }
+
+  if (writer.problemId.size() > 0) {
+    Environment s2NS = Environment::namespace_env("s2");
+    Function stopProblems = s2NS["stop_problems_create"];
+    stopProblems(writer.problemId, writer.problems);
+  }
+
+  return writer.output;
+}
+
+// [[Rcpp::export]]
+List s2_geography_from_wkt(CharacterVector wkt, bool oriented, bool check) {
+  WKCharacterVectorProvider provider(wkt);
+  WKGeographyWriter writer(wkt.size());
+  writer.setOriented(oriented);
+  writer.setCheck(check);
+
+  WKTReader reader(provider);
+  reader.setHandler(&writer);
+
+  while (reader.hasNextFeature()) {
+    checkUserInterrupt();
+    reader.iterateFeature();
+  }
+
+  if (writer.problemId.size() > 0) {
+    Environment s2NS = Environment::namespace_env("s2");
+    Function stopProblems = s2NS["stop_problems_create"];
+    stopProblems(writer.problemId, writer.problems);
+  }
+
+  return writer.output;
+}
+
+// [[Rcpp::export]]
+List s2_geography_full(LogicalVector x) { // create single geography with full polygon
+  std::unique_ptr<S2Loop> l = absl::make_unique<S2Loop>(S2Loop::kFull());
+  std::unique_ptr<S2Polygon> p = absl::make_unique<S2Polygon>(std::move(l));
+  Geography *pg = new PolygonGeography(std::move(p));
+  List ret(1);
+  ret(0) = Rcpp::XPtr<Geography>(pg);
+  return ret;
+}
+
+// [[Rcpp::export]]
+CharacterVector s2_geography_to_wkt(List s2_geography, int precision, bool trim) {
+  WKRcppSEXPProvider provider(s2_geography);
+  WKGeographyReader reader(provider);
+
+  WKCharacterVectorExporter exporter(reader.nFeatures());
+  exporter.setRoundingPrecision(precision);
+  exporter.setTrim(trim);
+  WKTWriter writer(exporter);
+
+  reader.setHandler(&writer);
+  while (reader.hasNextFeature()) {
+    checkUserInterrupt();
+    reader.iterateFeature();
+  }
+
+  return exporter.output;
+}
+
+// [[Rcpp::export]]
+List s2_geography_to_wkb(List s2_geography, int endian) {
+  WKRcppSEXPProvider provider(s2_geography);
+  WKGeographyReader reader(provider);
+
+  WKRawVectorListExporter exporter(reader.nFeatures());
+  WKBWriter writer(exporter);
+  writer.setEndian(endian);
+
+  reader.setHandler(&writer);
+  while (reader.hasNextFeature()) {
+    checkUserInterrupt();
+    reader.iterateFeature();
+  }
+
+  return exporter.output;
+}
+
+// [[Rcpp::export]]
+CharacterVector s2_geography_format(List s2_geography, int maxCoords, int precision, bool trim) {
+  WKRcppSEXPProvider provider(s2_geography);
+  WKGeographyReader reader(provider);
+
+  WKCharacterVectorExporter exporter(s2_geography.size());
+  exporter.setRoundingPrecision(precision);
+  exporter.setTrim(trim);
+  WKGeometryFormatter formatter(exporter, maxCoords);
+
+  reader.setHandler(&formatter);
+  while (reader.hasNextFeature()) {
+    checkUserInterrupt();
+    reader.iterateFeature();
+  }
+
+  return exporter.output;
+}
diff --git a/src/s2-lnglat.cpp b/src/s2-lnglat.cpp
new file mode 100644 (file)
index 0000000..764e5cc
--- /dev/null
@@ -0,0 +1,62 @@
+
+#include "s2/s2latlng.h"
+#include "s2/s2point.h"
+#include "wk/rcpp-io.hpp"
+#include "wk/wkb-reader.hpp"
+#include "wk/wkb-writer.hpp"
+
+#include <Rcpp.h>
+using namespace Rcpp;
+
+// [[Rcpp::export]]
+List s2_lnglat_from_numeric(NumericVector lng, NumericVector lat) {
+  List output(lat.size());
+
+  S2LatLng item;
+  for (R_xlen_t i = 0; i < lat.size(); i++) {
+    item = S2LatLng::FromDegrees(lat[i], lng[i]);
+    output[i] = XPtr<S2LatLng>(new S2LatLng(item));
+  }
+
+  return output;
+}
+
+// [[Rcpp::export]]
+List s2_lnglat_from_s2_point(List s2_point) {
+  List output(s2_point.size());
+
+  SEXP item;
+  S2LatLng newItem;
+  for (R_xlen_t i = 0; i < s2_point.size(); i++) {
+    item = s2_point[i];
+    if (item == R_NilValue) {
+      output[i] = R_NilValue;
+    } else {
+      XPtr<S2Point> ptr(item);
+      output[i] = XPtr<S2LatLng>(new S2LatLng(*ptr));
+    }
+  }
+
+  return output;
+}
+
+// [[Rcpp::export]]
+List data_frame_from_s2_lnglat(List xptr) {
+  NumericVector lng(xptr.size());
+  NumericVector lat(xptr.size());
+
+  SEXP item;
+  for (R_xlen_t i = 0; i < xptr.size(); i++) {
+    item = xptr[i];
+    if (item == R_NilValue) {
+      lng[i] = NA_REAL;
+      lat[i] = NA_REAL;
+    } else {
+      XPtr<S2LatLng> ptr(item);
+      lng[i] = ptr->lng().degrees();
+      lat[i] = ptr->lat().degrees();
+    }
+  }
+
+  return List::create(_["lng"] = lng, _["lat"] = lat);
+}
diff --git a/src/s2-matrix.cpp b/src/s2-matrix.cpp
new file mode 100644 (file)
index 0000000..e325ea6
--- /dev/null
@@ -0,0 +1,656 @@
+
+#include <unordered_map>
+#include <unordered_set>
+#include <algorithm>
+
+#include "s2/s2boolean_operation.h"
+#include "s2/s2closest_edge_query.h"
+#include "s2/s2furthest_edge_query.h"
+#include "s2/s2shape_index_region.h"
+
+#include "geography-operator.h"
+#include "s2-options.h"
+
+#include <Rcpp.h>
+using namespace Rcpp;
+
+std::unordered_map<int, R_xlen_t> buildSourcedIndex(List geog, MutableS2ShapeIndex* index) {
+  std::unordered_map<int, R_xlen_t> indexSource;
+  std::vector<int> shapeIds;
+
+  for (R_xlen_t j = 0; j < geog.size(); j++) {
+    checkUserInterrupt();
+    SEXP item2 = geog[j];
+
+    // build index and store index IDs so that shapeIds can be
+    // mapped back to the geog index
+    if (item2 == R_NilValue) {
+      Rcpp::stop("Missing `y` not allowed in binary indexed operators()");
+    } else {
+      Rcpp::XPtr<Geography> feature2(item2);
+      shapeIds = feature2->BuildShapeIndex(index);
+      for (size_t k = 0; k < shapeIds.size(); k ++) {
+        indexSource[shapeIds[k]] = j;
+      }
+    }
+  }
+
+  return indexSource;
+}
+
+std::unordered_set<R_xlen_t> findPossibleIntersections(const S2Region& region, 
+                                                       const MutableS2ShapeIndex* index,
+                                                       std::unordered_map<int, R_xlen_t>& source,
+                                                       int maxRegionCells) {
+  
+  std::unordered_set<R_xlen_t> mightIntersectIndices;
+  MutableS2ShapeIndex::Iterator indexIterator(index);
+
+  // generate a small covering of the region
+  S2RegionCoverer coverer;
+  coverer.mutable_options()->set_max_cells(maxRegionCells);
+  S2CellUnion covering = coverer.GetCovering(region);
+
+  // iterate over cells in the featureIndex
+  for (S2CellId featureCellId: covering) {
+    S2ShapeIndex::CellRelation relation = indexIterator.Locate(featureCellId);
+
+    if (relation == S2ShapeIndex::CellRelation::INDEXED) {
+      // we're in luck! these indexes have this cell in common
+      // add all the features it contains as possible intersectors for featureIndex
+      const S2ShapeIndexCell& cell = indexIterator.cell();
+      for (int k = 0; k < cell.num_clipped(); k++) {
+        int shapeId = cell.clipped(k).shape_id();
+        mightIntersectIndices.insert(source[shapeId]);
+      }
+    
+    } else if(relation  == S2ShapeIndex::CellRelation::SUBDIVIDED) {
+      // promising! the geog2 index has a child cell of it.id()
+      // (at which indexIterator is now positioned)
+      // keep iterating until the iterator is done OR we're no longer at a child cell of
+      // it.id(). The ordering of the iterator isn't guaranteed anywhere in the documentation;
+      // however, this ordering would be consistent with that of a Normalized
+      // S2CellUnion.
+      while (!indexIterator.done() && featureCellId.contains(indexIterator.id())) {
+        // potentially many cells in the indexIterator, so let the user cancel if this is
+        // running too long
+        checkUserInterrupt();
+
+        // add all the features the child cell contains as possible intersectors for featureIndex
+        const S2ShapeIndexCell& cell = indexIterator.cell();
+        for (int k = 0; k < cell.num_clipped(); k++) {
+          int shapeId = cell.clipped(k).shape_id();
+          mightIntersectIndices.insert(source[shapeId]);
+        }
+
+        // go to the next cell in the index
+        indexIterator.Next();
+      }
+    }
+
+    // else: relation == S2ShapeIndex::CellRelation::DISJOINT (do nothing)
+  }
+
+  return mightIntersectIndices;
+}
+
+template<class VectorType, class ScalarType>
+class IndexedBinaryGeographyOperator: public UnaryGeographyOperator<VectorType, ScalarType> {
+public:
+  std::unique_ptr<MutableS2ShapeIndex> geog2Index;
+  std::unordered_map<int, R_xlen_t> geog2IndexSource;
+
+  IndexedBinaryGeographyOperator() {
+    this->geog2Index = absl::make_unique<MutableS2ShapeIndex>();
+  }
+
+  // maxEdgesPerCell should be between 10 and 50, with lower numbers
+  // leading to more memory usage (but potentially faster query times). Benchmarking
+  // with binary prediates seems to indicate that values on the high end
+  // of the spectrum do a reasonable job of efficient preselection, and that
+  // decreasing this value does little to increase performance.
+  virtual void buildIndex(List geog2, int maxEdgesPerCell = 50) {
+    MutableS2ShapeIndex::Options indexOptions;
+    indexOptions.set_max_edges_per_cell(maxEdgesPerCell);
+    this->geog2Index = absl::make_unique<MutableS2ShapeIndex>(indexOptions);
+    this->geog2IndexSource = buildSourcedIndex(geog2, this->geog2Index.get());
+  }
+};
+
+// -------- closest/farthest feature ----------
+
+// [[Rcpp::export]]
+IntegerVector cpp_s2_closest_feature(List geog1, List geog2) {
+
+  class Op: public IndexedBinaryGeographyOperator<IntegerVector, int> {
+  public:
+    int processFeature(Rcpp::XPtr<Geography> feature, R_xlen_t i) {
+      S2ClosestEdgeQuery query(this->geog2Index.get());
+      S2ClosestEdgeQuery::ShapeIndexTarget target(feature->ShapeIndex());
+      const auto& result = query.FindClosestEdge(&target);
+      if (result.is_empty()) {
+        return NA_INTEGER;
+      } else {
+        // convert to R index (+1)
+        return this->geog2IndexSource[result.shape_id()] + 1;
+      }
+    }
+  };
+
+  Op op;
+  op.buildIndex(geog2);
+  return op.processVector(geog1);
+}
+
+// [[Rcpp::export]]
+IntegerVector cpp_s2_farthest_feature(List geog1, List geog2) {
+
+  class Op: public IndexedBinaryGeographyOperator<IntegerVector, int> {
+  public:
+    int processFeature(Rcpp::XPtr<Geography> feature, R_xlen_t i) {
+      S2FurthestEdgeQuery query(this->geog2Index.get());
+      S2FurthestEdgeQuery::ShapeIndexTarget target(feature->ShapeIndex());
+      const auto& result = query.FindFurthestEdge(&target);
+      if (result.is_empty()) {
+        return NA_INTEGER;
+      } else {
+        // convert to R index (+1)
+        return this->geog2IndexSource[result.shape_id()] + 1;
+      }
+    }
+  };
+
+  Op op;
+  op.buildIndex(geog2);
+  return op.processVector(geog1);
+}
+
+// [[Rcpp::export]]
+List cpp_s2_closest_edges(List geog1, List geog2, int n, double min_distance) {
+
+  class Op: public IndexedBinaryGeographyOperator<List, IntegerVector> {
+  public:
+    IntegerVector processFeature(Rcpp::XPtr<Geography> feature, R_xlen_t i) {
+      S2ClosestEdgeQuery query(this->geog2Index.get());
+      query.mutable_options()->set_max_results(n);
+      S2ClosestEdgeQuery::ShapeIndexTarget target(feature->ShapeIndex());
+      const auto& result = query.FindClosestEdges(&target);
+
+      // this code searches edges, which may come from the same feature
+      std::unordered_set<int> features;
+      for (S2ClosestEdgeQuery::Result res : result) {
+        if (res.distance().radians() > this->min_distance) {
+          features.insert(this->geog2IndexSource[res.shape_id()] + 1);
+        }
+      }
+
+      return IntegerVector(features.begin(), features.end());
+    }
+
+    int n;
+    double min_distance;
+  };
+
+  Op op;
+  op.n = n;
+  op.min_distance = min_distance;
+  op.buildIndex(geog2);
+  return op.processVector(geog1);
+}
+
+// ----------- indexed binary predicate operators -----------
+
+class IndexedMatrixPredicateOperator: public IndexedBinaryGeographyOperator<List, IntegerVector> {
+public:
+  // a max_cells value of 8 was suggested in the S2RegionCoverer docs as a
+  // reasonable approximation of a geometry, although benchmarking seems to indicate that
+  // increasing this number above 4 actually decreasses performance (using a value
+  // of 1 dramatically decreases performance)
+  IndexedMatrixPredicateOperator(List s2options, int maxFeatureCells = 4):
+    maxFeatureCells(maxFeatureCells) {
+    GeographyOperationOptions options(s2options);
+    this->options = options.booleanOperationOptions();
+  }
+
+  // See IndexedBinaryGeographyOperator::buildIndex() for why 50 is the default value
+  // for maxEdgesPerCell
+  void buildIndex(List geog2, int maxEdgesPerCell = 50) {
+    this->geog2  = geog2;
+    IndexedBinaryGeographyOperator<List, IntegerVector>::buildIndex(geog2, maxEdgesPerCell);
+  }
+
+  IntegerVector processFeature(Rcpp::XPtr<Geography> feature, R_xlen_t i) {
+    S2ShapeIndex* index1 = feature->ShapeIndex();
+    S2ShapeIndexRegion<S2ShapeIndex> region = MakeS2ShapeIndexRegion(index1);
+
+    // build a list of candidate feature indices
+    std::unordered_set<R_xlen_t> mightIntersectIndices = findPossibleIntersections(
+      region,
+      this->geog2Index.get(),
+      this->geog2IndexSource,
+      this->maxFeatureCells
+    );
+
+    // loop through features from geog2 that might intersect feature
+    // and build a list of indices that actually intersect (based on
+    // this->actuallyIntersects(), which might perform alternative
+    // comparisons)
+    std::vector<int> actuallyIntersectIndices;
+    for (R_xlen_t j: mightIntersectIndices) {
+      SEXP item = this->geog2[j];
+      XPtr<Geography> feature2(item);
+      if (this->actuallyIntersects(index1, feature2->ShapeIndex(), i, j)) {
+        // convert to R index here + 1
+        actuallyIntersectIndices.push_back(j + 1);
+      }
+    }
+
+    // return sorted integer vector
+    std::sort(actuallyIntersectIndices.begin(), actuallyIntersectIndices.end());
+    return Rcpp::IntegerVector(actuallyIntersectIndices.begin(), actuallyIntersectIndices.end());
+  };
+
+  virtual bool actuallyIntersects(S2ShapeIndex* index1, S2ShapeIndex* index2, R_xlen_t i, R_xlen_t j) = 0;
+
+  protected:
+    List geog2;
+    S2BooleanOperation::Options options;
+    int maxFeatureCells;
+};
+
+// [[Rcpp::export]]
+List cpp_s2_may_intersect_matrix(List geog1, List geog2, 
+                                 int maxEdgesPerCell, int maxFeatureCells, List s2options) {
+  class Op: public IndexedMatrixPredicateOperator {
+  public:
+    Op(List s2options, int maxFeatureCells): 
+      IndexedMatrixPredicateOperator(s2options, maxFeatureCells) {}
+    
+    bool actuallyIntersects(S2ShapeIndex* index1, S2ShapeIndex* index2, R_xlen_t i, R_xlen_t j) {
+      return true;
+    };
+  };
+
+  Op op(s2options, maxFeatureCells);
+  op.buildIndex(geog2, maxEdgesPerCell);
+  return op.processVector(geog1);
+}
+
+// [[Rcpp::export]]
+List cpp_s2_contains_matrix(List geog1, List geog2, List s2options) {
+  class Op: public IndexedMatrixPredicateOperator {
+  public:
+    Op(List s2options): IndexedMatrixPredicateOperator(s2options) {}
+    bool actuallyIntersects(S2ShapeIndex* index1, S2ShapeIndex* index2, R_xlen_t i, R_xlen_t j) {
+      return S2BooleanOperation::Contains(*index1, *index2, this->options);
+    };
+  };
+
+  Op op(s2options);
+  op.buildIndex(geog2);
+  return op.processVector(geog1);
+}
+
+// [[Rcpp::export]]
+List cpp_s2_within_matrix(List geog1, List geog2, List s2options) {
+  class Op: public IndexedMatrixPredicateOperator {
+  public:
+    Op(List s2options): IndexedMatrixPredicateOperator(s2options) {}
+    bool actuallyIntersects(S2ShapeIndex* index1, S2ShapeIndex* index2, R_xlen_t i, R_xlen_t j) {
+      // note reversed index2, index1
+      return S2BooleanOperation::Contains(*index2, *index1, this->options);
+    };
+  };
+
+  Op op(s2options);
+  op.buildIndex(geog2);
+  return op.processVector(geog1);
+}
+
+// [[Rcpp::export]]
+List cpp_s2_intersects_matrix(List geog1, List geog2, List s2options) {
+  class Op: public IndexedMatrixPredicateOperator {
+  public:
+    Op(List s2options): IndexedMatrixPredicateOperator(s2options) {}
+    bool actuallyIntersects(S2ShapeIndex* index1, S2ShapeIndex* index2, R_xlen_t i, R_xlen_t j) {
+      return S2BooleanOperation::Intersects(*index1, *index2, this->options);
+    };
+  };
+
+  Op op(s2options);
+  op.buildIndex(geog2);
+  return op.processVector(geog1);
+}
+
+// [[Rcpp::export]]
+List cpp_s2_equals_matrix(List geog1, List geog2, List s2options) {
+  class Op: public IndexedMatrixPredicateOperator {
+  public:
+    Op(List s2options): IndexedMatrixPredicateOperator(s2options) {}
+    bool actuallyIntersects(S2ShapeIndex* index1, S2ShapeIndex* index2, R_xlen_t i, R_xlen_t j) {
+      return S2BooleanOperation::Equals(*index1, *index2, this->options);
+    };
+  };
+
+  Op op(s2options);
+  op.buildIndex(geog2);
+  return op.processVector(geog1);
+}
+
+// [[Rcpp::export]]
+List cpp_s2_touches_matrix(List geog1, List geog2, List s2options) {
+  class Op: public IndexedMatrixPredicateOperator {
+  public:
+    Op(List s2options): IndexedMatrixPredicateOperator(s2options) {
+      this->closedOptions = this->options;
+      this->closedOptions.set_polygon_model(S2BooleanOperation::PolygonModel::CLOSED);
+      this->closedOptions.set_polyline_model(S2BooleanOperation::PolylineModel::CLOSED);
+
+      this->openOptions = this->options;
+      this->openOptions.set_polygon_model(S2BooleanOperation::PolygonModel::OPEN);
+      this->openOptions.set_polyline_model(S2BooleanOperation::PolylineModel::OPEN);
+    }
+
+    bool actuallyIntersects(S2ShapeIndex* index1, S2ShapeIndex* index2, R_xlen_t i, R_xlen_t j) {
+      // efficiently re-uses the index on geog2 and takes advantage of short-circuiting &&
+      return S2BooleanOperation::Intersects(*index1, *index2, this->closedOptions) &&
+        !S2BooleanOperation::Intersects(*index1, *index2, this->openOptions);
+    };
+
+  private:
+    S2BooleanOperation::Options closedOptions;
+    S2BooleanOperation::Options openOptions;
+  };
+
+  Op op(s2options);
+  op.buildIndex(geog2);
+  return op.processVector(geog1);
+}
+
+
+// ----------- brute force binary predicate operators ------------------
+
+class BruteForceMatrixPredicateOperator {
+public:
+  std::vector<S2ShapeIndex*> geog2Indices;
+  S2BooleanOperation::Options options;
+
+  BruteForceMatrixPredicateOperator() {}
+
+  BruteForceMatrixPredicateOperator(Rcpp::List s2options) {
+    GeographyOperationOptions options(s2options);
+    this->options = options.booleanOperationOptions();
+  }
+
+  List processVector(Rcpp::List geog1, Rcpp::List geog2) {
+    List output(geog1.size());
+
+    // using instead of IntegerVector because
+    // std::vector is much faster with repeated calls to .push_back()
+    std::vector<int> trueIndices;
+
+    for (R_xlen_t i = 0; i < geog1.size(); i++) {
+      trueIndices.clear();
+
+      SEXP item1 = geog1[i];
+      if (item1 ==  R_NilValue) {
+        output[i] = R_NilValue;
+      } else {
+        Rcpp::XPtr<Geography> feature1(item1);
+
+        for (size_t j = 0; j < geog2.size(); j++) {
+          checkUserInterrupt();
+          SEXP item2 = geog2[j];
+          if (item2 == R_NilValue) {
+            stop("Missing `y` not allowed in binary index operations");
+          }
+
+          XPtr<Geography> feature2(item2);
+
+          bool result = this->processFeature(feature1, feature2, i, j);
+          if (result) {
+            // convert to R index here (+1)
+            trueIndices.push_back(j + 1);
+          }
+        }
+
+        IntegerVector itemOut(trueIndices.size());
+        for (size_t k = 0; k < trueIndices.size(); k++) {
+          itemOut[k] = trueIndices[k];
+        }
+        output[i] = itemOut;
+      }
+    }
+
+    return output;
+  }
+
+  virtual bool processFeature(XPtr<Geography> feature1, XPtr<Geography> feature2,
+                              R_xlen_t i, R_xlen_t j) = 0;
+};
+
+// [[Rcpp::export]]
+List cpp_s2_dwithin_matrix(List geog1, List geog2, double distance) {
+  class Op: public BruteForceMatrixPredicateOperator {
+  public:
+    double distance;
+    Op(double distance): distance(distance) {}
+    bool processFeature(XPtr<Geography> feature1, XPtr<Geography> feature2,
+                        R_xlen_t i, R_xlen_t j) {
+      S2ClosestEdgeQuery query(feature2->ShapeIndex());
+      S2ClosestEdgeQuery::ShapeIndexTarget target(feature1->ShapeIndex());
+      return query.IsDistanceLessOrEqual(&target, S1ChordAngle::Radians(this->distance));
+    };
+  };
+
+  Op op(distance);
+  return op.processVector(geog1, geog2);
+}
+
+// ----------- distance matrix operators -------------------
+
+template<class MatrixType, class ScalarType>
+class MatrixGeographyOperator {
+public:
+  MatrixType processVector(Rcpp::List geog1, Rcpp::List geog2) {
+
+    MatrixType output(geog1.size(), geog2.size());
+
+    SEXP item1;
+    SEXP item2;
+
+    for (R_xlen_t i = 0; i < geog1.size(); i++) {
+      item1 = geog1[i];
+      if (item1 ==  R_NilValue) {
+        for (R_xlen_t j = 0; j < geog2.size(); j++) {
+          output(i, j) = MatrixType::get_na();
+        }
+      } else {
+        Rcpp::XPtr<Geography> feature1(item1);
+
+        for (R_xlen_t j = 0; j < geog2.size(); j++) {
+          checkUserInterrupt();
+          item2 = geog2[j];
+
+          if (item2 == R_NilValue) {
+            output(i, j) = MatrixType::get_na();
+          } else {
+            Rcpp::XPtr<Geography> feature2(item2);
+            output(i, j) = this->processFeature(feature1, feature2, i, j);
+          }
+        }
+      }
+    }
+
+    return output;
+  }
+
+  virtual ScalarType processFeature(Rcpp::XPtr<Geography> feature1,
+                                    Rcpp::XPtr<Geography> feature2,
+                                    R_xlen_t i, R_xlen_t j) = 0;
+};
+
+// [[Rcpp::export]]
+NumericMatrix cpp_s2_distance_matrix(List geog1, List geog2) {
+  class Op: public MatrixGeographyOperator<NumericMatrix, double> {
+
+    double processFeature(XPtr<Geography> feature1, XPtr<Geography> feature2,
+                          R_xlen_t i, R_xlen_t j) {
+      S2ClosestEdgeQuery query(feature1->ShapeIndex());
+      S2ClosestEdgeQuery::ShapeIndexTarget target(feature2->ShapeIndex());
+      const auto& result = query.FindClosestEdge(&target);
+
+      S1ChordAngle angle = result.distance();
+      double distance = angle.ToAngle().radians();
+
+      if (distance == R_PosInf) {
+        return NA_REAL;
+      } else {
+        return distance;
+      }
+    }
+  };
+
+  Op op;
+  return op.processVector(geog1, geog2);
+}
+
+// [[Rcpp::export]]
+NumericMatrix cpp_s2_max_distance_matrix(List geog1, List geog2) {
+  class Op: public MatrixGeographyOperator<NumericMatrix, double> {
+
+    double processFeature(XPtr<Geography> feature1, XPtr<Geography> feature2,
+                          R_xlen_t i, R_xlen_t j) {
+      S2FurthestEdgeQuery query(feature1->ShapeIndex());
+      S2FurthestEdgeQuery::ShapeIndexTarget target(feature2->ShapeIndex());
+      const auto& result = query.FindFurthestEdge(&target);
+
+      S1ChordAngle angle = result.distance();
+      double distance = angle.ToAngle().radians();
+
+      // returns -1 if one of the indexes is empty
+      // NA is more consistent with the BigQuery
+      // function, and makes way more sense
+      if (distance < 0) {
+        return NA_REAL;
+      } else {
+        return distance;
+      }
+    }
+  };
+
+  Op op;
+  return op.processVector(geog1, geog2);
+}
+
+
+// ----------- brute force binary predicate operators (for testing) ------------------
+
+// [[Rcpp::export]]
+List cpp_s2_contains_matrix_brute_force(List geog1, List geog2, List s2options) {
+  class Op: public BruteForceMatrixPredicateOperator {
+  public:
+    Op(List s2options): BruteForceMatrixPredicateOperator(s2options) {}
+    bool processFeature(XPtr<Geography> feature1, XPtr<Geography> feature2,
+                        R_xlen_t i, R_xlen_t j) {
+      // by default Contains() will return true for Contains(x, EMPTY), which is
+      // not true in BigQuery or GEOS
+      if (feature2->IsEmpty()) {
+        return false;
+      } else {
+        return S2BooleanOperation::Contains(
+          *feature1->ShapeIndex(), 
+          *feature2->ShapeIndex(), 
+          this->options
+        );
+      }
+    };
+  };
+
+  Op op(s2options);
+  return op.processVector(geog1, geog2);
+}
+
+// [[Rcpp::export]]
+List cpp_s2_within_matrix_brute_force(List geog1, List geog2, List s2options) {
+  class Op: public BruteForceMatrixPredicateOperator {
+  public:
+    Op(List s2options): BruteForceMatrixPredicateOperator(s2options) {}
+    bool processFeature(XPtr<Geography> feature1, XPtr<Geography> feature2,
+                        R_xlen_t i, R_xlen_t j) {
+      // note reversed index2, index1
+      
+      // by default Contains() will return true for Contains(x, EMPTY), which is
+      // not true in BigQuery or GEOS
+      if (feature1->IsEmpty()) {
+        return false;
+      } else {
+        return S2BooleanOperation::Contains(
+          *feature2->ShapeIndex(),
+          *feature1->ShapeIndex(),
+          this->options
+        );
+      }      
+    };
+  };
+
+  Op op(s2options);
+  return op.processVector(geog1, geog2);
+}
+
+// [[Rcpp::export]]
+List cpp_s2_intersects_matrix_brute_force(List geog1, List geog2, List s2options) {
+  class Op: public BruteForceMatrixPredicateOperator {
+  public:
+    Op(List s2options): BruteForceMatrixPredicateOperator(s2options) {}
+    bool processFeature(XPtr<Geography> feature1, XPtr<Geography> feature2,
+                        R_xlen_t i, R_xlen_t j) {
+      return S2BooleanOperation::Intersects(
+        *feature1->ShapeIndex(),
+        *feature2->ShapeIndex(),
+        this->options
+      );
+    }
+  };
+
+  Op op(s2options);
+  return op.processVector(geog1, geog2);
+}
+
+// [[Rcpp::export]]
+List cpp_s2_disjoint_matrix_brute_force(List geog1, List geog2, List s2options) {
+  class Op: public BruteForceMatrixPredicateOperator {
+  public:
+    Op(List s2options): BruteForceMatrixPredicateOperator(s2options) {}
+    bool processFeature(XPtr<Geography> feature1, XPtr<Geography> feature2,
+                        R_xlen_t i, R_xlen_t j) {
+      return !S2BooleanOperation::Intersects(
+        *feature1->ShapeIndex(),
+        *feature2->ShapeIndex(),
+        this->options
+      );
+    }
+  };
+
+  Op op(s2options);
+  return op.processVector(geog1, geog2);
+}
+
+// [[Rcpp::export]]
+List cpp_s2_equals_matrix_brute_force(List geog1, List geog2, List s2options) {
+  class Op: public BruteForceMatrixPredicateOperator {
+  public:
+    Op(List s2options): BruteForceMatrixPredicateOperator(s2options) {}
+    bool processFeature(XPtr<Geography> feature1, XPtr<Geography> feature2,
+                        R_xlen_t i, R_xlen_t j) {
+      return S2BooleanOperation::Equals(
+        *feature1->ShapeIndex(),
+        *feature2->ShapeIndex(),
+        this->options
+      );
+    }
+  };
+
+  Op op(s2options);
+  return op.processVector(geog1, geog2);
+}
diff --git a/src/s2-options.h b/src/s2-options.h
new file mode 100644 (file)
index 0000000..778628d
--- /dev/null
@@ -0,0 +1,347 @@
+
+#ifndef S2_OPTIONS_H
+#define S2_OPTIONS_H
+
+#include <sstream>
+#include <Rcpp.h>
+#include "s2/s2boolean_operation.h"
+#include "s2/s2builderutil_snap_functions.h"
+#include "s2/s2builderutil_s2polygon_layer.h"
+#include "s2/s2builderutil_s2polyline_vector_layer.h"
+#include "s2/s2builderutil_s2point_vector_layer.h"
+
+// This class wraps several concepts in the S2BooleanOperation,
+// and S2Layer, parameterized such that these can be specified from R
+class GeographyOperationOptions {
+public:
+  int polygonModel;
+  int polylineModel;
+  Rcpp::List snap;
+  double snapRadius;
+  int duplicatePointEdges;
+  int duplicatePolylineEdges;
+  int duplicatePolygonEdges;
+  int polylineEdgeType;
+  int polygonEdgeType;
+  int validatePolyline;
+  int validatePolygon;
+  int polylineType;
+  int polylineSiblingPairs;
+  int simplifyEdgeChains;
+  int splitCrossingEdges;
+  int idempotent;
+  int dimensions;
+
+  enum Dimension {
+    POINT = 1,
+    POLYLINE = 2,
+    POLYGON = 4
+  };
+
+  // Wraps options for the three layer types
+  class LayerOptions {
+    public:
+    s2builderutil::S2PointVectorLayer::Options pointLayerOptions;
+    s2builderutil::S2PolylineVectorLayer::Options polylineLayerOptions;
+    s2builderutil::S2PolygonLayer::Options polygonLayerOptions;
+    int dimensions;
+  };
+
+  // deaults: use S2 defaults
+  GeographyOperationOptions(): polygonModel(-1), polylineModel(-1), snapRadius(-1) {
+    this->snap.attr("class") = "snap_identity";
+  }
+
+  // create from s2_options() object
+  GeographyOperationOptions(Rcpp::List s2options): GeographyOperationOptions() {
+    if (!Rf_inherits(s2options, "s2_options")) {
+      Rcpp::stop("`options` must be created using s2_options()");
+    }
+
+    // if these items are of an incorrect type (e.g., list() instead of int)
+    // the default errors are very difficult to diagnose.
+    try {
+      int model = s2options["model"];
+      this->polylineModel = model;
+      this->polygonModel = model;
+    } catch (std::exception& e) {
+      std::stringstream err;
+      err << "Error setting s2_options() `model`: " << e.what();
+      Rcpp::stop(err.str());
+    }
+
+    try {
+      this->snap = s2options["snap"];
+    } catch (std::exception& e) {
+      std::stringstream err;
+      err << "Error setting s2_options() `snap`: " << e.what();
+      Rcpp::stop(err.str());
+    }
+
+    try {
+      this->snapRadius = s2options["snap_radius"];
+    } catch (std::exception& e) {
+      std::stringstream err;
+      err << "Error setting s2_options() `snap_radius`: " << e.what();
+      Rcpp::stop(err.str());
+    }
+
+    try {
+      int duplicateEdges = s2options["duplicate_edges"];
+      this->duplicatePointEdges = duplicateEdges;
+      this->duplicatePolylineEdges = duplicateEdges;
+      this->duplicatePolygonEdges = duplicateEdges;
+    } catch (std::exception& e) {
+      std::stringstream err;
+      err << "Error setting s2_options() `duplicate_edges`: " << e.what();
+      Rcpp::stop(err.str());
+    }
+
+    try {
+      int edgeType = s2options["edge_type"];
+      this->polylineEdgeType = edgeType;
+      this->polygonEdgeType = edgeType;
+    } catch (std::exception& e) {
+      std::stringstream err;
+      err << "Error setting s2_options() `edge_type`: " << e.what();
+      Rcpp::stop(err.str());
+    }
+
+    try {
+      int validate = s2options["validate"];
+      this->validatePolyline = validate;
+      this->validatePolygon = validate;
+    } catch (std::exception& e) {
+      std::stringstream err;
+      err << "Error setting s2_options() `duplicate_edges`: " << e.what();
+      Rcpp::stop(err.str());
+    }
+
+    try {
+      this->polylineType = s2options["polyline_type"];
+    } catch (std::exception& e) {
+      std::stringstream err;
+      err << "Error setting s2_options() `polyline_type`: " << e.what();
+      Rcpp::stop(err.str());
+    }
+
+    try {
+      this->polylineSiblingPairs = s2options["polyline_sibling_pairs"];
+    } catch (std::exception& e) {
+      std::stringstream err;
+      err << "Error setting s2_options() `polyline_sibling_pairs`: " << e.what();
+      Rcpp::stop(err.str());
+    }
+
+    try {
+      this->simplifyEdgeChains = s2options["simplify_edge_chains"];
+    } catch (std::exception& e) {
+      std::stringstream err;
+      err << "Error setting s2_options() `simplify_edge_chains`: " << e.what();
+      Rcpp::stop(err.str());
+    }
+
+    try {
+      this->splitCrossingEdges = s2options["split_crossing_edges"];
+    } catch (std::exception& e) {
+      std::stringstream err;
+      err << "Error setting s2_options() `split_crossing_edges`: " << e.what();
+      Rcpp::stop(err.str());
+    }
+
+    try {
+      this->idempotent = s2options["idempotent"];
+    } catch (std::exception& e) {
+      std::stringstream err;
+      err << "Error setting s2_options() `idempotent`: " << e.what();
+      Rcpp::stop(err.str());
+    }
+
+    try {
+      this->dimensions = 0;
+      Rcpp::IntegerVector dim = s2options["dimensions"];
+      for (int i = 0; i < dim.size(); i++) {
+        switch (dim[i]) {
+        case 1:
+          this->dimensions |= Dimension::POINT;
+          break;
+        case 2:
+          this->dimensions |= Dimension::POLYLINE;
+          break;
+        case 3:
+          this->dimensions |= Dimension::POLYGON;
+          break;
+        }
+      }
+    } catch (std::exception& e) {
+      std::stringstream err;
+      err << "Error setting s2_options() `dimensions`: " << e.what();
+      Rcpp::stop(err.str());
+    }
+  }
+
+  // build options for passing this to the S2BooleanOperation
+  S2BooleanOperation::Options booleanOperationOptions() {
+    S2BooleanOperation::Options options;
+    if (this->polygonModel >= 0) {
+      options.set_polygon_model(getPolygonModel(this->polygonModel));
+    }
+    if (this->polylineModel >= 0) {
+      options.set_polyline_model(getPolylineModel(this->polylineModel));
+    }
+    this->setSnapFunction<S2BooleanOperation::Options>(options);
+
+    return options;
+  }
+
+  // build options for S2Builder
+  S2Builder::Options builderOptions() {
+    S2Builder::Options options;
+    options.set_simplify_edge_chains(this->simplifyEdgeChains);
+    options.set_split_crossing_edges(this->splitCrossingEdges);
+    options.set_idempotent(this->idempotent);
+    this->setSnapFunction<S2Builder::Options>(options);
+    return options;
+  }
+
+  // build options for point, polyline, and polygon layers
+  LayerOptions layerOptions() {
+    LayerOptions out;
+
+    // point layer
+    out.pointLayerOptions.set_duplicate_edges(getDuplicateEdges(this->duplicatePointEdges));
+
+    // polyline layer
+    out.polylineLayerOptions.set_duplicate_edges(getDuplicateEdges(this->duplicatePolylineEdges));
+    out.polylineLayerOptions.set_edge_type(getEdgeType(this->polylineEdgeType));
+    out.polylineLayerOptions.set_polyline_type(getPolylineType(this->polylineType));
+    out.polylineLayerOptions.set_sibling_pairs(getSiblingPairs(this->polylineSiblingPairs));
+    out.polylineLayerOptions.set_validate(this->validatePolyline);
+
+    // always disable debugging where possible
+    out.polylineLayerOptions.set_s2debug_override(S2Debug::DISABLE);
+
+    // polygon layer
+    out.polygonLayerOptions.set_edge_type(getEdgeType(this->polygonEdgeType));
+    out.polygonLayerOptions.set_validate(this->validatePolygon);
+
+    // dimensions
+    out.dimensions = this->dimensions;
+
+    return out;
+  }
+
+  template <class OptionsType>
+  void setSnapFunction(OptionsType& options) {
+    // S2Builder::SnapFunction is abstract and can't be returned
+    // hence the templated function
+
+    if (Rf_inherits(this->snap, "snap_identity")) {
+      s2builderutil::IdentitySnapFunction snapFunction;
+      if (this->snapRadius > 0) {
+        snapFunction.set_snap_radius(S1Angle::Radians(this->snapRadius));
+      }
+      options.set_snap_function(snapFunction);
+
+    } else if (Rf_inherits(this->snap, "snap_level")) {
+      int snapLevel = this->snap["level"];
+      s2builderutil::S2CellIdSnapFunction snapFunction(snapLevel);
+      if (this->snapRadius > 0) {
+        snapFunction.set_snap_radius(S1Angle::Radians(this->snapRadius));
+      }
+      options.set_snap_function(snapFunction);
+
+    } else if (Rf_inherits(this->snap, "snap_precision")) {
+      int exponent = snap["exponent"];
+      s2builderutil::IntLatLngSnapFunction snapFunction(exponent);
+      if (this->snapRadius > 0) {
+        snapFunction.set_snap_radius(S1Angle::Radians(this->snapRadius));
+      }
+      options.set_snap_function(snapFunction);
+
+    } else if (Rf_inherits(this->snap, "snap_distance")) {
+      double distance = snap["distance"];
+      double snapLevel = s2builderutil::S2CellIdSnapFunction::LevelForMaxSnapRadius(
+        S1Angle::Radians(distance)
+      );
+      s2builderutil::S2CellIdSnapFunction snapFunction(snapLevel);
+      if (this->snapRadius > 0) {
+        snapFunction.set_snap_radius(S1Angle::Radians(this->snapRadius));
+      }
+      options.set_snap_function(snapFunction);
+
+    } else {
+      Rcpp::stop("`snap` must be specified using s2_snap_*()");
+    }
+  }
+
+  static S2BooleanOperation::PolygonModel getPolygonModel(int model) {
+    switch (model) {
+      case 1: return S2BooleanOperation::PolygonModel::OPEN;
+      case 2: return S2BooleanOperation::PolygonModel::SEMI_OPEN;
+      case 3: return S2BooleanOperation::PolygonModel::CLOSED;
+      default:
+        std::stringstream err;
+        err << "Invalid value for polygon model: " << model;
+        Rcpp::stop(err.str());
+    }
+  }
+
+  static S2BooleanOperation::PolylineModel getPolylineModel(int model) {
+    switch (model) {
+      case 1: return S2BooleanOperation::PolylineModel::OPEN;
+      case 2: return S2BooleanOperation::PolylineModel::SEMI_OPEN;
+      case 3: return S2BooleanOperation::PolylineModel::CLOSED;
+      default:
+        std::stringstream err;
+        err << "Invalid value for polyline model: " << model;
+        Rcpp::stop(err.str());
+    }
+  }
+
+  static S2Builder::GraphOptions::DuplicateEdges getDuplicateEdges(int value) {
+    switch (value) {
+      case 0: return S2Builder::GraphOptions::DuplicateEdges::MERGE;
+      case 1: return S2Builder::GraphOptions::DuplicateEdges::KEEP;
+      default:
+        std::stringstream err;
+        err << "Invalid value for duplicate edges: " << value;
+        Rcpp::stop(err.str());
+    }
+  }
+
+  static S2Builder::GraphOptions::EdgeType getEdgeType(int value) {
+    switch (value) {
+      case 1: return S2Builder::GraphOptions::EdgeType::DIRECTED;
+      case 2: return S2Builder::GraphOptions::EdgeType::UNDIRECTED;
+      default:
+        std::stringstream err;
+        err << "Invalid value for edge type: " << value;
+        Rcpp::stop(err.str());
+    }
+  }
+
+  static S2Builder::GraphOptions::SiblingPairs getSiblingPairs(int value) {
+    switch (value) {
+      case 1: return S2Builder::GraphOptions::SiblingPairs::DISCARD;
+      case 2: return S2Builder::GraphOptions::SiblingPairs::KEEP;
+      default:
+        std::stringstream err;
+        err << "Invalid value for sibling pairs: " << value;
+        Rcpp::stop(err.str());
+    }
+  }
+
+  static S2Builder::Graph::PolylineType getPolylineType(int value) {
+    switch (value) {
+      case 1: return S2Builder::Graph::PolylineType::PATH;
+      case 2: return S2Builder::Graph::PolylineType::WALK;
+      default:
+        std::stringstream err;
+        err << "Invalid value for polylie type: " << value;
+        Rcpp::stop(err.str());
+    }
+  }
+};
+
+#endif
diff --git a/src/s2-point.cpp b/src/s2-point.cpp
new file mode 100644 (file)
index 0000000..ec1a7d3
--- /dev/null
@@ -0,0 +1,60 @@
+
+#include "s2/s2point.h"
+#include "s2/s2latlng.h"
+#include <Rcpp.h>
+using namespace Rcpp;
+
+// [[Rcpp::export]]
+List s2_point_from_numeric(NumericVector x, NumericVector y, NumericVector z) {
+  List output(x.size());
+
+  for (R_xlen_t i = 0; i < x.size(); i++) {
+    output[i] = XPtr<S2Point>(new S2Point(x[i], y[i], z[i]));
+  }
+
+  return output;
+}
+
+// [[Rcpp::export]]
+List s2_point_from_s2_lnglat(List s2_lnglat) {
+  List output(s2_lnglat.size());
+
+  SEXP item;
+  S2Point newItem;
+  for (R_xlen_t i = 0; i < s2_lnglat.size(); i++) {
+    item = s2_lnglat[i];
+    if (item == R_NilValue) {
+      output[i] = R_NilValue;
+    } else {
+      XPtr<S2LatLng> ptr(item);
+      newItem = ptr->Normalized().ToPoint();
+      output[i] = XPtr<S2Point>(new S2Point(newItem));
+    }
+  }
+
+  return output;
+}
+
+// [[Rcpp::export]]
+List data_frame_from_s2_point(List s2_point) {
+  NumericVector x(s2_point.size());
+  NumericVector y(s2_point.size());
+  NumericVector z(s2_point.size());
+
+  SEXP item;
+  for (R_xlen_t i = 0; i < s2_point.size(); i++) {
+    item = s2_point[i];
+    if (item == R_NilValue) {
+      x[i] = NA_REAL;
+      y[i] = NA_REAL;
+      z[i] = NA_REAL;
+    } else {
+      XPtr<S2Point> ptr(item);
+      x[i] = ptr->x();
+      y[i] = ptr->y();
+      z[i] = ptr->z();
+    }
+  }
+
+  return List::create(_["x"] = x, _["y"] = y, _["z"] = z);
+}
diff --git a/src/s2-predicates.cpp b/src/s2-predicates.cpp
new file mode 100644 (file)
index 0000000..67aea0b
--- /dev/null
@@ -0,0 +1,231 @@
+
+#include "s2/s2boolean_operation.h"
+#include "s2/s2closest_edge_query.h"
+#include "s2/s2latlng_rect.h"
+#include "s2/s2polygon.h"
+#include "s2/s2testing.h"
+#include "s2/s2builderutil_snap_functions.h"
+
+#include "geography-operator.h"
+#include "s2-options.h"
+
+#include <Rcpp.h>
+using namespace Rcpp;
+
+class BinaryPredicateOperator: public BinaryGeographyOperator<LogicalVector, int> {
+public:
+  S2BooleanOperation::Options options;
+
+  BinaryPredicateOperator(List s2options) {
+    GeographyOperationOptions options(s2options);
+    this->options = options.booleanOperationOptions();
+  }
+};
+
+// [[Rcpp::export]]
+LogicalVector cpp_s2_intersects(List geog1, List geog2, List s2options) {
+  class Op: public BinaryPredicateOperator {
+  public:
+    Op(List s2options): BinaryPredicateOperator(s2options) {}
+    int processFeature(XPtr<Geography> feature1, XPtr<Geography> feature2, R_xlen_t i) {
+      return S2BooleanOperation::Intersects(
+        *feature1->ShapeIndex(),
+        *feature2->ShapeIndex(),
+        options
+      );
+    };
+  };
+
+  Op op(s2options);
+  return op.processVector(geog1, geog2);
+}
+
+// [[Rcpp::export]]
+LogicalVector cpp_s2_equals(List geog1, List geog2, List s2options) {
+  // for s2_equals(), handling polygon_model wouldn't make sense, right?
+  class Op: public BinaryPredicateOperator {
+  public:
+    Op(List s2options): BinaryPredicateOperator(s2options) {}
+    int processFeature(XPtr<Geography> feature1, XPtr<Geography> feature2, R_xlen_t i) {
+      return S2BooleanOperation::Equals(
+        *feature1->ShapeIndex(),
+        *feature2->ShapeIndex(),
+        this->options
+      );
+    }
+  };
+
+  Op op(s2options);
+  return op.processVector(geog1, geog2);
+}
+
+// [[Rcpp::export]]
+LogicalVector cpp_s2_contains(List geog1, List geog2, List s2options) {
+  class Op: public BinaryPredicateOperator {
+  public:
+    Op(List s2options): BinaryPredicateOperator(s2options) {}
+    int processFeature(XPtr<Geography> feature1, XPtr<Geography> feature2, R_xlen_t i) {
+      // by default Contains() will return true for Contains(x, EMPTY), which is
+      // not true in BigQuery or GEOS
+      if (feature2->IsEmpty()) {
+        return false;
+      } else {
+        return S2BooleanOperation::Contains(
+          *feature1->ShapeIndex(),
+          *feature2->ShapeIndex(),
+          this->options
+        );
+      }
+    }
+  };
+
+  Op op(s2options);
+  return op.processVector(geog1, geog2);
+}
+
+// [[Rcpp::export]]
+LogicalVector cpp_s2_touches(List geog1, List geog2, List s2options) {
+  class Op: public BinaryPredicateOperator {
+  public:
+    Op(List s2options): BinaryPredicateOperator(s2options) {
+      this->closedOptions = this->options;
+      this->closedOptions.set_polygon_model(S2BooleanOperation::PolygonModel::CLOSED);
+      this->closedOptions.set_polyline_model(S2BooleanOperation::PolylineModel::CLOSED);
+
+      this->openOptions = this->options;
+      this->openOptions.set_polygon_model(S2BooleanOperation::PolygonModel::OPEN);
+      this->openOptions.set_polyline_model(S2BooleanOperation::PolylineModel::OPEN);
+    }
+
+    int processFeature(XPtr<Geography> feature1, XPtr<Geography> feature2, R_xlen_t i) {
+      return S2BooleanOperation::Intersects(
+        *feature1->ShapeIndex(),
+        *feature2->ShapeIndex(),
+        this->closedOptions
+      ) &&
+        !S2BooleanOperation::Intersects(
+          *feature1->ShapeIndex(),
+          *feature2->ShapeIndex(),
+          this->openOptions
+        );
+    }
+
+  private:
+    S2BooleanOperation::Options closedOptions;
+    S2BooleanOperation::Options openOptions;
+  };
+
+  Op op(s2options);
+  return op.processVector(geog1, geog2);
+}
+
+// [[Rcpp::export]]
+LogicalVector cpp_s2_dwithin(List geog1, List geog2, NumericVector distance) {
+  if (distance.size() != geog1.size())  {
+    stop("Incompatible lengths"); // #nocov
+  }
+
+  class Op: public BinaryGeographyOperator<LogicalVector, int> {
+  public:
+    NumericVector distance;
+    Op(NumericVector distance): distance(distance) {}
+
+    int processFeature(XPtr<Geography> feature1, XPtr<Geography> feature2, R_xlen_t i) {
+      S2ClosestEdgeQuery query(feature1->ShapeIndex());
+      S2ClosestEdgeQuery::ShapeIndexTarget target(feature2->ShapeIndex());
+      return query.IsDistanceLessOrEqual(&target, S1ChordAngle::Radians(this->distance[i]));
+    }
+  };
+
+  Op op(distance);
+  return op.processVector(geog1, geog2);
+}
+
+// [[Rcpp::export]]
+LogicalVector cpp_s2_intersects_box(List geog,
+                                    NumericVector lng1, NumericVector lat1,
+                                    NumericVector lng2, NumericVector lat2,
+                                    IntegerVector detail,
+                                    List s2options) {
+
+  class Op: public UnaryGeographyOperator<LogicalVector, int> {
+  public:
+    NumericVector lng1, lat1, lng2, lat2;
+    IntegerVector detail;
+    S2BooleanOperation::Options options;
+
+    Op(NumericVector lng1, NumericVector lat1,
+       NumericVector lng2, NumericVector lat2,
+       IntegerVector detail, List s2options):
+      lng1(lng1), lat1(lat1), lng2(lng2), lat2(lat2), detail(detail) {
+
+      GeographyOperationOptions options(s2options);
+      this->options = options.booleanOperationOptions();
+    }
+
+    int processFeature(XPtr<Geography> feature, R_xlen_t i) {
+      // construct polygon
+      // this might be easier with an s2region intersection
+      double xmin = this->lng1[i];
+      double ymin = this->lat1[i];
+      double xmax = this->lng2[i];
+      double ymax = this->lat2[i];
+      int detail = this->detail[i];
+
+      if (detail < 1) {
+        stop("Can't create polygon from bounding box with detail < 1");
+      }
+
+      // can't just do xmax - xmin because these boxes can wrap around the date line
+      S2Point westEquator = S2LatLng::FromDegrees(0, xmin).Normalized().ToPoint();
+      S2Point eastEquator = S2LatLng::FromDegrees(0, xmax).Normalized().ToPoint();
+      S1ChordAngle width(westEquator, eastEquator);
+      double widthDegrees = width.degrees();
+      double deltaDegrees = widthDegrees / (double) detail;
+      double heightDegrees = ymax - ymin;
+
+      // these situations would result in an error below because of
+      // duplicate vertices
+      if (widthDegrees == 0 || heightDegrees == 0) {
+        return false;
+      }
+
+      // create polygon vertices
+      std::vector<S2Point> points(2 + 2 * detail);
+      S2LatLng vertex;
+
+      // south edge
+      for (int i = 0; i <= detail; i++) {
+        vertex = S2LatLng::FromDegrees(xmin + deltaDegrees * i, ymin).Normalized();
+        points[i] = vertex.ToPoint();
+      }
+
+      // north edge
+      for (int i = 0; i <= detail; i++) {
+        vertex = S2LatLng::FromDegrees(xmax - deltaDegrees * i, ymax).Normalized();
+        points[detail + 1 + i] = vertex.ToPoint();
+      }
+
+      // create polygon
+      std::unique_ptr<S2Loop> loop(new S2Loop());
+      loop->set_s2debug_override(S2Debug::DISABLE);
+      loop->Init(points);
+      loop->Normalize();
+
+      std::vector<std::unique_ptr<S2Loop>> loops(1);
+      loops[0] = std::move(loop);
+      S2Polygon polygon;
+      polygon.InitOriented(std::move(loops));
+
+      // test intersection
+      return S2BooleanOperation::Intersects(
+        polygon.index(),
+        *feature->ShapeIndex(),
+        this->options
+      );
+    }
+  };
+
+  Op op(lng1, lat1, lng2, lat2, detail, s2options);
+  return op.processVector(geog);
+}
diff --git a/src/s2-transformers.cpp b/src/s2-transformers.cpp
new file mode 100644 (file)
index 0000000..6aab3f8
--- /dev/null
@@ -0,0 +1,673 @@
+
+#include "s2/s2boolean_operation.h"
+#include "s2/s2closest_edge_query.h"
+#include "s2/s2polygon.h"
+#include "s2/s2polyline.h"
+#include "s2/s2point.h"
+#include "s2/s2error.h"
+#include "s2/s2boolean_operation.h"
+#include "s2/s2builder.h"
+#include "s2/s2builderutil_s2polygon_layer.h"
+#include "s2/s2builderutil_s2polyline_vector_layer.h"
+#include "s2/s2builderutil_s2point_vector_layer.h"
+#include "s2/s2builderutil_closed_set_normalizer.h"
+#include "s2/s2builderutil_snap_functions.h"
+#include "s2/s2shape_index_buffered_region.h"
+#include "s2/s2region_coverer.h"
+
+#include "s2-options.h"
+#include "geography-operator.h"
+#include "point-geography.h"
+#include "polyline-geography.h"
+#include "polygon-geography.h"
+#include "geography-collection.h"
+
+#include <Rcpp.h>
+using namespace Rcpp;
+
+std::unique_ptr<Geography> geographyFromLayers(std::vector<S2Point> points,
+                                               std::vector<std::unique_ptr<S2Polyline>> polylines,
+                                               std::unique_ptr<S2Polygon> polygon,
+                                               int dimensions) {
+  // count non-empty dimensions
+  bool has_polygon = (dimensions & GeographyOperationOptions::Dimension::POLYGON) &&
+    !polygon->is_empty();
+  bool has_polyline = (dimensions & GeographyOperationOptions::Dimension::POLYLINE) &&
+    (polylines.size() > 0);
+  bool has_points = (dimensions & GeographyOperationOptions::Dimension::POINT) &&
+    (points.size() > 0);
+  int nonEmptyDimensions = has_polygon + has_polyline + has_points;
+
+  // return empty output
+  if (nonEmptyDimensions == 0) {
+    return absl::make_unique<GeographyCollection>();
+  }
+
+  // return mixed dimension output
+  if (nonEmptyDimensions > 1) {
+    std::vector<std::unique_ptr<Geography>> features;
+
+    if (has_points) {
+      features.push_back(absl::make_unique<PointGeography>(std::move(points)));
+    }
+
+    if (has_polyline) {
+      features.push_back(absl::make_unique<PolylineGeography>(std::move(polylines)));
+    }
+
+    if (has_polygon) {
+      features.push_back(absl::make_unique<PolygonGeography>(std::move(polygon)));
+    }
+
+    return absl::make_unique<GeographyCollection>(std::move(features));
+  }
+
+  // return single dimension output
+  if (has_polygon) {
+    return absl::make_unique<PolygonGeography>(std::move(polygon));
+  } else if (has_polyline) {
+    return absl::make_unique<PolylineGeography>(std::move(polylines));
+  } else {
+    return absl::make_unique<PointGeography>(std::move(points));
+  }
+}
+
+std::unique_ptr<Geography> doBooleanOperation(S2ShapeIndex* index1, S2ShapeIndex* index2,
+                                              S2BooleanOperation::OpType opType,
+                                              S2BooleanOperation::Options options,
+                                              GeographyOperationOptions::LayerOptions layerOptions) {
+
+  // create the data structures that will contain the output
+  std::vector<S2Point> points;
+  std::vector<std::unique_ptr<S2Polyline>> polylines;
+  std::unique_ptr<S2Polygon> polygon = absl::make_unique<S2Polygon>();
+
+  s2builderutil::LayerVector layers(3);
+  layers[0] = absl::make_unique<s2builderutil::S2PointVectorLayer>(&points, layerOptions.pointLayerOptions);
+  layers[1] = absl::make_unique<s2builderutil::S2PolylineVectorLayer>(&polylines, layerOptions.polylineLayerOptions);
+  layers[2] = absl::make_unique<s2builderutil::S2PolygonLayer>(polygon.get(), layerOptions.polygonLayerOptions);
+
+  // do the boolean operation
+  S2BooleanOperation booleanOp(
+    opType,
+    // normalizing the closed set here is required for line intersections
+    // to work as expected
+    s2builderutil::NormalizeClosedSet(std::move(layers)),
+    options
+  );
+
+  // build and check for errors
+  S2Error error;
+  if (!booleanOp.Build(*index1, *index2, &error)) {
+    stop(error.text());
+  }
+
+  // construct output
+  return geographyFromLayers(
+    std::move(points),
+    std::move(polylines),
+    std::move(polygon),
+    layerOptions.dimensions
+  );
+}
+
+std::unique_ptr<Geography> rebuildGeography(S2ShapeIndex* index,
+                                            S2Builder::Options options,
+                                            GeographyOperationOptions::LayerOptions layerOptions) {
+  // create the builder
+  S2Builder builder(options);
+
+  // create the data structures that will contain the output
+  std::vector<S2Point> points;
+  std::vector<std::unique_ptr<S2Polyline>> polylines;
+  std::unique_ptr<S2Polygon> polygon = absl::make_unique<S2Polygon>();
+
+  // add shapes to the layer with the appropriate dimension
+  builder.StartLayer(
+    absl::make_unique<s2builderutil::S2PointVectorLayer>(&points, layerOptions.pointLayerOptions)
+  );
+  for (S2Shape* shape : *index) {
+    if (shape->dimension() == 0) {
+      builder.AddShape(*shape);
+    }
+  }
+
+  builder.StartLayer(
+    absl::make_unique<s2builderutil::S2PolylineVectorLayer>(&polylines, layerOptions.polylineLayerOptions)
+  );
+  for (S2Shape* shape : *index) {
+    if (shape->dimension() == 1) {
+      builder.AddShape(*shape);
+    }
+  }
+
+  builder.StartLayer(
+    absl::make_unique<s2builderutil::S2PolygonLayer>(polygon.get(), layerOptions.polygonLayerOptions)
+  );
+  for (S2Shape* shape : *index) {
+    if (shape->dimension() == 2) {
+      builder.AddShape(*shape);
+    }
+  }
+
+  // build the output
+  S2Error error;
+  if (!builder.Build(&error)) {
+    throw GeographyOperatorException(error.text());
+  }
+
+  // construct output
+  return geographyFromLayers(
+    std::move(points),
+    std::move(polylines),
+    std::move(polygon),
+    layerOptions.dimensions
+  );
+}
+
+class BooleanOperationOp: public BinaryGeographyOperator<List, SEXP> {
+public:
+  BooleanOperationOp(S2BooleanOperation::OpType opType, List s2options):
+    opType(opType) {
+      GeographyOperationOptions options(s2options);
+      this->options = options.booleanOperationOptions();
+      this->layerOptions = options.layerOptions();
+    }
+
+  SEXP processFeature(XPtr<Geography> feature1, XPtr<Geography> feature2, R_xlen_t i) {
+    std::unique_ptr<Geography> geography = doBooleanOperation(
+      feature1->ShapeIndex(),
+      feature2->ShapeIndex(),
+      this->opType,
+      this->options,
+      this->layerOptions
+    );
+
+    return Rcpp::XPtr<Geography>(geography.release());
+  }
+
+private:
+  S2BooleanOperation::OpType opType;
+  S2BooleanOperation::Options options;
+  GeographyOperationOptions::LayerOptions layerOptions;
+};
+
+// [[Rcpp::export]]
+List cpp_s2_intersection(List geog1, List geog2, List s2options) {
+  BooleanOperationOp op(S2BooleanOperation::OpType::INTERSECTION, s2options);
+  return op.processVector(geog1, geog2);
+}
+
+// [[Rcpp::export]]
+List cpp_s2_union(List geog1, List geog2, List s2options) {
+  BooleanOperationOp op(S2BooleanOperation::OpType::UNION, s2options);
+  return op.processVector(geog1, geog2);
+}
+
+// [[Rcpp::export]]
+List cpp_s2_difference(List geog1, List geog2, List s2options) {
+  BooleanOperationOp op(S2BooleanOperation::OpType::DIFFERENCE, s2options);
+  return op.processVector(geog1, geog2);
+}
+
+// [[Rcpp::export]]
+List cpp_s2_sym_difference(List geog1, List geog2, List s2options) {
+  BooleanOperationOp op(S2BooleanOperation::OpType::SYMMETRIC_DIFFERENCE, s2options);
+  return op.processVector(geog1, geog2);
+}
+
+// [[Rcpp::export]]
+List cpp_s2_coverage_union_agg(List geog, List s2options, bool naRm) {
+  GeographyOperationOptions options(s2options);
+
+  MutableS2ShapeIndex index;
+  SEXP item;
+  for (R_xlen_t i = 0; i < geog.size(); i++) {
+    item = geog[i];
+    if (item == R_NilValue && !naRm) {
+      return List::create(R_NilValue);
+    }
+
+    if (item != R_NilValue) {
+      Rcpp::XPtr<Geography> feature(item);
+      feature->BuildShapeIndex(&index);
+    }
+  }
+
+  MutableS2ShapeIndex emptyIndex;
+  std::unique_ptr<Geography> geography = doBooleanOperation(
+    &index,
+    &emptyIndex,
+    S2BooleanOperation::OpType::UNION,
+    options.booleanOperationOptions(),
+    options.layerOptions()
+  );
+
+  return List::create(Rcpp::XPtr<Geography>(geography.release()));
+}
+
+// This approach to aggregation is slow but accurate. There is probably a more efficient way
+// to accumulate geometries and/or re-use the layers vector but thus far I haven't figured
+// out a way to make that work.
+// [[Rcpp::export]]
+List cpp_s2_union_agg(List geog, List s2options, bool naRm) {
+  GeographyOperationOptions options(s2options);
+  GeographyOperationOptions::LayerOptions layerOptions = options.layerOptions();
+  S2BooleanOperation::Options unionOptions = options.booleanOperationOptions();
+  S2Builder::Options buillderOptions = options.builderOptions();
+
+  // using smart pointers here so that we can use swap() to
+  // use replace accumulatedIndex with index after each union
+  std::unique_ptr<MutableS2ShapeIndex> index = absl::make_unique<MutableS2ShapeIndex>();
+  std::unique_ptr<MutableS2ShapeIndex> accumulatedIndex = absl::make_unique<MutableS2ShapeIndex>();
+
+  SEXP item;
+  for (R_xlen_t i = 0; i < geog.size(); i++) {
+    item = geog[i];
+    if (item == R_NilValue && !naRm) {
+      return List::create(R_NilValue);
+    }
+
+    if (item != R_NilValue) {
+      Rcpp::XPtr<Geography> feature(item);
+
+      index->Clear();
+      s2builderutil::LayerVector layers(3);
+      layers[0] = absl::make_unique<s2builderutil::IndexedS2PointVectorLayer>(index.get(), layerOptions.pointLayerOptions);
+      layers[1] = absl::make_unique<s2builderutil::IndexedS2PolylineVectorLayer>(index.get(), layerOptions.polylineLayerOptions);
+      layers[2] = absl::make_unique<s2builderutil::IndexedS2PolygonLayer>(index.get(), layerOptions.polygonLayerOptions);
+
+      S2BooleanOperation booleanOp(
+        S2BooleanOperation::OpType::UNION,
+        s2builderutil::NormalizeClosedSet(std::move(layers)),
+        unionOptions
+      );
+
+      S2Error error;
+      if (!booleanOp.Build(*accumulatedIndex, *(feature->ShapeIndex()), &error)) {
+        stop(error.text());
+      }
+
+      accumulatedIndex.swap(index);
+    }
+  }
+
+  std::unique_ptr<Geography> geography = rebuildGeography(
+    accumulatedIndex.get(),
+    options.builderOptions(),
+    options.layerOptions()
+  );
+
+  return List::create(Rcpp::XPtr<Geography>(geography.release()));
+}
+
+// [[Rcpp::export]]
+List cpp_s2_centroid_agg(List geog, bool naRm) {
+  S2Point cumCentroid;
+
+  SEXP item;
+  for (R_xlen_t i = 0; i < geog.size(); i++) {
+    item = geog[i];
+    if (item == R_NilValue && !naRm) {
+      return List::create(R_NilValue);
+    }
+
+    if (item != R_NilValue) {
+      Rcpp::XPtr<Geography> feature(item);
+      S2Point centroid = feature->Centroid();
+      if (centroid.Norm2() > 0) {
+        cumCentroid += centroid.Normalize();
+      }
+    }
+  }
+
+  List output(1);
+  if (cumCentroid.Norm2() == 0) {
+    output[0] = Rcpp::XPtr<Geography>(new PointGeography());
+  } else {
+    output[0] = Rcpp::XPtr<Geography>(new PointGeography(cumCentroid.Normalize()));
+  }
+
+  return output;
+}
+
+// [[Rcpp::export]]
+List cpp_s2_rebuild_agg(List geog, List s2options, bool naRm) {
+  GeographyOperationOptions options(s2options);
+
+  MutableS2ShapeIndex index;
+  SEXP item;
+  for (R_xlen_t i = 0; i < geog.size(); i++) {
+    item = geog[i];
+    if (item == R_NilValue && !naRm) {
+      return List::create(R_NilValue);
+    }
+
+    if (item != R_NilValue) {
+      Rcpp::XPtr<Geography> feature(item);
+      feature->BuildShapeIndex(&index);
+    }
+  }
+
+  std::unique_ptr<Geography> geography = rebuildGeography(
+    &index,
+    options.builderOptions(),
+    options.layerOptions()
+  );
+
+  return List::create(Rcpp::XPtr<Geography>(geography.release()));
+}
+
+std::vector<S2Point> findClosestPoints(S2ShapeIndex* index1, S2ShapeIndex* index2) {
+      // see http://s2geometry.io/devguide/s2closestedgequery.html section on Modeling Accuracy:
+
+      // Find the edge from index2 that is closest to index1
+      S2ClosestEdgeQuery query1(index1);
+      query1.mutable_options()->set_include_interiors(false);
+      S2ClosestEdgeQuery::ShapeIndexTarget target1(index2);
+      auto result1 = query1.FindClosestEdge(&target1);
+
+      if (result1.edge_id() == -1) {
+        return std::vector<S2Point>();
+      }
+
+      // Get the edge from index1 (edge1) that is closest to index2.
+      S2Shape::Edge edge1 = query1.GetEdge(result1);
+
+      // Now find the edge from index2 (edge2) that is closest to edge1.
+      S2ClosestEdgeQuery query2(index2);
+      query2.mutable_options()->set_include_interiors(false);
+      S2ClosestEdgeQuery::EdgeTarget target2(edge1.v0, edge1.v1);
+      auto result2 = query2.FindClosestEdge(&target2);
+
+      // what if result2 has no edges?
+      if (result2.is_interior()) {
+        stop("S2ClosestEdgeQuery result is interior!");
+      }
+      S2Shape::Edge edge2 = query2.GetEdge(result2);
+
+      // Find the closest point pair on edge1 and edge2.
+      std::pair<S2Point, S2Point> closest = S2::GetEdgePairClosestPoints(
+        edge1.v0, edge1.v1,
+        edge2.v0, edge2.v1
+      );
+
+      std::vector<S2Point> pts(2);
+      pts[0] = closest.first;
+      pts[1] = closest.second;
+      return pts;
+}
+
+// [[Rcpp::export]]
+List cpp_s2_closest_point(List geog1, List geog2) {
+  class Op: public BinaryGeographyOperator<List, SEXP> {
+
+    SEXP processFeature(XPtr<Geography> feature1, XPtr<Geography> feature2, R_xlen_t i) {
+      std::vector<S2Point> pts = findClosestPoints(feature1->ShapeIndex(), feature2->ShapeIndex());
+
+      if (pts.size() == 0) {
+        return XPtr<Geography>(new PointGeography());
+      } else {
+        return XPtr<Geography>(new PointGeography(pts[0]));
+      }
+    }
+  };
+
+  Op op;
+  return op.processVector(geog1, geog2);
+}
+
+// [[Rcpp::export]]
+List cpp_s2_minimum_clearance_line_between(List geog1, List geog2) {
+  class Op: public BinaryGeographyOperator<List, SEXP> {
+
+    SEXP processFeature(XPtr<Geography> feature1, XPtr<Geography> feature2, R_xlen_t i) {
+      std::vector<S2Point> pts = findClosestPoints(feature1->ShapeIndex(), feature2->ShapeIndex());
+
+      if (pts.size() == 0) {
+        return XPtr<Geography>(new PolylineGeography());
+      } else if (pts[0] == pts[1]) {
+        return XPtr<Geography>(new PointGeography(pts));
+      } else {
+        std::unique_ptr<S2Polyline> polyline = absl::make_unique<S2Polyline>();
+        polyline->Init(pts);
+        std::vector<std::unique_ptr<S2Polyline>> polylines(1);
+        polylines[0] = std::move(polyline);
+        return XPtr<Geography>(new PolylineGeography(std::move(polylines)));
+      }
+    }
+  };
+
+  Op op;
+  return op.processVector(geog1, geog2);
+}
+
+// [[Rcpp::export]]
+List cpp_s2_centroid(List geog) {
+  class Op: public UnaryGeographyOperator<List, SEXP> {
+    SEXP processFeature(XPtr<Geography> feature, R_xlen_t i) {
+      S2Point centroid = feature->Centroid();
+      if (centroid.Norm2() == 0) {
+        return XPtr<Geography>(new PointGeography());
+      } else {
+        return XPtr<Geography>(new PointGeography(centroid.Normalize()));
+      }
+    }
+  };
+
+  Op op;
+  return op.processVector(geog);
+}
+
+// [[Rcpp::export]]
+List cpp_s2_boundary(List geog) {
+  class Op: public UnaryGeographyOperator<List, SEXP> {
+    SEXP processFeature(XPtr<Geography> feature, R_xlen_t i) {
+      std::unique_ptr<Geography> ptr = feature->Boundary();
+      return XPtr<Geography>(ptr.release());
+    }
+  };
+
+  Op op;
+  return op.processVector(geog);
+}
+
+// [[Rcpp::export]]
+List cpp_s2_rebuild(List geog, List s2options) {
+  class Op: public UnaryGeographyOperator<List, SEXP> {
+  public:
+    Op(List s2options) {
+      GeographyOperationOptions options(s2options);
+      this->options = options.builderOptions();
+      this->layerOptions = options.layerOptions();
+    }
+
+    SEXP processFeature(XPtr<Geography> feature, R_xlen_t i) {
+      std::unique_ptr<Geography> ptr = rebuildGeography(
+        feature->ShapeIndex(),
+        this->options,
+        this->layerOptions
+      );
+      return XPtr<Geography>(ptr.release());
+    }
+
+  private:
+    S2Builder::Options options;
+    GeographyOperationOptions::LayerOptions layerOptions;
+  };
+
+  Op op(s2options);
+  return op.processVector(geog);
+}
+
+// [[Rcpp::export]]
+List cpp_s2_unary_union(List geog, List s2options) {
+  class Op: public UnaryGeographyOperator<List, SEXP> {
+  public:
+    Op(List s2options) {
+      GeographyOperationOptions options(s2options);
+      this->options = options.booleanOperationOptions();
+      this->layerOptions = options.layerOptions();
+    }
+
+    SEXP processFeature(XPtr<Geography> feature, R_xlen_t i) {
+      // complex union only needed when a polygon is involved
+      bool simpleUnionOK = feature->IsEmpty() ||
+        (feature->Dimension() < 2);
+
+      // valid polygons that are not part of a collection can also use a
+      // simple union (common)
+      if (feature->GeographyType() == Geography::Type::GEOGRAPHY_POLYGON) {
+        S2Error validationError;
+        if(!(feature->Polygon()->FindValidationError(&validationError))) {
+          simpleUnionOK = true;
+        }
+      }
+
+      if (simpleUnionOK) {
+        MutableS2ShapeIndex emptyIndex;
+
+        std::unique_ptr<Geography> ptr = doBooleanOperation(
+          feature->ShapeIndex(),
+          &emptyIndex,
+          S2BooleanOperation::OpType::UNION,
+          this->options,
+          this->layerOptions
+        );
+
+        return XPtr<Geography>(ptr.release());
+      } else if (feature->GeographyType() == Geography::Type::GEOGRAPHY_POLYGON) {
+        // If we've made it here we have an invalid polygon on our hands. A geography with
+        // invalid loops won't work with the S2BooleanOperation we will use to accumulate
+        // (i.e., union) valid polygons, so we need to rebuild each loop as its own polygon,
+        // splitting crossed edges along the way.
+        const S2Polygon* originalPoly = feature->Polygon();
+
+        // Not exposing these options as an argument (except snap function)
+        // because a particular combiation of them is required for this to work
+        S2Builder::Options builderOptions;
+        builderOptions.set_split_crossing_edges(true);
+        builderOptions.set_snap_function(this->options.snap_function());
+        s2builderutil::S2PolygonLayer::Options layerOptions;
+        layerOptions.set_edge_type(S2Builder::EdgeType::UNDIRECTED);
+        layerOptions.set_validate(false);
+
+        // Rebuild all loops as polygons using the S2Builder()
+        std::vector<std::unique_ptr<S2Polygon>> loops;
+        for (int i = 0; i < originalPoly->num_loops(); i++) {
+          std::unique_ptr<S2Polygon> loop = absl::make_unique<S2Polygon>();
+          S2Builder builder(builderOptions);
+          builder.StartLayer(absl::make_unique<s2builderutil::S2PolygonLayer>(loop.get()));
+          builder.AddShape(S2Loop::Shape(originalPoly->loop(i)));
+          S2Error error;
+          if (!builder.Build(&error)) {
+            throw GeographyOperatorException(error.text());
+          }
+
+          // Check if the builder created a polygon whose boundary contained more than
+          // half the earth (and invert it if so)
+          if (loop->GetArea() > (2 * M_PI)) {
+            loop->Invert();
+          }
+
+          loops.push_back(std::move(loop));
+        }
+
+        // Accumulate the union of outer loops (but difference of inner loops)
+        std::unique_ptr<S2Polygon> accumulatedPolygon = absl::make_unique<S2Polygon>();
+        for (int i = 0; i < originalPoly->num_loops(); i++) {
+          std::unique_ptr<S2Polygon> polygonResult = absl::make_unique<S2Polygon>();
+
+          // Use original nesting to suggest if this loop should be unioned or diffed.
+          // For valid polygons loops are arranged such that the biggest loop is on the outside
+          // followed by holes such that the below strategy should work (since we are
+          // just iterating along the original loop structure)
+          if ((originalPoly->loop(i)->depth() % 2) == 0) {
+            polygonResult->InitToUnion(accumulatedPolygon.get(), loops[i].get());
+          } else {
+            polygonResult->InitToDifference(accumulatedPolygon.get(), loops[i].get());
+          }
+
+          accumulatedPolygon.swap(polygonResult);
+        }
+
+        return XPtr<Geography>(new PolygonGeography(std::move(accumulatedPolygon)));
+      } else {
+        // This is a less common case (mixed dimension output that includes a polygon).
+        // In the absence of a clean solution, saving this battle for another day.
+        throw GeographyOperatorException("Unary union for collections is not implemented");
+      }
+    }
+
+  private:
+    S2BooleanOperation::Options options;
+    GeographyOperationOptions::LayerOptions layerOptions;
+  };
+
+  Op op(s2options);
+  return op.processVector(geog);
+}
+
+// [[Rcpp::export]]
+List cpp_s2_interpolate_normalized(List geog, NumericVector distanceNormalized) {
+  class Op: public UnaryGeographyOperator<List, SEXP> {
+  public:
+    NumericVector distanceNormalized;
+    Op(NumericVector distanceNormalized): distanceNormalized(distanceNormalized) {}
+    SEXP processFeature(XPtr<Geography> feature, R_xlen_t i) {
+      if (NumericVector::is_na(this->distanceNormalized[i])) {
+        return R_NilValue;
+      }
+
+      if (feature->IsCollection()) {
+        throw GeographyOperatorException("`x` must be a simple geography");
+      }
+
+      if (feature->IsEmpty()) {
+        return R_NilValue;
+      }
+
+      if (feature->GeographyType() == Geography::Type::GEOGRAPHY_POLYLINE) {
+        S2Point point = feature->Polyline()->at(0)->Interpolate(this->distanceNormalized[i]);
+        return XPtr<PointGeography>(new PointGeography(point));
+      } else {
+        throw GeographyOperatorException("`x` must be a polyline geography");
+      }
+    }
+  };
+
+  Op op(distanceNormalized);
+  return op.processVector(geog);
+}
+
+// [[Rcpp::export]]
+List cpp_s2_buffer_cells(List geog, NumericVector distance, int maxCells, int minLevel) {
+  class Op: public UnaryGeographyOperator<List, SEXP> {
+  public:
+    NumericVector distance;
+    S2RegionCoverer coverer;
+
+    Op(NumericVector distance, int maxCells, int minLevel): distance(distance) {
+      this->coverer.mutable_options()->set_max_cells(maxCells);
+      if (minLevel > 0) {
+        this->coverer.mutable_options()->set_min_level(minLevel);
+      }
+    }
+
+    SEXP processFeature(XPtr<Geography> feature, R_xlen_t i) {
+      S2ShapeIndexBufferedRegion region;
+      region.Init(feature->ShapeIndex(), S1ChordAngle::Radians(this->distance[i]));
+
+      S2CellUnion cellUnion;
+      cellUnion = coverer.GetCovering(region);
+
+      std::unique_ptr<S2Polygon> polygon = absl::make_unique<S2Polygon>();
+      polygon->InitToCellUnionBorder(cellUnion);
+
+      return XPtr<PolygonGeography>(new PolygonGeography(std::move(polygon)));
+    }
+  };
+
+  Op op(distance, maxCells, minLevel);
+  return op.processVector(geog);
+}
diff --git a/src/s2-xptr.cpp b/src/s2-xptr.cpp
new file mode 100644 (file)
index 0000000..ba39a21
--- /dev/null
@@ -0,0 +1,50 @@
+#include <Rcpp.h>
+using namespace Rcpp;
+
+class XPtrTest {
+public:
+  XPtrTest() {
+    try {
+      Rcout << "Allocating XPtrTest at " << this << "\n";
+    } catch (std::exception& error) {
+
+    }
+  }
+
+  void test() {
+    Rcout << "test() on XPtrTest at " << this << "\n";
+  }
+
+  ~XPtrTest() {
+    try {
+      Rcout << "Destroying XPtrTest at " << this << "\n";
+    } catch (std::exception& error) {
+
+    }
+  }
+};
+
+// [[Rcpp::export]]
+List s2_xptr_test(R_xlen_t size) {
+  List output(size);
+  for (R_xlen_t i = 0; i < size; i++) {
+    output[i] = XPtr<XPtrTest>(new XPtrTest());
+  }
+  return output;
+}
+
+// [[Rcpp::export]]
+void s2_xptr_test_op(List s2_xptr_test) {
+  SEXP item;
+  for (R_xlen_t i = 0; i < s2_xptr_test.size(); i++) {
+    item = s2_xptr_test[i];
+    if (item == R_NilValue) {
+      Rcout << "Item is NULL\n";
+    } else  {
+      // the general idea is to make sure that this operation doesn't copy
+      // the pointer or cause it to get destroyed
+      XPtr<XPtrTest> ptr(item);
+      ptr->test();
+    }
+  }
+}
diff --git a/src/s2/_fp_contract_off.h b/src/s2/_fp_contract_off.h
new file mode 100644 (file)
index 0000000..a053c7a
--- /dev/null
@@ -0,0 +1,60 @@
+// Copyright 2015 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// Author: ericv@google.com (Eric Veach)
+
+#ifndef S2__FP_CONTRACT_OFF_H_
+#define S2__FP_CONTRACT_OFF_H_
+
+// Turn off the fused multiply-add optimization ("fp-contract").  With
+// fp-contract on, any expression of the form "a * b + c" has two possible
+// results, and the compiler is free to choose either of them.  Effectively
+// this makes it impossible to write deterministic functions that involve
+// floating-point math.
+//
+// S2 requires deterministic arithmetic for correctness.  We need to turn off
+// fp-contract for the entire compilation unit, because S2 has public inline
+// functions, and the optimization is controlled by the setting in effect when
+// inline functions are instantiated (not when they are defined).
+//
+// Note that there is a standard C pragma to turn off FP contraction:
+//   #pragma STDC FP_CONTRACT OFF
+// but it is not implemented in GCC because the standard pragma allows control
+// at the level of compound statements rather than entire functions.
+//
+// This file may be included with other files in any order, as long as it
+// appears before the first non-inline function definition.  It is
+// named with an underscore so that it is included first among the S2 headers.
+
+// TODO(compiler-team): Figure out how to do this in a portable way.
+#if defined(HAVE_ARMEABI_V7A)
+// Some android builds use a buggy compiler that runs out of memory while
+// parsing the pragma (--cpu=armeabi-v7a).
+
+#elif defined(__ANDROID__)
+// Other android builds use a buggy compiler that crashes with an internal
+// error (Android NDK R9).
+
+#elif defined(__clang__)
+// Clang supports the standard C++ pragma for turning off this optimization.
+#pragma STDC FP_CONTRACT OFF
+
+#elif defined(__GNUC__)
+// GCC defines its own pragma that operates at the function level rather than
+// the statement level.
+#pragma GCC optimize("fp-contract=off")
+#endif
+
+#endif  // S2__FP_CONTRACT_OFF_H_
diff --git a/src/s2/base/casts.h b/src/s2/base/casts.h
new file mode 100644 (file)
index 0000000..84880c7
--- /dev/null
@@ -0,0 +1,318 @@
+// Copyright 2009 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+
+//
+// Various Google-specific casting templates.
+//
+// This code is compiled directly on many platforms, including client
+// platforms like Windows, Mac, and embedded systems.  Before making
+// any changes here, make sure that you're not breaking any platforms.
+//
+
+#ifndef S2_BASE_CASTS_H_
+#define S2_BASE_CASTS_H_
+
+#include <cassert>         // for use with down_cast<>
+#include <climits>         // for enumeration casts and tests
+#include <type_traits>
+
+#include "absl/base/casts.h"
+#include "absl/base/macros.h"
+
+// An "upcast", i.e. a conversion from a pointer to an object to a pointer to a
+// base subobject, always succeeds if the base is unambiguous and accessible,
+// and so it's fine to use implicit_cast.
+//
+// A "downcast", i.e. a conversion from a pointer to an object to a pointer
+// to a more-derived object that may contain the original object as a base
+// subobject, cannot safely be done using static_cast, because you do not
+// generally know whether the source object is really the base subobject of
+// a containing, more-derived object of the target type. Thus, when you
+// downcast in a polymorphic type hierarchy, you should use the following
+// function template.
+//
+// In debug mode, we use dynamic_cast to double-check whether the downcast is
+// legal (we die if it's not). In normal mode, we do the efficient static_cast
+// instead. Thus, it's important to test in debug mode to make sure the cast is
+// legal!
+//
+// This is the only place in the codebase we should use dynamic_cast.
+// In particular, you should NOT use dynamic_cast for RTTI, e.g. for
+// code like this:
+//    if (auto* p = dynamic_cast<Subclass1*>(foo)) HandleASubclass1Object(p);
+//    if (auto* p = dynamic_cast<Subclass2*>(foo)) HandleASubclass2Object(p);
+// You should design the code some other way not to need this.
+
+template<typename To, typename From>     // use like this: down_cast<T*>(foo);
+inline To down_cast(From* f) {           // so we only accept pointers
+  static_assert(
+      (std::is_base_of<From, typename std::remove_pointer<To>::type>::value),
+      "target type not derived from source type");
+
+  // We skip the assert and hence the dynamic_cast if RTTI is disabled.
+#if !defined(__GNUC__) || defined(__GXX_RTTI)
+  // Uses RTTI in dbg and fastbuild. asserts are disabled in opt builds.
+  assert(f == nullptr || dynamic_cast<To>(f) != nullptr);
+#endif  // !defined(__GNUC__) || defined(__GXX_RTTI)
+
+  return static_cast<To>(f);
+}
+
+// Overload of down_cast for references. Use like this: down_cast<T&>(foo).
+// The code is slightly convoluted because we're still using the pointer
+// form of dynamic cast. (The reference form throws an exception if it
+// fails.)
+//
+// There's no need for a special const overload either for the pointer
+// or the reference form. If you call down_cast with a const T&, the
+// compiler will just bind From to const T.
+template<typename To, typename From>
+inline To down_cast(From& f) {
+  static_assert(
+      std::is_lvalue_reference<To>::value, "target type not a reference");
+  static_assert(
+      (std::is_base_of<From, typename std::remove_reference<To>::type>::value),
+      "target type not derived from source type");
+
+  // We skip the assert and hence the dynamic_cast if RTTI is disabled.
+#if !defined(__GNUC__) || defined(__GXX_RTTI)
+  // RTTI: debug mode only
+  assert(dynamic_cast<typename std::remove_reference<To>::type*>(&f) !=
+         nullptr);
+#endif  // !defined(__GNUC__) || defined(__GXX_RTTI)
+
+  return static_cast<To>(f);
+}
+
+// **** Enumeration Casts and Tests
+//
+// C++ requires that the value of an integer that is converted to an
+// enumeration be within the value bounds of the enumeration.  Modern
+// compilers can and do take advantage of this requirement to optimize
+// programs.  So, using a raw static_cast with enums can be bad.  See
+//
+// The following templates and macros enable casting from an int to an enum
+// with checking against the appropriate bounds.  First, when defining an
+// enumeration, identify the limits of the values of its enumerators.
+//
+//   enum A { A_min = -18, A_max = 33 };
+//   MAKE_ENUM_LIMITS(A, A_min, A_max)
+//
+// Convert an int to an enum in one of two ways.  The prefered way is a
+// tight conversion, which ensures that A_min <= value <= A_max.
+//
+//   A var = tight_enum_cast<A>(3);
+//
+// However, the C++ language defines the set of possible values for an
+// enumeration to be essentially the range of a bitfield that can represent
+// all the enumerators, i.e. those within the nearest containing power
+// of two.  In the example above, the nearest positive power of two is 64,
+// and so the upper bound is 63.  The nearest negative power of two is
+// -32 and so the lower bound is -32 (two's complement), which is upgraded
+// to match the upper bound, becoming -64.  The values within this range
+// of -64 to 63 are valid, according to the C++ standard.  You can cast
+// values within this range as follows.
+//
+//   A var = loose_enum_cast<A>(45);
+//
+// These casts will log a message if the value does not reside within the
+// specified range, and will be fatal when in debug mode.
+//
+// For those times when an assert too strong, there are test functions.
+//
+//   bool var = tight_enum_test<A>(3);
+//   bool var = loose_enum_test<A>(45);
+//
+// For code that needs to use the enumeration value if and only if
+// it is good, there is a function that both tests and casts.
+//
+//   int i = ....;
+//   A var;
+//   if (tight_enum_test_cast<A>(i, &var))
+//     .... // use valid var with value as indicated by i
+//   else
+//     .... // handle invalid enum cast
+//
+// The enum test/cast facility is currently limited to enumerations that
+// fit within an int.  It is also limited to two's complement ints.
+
+// ** Implementation Description
+//
+// The enum_limits template class captures the minimum and maximum
+// enumerator.  All uses of this template are intended to be of
+// specializations, so the generic has a field to identify itself as
+// not specialized.  The test/cast templates assert specialization.
+
+template <typename Enum>
+class enum_limits {
+ public:
+  static const Enum min_enumerator = 0;
+  static const Enum max_enumerator = 0;
+  static const bool is_specialized = false;
+};
+
+// Now we define the macro to define the specialization for enum_limits.
+// The specialization checks that the enumerators fit within an int.
+// This checking relies on integral promotion.
+
+#define MAKE_ENUM_LIMITS(ENUM_TYPE, ENUM_MIN, ENUM_MAX) \
+template <> \
+class enum_limits<ENUM_TYPE> { \
+public: \
+  static const ENUM_TYPE min_enumerator = ENUM_MIN; \
+  static const ENUM_TYPE max_enumerator = ENUM_MAX; \
+  static const bool is_specialized = true; \
+  static_assert(ENUM_MIN >= INT_MIN, "enumerator too negative for int"); \
+  static_assert(ENUM_MAX <= INT_MAX, "enumerator too positive for int"); \
+};
+
+// The loose enum test/cast is actually the more complicated one,
+// because of the problem of finding the bounds.
+//
+// The unary upper bound, ub, on a positive number is its positive
+// saturation, i.e. for a value v within pow(2,k-1) <= v < pow(2,k),
+// the upper bound is pow(2,k)-1.
+//
+// The unary lower bound, lb, on a negative number is its negative
+// saturation, i.e. for a value v within -pow(2,k) <= v < -pow(2,k-1),
+// the lower bound is -pow(2,k).
+//
+// The actual bounds are (1) the binary upper bound over the maximum
+// enumerator and the one's complement of a negative minimum enumerator
+// and (2) the binary lower bound over the minimum enumerator and the
+// one's complement of the positive maximum enumerator, except that if no
+// enumerators are negative, the lower bound is zero.
+//
+// The algorithm relies heavily on the observation that
+//
+//   a,b>0 then ub(a,b) == ub(a) | ub(b) == ub(a|b)
+//   a,b<0 then lb(a,b) == lb(a) & lb(b) == lb(a&b)
+//
+// Note that the compiler will boil most of this code away
+// because of value propagation on the constant enumerator bounds.
+
+template <typename Enum>
+inline bool loose_enum_test(int e_val) {
+  static_assert(enum_limits<Enum>::is_specialized, "missing MAKE_ENUM_LIMITS");
+  const Enum e_min = enum_limits<Enum>::min_enumerator;
+  const Enum e_max = enum_limits<Enum>::max_enumerator;
+  static_assert(sizeof(e_val) == 4 || sizeof(e_val) == 8,
+                "unexpected int size");
+
+  // Find the unary bounding negative number of e_min and e_max.
+
+  // Find the unary bounding negative number of e_max.
+  // This would be b_min = e_max < 0 ? e_max : ~e_max,
+  // but we want to avoid branches to help the compiler.
+  int e_max_sign = e_max >> (sizeof(e_val)*8 - 1);
+  int b_min = ~e_max_sign ^ e_max;
+
+  // Find the binary bounding negative of both e_min and e_max.
+  b_min &= e_min;
+
+  // However, if e_min is positive, the result will be positive.
+  // Now clear all bits right of the most significant clear bit,
+  // which is a negative saturation for negative numbers.
+  // In the case of positive numbers, this is flush to zero.
+  b_min &= b_min >> 1;
+  b_min &= b_min >> 2;
+  b_min &= b_min >> 4;
+  b_min &= b_min >> 8;
+  b_min &= b_min >> 16;
+#if INT_MAX > 2147483647
+  b_min &= b_min >> 32;
+#endif
+
+  // Find the unary bounding positive number of e_max.
+  int b_max = e_max_sign ^ e_max;
+
+  // Find the binary bounding positive number of that
+  // and the unary bounding positive number of e_min.
+  int e_min_sign = e_min >> (sizeof(e_val)*8 - 1);
+  b_max |= e_min_sign ^ e_min;
+
+  // Now set all bits right of the most significant set bit,
+  // which is a positive saturation for positive numbers.
+  b_max |= b_max >> 1;
+  b_max |= b_max >> 2;
+  b_max |= b_max >> 4;
+  b_max |= b_max >> 8;
+  b_max |= b_max >> 16;
+#if INT_MAX > 2147483647
+  b_max |= b_max >> 32;
+#endif
+
+  // Finally test the bounds.
+  return b_min <= e_val && e_val <= b_max;
+}
+
+template <typename Enum>
+inline bool tight_enum_test(int e_val) {
+  static_assert(enum_limits<Enum>::is_specialized, "missing MAKE_ENUM_LIMITS");
+  const Enum e_min = enum_limits<Enum>::min_enumerator;
+  const Enum e_max = enum_limits<Enum>::max_enumerator;
+  return e_min <= e_val && e_val <= e_max;
+}
+
+template <typename Enum>
+inline bool loose_enum_test_cast(int e_val, Enum* e_var) {
+  if (loose_enum_test<Enum>(e_val)) {
+     *e_var = static_cast<Enum>(e_val);
+     return true;
+  } else {
+     return false;
+  }
+}
+
+template <typename Enum>
+inline bool tight_enum_test_cast(int e_val, Enum* e_var) {
+  if (tight_enum_test<Enum>(e_val)) {
+     *e_var = static_cast<Enum>(e_val);
+     return true;
+  } else {
+     return false;
+  }
+}
+
+// The plain casts require logging, and we get header recursion if
+// it is done directly.  So, we do it indirectly.
+// The following function is defined in logging.cc.
+
+namespace base {
+namespace internal {
+
+void WarnEnumCastError(int value_of_int);
+
+}  // namespace internal
+}  // namespace base
+
+template <typename Enum>
+inline Enum loose_enum_cast(int e_val) {
+  if (!loose_enum_test<Enum>(e_val)) {
+    base::internal::WarnEnumCastError(e_val);
+  }
+  return static_cast<Enum>(e_val);
+}
+
+template <typename Enum>
+inline Enum tight_enum_cast(int e_val) {
+  if (!tight_enum_test<Enum>(e_val)) {
+    base::internal::WarnEnumCastError(e_val);
+  }
+  return static_cast<Enum>(e_val);
+}
+
+#endif  // S2_BASE_CASTS_H_
diff --git a/src/s2/base/commandlineflags.h b/src/s2/base/commandlineflags.h
new file mode 100644 (file)
index 0000000..1763be0
--- /dev/null
@@ -0,0 +1,51 @@
+// Copyright Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#ifndef S2_BASE_COMMANDLINEFLAGS_H_
+#define S2_BASE_COMMANDLINEFLAGS_H_
+
+#ifdef S2_USE_GFLAGS
+
+#include <gflags/gflags.h>
+
+#else  // !defined(S2_USE_GFLAGS)
+
+#include <string>
+
+#include "s2/base/integral_types.h"
+
+#define DEFINE_bool(name, default_value, description) \
+  bool FLAGS_##name = default_value
+#define DECLARE_bool(name) \
+  extern bool FLAGS_##name
+
+#define DEFINE_double(name, default_value, description) \
+  double FLAGS_##name = default_value
+#define DECLARE_double(name) \
+  extern double FLAGS_##name
+
+#define DEFINE_int32(name, default_value, description) \
+  int32 FLAGS_##name = default_value
+#define DECLARE_int32(name) \
+  extern int32 FLAGS_##name
+
+#define DEFINE_string(name, default_value, description) \
+  std::string FLAGS_##name = default_value
+#define DECLARE_string(name) \
+  extern std::string FLAGS_##name
+
+#endif  // !defined(S2_USE_GFLAGS)
+
+#endif  // S2_BASE_COMMANDLINEFLAGS_H_
diff --git a/src/s2/base/integral_types.h b/src/s2/base/integral_types.h
new file mode 100644 (file)
index 0000000..d20f35f
--- /dev/null
@@ -0,0 +1,31 @@
+// Copyright 2018 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#ifndef S2_BASE_INTEGRAL_TYPES_H_
+#define S2_BASE_INTEGRAL_TYPES_H_
+
+using int8 = signed char;
+using int16 = short;
+using int32 = int;
+using int64 = long long;
+
+using uint8 = unsigned char;
+using uint16 = unsigned short;
+using uint32 = unsigned int;
+using uint64 = unsigned long long;
+
+using uword_t = unsigned long;
+
+#endif  // S2_BASE_INTEGRAL_TYPES_H_
diff --git a/src/s2/base/log_severity.h b/src/s2/base/log_severity.h
new file mode 100644 (file)
index 0000000..b0e9de3
--- /dev/null
@@ -0,0 +1,40 @@
+// Copyright Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#ifndef S2_BASE_LOG_SEVERITY_H_
+#define S2_BASE_LOG_SEVERITY_H_
+
+#ifdef S2_USE_GLOG
+
+#include <glog/log_severity.h>
+
+#else  // !defined(S2_USE_GLOG)
+
+#include "absl/base/log_severity.h"
+
+// Stay compatible with glog.
+namespace google {
+
+#ifdef NDEBUG
+constexpr bool DEBUG_MODE = false;
+#else
+constexpr bool DEBUG_MODE = true;
+#endif
+
+}  // namespace google
+
+#endif  // !defined(S2_USE_GLOG)
+
+#endif  // S2_BASE_LOG_SEVERITY_H_
diff --git a/src/s2/base/logging.h b/src/s2/base/logging.h
new file mode 100644 (file)
index 0000000..d32b611
--- /dev/null
@@ -0,0 +1,177 @@
+// Copyright Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#ifndef S2_BASE_LOGGING_H_
+#define S2_BASE_LOGGING_H_
+#include "cpp-compat.h"
+
+#ifdef S2_USE_GLOG
+
+#include <glog/logging.h>
+
+// The names CHECK, etc. are too common and may conflict with other
+// packages.  We use S2_CHECK to make it easier to switch to
+// something other than GLOG for logging.
+
+#define S2_LOG LOG
+#define S2_LOG_IF LOG_IF
+#define S2_DLOG_IF DLOG_IF
+
+#define S2_CHECK CHECK
+#define S2_CHECK_EQ CHECK_EQ
+#define S2_CHECK_NE CHECK_NE
+#define S2_CHECK_LT CHECK_LT
+#define S2_CHECK_LE CHECK_LE
+#define S2_CHECK_GT CHECK_GT
+#define S2_CHECK_GE CHECK_GE
+
+#define S2_DCHECK DCHECK
+#define S2_DCHECK_EQ DCHECK_EQ
+#define S2_DCHECK_NE DCHECK_NE
+#define S2_DCHECK_LT DCHECK_LT
+#define S2_DCHECK_LE DCHECK_LE
+#define S2_DCHECK_GT DCHECK_GT
+#define S2_DCHECK_GE DCHECK_GE
+
+#define S2_VLOG VLOG
+#define S2_VLOG_IS_ON VLOG_IS_ON
+
+#else  // !defined(S2_USE_GLOG)
+
+#include <iostream>
+
+#include "s2/base/log_severity.h"
+#include "absl/base/attributes.h"
+#include "absl/base/log_severity.h"
+
+class S2LogMessage {
+ public:
+  S2LogMessage(const char* file, int line,
+               absl::LogSeverity severity, std::ostream& stream)
+    : severity_(severity), stream_(stream) {
+    if (enabled()) {
+      stream_ << file << ":" << line << " "
+              << absl::LogSeverityName(severity) << " ";
+    }
+  }
+  ~S2LogMessage() { if (enabled()) stream_ << std::endl; }
+
+  std::ostream& stream() { return stream_; }
+
+  // silences an 'unused member' compiler warning
+  absl::LogSeverity severity() { return severity_; }
+
+ private:
+  bool enabled() const {
+#ifdef ABSL_MIN_LOG_LEVEL
+    return (static_cast<int>(severity_) >= ABSL_MIN_LOG_LEVEL ||
+            severity_ >= absl::LogSeverity::kFatal);
+#else
+    return true;
+#endif
+  }
+
+  absl::LogSeverity severity_;
+  std::ostream& stream_;
+};
+
+// Same as S2LogMessage, but destructor is marked no-return to avoid
+// "no return value warnings" in functions that return non-void.
+class S2FatalLogMessage : public S2LogMessage {
+ public:
+  S2FatalLogMessage(const char* file, int line,
+                    absl::LogSeverity severity, std::ostream& stream)
+      ABSL_ATTRIBUTE_COLD
+    : S2LogMessage(file, line, severity, stream) {}
+  ABSL_ATTRIBUTE_NORETURN ~S2FatalLogMessage() { cpp_compat_abort(); }
+};
+
+// Logging stream that does nothing.
+struct S2NullStream {
+  template <typename T>
+  S2NullStream& operator<<(const T& v) { return *this; }
+};
+
+// Used to suppress "unused value" warnings.
+struct S2LogMessageVoidify {
+  // Must have precedence lower than << but higher than ?:.
+  void operator&(std::ostream&) {}
+};
+
+#define S2_LOG_MESSAGE_(LogMessageClass, log_severity) \
+    LogMessageClass(__FILE__, __LINE__, log_severity, cpp_compat_cerr)
+#define S2_LOG_INFO \
+    S2_LOG_MESSAGE_(S2LogMessage, absl::LogSeverity::kInfo)
+#define S2_LOG_WARNING \
+    S2_LOG_MESSAGE_(S2LogMessage, absl::LogSeverity::kWarning)
+#define S2_LOG_ERROR \
+    S2_LOG_MESSAGE_(S2LogMessage, absl::LogSeverity::kError)
+#define S2_LOG_FATAL \
+    S2_LOG_MESSAGE_(S2FatalLogMessage, absl::LogSeverity::kFatal)
+#ifndef NDEBUG
+#define S2_LOG_DFATAL S2_LOG_FATAL
+#else
+#define S2_LOG_DFATAL S2_LOG_ERROR
+#endif
+
+#define S2_LOG(severity) S2_LOG_##severity.stream()
+
+// Implementing this as if (...) {} else S2_LOG(...) will cause dangling else
+// warnings when someone does if (...) S2_LOG_IF(...), so do this tricky
+// thing instead.
+#define S2_LOG_IF(severity, condition) \
+    !(condition) ? (void)0 : S2LogMessageVoidify() & S2_LOG(severity)
+
+#define S2_CHECK(condition) \
+    S2_LOG_IF(FATAL, ABSL_PREDICT_FALSE(!(condition))) \
+        << ("Check failed: " #condition " ")
+
+#ifndef NDEBUG
+
+#define S2_DLOG_IF S2_LOG_IF
+#define S2_DCHECK S2_CHECK
+
+#else  // defined(NDEBUG)
+
+#define S2_DLOG_IF(severity, condition) \
+    while (false && (condition)) S2NullStream()
+#define S2_DCHECK(condition) \
+    while (false && (condition)) S2NullStream()
+
+#endif  // defined(NDEBUG)
+
+#define S2_CHECK_OP(op, val1, val2) S2_CHECK((val1) op (val2))
+#define S2_CHECK_EQ(val1, val2) S2_CHECK_OP(==, val1, val2)
+#define S2_CHECK_NE(val1, val2) S2_CHECK_OP(!=, val1, val2)
+#define S2_CHECK_LT(val1, val2) S2_CHECK_OP(<, val1, val2)
+#define S2_CHECK_LE(val1, val2) S2_CHECK_OP(<=, val1, val2)
+#define S2_CHECK_GT(val1, val2) S2_CHECK_OP(>, val1, val2)
+#define S2_CHECK_GE(val1, val2) S2_CHECK_OP(>=, val1, val2)
+
+#define S2_DCHECK_OP(op, val1, val2) S2_DCHECK((val1) op (val2))
+#define S2_DCHECK_EQ(val1, val2) S2_DCHECK_OP(==, val1, val2)
+#define S2_DCHECK_NE(val1, val2) S2_DCHECK_OP(!=, val1, val2)
+#define S2_DCHECK_LT(val1, val2) S2_DCHECK_OP(<, val1, val2)
+#define S2_DCHECK_LE(val1, val2) S2_DCHECK_OP(<=, val1, val2)
+#define S2_DCHECK_GT(val1, val2) S2_DCHECK_OP(>, val1, val2)
+#define S2_DCHECK_GE(val1, val2) S2_DCHECK_OP(>=, val1, val2)
+
+// We don't support VLOG.
+#define S2_VLOG(verbose_level) S2NullStream()
+#define S2_VLOG_IS_ON(verbose_level) (false)
+
+#endif  // !defined(S2_USE_GLOG)
+
+#endif  // S2_BASE_LOGGING_H_
diff --git a/src/s2/base/mutex.h b/src/s2/base/mutex.h
new file mode 100644 (file)
index 0000000..031d21e
--- /dev/null
@@ -0,0 +1,61 @@
+// Copyright Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#ifndef S2_BASE_MUTEX_H_
+#define S2_BASE_MUTEX_H_
+
+#include <condition_variable>
+#include <mutex>
+
+namespace absl {
+
+class Mutex {
+ public:
+  Mutex() = default;
+  ~Mutex() = default;
+  Mutex(Mutex const&) = delete;
+  Mutex& operator=(Mutex const&) = delete;
+
+  inline void Lock() { mutex_.lock(); }
+  inline void Unlock() { mutex_.unlock(); }
+
+ private:
+  std::mutex mutex_;
+
+  friend class CondVar;
+};
+
+class CondVar {
+ public:
+  CondVar() = default;
+  ~CondVar() = default;
+  CondVar(CondVar const&) = delete;
+  CondVar& operator=(CondVar const&) = delete;
+
+  inline void Wait(Mutex* mu) {
+    std::unique_lock<std::mutex> lock(mu->mutex_, std::adopt_lock);
+    cond_var_.wait(lock);
+    lock.release();
+  }
+  inline void Signal() { cond_var_.notify_one(); }
+  inline void SignalAll() { cond_var_.notify_all(); }
+
+ private:
+  std::condition_variable cond_var_;
+};
+
+}  // namespace absl
+
+#endif  // S2_BASE_MUTEX_H_
diff --git a/src/s2/base/port.h b/src/s2/base/port.h
new file mode 100644 (file)
index 0000000..1072471
--- /dev/null
@@ -0,0 +1,1013 @@
+// Copyright Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#ifndef S2_BASE_PORT_H_
+#define S2_BASE_PORT_H_
+
+// This file contains things that are not used in third_party/absl but needed by
+// - Platform specific requirement
+//   - MSVC
+// - Utility macros
+// - Endianness
+// - Hash
+// - Global variables
+// - Type alias
+// - Predefined system/language macros
+// - Predefined system/language functions
+// - Performance optimization (alignment)
+// - Obsolete
+
+#include <cassert>
+#include <climits>
+#include <cstdlib>
+#include <cstring>
+
+#include "s2/base/integral_types.h"
+#include "absl/base/config.h"
+#include "absl/base/port.h"
+
+#ifdef SWIG
+%include "third_party/absl/base/port.h"
+#endif
+
+// -----------------------------------------------------------------------------
+// MSVC Specific Requirements
+// -----------------------------------------------------------------------------
+
+#ifdef _MSC_VER /* if Visual C++ */
+
+#include <winsock2.h>  // Must come before <windows.h>
+#include <intrin.h>
+#include <process.h>  // _getpid()
+#include <windows.h>
+#undef ERROR
+#undef DELETE
+#undef DIFFERENCE
+#define STDIN_FILENO 0
+#define STDOUT_FILENO 1
+#define STDERR_FILENO 2
+#define S_IRUSR 00400
+#define S_IWUSR 00200
+#define S_IXUSR 00100
+#define S_IRGRP 00040
+#define S_IWGRP 00020
+#define S_IXGRP 00010
+#define S_IROTH 00004
+#define S_IWOTH 00002
+#define S_IXOTH 00001
+
+// This compiler flag can be easily overlooked on MSVC.
+// _CHAR_UNSIGNED gets set with the /J flag.
+#ifndef _CHAR_UNSIGNED
+#error chars must be unsigned!  Use the /J flag on the compiler command line.  // NOLINT
+#endif
+
+// Allow comparisons between signed and unsigned values.
+//
+// Lots of Google code uses this pattern:
+//   for (int i = 0; i < container.size(); ++i)
+// Since size() returns an unsigned value, this warning would trigger
+// frequently.  Very few of these instances are actually bugs since containers
+// rarely exceed MAX_INT items.  Unfortunately, there are bugs related to
+// signed-unsigned comparisons that have been missed because we disable this
+// warning.  For example:
+//   const long stop_time = os::GetMilliseconds() + kWaitTimeoutMillis;
+//   while (os::GetMilliseconds() <= stop_time) { ... }
+#pragma warning(disable : 4018)  // level 3
+#pragma warning(disable : 4267)  // level 3
+
+// Don't warn about unused local variables.
+//
+// extension to silence particular instances of this warning.  There's no way
+// to define ABSL_ATTRIBUTE_UNUSED to quiet particular instances of this warning
+// in VC++, so we disable it globally.  Currently, there aren't many false
+// positives, so perhaps we can address those in the future and re-enable these
+// warnings, which sometimes catch real bugs.
+#pragma warning(disable : 4101)  // level 3
+
+// Allow initialization and assignment to a smaller type without warnings about
+// possible loss of data.
+//
+// There is a distinct warning, 4267, that warns about size_t conversions to
+// smaller types, but we don't currently disable that warning.
+//
+// Correct code can be written in such a way as to avoid false positives
+// by making the conversion explicit, but Google code isn't usually that
+// verbose.  There are too many false positives to address at this time.  Note
+// that this warning triggers at levels 2, 3, and 4 depending on the specific
+// type of conversion.  By disabling it, we not only silence minor narrowing
+// conversions but also serious ones.
+#pragma warning(disable : 4244)  // level 2, 3, and 4
+
+// Allow silent truncation of double to float.
+//
+// Silencing this warning has caused us to miss some subtle bugs.
+#pragma warning(disable : 4305)  // level 1
+
+// Allow a constant to be assigned to a type that is too small.
+//
+// I don't know why we allow this at all.  I can't think of a case where this
+// wouldn't be a bug, but enabling the warning breaks many builds today.
+#pragma warning(disable : 4307)  // level 2
+
+// Allow passing the this pointer to an initializer even though it refers
+// to an uninitialized object.
+//
+// Some observer implementations rely on saving the this pointer.  Those are
+// safe because the pointer is not dereferenced until after the object is fully
+// constructed.  This could however, obscure other instances.  In the future, we
+// should look into disabling this warning locally rather globally.
+#pragma warning(disable : 4355)  // level 1 and 4
+
+// Allow implicit coercion from an integral type to a bool.
+//
+// These could be avoided by making the code more explicit, but that's never
+// been the style here, so there would be many false positives.  It's not
+// obvious if a true positive would ever help to find an actual bug.
+#pragma warning(disable : 4800)  // level 3
+
+#endif  // _MSC_VER
+
+// -----------------------------------------------------------------------------
+// Utility Macros
+// -----------------------------------------------------------------------------
+
+// OS_IOS
+#if defined(__APPLE__)
+// Currently, blaze supports iOS yet doesn't define a flag. Mac users have
+// traditionally defined OS_IOS themselves via other build systems, since mac
+// hasn't been supported by blaze.
+// TODO(user): Remove this when all toolchains make the proper defines.
+#include <TargetConditionals.h>
+#if defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE
+#ifndef OS_IOS
+#define OS_IOS 1
+#endif
+#endif  // defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE
+#endif  // defined(__APPLE__)
+
+// __GLIBC_PREREQ
+#if defined __linux__
+// GLIBC-related macros.
+#include <features.h>
+
+#ifndef __GLIBC_PREREQ
+#define __GLIBC_PREREQ(a, b) 0  // not a GLIBC system
+#endif
+#endif  // __linux__
+
+// STATIC_ANALYSIS
+// Klocwork static analysis tool's C/C++ complier kwcc
+#if defined(__KLOCWORK__)
+#define STATIC_ANALYSIS
+#endif  // __KLOCWORK__
+
+// SIZEOF_MEMBER, OFFSETOF_MEMBER
+#define SIZEOF_MEMBER(t, f) sizeof(reinterpret_cast<t *>(4096)->f)
+
+#define OFFSETOF_MEMBER(t, f)                                  \
+  (reinterpret_cast<char *>(&(reinterpret_cast<t *>(16)->f)) - \
+   reinterpret_cast<char *>(16))
+
+// LANG_CXX11
+// GXX_EXPERIMENTAL_CXX0X is defined by gcc and clang up to at least
+// gcc-4.7 and clang-3.1 (2011-12-13).  __cplusplus was defined to 1
+// in gcc before 4.7 (Crosstool 16) and clang before 3.1, but is
+// defined according to the language version in effect thereafter.
+// Microsoft Visual Studio 14 (2015) sets __cplusplus==199711 despite
+// reasonably good C++11 support, so we set LANG_CXX for it and
+// newer versions (_MSC_VER >= 1900).
+#if (defined(__GXX_EXPERIMENTAL_CXX0X__) || __cplusplus >= 201103L || \
+     (defined(_MSC_VER) && _MSC_VER >= 1900))
+// DEPRECATED: Do not key off LANG_CXX11. Instead, write more accurate condition
+// that checks whether the C++ feature you need is available or missing, and
+// define a more specific feature macro (GOOGLE_HAVE_FEATURE_FOO). You can check
+// http://en.cppreference.com/w/cpp/compiler_support for compiler support on C++
+// features.
+// Define this to 1 if the code is compiled in C++11 mode; leave it
+// undefined otherwise.  Do NOT define it to 0 -- that causes
+// '#ifdef LANG_CXX11' to behave differently from '#if LANG_CXX11'.
+#define LANG_CXX11 1
+#endif
+
+// This sanity check can be removed when all references to
+// LANG_CXX11 is removed from the code base.
+#if defined(__cplusplus) && !defined(LANG_CXX11) && !defined(SWIG)
+#error "LANG_CXX11 is required."
+#endif
+
+// GOOGLE_OBSCURE_SIGNAL
+#if defined(__APPLE__)
+// No SIGPWR on MacOSX.  SIGINFO seems suitably obscure.
+#define GOOGLE_OBSCURE_SIGNAL SIGINFO
+#else
+/* We use SIGPWR since that seems unlikely to be used for other reasons. */
+#define GOOGLE_OBSCURE_SIGNAL SIGPWR
+#endif
+
+// ABSL_FUNC_PTR_TO_CHAR_PTR
+// On some platforms, a "function pointer" points to a function descriptor
+// rather than directly to the function itself.
+// Use ABSL_FUNC_PTR_TO_CHAR_PTR(func) to get a char-pointer to the first
+// instruction of the function func.
+// TODO(b/30407660): Move this macro into Abseil when symbolizer is released in
+// Abseil.
+#if defined(__cplusplus)
+#if (defined(__powerpc__) && !(_CALL_ELF > 1)) || defined(__ia64)
+// use opd section for function descriptors on these platforms, the function
+// address is the first word of the descriptor
+namespace absl {
+enum { kPlatformUsesOPDSections = 1 };
+}  // namespace absl
+#define ABSL_FUNC_PTR_TO_CHAR_PTR(func) (reinterpret_cast<char **>(func)[0])
+#else  // not PPC or IA64
+namespace absl {
+enum { kPlatformUsesOPDSections = 0 };
+}  // namespace absl
+#define ABSL_FUNC_PTR_TO_CHAR_PTR(func) (reinterpret_cast<char *>(func))
+#endif  // PPC or IA64
+#endif  // __cplusplus
+
+// -----------------------------------------------------------------------------
+// Utility Functions
+// -----------------------------------------------------------------------------
+
+// sized_delete
+#ifdef __cplusplus
+namespace base {
+// We support C++14's sized deallocation for all C++ builds,
+// though for other toolchains, we fall back to using delete.
+inline void sized_delete(void *ptr, size_t size) {
+#ifdef GOOGLE_HAVE_SIZED_DELETE
+  ::operator delete(ptr, size);
+#else
+  (void)size;
+  ::operator delete(ptr);
+#endif  // GOOGLE_HAVE_SIZED_DELETE
+}
+
+inline void sized_delete_array(void *ptr, size_t size) {
+#ifdef GOOGLE_HAVE_SIZED_DELETEARRAY
+  ::operator delete[](ptr, size);
+#else
+  (void) size;
+  ::operator delete[](ptr);
+#endif
+}
+}  // namespace base
+#endif  // __cplusplus
+
+// -----------------------------------------------------------------------------
+// Endianness
+// -----------------------------------------------------------------------------
+
+// IS_LITTLE_ENDIAN, IS_BIG_ENDIAN
+
+// Allow compiler -D defines to override detection here
+// which occasionally fails (e.g., on CRAN Solaris)
+#if defined(IS_LITTLE_ENDIAN)
+#undef IS_BIG_ENDIAN
+#elif defined(IS_BIG_ENDIAN)
+#undef IS_LITTLE_ENDIAN
+#else
+
+#if defined __linux__ || defined OS_ANDROID || defined(__ANDROID__)
+// TODO(user): http://b/21460321; use one of OS_ANDROID or __ANDROID__.
+// _BIG_ENDIAN
+#include <endian.h>
+
+#elif defined(__APPLE__)
+
+// BIG_ENDIAN
+#include <machine/endian.h>  // NOLINT(build/include)
+/* Let's try and follow the Linux convention */
+#define __BYTE_ORDER  BYTE_ORDER
+#define __LITTLE_ENDIAN LITTLE_ENDIAN
+#define __BIG_ENDIAN BIG_ENDIAN
+
+#endif
+
+// defines __BYTE_ORDER for MSVC
+#ifdef _MSC_VER
+#define __BYTE_ORDER __LITTLE_ENDIAN
+#define IS_LITTLE_ENDIAN
+#else
+
+// define the macros IS_LITTLE_ENDIAN or IS_BIG_ENDIAN
+// using the above endian definitions from endian.h if
+// endian.h was included
+#ifdef __BYTE_ORDER
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+#define IS_LITTLE_ENDIAN
+#endif
+
+#if __BYTE_ORDER == __BIG_ENDIAN
+#define IS_BIG_ENDIAN
+#endif
+
+#else  // __BYTE_ORDER
+
+#if defined(__LITTLE_ENDIAN__)
+#define IS_LITTLE_ENDIAN
+#elif defined(__BIG_ENDIAN__)
+#define IS_BIG_ENDIAN
+#endif
+
+#endif  // __BYTE_ORDER
+#endif  // _MSC_VER
+#endif // #if defined(IS_LITTLE_ENDIAN) ... #else
+
+// byte swap functions (bswap_16, bswap_32, bswap_64).
+
+// The following guarantees declaration of the byte swap functions
+#ifdef _MSC_VER
+#include <cstdlib>  // NOLINT(build/include)
+#define bswap_16(x) _byteswap_ushort(x)
+#define bswap_32(x) _byteswap_ulong(x)
+#define bswap_64(x) _byteswap_uint64(x)
+
+#elif defined(__APPLE__)
+// Mac OS X / Darwin features
+#include <libkern/OSByteOrder.h>
+#define bswap_16(x) OSSwapInt16(x)
+#define bswap_32(x) OSSwapInt32(x)
+#define bswap_64(x) OSSwapInt64(x)
+
+#elif defined(__GLIBC__) || defined(__BIONIC__) || defined(__ASYLO__)
+#include <byteswap.h>  // IWYU pragma: export
+
+#else
+
+static inline uint16 bswap_16(uint16 x) {
+#ifdef __cplusplus
+  return static_cast<uint16>(((x & 0xFF) << 8) | ((x & 0xFF00) >> 8));
+#else
+  return (uint16)(((x & 0xFF) << 8) | ((x & 0xFF00) >> 8));  // NOLINT
+#endif  // __cplusplus
+}
+#define bswap_16(x) bswap_16(x)
+static inline uint32 bswap_32(uint32 x) {
+  return (((x & 0xFF) << 24) |
+          ((x & 0xFF00) << 8) |
+          ((x & 0xFF0000) >> 8) |
+          ((x & 0xFF000000) >> 24));
+}
+#define bswap_32(x) bswap_32(x)
+static inline uint64 bswap_64(uint64 x) {
+  return (((x & 0xFFULL) << 56) |
+          ((x & 0xFF00ULL) << 40) |
+          ((x & 0xFF0000ULL) << 24) |
+          ((x & 0xFF000000ULL) << 8) |
+          ((x & 0xFF00000000ULL) >> 8) |
+          ((x & 0xFF0000000000ULL) >> 24) |
+          ((x & 0xFF000000000000ULL) >> 40) |
+          ((x & 0xFF00000000000000ULL) >> 56));
+}
+#define bswap_64(x) bswap_64(x)
+
+#endif
+
+// -----------------------------------------------------------------------------
+// Hash
+// -----------------------------------------------------------------------------
+
+#ifdef __cplusplus
+#ifdef STL_MSVC  // not always the same as _MSC_VER
+#include "absl/base/internal/port_hash.inc"
+#else
+struct PortableHashBase {};
+#endif  // STL_MSVC
+#endif  // __cplusplus
+
+// -----------------------------------------------------------------------------
+// Global Variables
+// -----------------------------------------------------------------------------
+
+// PATH_SEPARATOR
+// Define the OS's path separator
+//
+// NOTE: Assuming the path separator at compile time is discouraged.
+// Prefer instead to be tolerant of both possible separators whenever possible.
+#ifdef __cplusplus  // C won't merge duplicate const variables at link time
+// Some headers provide a macro for this (GCC's system.h), remove it so that we
+// can use our own.
+#undef PATH_SEPARATOR
+#if defined(_WIN32)
+const char PATH_SEPARATOR = '\\';
+#else
+const char PATH_SEPARATOR = '/';
+#endif  // _WIN32
+#endif  // __cplusplus
+
+// -----------------------------------------------------------------------------
+// Type Alias
+// -----------------------------------------------------------------------------
+
+// uint, ushort, ulong
+#if defined __linux__
+// The uint mess:
+// mysql.h sets _GNU_SOURCE which sets __USE_MISC in <features.h>
+// sys/types.h typedefs uint if __USE_MISC
+// mysql typedefs uint if HAVE_UINT not set
+// The following typedef is carefully considered, and should not cause
+//  any clashes
+#if !defined(__USE_MISC)
+#if !defined(HAVE_UINT)
+#define HAVE_UINT 1
+typedef unsigned int uint;
+#endif  // !HAVE_UINT
+#if !defined(HAVE_USHORT)
+#define HAVE_USHORT 1
+typedef unsigned short ushort;  // NOLINT
+#endif  // !HAVE_USHORT
+#if !defined(HAVE_ULONG)
+#define HAVE_ULONG 1
+typedef unsigned long ulong;  // NOLINT
+#endif  // !HAVE_ULONG
+#endif  // !__USE_MISC
+
+#endif  // __linux__
+
+#ifdef _MSC_VER /* if Visual C++ */
+// VC++ doesn't understand "uint"
+#ifndef HAVE_UINT
+#define HAVE_UINT 1
+typedef unsigned int uint;
+#endif  // !HAVE_UINT
+#endif  // _MSC_VER
+
+#ifdef _MSC_VER
+// uid_t
+// MSVC doesn't have uid_t
+typedef int uid_t;
+
+// pid_t
+// Defined all over the place.
+typedef int pid_t;
+#endif  // _MSC_VER
+
+// mode_t
+#ifdef _MSC_VER
+// From stat.h
+typedef unsigned int mode_t;
+#endif  // _MSC_VER
+
+// sig_t
+#ifdef _MSC_VER
+typedef void (*sig_t)(int);
+#endif  // _MSC_VER
+
+// u_int16_t, int16_t
+#ifdef _MSC_VER
+// u_int16_t, int16_t don't exist in MSVC
+typedef unsigned short u_int16_t;  // NOLINT
+typedef short int16_t;             // NOLINT
+#endif                             // _MSC_VER
+
+// using std::hash
+#ifdef _MSC_VER
+#ifdef __cplusplus
+// Define a minimal set of things typically available in the global
+// namespace in Google code.  ::string is handled elsewhere, and uniformly
+// for all targets.
+#include <functional>
+using std::hash;
+#endif  // __cplusplus
+#endif  // _MSC_VER
+
+// printf macros
+// __STDC_FORMAT_MACROS must be defined before inttypes.h inclusion */
+#if defined(__APPLE__)
+/* From MacOSX's inttypes.h:
+ * "C++ implementations should define these macros only when
+ *  __STDC_FORMAT_MACROS is defined before <inttypes.h> is included." */
+#ifndef __STDC_FORMAT_MACROS
+#define __STDC_FORMAT_MACROS
+#endif /* __STDC_FORMAT_MACROS */
+#endif /* __APPLE__ */
+
+// printf macros for size_t, in the style of inttypes.h
+#if defined(_LP64) || defined(__APPLE__)
+#define __PRIS_PREFIX "z"
+#else
+#define __PRIS_PREFIX
+#endif
+
+// Use these macros after a % in a printf format string
+// to get correct 32/64 bit behavior, like this:
+// size_t size = records.size();
+// printf("%" PRIuS "\n", size);
+#define PRIdS __PRIS_PREFIX "d"
+#define PRIxS __PRIS_PREFIX "x"
+#define PRIuS __PRIS_PREFIX "u"
+#define PRIXS __PRIS_PREFIX "X"
+#define PRIoS __PRIS_PREFIX "o"
+
+#define GPRIuPTHREAD "lu"
+#define GPRIxPTHREAD "lx"
+#if defined(__APPLE__)
+#define PRINTABLE_PTHREAD(pthreadt) reinterpret_cast<uintptr_t>(pthreadt)
+#else
+#define PRINTABLE_PTHREAD(pthreadt) pthreadt
+#endif
+
+#ifdef PTHREADS_REDHAT_WIN32
+#include <pthread.h>  // NOLINT(build/include)
+#include <iosfwd>     // NOLINT(build/include)
+// pthread_t is not a simple integer or pointer on Win32
+std::ostream &operator<<(std::ostream &out, const pthread_t &thread_id);
+#endif
+
+// -----------------------------------------------------------------------------
+// Predefined System/Language Macros
+// -----------------------------------------------------------------------------
+
+// EXFULL
+#if defined(__APPLE__)
+// Linux has this in <linux/errno.h>
+#define EXFULL ENOMEM  // not really that great a translation...
+#endif                 // __APPLE__
+#ifdef _MSC_VER
+// This actually belongs in errno.h but there's a name conflict in errno
+// on WinNT. They (and a ton more) are also found in Winsock2.h, but
+// if'd out under NT. We need this subset at minimum.
+#define EXFULL ENOMEM  // not really that great a translation...
+#endif                 // _MSC_VER
+
+// MSG_NOSIGNAL
+#if defined(__APPLE__)
+// Doesn't exist on OSX.
+#define MSG_NOSIGNAL 0
+#endif  // __APPLE__
+
+// __ptr_t
+#if defined(__APPLE__)
+// Linux has this in <sys/cdefs.h>
+#define __ptr_t void *
+#endif  // __APPLE__
+#ifdef _MSC_VER
+// From glob.h
+#define __ptr_t void *
+#endif
+
+// HUGE_VALF
+#ifdef _MSC_VER
+#include <cmath>  // for HUGE_VAL
+
+#ifndef HUGE_VALF
+#define HUGE_VALF (static_cast<float>(HUGE_VAL))
+#endif
+#endif  // _MSC_VER
+
+// MAP_ANONYMOUS
+#if defined(__APPLE__)
+// For mmap, Linux defines both MAP_ANONYMOUS and MAP_ANON and says MAP_ANON is
+// deprecated. In Darwin, MAP_ANON is all there is.
+#if !defined MAP_ANONYMOUS
+#define MAP_ANONYMOUS MAP_ANON
+#endif  // !MAP_ANONYMOUS
+#endif  // __APPLE__
+
+// PATH_MAX
+// You say tomato, I say atotom
+#ifdef _MSC_VER
+#define PATH_MAX MAX_PATH
+#endif
+
+// -----------------------------------------------------------------------------
+// Predefined System/Language Functions
+// -----------------------------------------------------------------------------
+
+// strtoq, strtouq, atoll
+#ifdef _MSC_VER
+#define strtoq _strtoi64
+#define strtouq _strtoui64
+#define atoll _atoi64
+#endif  // _MSC_VER
+
+#ifdef _MSC_VER
+// You say tomato, I say _tomato
+#define strcasecmp _stricmp
+#define strncasecmp _strnicmp
+#define strdup _strdup
+#define tempnam _tempnam
+#define chdir _chdir
+#define getpid _getpid
+#define getcwd _getcwd
+#define putenv _putenv
+#define timezone _timezone
+#define tzname _tzname
+#endif  // _MSC_VER
+
+// random, srandom
+#ifdef _MSC_VER
+// You say tomato, I say toma
+inline int random() { return rand(); }
+inline void srandom(unsigned int seed) { srand(seed); }
+#endif  // _MSC_VER
+
+// bcopy, bzero
+#ifdef _MSC_VER
+// You say juxtapose, I say transpose
+#define bcopy(s, d, n) memcpy(d, s, n)
+// Really from <string.h>
+inline void bzero(void *s, int n) { memset(s, 0, n); }
+#endif  // _MSC_VER
+
+// gethostbyname
+#if defined(_WIN32) || defined(__APPLE__)
+// gethostbyname() *is* thread-safe for Windows native threads. It is also
+// safe on Mac OS X and iOS, where it uses thread-local storage, even though the
+// manpages claim otherwise. For details, see
+// http://lists.apple.com/archives/Darwin-dev/2006/May/msg00008.html
+#else
+// gethostbyname() is not thread-safe.  So disallow its use.  People
+// should either use the HostLookup::Lookup*() methods, or gethostbyname_r()
+#define gethostbyname gethostbyname_is_not_thread_safe_DO_NOT_USE
+#endif
+
+// -----------------------------------------------------------------------------
+// Performance Optimization
+// -----------------------------------------------------------------------------
+
+// Alignment
+
+// Unaligned APIs
+
+// Portable handling of unaligned loads, stores, and copies.
+// On some platforms, like ARM, the copy functions can be more efficient
+// then a load and a store.
+//
+// It is possible to implement all of these these using constant-length memcpy
+// calls, which is portable and will usually be inlined into simple loads and
+// stores if the architecture supports it. However, such inlining usually
+// happens in a pass that's quite late in compilation, which means the resulting
+// loads and stores cannot participate in many other optimizations, leading to
+// overall worse code.
+// TODO(user): These APIs are forked in Abseil, see
+// LLVM, we should reimplement these APIs with functions calling memcpy(), and
+// maybe publish them in Abseil.
+
+// The unaligned API is C++ only.  The declarations use C++ features
+// (namespaces, inline) which are absent or incompatible in C.
+#if defined(__cplusplus)
+
+#if defined(ADDRESS_SANITIZER) || defined(THREAD_SANITIZER) || \
+    defined(MEMORY_SANITIZER)
+// Consider we have an unaligned load/store of 4 bytes from address 0x...05.
+// AddressSanitizer will treat it as a 3-byte access to the range 05:07 and
+// will miss a bug if 08 is the first unaddressable byte.
+// ThreadSanitizer will also treat this as a 3-byte access to 05:07 and will
+// miss a race between this access and some other accesses to 08.
+// MemorySanitizer will correctly propagate the shadow on unaligned stores
+// and correctly report bugs on unaligned loads, but it may not properly
+// update and report the origin of the uninitialized memory.
+// For all three tools, replacing an unaligned access with a tool-specific
+// callback solves the problem.
+
+// Make sure uint16_t/uint32_t/uint64_t are defined.
+#include <cstdint>
+
+extern "C" {
+uint16_t __sanitizer_unaligned_load16(const void *p);
+uint32_t __sanitizer_unaligned_load32(const void *p);
+uint64_t __sanitizer_unaligned_load64(const void *p);
+void __sanitizer_unaligned_store16(void *p, uint16_t v);
+void __sanitizer_unaligned_store32(void *p, uint32_t v);
+void __sanitizer_unaligned_store64(void *p, uint64_t v);
+}  // extern "C"
+
+inline uint16 UNALIGNED_LOAD16(const void *p) {
+  return __sanitizer_unaligned_load16(p);
+}
+
+inline uint32 UNALIGNED_LOAD32(const void *p) {
+  return __sanitizer_unaligned_load32(p);
+}
+
+inline uint64 UNALIGNED_LOAD64(const void *p) {
+  return __sanitizer_unaligned_load64(p);
+}
+
+inline void UNALIGNED_STORE16(void *p, uint16 v) {
+  __sanitizer_unaligned_store16(p, v);
+}
+
+inline void UNALIGNED_STORE32(void *p, uint32 v) {
+  __sanitizer_unaligned_store32(p, v);
+}
+
+inline void UNALIGNED_STORE64(void *p, uint64 v) {
+  __sanitizer_unaligned_store64(p, v);
+}
+
+#elif defined(UNDEFINED_BEHAVIOR_SANITIZER)
+
+inline uint16 UNALIGNED_LOAD16(const void *p) {
+  uint16 t;
+  memcpy(&t, p, sizeof t);
+  return t;
+}
+
+inline uint32 UNALIGNED_LOAD32(const void *p) {
+  uint32 t;
+  memcpy(&t, p, sizeof t);
+  return t;
+}
+
+inline uint64 UNALIGNED_LOAD64(const void *p) {
+  uint64 t;
+  memcpy(&t, p, sizeof t);
+  return t;
+}
+
+inline void UNALIGNED_STORE16(void *p, uint16 v) { memcpy(p, &v, sizeof v); }
+
+inline void UNALIGNED_STORE32(void *p, uint32 v) { memcpy(p, &v, sizeof v); }
+
+inline void UNALIGNED_STORE64(void *p, uint64 v) { memcpy(p, &v, sizeof v); }
+
+#elif defined(__x86_64__) || defined(_M_X64) || defined(__i386) || \
+    defined(_M_IX86) || defined(__ppc__) || defined(__PPC__) ||    \
+    defined(__ppc64__) || defined(__PPC64__)
+
+// x86 and x86-64 can perform unaligned loads/stores directly;
+// modern PowerPC hardware can also do unaligned integer loads and stores;
+// but note: the FPU still sends unaligned loads and stores to a trap handler!
+
+#define UNALIGNED_LOAD16(_p) (*reinterpret_cast<const uint16 *>(_p))
+#define UNALIGNED_LOAD32(_p) (*reinterpret_cast<const uint32 *>(_p))
+#define UNALIGNED_LOAD64(_p) (*reinterpret_cast<const uint64 *>(_p))
+
+#define UNALIGNED_STORE16(_p, _val) (*reinterpret_cast<uint16 *>(_p) = (_val))
+#define UNALIGNED_STORE32(_p, _val) (*reinterpret_cast<uint32 *>(_p) = (_val))
+#define UNALIGNED_STORE64(_p, _val) (*reinterpret_cast<uint64 *>(_p) = (_val))
+
+#elif defined(__arm__) && !defined(__ARM_ARCH_5__) &&          \
+    !defined(__ARM_ARCH_5T__) && !defined(__ARM_ARCH_5TE__) && \
+    !defined(__ARM_ARCH_5TEJ__) && !defined(__ARM_ARCH_6__) && \
+    !defined(__ARM_ARCH_6J__) && !defined(__ARM_ARCH_6K__) &&  \
+    !defined(__ARM_ARCH_6Z__) && !defined(__ARM_ARCH_6ZK__) && \
+    !defined(__ARM_ARCH_6T2__)
+
+// ARMv7 and newer support native unaligned accesses, but only of 16-bit
+// and 32-bit values (not 64-bit); older versions either raise a fatal signal,
+// do an unaligned read and rotate the words around a bit, or do the reads very
+// slowly (trip through kernel mode). There's no simple #define that says just
+// “ARMv7 or higher”, so we have to filter away all ARMv5 and ARMv6
+// sub-architectures. Newer gcc (>= 4.6) set an __ARM_FEATURE_ALIGNED #define,
+// so in time, maybe we can move on to that.
+//
+// This is a mess, but there's not much we can do about it.
+//
+// To further complicate matters, only LDR instructions (single reads) are
+// allowed to be unaligned, not LDRD (two reads) or LDM (many reads). Unless we
+// explicitly tell the compiler that these accesses can be unaligned, it can and
+// will combine accesses. On armcc, the way to signal this is done by accessing
+// through the type (uint32 __packed *), but GCC has no such attribute
+// (it ignores __attribute__((packed)) on individual variables). However,
+// we can tell it that a _struct_ is unaligned, which has the same effect,
+// so we do that.
+
+namespace base {
+namespace internal {
+
+struct Unaligned16Struct {
+  uint16 value;
+  uint8 dummy;  // To make the size non-power-of-two.
+} ABSL_ATTRIBUTE_PACKED;
+
+struct Unaligned32Struct {
+  uint32 value;
+  uint8 dummy;  // To make the size non-power-of-two.
+} ABSL_ATTRIBUTE_PACKED;
+
+}  // namespace internal
+}  // namespace base
+
+#define UNALIGNED_LOAD16(_p) \
+  ((reinterpret_cast<const ::base::internal::Unaligned16Struct *>(_p))->value)
+#define UNALIGNED_LOAD32(_p) \
+  ((reinterpret_cast<const ::base::internal::Unaligned32Struct *>(_p))->value)
+
+#define UNALIGNED_STORE16(_p, _val)                                        \
+  ((reinterpret_cast< ::base::internal::Unaligned16Struct *>(_p))->value = \
+       (_val))
+#define UNALIGNED_STORE32(_p, _val)                                        \
+  ((reinterpret_cast< ::base::internal::Unaligned32Struct *>(_p))->value = \
+       (_val))
+
+// TODO(user): NEON supports unaligned 64-bit loads and stores.
+// See if that would be more efficient on platforms supporting it,
+// at least for copies.
+
+inline uint64 UNALIGNED_LOAD64(const void *p) {
+  uint64 t;
+  memcpy(&t, p, sizeof t);
+  return t;
+}
+
+inline void UNALIGNED_STORE64(void *p, uint64 v) { memcpy(p, &v, sizeof v); }
+
+#else
+
+#define NEED_ALIGNED_LOADS
+
+// These functions are provided for architectures that don't support
+// unaligned loads and stores.
+
+inline uint16 UNALIGNED_LOAD16(const void *p) {
+  uint16 t;
+  memcpy(&t, p, sizeof t);
+  return t;
+}
+
+inline uint32 UNALIGNED_LOAD32(const void *p) {
+  uint32 t;
+  memcpy(&t, p, sizeof t);
+  return t;
+}
+
+inline uint64 UNALIGNED_LOAD64(const void *p) {
+  uint64 t;
+  memcpy(&t, p, sizeof t);
+  return t;
+}
+
+inline void UNALIGNED_STORE16(void *p, uint16 v) { memcpy(p, &v, sizeof v); }
+
+inline void UNALIGNED_STORE32(void *p, uint32 v) { memcpy(p, &v, sizeof v); }
+
+inline void UNALIGNED_STORE64(void *p, uint64 v) { memcpy(p, &v, sizeof v); }
+
+#endif
+
+// The UNALIGNED_LOADW and UNALIGNED_STOREW macros load and store values
+// of type uword_t.
+#ifdef _LP64
+#define UNALIGNED_LOADW(_p) UNALIGNED_LOAD64(_p)
+#define UNALIGNED_STOREW(_p, _val) UNALIGNED_STORE64(_p, _val)
+#else
+#define UNALIGNED_LOADW(_p) UNALIGNED_LOAD32(_p)
+#define UNALIGNED_STOREW(_p, _val) UNALIGNED_STORE32(_p, _val)
+#endif
+
+inline void UnalignedCopy16(const void *src, void *dst) {
+  UNALIGNED_STORE16(dst, UNALIGNED_LOAD16(src));
+}
+
+inline void UnalignedCopy32(const void *src, void *dst) {
+  UNALIGNED_STORE32(dst, UNALIGNED_LOAD32(src));
+}
+
+inline void UnalignedCopy64(const void *src, void *dst) {
+  if (sizeof(void *) == 8) {
+    UNALIGNED_STORE64(dst, UNALIGNED_LOAD64(src));
+  } else {
+    const char *src_char = reinterpret_cast<const char *>(src);
+    char *dst_char = reinterpret_cast<char *>(dst);
+
+    UNALIGNED_STORE32(dst_char, UNALIGNED_LOAD32(src_char));
+    UNALIGNED_STORE32(dst_char + 4, UNALIGNED_LOAD32(src_char + 4));
+  }
+}
+
+#endif  // defined(__cplusplus), end of unaligned API
+
+// aligned_malloc, aligned_free
+#if defined(__ANDROID__) || defined(__ASYLO__) || defined(_WIN32)
+#include <malloc.h>  // for memalign()
+#endif
+
+// __ASYLO__ platform uses newlib without an underlying OS, which provides
+// memalign, but not posix_memalign.
+#if defined(__cplusplus) &&                                             \
+    (((defined(__GNUC__) || defined(__APPLE__) ||                  \
+       defined(__NVCC__)) &&   \
+      !defined(SWIG)) ||                                                \
+     ((__GNUC__ >= 3 || defined(__clang__)) && defined(__ANDROID__)) || \
+     defined(__ASYLO__))
+inline void *aligned_malloc(size_t size, size_t minimum_alignment) {
+#if defined(__ANDROID__) || defined(OS_ANDROID) || defined(__ASYLO__) || defined(_WIN32)  || defined(__sun) || defined(sun)
+# if defined(_WIN32)
+  return _aligned_malloc(size, minimum_alignment);
+# else
+  return memalign(minimum_alignment, size);
+# endif
+#else  // !__ANDROID__ && !OS_ANDROID && !__ASYLO__
+  // posix_memalign requires that the requested alignment be at least
+  // sizeof(void*). In this case, fall back on malloc which should return memory
+  // aligned to at least the size of a pointer.
+  const size_t required_alignment = sizeof(void*);
+  if (minimum_alignment < required_alignment)
+    return malloc(size);
+  void *ptr = nullptr;
+  if (posix_memalign(&ptr, minimum_alignment, size) == 0)
+    return ptr;
+  return nullptr;
+#endif
+}
+
+inline void aligned_free(void *aligned_memory) {
+  free(aligned_memory);
+}
+
+#elif defined(_MSC_VER)  // MSVC
+
+inline void *aligned_malloc(size_t size, size_t minimum_alignment) {
+  return _aligned_malloc(size, minimum_alignment);
+}
+
+inline void aligned_free(void *aligned_memory) {
+  _aligned_free(aligned_memory);
+}
+
+#endif  // aligned_malloc, aligned_free
+
+// ALIGNED_CHAR_ARRAY
+//
+// Provides a char array with the exact same alignment as another type. The
+// first parameter must be a complete type, the second parameter is how many
+// of that type to provide space for.
+//
+//   ALIGNED_CHAR_ARRAY(struct stat, 16) storage_;
+//
+#if defined(__cplusplus)
+#undef ALIGNED_CHAR_ARRAY
+// Because MSVC and older GCCs require that the argument to their alignment
+// construct to be a literal constant integer, we use a template instantiated
+// at all the possible powers of two.
+#ifndef SWIG
+template<int alignment, int size> struct AlignType { };
+template<int size> struct AlignType<0, size> { typedef char result[size]; };
+#if defined(_MSC_VER)
+#define BASE_PORT_H_ALIGN_ATTRIBUTE(X) __declspec(align(X))
+#define BASE_PORT_H_ALIGN_OF(T) __alignof(T)
+#elif defined(__GNUC__) || defined(__INTEL_COMPILER)
+#define BASE_PORT_H_ALIGN_ATTRIBUTE(X) __attribute__((aligned(X)))
+#define BASE_PORT_H_ALIGN_OF(T) __alignof__(T)
+#endif
+
+#if defined(BASE_PORT_H_ALIGN_ATTRIBUTE)
+
+#define BASE_PORT_H_ALIGNTYPE_TEMPLATE(X) \
+  template<int size> struct AlignType<X, size> { \
+    typedef BASE_PORT_H_ALIGN_ATTRIBUTE(X) char result[size]; \
+  }
+
+BASE_PORT_H_ALIGNTYPE_TEMPLATE(1);
+BASE_PORT_H_ALIGNTYPE_TEMPLATE(2);
+BASE_PORT_H_ALIGNTYPE_TEMPLATE(4);
+BASE_PORT_H_ALIGNTYPE_TEMPLATE(8);
+BASE_PORT_H_ALIGNTYPE_TEMPLATE(16);
+BASE_PORT_H_ALIGNTYPE_TEMPLATE(32);
+BASE_PORT_H_ALIGNTYPE_TEMPLATE(64);
+BASE_PORT_H_ALIGNTYPE_TEMPLATE(128);
+BASE_PORT_H_ALIGNTYPE_TEMPLATE(256);
+BASE_PORT_H_ALIGNTYPE_TEMPLATE(512);
+BASE_PORT_H_ALIGNTYPE_TEMPLATE(1024);
+BASE_PORT_H_ALIGNTYPE_TEMPLATE(2048);
+BASE_PORT_H_ALIGNTYPE_TEMPLATE(4096);
+BASE_PORT_H_ALIGNTYPE_TEMPLATE(8192);
+// Any larger and MSVC++ will complain.
+
+#define ALIGNED_CHAR_ARRAY(T, Size) \
+  typename AlignType<BASE_PORT_H_ALIGN_OF(T), sizeof(T) * Size>::result
+
+#undef BASE_PORT_H_ALIGNTYPE_TEMPLATE
+#undef BASE_PORT_H_ALIGN_ATTRIBUTE
+
+#else  // defined(BASE_PORT_H_ALIGN_ATTRIBUTE)
+#define ALIGNED_CHAR_ARRAY \
+  you_must_define_ALIGNED_CHAR_ARRAY_for_your_compiler_in_base_port_h
+#endif  // defined(BASE_PORT_H_ALIGN_ATTRIBUTE)
+
+#else  // !SWIG
+
+// SWIG can't represent alignment and doesn't care about alignment on data
+// members (it works fine without it).
+template<typename Size>
+struct AlignType { typedef char result[Size]; };
+#define ALIGNED_CHAR_ARRAY(T, Size) AlignType<Size * sizeof(T)>::result
+
+// Enough to parse with SWIG, will never be used by running code.
+#define BASE_PORT_H_ALIGN_OF(Type) 16
+
+#endif  // !SWIG
+#else  // __cplusplus
+#define ALIGNED_CHAR_ARRAY ALIGNED_CHAR_ARRAY_is_not_available_without_Cplusplus
+#endif  // __cplusplus
+
+#endif  // S2_BASE_PORT_H_
diff --git a/src/s2/base/spinlock.h b/src/s2/base/spinlock.h
new file mode 100644 (file)
index 0000000..5a5a36f
--- /dev/null
@@ -0,0 +1,60 @@
+// Copyright Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#ifndef S2_BASE_SPINLOCK_H_
+#define S2_BASE_SPINLOCK_H_
+
+#include <atomic>
+
+
+class SpinLock {
+ public:
+  SpinLock() = default;
+  ~SpinLock() = default;
+  SpinLock(SpinLock const&) = delete;
+  SpinLock& operator=(SpinLock const&) = delete;
+
+  inline void Lock() {
+    while (locked_.exchange(true, std::memory_order_acquire)) {
+      // Spin.
+      continue;
+    }
+  }
+
+  inline void Unlock() {
+    locked_.store(false, std::memory_order_release);
+  }
+
+  inline bool IsHeld() const {
+    return locked_.load(std::memory_order_relaxed);
+  }
+
+ private:
+  std::atomic_bool locked_{false};
+};
+
+class SpinLockHolder {
+ public:
+  inline explicit SpinLockHolder(SpinLock* l) : lock_(l) { lock_->Lock(); }
+  inline ~SpinLockHolder() { lock_->Unlock(); }
+
+  SpinLockHolder(const SpinLockHolder&) = delete;
+  SpinLockHolder& operator=(const SpinLockHolder&) = delete;
+
+ private:
+  SpinLock* lock_;
+};
+
+#endif  // S2_BASE_SPINLOCK_H_
diff --git a/src/s2/base/stringprintf.cc b/src/s2/base/stringprintf.cc
new file mode 100644 (file)
index 0000000..501cdb7
--- /dev/null
@@ -0,0 +1,107 @@
+// Copyright 2002 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+
+#include "s2/base/stringprintf.h"
+
+#include <cerrno>
+#include <cstdarg> // For va_list and related operations
+#include <cstdio> // MSVC requires this for _vsnprintf
+#include <vector>
+
+#include "s2/base/logging.h"
+
+#ifdef _MSC_VER
+enum { IS__MSC_VER = 1 };
+#else
+enum { IS__MSC_VER = 0 };
+#endif
+
+void StringAppendV(std::string* dst, const char* format, va_list ap) {
+  // First try with a small fixed size buffer
+  static const int kSpaceLength = 1024;
+  char space[kSpaceLength];
+
+  // It's possible for methods that use a va_list to invalidate
+  // the data in it upon use.  The fix is to make a copy
+  // of the structure before using it and use that copy instead.
+  va_list backup_ap;
+  va_copy(backup_ap, ap);
+  int result = vsnprintf(space, kSpaceLength, format, backup_ap);
+  va_end(backup_ap);
+
+  if (result < kSpaceLength) {
+    if (result >= 0) {
+      // Normal case -- everything fit.
+      dst->append(space, result);
+      return;
+    }
+
+    if (IS__MSC_VER) {
+      // Error or MSVC running out of space.  MSVC 8.0 and higher
+      // can be asked about space needed with the special idiom below:
+      va_copy(backup_ap, ap);
+      result = vsnprintf(nullptr, 0, format, backup_ap);
+      va_end(backup_ap);
+    }
+
+    if (result < 0) {
+      // Just an error.
+      return;
+    }
+  }
+
+  // Increase the buffer size to the size requested by vsnprintf,
+  // plus one for the closing \0.
+  int length = result+1;
+  char* buf = new char[length];
+
+  // Restore the va_list before we use it again
+  va_copy(backup_ap, ap);
+  result = vsnprintf(buf, length, format, backup_ap);
+  va_end(backup_ap);
+
+  if (result >= 0 && result < length) {
+    // It fit
+    dst->append(buf, result);
+  }
+  delete[] buf;
+}
+
+
+std::string StringPrintf(const char* format, ...) {
+  va_list ap;
+  va_start(ap, format);
+  std::string result;
+  StringAppendV(&result, format, ap);
+  va_end(ap);
+  return result;
+}
+
+const std::string& SStringPrintf(std::string* dst, const char* format, ...) {
+  va_list ap;
+  va_start(ap, format);
+  dst->clear();
+  StringAppendV(dst, format, ap);
+  va_end(ap);
+  return *dst;
+}
+
+void StringAppendF(std::string* dst, const char* format, ...) {
+  va_list ap;
+  va_start(ap, format);
+  StringAppendV(dst, format, ap);
+  va_end(ap);
+}
diff --git a/src/s2/base/stringprintf.h b/src/s2/base/stringprintf.h
new file mode 100644 (file)
index 0000000..9a97e2d
--- /dev/null
@@ -0,0 +1,53 @@
+// Copyright Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// NOTE: See third_party/absl/strings for more options.
+//
+// As of 2017q4, most use of these routines is considered legacy: use
+// of absl::StrCat, absl::Substitute, or absl::StrFormat is preferred for
+// performance and safety reasons.
+
+#ifndef S2_BASE_STRINGPRINTF_H_
+#define S2_BASE_STRINGPRINTF_H_
+
+#include <cstdarg>
+#include <string>
+#include <vector>
+
+#include "s2/base/port.h"
+
+// Return a C++ string
+extern std::string StringPrintf(const char* format, ...)
+    // Tell the compiler to do printf format string checking.
+    ABSL_PRINTF_ATTRIBUTE(1, 2);
+
+// Store result into a supplied string and return it
+extern const std::string& SStringPrintf(std::string* dst, const char* format, ...)
+    // Tell the compiler to do printf format string checking.
+    ABSL_PRINTF_ATTRIBUTE(2, 3);
+
+// Append result to a supplied string
+extern void StringAppendF(std::string* dst, const char* format, ...)
+    // Tell the compiler to do printf format string checking.
+    ABSL_PRINTF_ATTRIBUTE(2, 3);
+
+// Lower-level routine that takes a va_list and appends to a specified
+// string.  All other routines are just convenience wrappers around it.
+//
+// Implementation note: the va_list is never modified, this implementation
+// always operates on copies.
+extern void StringAppendV(std::string* dst, const char* format, va_list ap);
+
+#endif  // S2_BASE_STRINGPRINTF_H_
diff --git a/src/s2/base/strtoint.cc b/src/s2/base/strtoint.cc
new file mode 100644 (file)
index 0000000..b626f2d
--- /dev/null
@@ -0,0 +1,65 @@
+// Copyright 2008 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+//
+// Architecture-neutral plug compatible replacements for strtol() friends.
+// See strtoint.h for details on how to use this component.
+//
+
+#include <cerrno>
+#include <climits>
+#include <limits>
+
+#include "s2/base/integral_types.h"
+#include "s2/base/port.h"
+#include "s2/base/strtoint.h"
+
+// Replacement strto[u]l functions that have identical overflow and underflow
+// characteristics for both ILP-32 and LP-64 platforms, including errno
+// preservation for error-free calls.
+int32 strto32_adapter(const char *nptr, char **endptr, int base) {
+  const int saved_errno = errno;
+  errno = 0;
+  const long result = strtol(nptr, endptr, base);
+  if (errno == ERANGE && result == LONG_MIN) {
+    return std::numeric_limits<int32>::min();
+  } else if (errno == ERANGE && result == LONG_MAX) {
+    return std::numeric_limits<int32>::max();
+  } else if (errno == 0 && result < std::numeric_limits<int32>::min()) {
+    errno = ERANGE;
+    return std::numeric_limits<int32>::min();
+  } else if (errno == 0 && result > std::numeric_limits<int32>::max()) {
+    errno = ERANGE;
+    return std::numeric_limits<int32>::max();
+  }
+  if (errno == 0)
+    errno = saved_errno;
+  return static_cast<int32>(result);
+}
+
+uint32 strtou32_adapter(const char *nptr, char **endptr, int base) {
+  const int saved_errno = errno;
+  errno = 0;
+  const unsigned long result = strtoul(nptr, endptr, base);
+  if (errno == ERANGE && result == ULONG_MAX) {
+    return std::numeric_limits<uint32>::max();
+  } else if (errno == 0 && result > std::numeric_limits<uint32>::max()) {
+    errno = ERANGE;
+    return std::numeric_limits<uint32>::max();
+  }
+  if (errno == 0)
+    errno = saved_errno;
+  return static_cast<uint32>(result);
+}
diff --git a/src/s2/base/strtoint.h b/src/s2/base/strtoint.h
new file mode 100644 (file)
index 0000000..479624f
--- /dev/null
@@ -0,0 +1,106 @@
+// Copyright 2008 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+//
+// Architecture-neutral plug compatible replacements for strtol() friends.
+//
+// Long's have different lengths on ILP-32 and LP-64 platforms, and so overflow
+// behavior across the two varies when strtol() and similar are used to parse
+// 32-bit integers.  Similar problems exist with atoi(), because although it
+// has an all-integer interface, it uses strtol() internally, and so suffers
+// from the same narrowing problems on assignments to int.
+//
+// Examples:
+//   errno = 0;
+//   i = strtol("3147483647", nullptr, 10);
+//   printf("%d, errno %d\n", i, errno);
+//   //   32-bit platform: 2147483647, errno 34
+//   //   64-bit platform: -1147483649, errno 0
+//
+//   printf("%d\n", atoi("3147483647"));
+//   //   32-bit platform: 2147483647
+//   //   64-bit platform: -1147483649
+//
+// A way round this is to define local replacements for these, and use them
+// instead of the standard libc functions.
+//
+// In most 32-bit cases the replacements can be inlined away to a call to the
+// libc function.  In a couple of 64-bit cases, however, adapters are required,
+// to provide the right overflow and errno behavior.
+//
+
+#ifndef S2_BASE_STRTOINT_H_
+#define S2_BASE_STRTOINT_H_
+
+#include <cstdlib> // For strtol* functions.
+#include <string>
+#include "s2/base/integral_types.h"
+#include "s2/base/port.h"
+#include "absl/base/macros.h"
+
+// Adapter functions for handling overflow and errno.
+int32 strto32_adapter(const char *nptr, char **endptr, int base);
+uint32 strtou32_adapter(const char *nptr, char **endptr, int base);
+
+// Conversions to a 32-bit integer can pass the call to strto[u]l on 32-bit
+// platforms, but need a little extra work on 64-bit platforms.
+inline int32 strto32(const char *nptr, char **endptr, int base) {
+  if (sizeof(int32) == sizeof(long))
+    return static_cast<int32>(strtol(nptr, endptr, base));
+  else
+    return strto32_adapter(nptr, endptr, base);
+}
+
+inline uint32 strtou32(const char *nptr, char **endptr, int base) {
+  if (sizeof(uint32) == sizeof(unsigned long))
+    return static_cast<uint32>(strtoul(nptr, endptr, base));
+  else
+    return strtou32_adapter(nptr, endptr, base);
+}
+
+// For now, long long is 64-bit on all the platforms we care about, so these
+// functions can simply pass the call to strto[u]ll.
+inline int64 strto64(const char *nptr, char **endptr, int base) {
+  static_assert(sizeof(int64) == sizeof(long long),
+                "sizeof int64 is not sizeof long long");
+  return strtoll(nptr, endptr, base);
+}
+
+inline uint64 strtou64(const char *nptr, char **endptr, int base) {
+  static_assert(sizeof(uint64) == sizeof(unsigned long long),
+                "sizeof uint64 is not sizeof long long");
+  return strtoull(nptr, endptr, base);
+}
+
+// Although it returns an int, atoi() is implemented in terms of strtol, and
+// so has differing overflow and underflow behavior.  atol is the same.
+inline int32 atoi32(const char *nptr) {
+  return strto32(nptr, nullptr, 10);
+}
+
+inline int64 atoi64(const char *nptr) {
+  return strto64(nptr, nullptr, 10);
+}
+
+// Convenience versions of the above that take a string argument.
+inline int32 atoi32(const std::string &s) {
+  return atoi32(s.c_str());
+}
+
+inline int64 atoi64(const std::string &s) {
+  return atoi64(s.c_str());
+}
+
+#endif  // S2_BASE_STRTOINT_H_
diff --git a/src/s2/base/timer.h b/src/s2/base/timer.h
new file mode 100644 (file)
index 0000000..90419c5
--- /dev/null
@@ -0,0 +1,50 @@
+// Copyright Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#ifndef S2_BASE_TIMER_H_
+#define S2_BASE_TIMER_H_
+
+#include <chrono>
+
+#include "s2/base/integral_types.h"
+
+class CycleTimer {
+ public:
+  CycleTimer() = default;
+
+  void Start() {
+    start_ = Now();
+  }
+
+  int64 GetInMs() const {
+    using msec = std::chrono::milliseconds;
+    return std::chrono::duration_cast<msec>(GetDuration()).count();
+  }
+
+ private:
+  using Clock = std::chrono::high_resolution_clock;
+
+  static Clock::time_point Now() {
+    return Clock::now();
+  }
+
+  Clock::duration GetDuration() const {
+    return Now() - start_;
+  }
+
+  Clock::time_point start_;
+};
+
+#endif  // S2_BASE_TIMER_H_
diff --git a/src/s2/encoded_s2cell_id_vector.cc b/src/s2/encoded_s2cell_id_vector.cc
new file mode 100644 (file)
index 0000000..b3ebf20
--- /dev/null
@@ -0,0 +1,164 @@
+// Copyright 2018 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// Author: ericv@google.com (Eric Veach)
+
+#include "s2/encoded_s2cell_id_vector.h"
+
+using absl::Span;
+using std::max;
+using std::min;
+using std::vector;
+
+namespace s2coding {
+
+void EncodeS2CellIdVector(Span<const S2CellId> v, Encoder* encoder) {
+  // v[i] is encoded as (base + (deltas[i] << shift)).
+  //
+  // "base" consists of 0-7 bytes, and is always shifted so that its bytes are
+  // the most-significant bytes of a uint64.
+  //
+  // "deltas" is an EncodedUintVector<uint64>, which means that all deltas
+  // have a fixed-length encoding determined by the largest delta.
+  //
+  // "shift" is in the range 0..56.  The shift value is odd only if all
+  // S2CellIds are at the same level, in which case the bit at position
+  // (shift - 1) is automatically set to 1 in "base".
+  //
+  // "base" (3 bits) and "shift" (6 bits) are encoded in either one or two
+  // bytes as follows:
+  //
+  //   - if (shift <= 4 or shift is even), then 1 byte
+  //   - otherwise 2 bytes
+  //
+  // Note that (shift == 1) means that all S2CellIds are leaf cells, and
+  // (shift == 2) means that all S2CellIds are at level 29.
+  //
+  // The full encoded format is as follows:
+  //
+  //  Byte 0, bits 0-2: base length (0-7 bytes)
+  //  Byte 0, bits 3-7: encoded shift (see below)
+  //  Byte 1: extended shift code (only needed for odd shifts >= 5)
+  //  Followed by 0-7 bytes of "base"
+  //  Followed by an EncodedUintVector of deltas.
+
+  uint64 v_or = 0, v_and = ~0ULL, v_min = ~0ULL, v_max = 0;
+  for (auto cellid : v) {
+    v_or |= cellid.id();
+    v_and &= cellid.id();
+    v_min = min(v_min, cellid.id());
+    v_max = max(v_max, cellid.id());
+  }
+  // These variables represent the values that will used during encoding.
+  uint64 e_base = 0;        // Base value.
+  int e_base_len = 0;       // Number of bytes to represent "base".
+  int e_shift = 0;          // Delta shift.
+  int e_max_delta_msb = 0;  // Bit position of the MSB of the largest delta.
+  if (v_or > 0) {
+    // We only allow even shifts, unless all values have the same low bit (in
+    // which case the shift is odd and the preceding bit is implicitly on).
+    // There is no point in allowing shifts > 56 since deltas are encoded in
+    // at least 1 byte each.
+    e_shift = min(56, Bits::FindLSBSetNonZero64(v_or) & ~1);
+    if (v_and & (1ULL << e_shift)) ++e_shift;  // All S2CellIds same level.
+
+    // "base" consists of the "base_len" most significant bytes of the minimum
+    // S2CellId.  We consider all possible values of "base_len" (0..7) and
+    // choose the one that minimizes the total encoding size.
+    uint64 e_bytes = ~0ULL;  // Best encoding size so far.
+    for (int len = 0; len < 8; ++len) {
+      // "t_base" is the base value being tested (first "len" bytes of v_min).
+      // "t_max_delta_msb" is the most-significant bit position of the largest
+      // delta (or zero if there are no deltas, i.e. if v.size() == 0).
+      // "t_bytes" is the total size of the variable portion of the encoding.
+      uint64 t_base = v_min & ~(~0ULL >> (8 * len));
+      int t_max_delta_msb =
+          max(0, Bits::Log2Floor64((v_max - t_base) >> e_shift));
+      uint64 t_bytes = len + v.size() * ((t_max_delta_msb >> 3) + 1);
+      if (t_bytes < e_bytes) {
+        e_base = t_base;
+        e_base_len = len;
+        e_max_delta_msb = t_max_delta_msb;
+        e_bytes = t_bytes;
+      }
+    }
+    // It takes one extra byte to encode odd shifts (i.e., the case where all
+    // S2CellIds are at the same level), so check whether we can get the same
+    // encoding size per delta using an even shift.
+    if ((e_shift & 1) && (e_max_delta_msb & 7) != 7) --e_shift;
+  }
+  S2_DCHECK_LE(e_base_len, 7);
+  S2_DCHECK_LE(e_shift, 56);
+  encoder->Ensure(2 + e_base_len);
+
+  // As described above, "shift" and "base_len" are encoded in 1 or 2 bytes.
+  // "shift_code" is 5 bits:
+  //   values <= 28 represent even shifts in the range 0..56
+  //   values 29, 30 represent odd shifts 1 and 3
+  //   value 31 indicates that the shift is odd and encoded in the next byte
+  int shift_code = e_shift >> 1;
+  if (e_shift & 1) shift_code = min(31, shift_code + 29);
+  encoder->put8((shift_code << 3) | e_base_len);
+  if (shift_code == 31) {
+    encoder->put8(e_shift >> 1);  // Shift is always odd, so 3 bits unused.
+  }
+  // Encode the "base_len" most-significant bytes of "base".
+  uint64 base_bytes = e_base >> (64 - 8 * max(1, e_base_len));
+  EncodeUintWithLength<uint64>(base_bytes, e_base_len, encoder);
+
+  // Finally, encode the vector of deltas.
+  vector<uint64> deltas;
+  deltas.reserve(v.size());
+  for (auto cellid : v) {
+    deltas.push_back((cellid.id() - e_base) >> e_shift);
+  }
+  EncodeUintVector<uint64>(deltas, encoder);
+}
+
+bool EncodedS2CellIdVector::Init(Decoder* decoder) {
+  // All encodings have at least 2 bytes (one for our header and one for the
+  // EncodedUintVector header), so this is safe.
+  if (decoder->avail() < 2) return false;
+
+  // Invert the encoding of (shift_code, base_len) described above.
+  int code_plus_len = decoder->get8();
+  int shift_code = code_plus_len >> 3;
+  if (shift_code == 31) {
+    shift_code = 29 + decoder->get8();
+  }
+  // Decode the "base_len" most-significant bytes of "base".
+  int base_len = code_plus_len & 7;
+  if (!DecodeUintWithLength(base_len, decoder, &base_)) return false;
+  base_ <<= 64 - 8 * max(1, base_len);
+
+  // Invert the encoding of "shift_code" described above.
+  if (shift_code >= 29) {
+    shift_ = 2 * (shift_code - 29) + 1;
+    base_ |= 1ULL << (shift_ - 1);
+  } else {
+    shift_ = 2 * shift_code;
+  }
+  return deltas_.Init(decoder);
+}
+
+vector<S2CellId> EncodedS2CellIdVector::Decode() const {
+  vector<S2CellId> result(size());
+  for (int i = 0; i < size(); ++i) {
+    result[i] = (*this)[i];
+  }
+  return result;
+}
+
+}  // namespace s2coding
diff --git a/src/s2/encoded_s2cell_id_vector.h b/src/s2/encoded_s2cell_id_vector.h
new file mode 100644 (file)
index 0000000..3b2e7f4
--- /dev/null
@@ -0,0 +1,110 @@
+// Copyright 2018 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// Author: ericv@google.com (Eric Veach)
+
+#ifndef S2_ENCODED_S2CELL_ID_VECTOR_H_
+#define S2_ENCODED_S2CELL_ID_VECTOR_H_
+
+#include "absl/types/span.h"
+#include "s2/encoded_uint_vector.h"
+#include "s2/s2cell_id.h"
+
+namespace s2coding {
+
+// Encodes a vector of S2CellIds in a format that can later be decoded as an
+// EncodedS2CellIdVector.  The S2CellIds do not need to be valid.
+//
+// REQUIRES: "encoder" uses the default constructor, so that its buffer
+//           can be enlarged as necessary by calling Ensure(int).
+void EncodeS2CellIdVector(absl::Span<const S2CellId> v, Encoder* encoder);
+
+// This class represents an encoded vector of S2CellIds.  Values are decoded
+// only when they are accessed.  This allows for very fast initialization and
+// no additional memory use beyond the encoded data.  The encoded data is not
+// owned by this class; typically it points into a large contiguous buffer
+// that contains other encoded data as well.
+//
+// This is one of several helper classes that allow complex data structures to
+// be initialized from an encoded format in constant time and then decoded on
+// demand.  This can be a big performance advantage when only a small part of
+// the data structure is actually used.
+//
+// The S2CellIds do not need to be sorted or at the same level.  The
+// implementation is biased towards minimizing decoding times rather than
+// space usage.
+//
+// NOTE: If your S2CellIds represent S2Points that have been snapped to
+// S2CellId centers, then EncodedS2PointVector is both faster and smaller.
+class EncodedS2CellIdVector {
+ public:
+  // Constructs an uninitialized object; requires Init() to be called.
+  EncodedS2CellIdVector() {}
+
+  // Initializes the EncodedS2CellIdVector.
+  //
+  // REQUIRES: The Decoder data buffer must outlive this object.
+  bool Init(Decoder* decoder);
+
+  // Returns the size of the original vector.
+  size_t size() const;
+
+  // Returns the element at the given index.
+  S2CellId operator[](int i) const;
+
+  // Returns the index of the first element x such that (x >= target), or
+  // size() if no such element exists.
+  //
+  // REQUIRES: The vector elements are sorted in non-decreasing order.
+  size_t lower_bound(S2CellId target) const;
+
+  // Decodes and returns the entire original vector.
+  std::vector<S2CellId> Decode() const;
+
+ private:
+  // Values are decoded as (base_ + (deltas_[i] << shift_)).
+  EncodedUintVector<uint64> deltas_;
+  uint64 base_;
+  uint8 shift_;
+};
+
+
+//////////////////   Implementation details follow   ////////////////////
+
+
+inline size_t EncodedS2CellIdVector::size() const {
+  return deltas_.size();
+}
+
+inline S2CellId EncodedS2CellIdVector::operator[](int i) const {
+  return S2CellId((deltas_[i] << shift_) + base_);
+}
+
+inline size_t EncodedS2CellIdVector::lower_bound(S2CellId target) const {
+  // We optimize the search by converting "target" to the corresponding delta
+  // value and then searching directly in the deltas_ vector.
+  //
+  // To invert operator[], we essentially compute ((target - base_) >> shift_)
+  // except that we also need to round up when shifting.  The first two cases
+  // ensure that "target" doesn't wrap around past zero when we do this.
+  if (target.id() <= base_) return 0;
+  if (target >= S2CellId::End(S2CellId::kMaxLevel)) return size();
+  return deltas_.lower_bound(
+      (target.id() - base_ + (1ULL << shift_) - 1) >> shift_);
+}
+
+}  // namespace s2coding
+
+#endif  // S2_ENCODED_S2CELL_ID_VECTOR_H_
diff --git a/src/s2/encoded_s2point_vector.cc b/src/s2/encoded_s2point_vector.cc
new file mode 100644 (file)
index 0000000..b7fdb23
--- /dev/null
@@ -0,0 +1,838 @@
+// Copyright 2018 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// Author: ericv@google.com (Eric Veach)
+
+#include "s2/encoded_s2point_vector.h"
+
+#include "absl/base/internal/unaligned_access.h"
+#include "s2/util/bits/bits.h"
+#include "s2/s2cell_id.h"
+#include "s2/s2coords.h"
+
+using absl::MakeSpan;
+using absl::Span;
+using std::max;
+using std::min;
+using std::vector;
+
+namespace s2coding {
+
+// Like util_bits::InterleaveUint32, but interleaves bit pairs rather than
+// individual bits.  This format is faster to decode than the fully interleaved
+// format, and produces the same results for our use case.
+inline uint64 InterleaveUint32BitPairs(const uint32 val0, const uint32 val1) {
+  uint64 v0 = val0, v1 = val1;
+  v0 = (v0 | (v0 << 16)) & 0x0000ffff0000ffff;
+  v1 = (v1 | (v1 << 16)) & 0x0000ffff0000ffff;
+  v0 = (v0 | (v0 << 8)) & 0x00ff00ff00ff00ff;
+  v1 = (v1 | (v1 << 8)) & 0x00ff00ff00ff00ff;
+  v0 = (v0 | (v0 << 4)) & 0x0f0f0f0f0f0f0f0f;
+  v1 = (v1 | (v1 << 4)) & 0x0f0f0f0f0f0f0f0f;
+  v0 = (v0 | (v0 << 2)) & 0x3333333333333333;
+  v1 = (v1 | (v1 << 2)) & 0x3333333333333333;
+  return v0 | (v1 << 2);
+}
+
+// This code is about 50% faster than util_bits::DeinterleaveUint32, which
+// uses a lookup table.  The speed advantage is expected to be even larger in
+// code that mixes bit interleaving with other significant operations since it
+// doesn't require keeping a 256-byte lookup table in the L1 data cache.
+inline void DeinterleaveUint32BitPairs(uint64 code,
+                                       uint32 *val0, uint32 *val1) {
+  uint64 v0 = code, v1 = code >> 2;
+  v0 &= 0x3333333333333333;
+  v0 |= v0 >> 2;
+  v1 &= 0x3333333333333333;
+  v1 |= v1 >> 2;
+  v0 &= 0x0f0f0f0f0f0f0f0f;
+  v0 |= v0 >> 4;
+  v1 &= 0x0f0f0f0f0f0f0f0f;
+  v1 |= v1 >> 4;
+  v0 &= 0x00ff00ff00ff00ff;
+  v0 |= v0 >> 8;
+  v1 &= 0x00ff00ff00ff00ff;
+  v1 |= v1 >> 8;
+  v0 &= 0x0000ffff0000ffff;
+  v0 |= v0 >> 16;
+  v1 &= 0x0000ffff0000ffff;
+  v1 |= v1 >> 16;
+  *val0 = v0;
+  *val1 = v1;
+}
+
+// Forward declarations.
+void EncodeS2PointVectorFast(Span<const S2Point> points, Encoder* encoder);
+void EncodeS2PointVectorCompact(Span<const S2Point> points, Encoder* encoder);
+
+// To save space (especially for vectors of length 0, 1, and 2), the encoding
+// format is encoded in the low-order 3 bits of the vector size.  Up to 7
+// encoding formats are supported (only 2 are currently defined).  Additional
+// formats could be supported by using "7" as an overflow indicator and
+// encoding the actual format separately, but it seems unlikely we will ever
+// need to do that.
+static const int kEncodingFormatBits = 3;
+static const uint8 kEncodingFormatMask = (1 << kEncodingFormatBits) - 1;
+
+void EncodeS2PointVector(Span<const S2Point> points, CodingHint hint,
+                         Encoder* encoder) {
+  switch (hint) {
+    case CodingHint::FAST:
+      return EncodeS2PointVectorFast(points, encoder);
+
+    case CodingHint::COMPACT:
+      return EncodeS2PointVectorCompact(points, encoder);
+
+    default:
+      S2_LOG(DFATAL) << "Unknown CodingHint: " << static_cast<int>(hint);
+  }
+}
+
+bool EncodedS2PointVector::Init(Decoder* decoder) {
+  if (decoder->avail() < 1) return false;
+
+  // Peek at the format but don't advance the decoder; the format-specific
+  // Init functions will do that.
+  format_ = static_cast<Format>(*decoder->ptr() & kEncodingFormatMask);
+  switch (format_) {
+    case UNCOMPRESSED:
+      return InitUncompressedFormat(decoder);
+
+    case CELL_IDS:
+      return InitCellIdsFormat(decoder);
+
+    default:
+      return false;
+  }
+}
+
+vector<S2Point> EncodedS2PointVector::Decode() const {
+  vector<S2Point> points;
+  points.reserve(size_);
+  for (int i = 0; i < size_; ++i) {
+    points.push_back((*this)[i]);
+  }
+  return points;
+}
+
+
+//////////////////////////////////////////////////////////////////////////////
+//                     UNCOMPRESSED Encoding Format
+//////////////////////////////////////////////////////////////////////////////
+
+// Encodes a vector of points, optimizing for (encoding and decoding) speed.
+void EncodeS2PointVectorFast(Span<const S2Point> points, Encoder* encoder) {
+#ifndef IS_LITTLE_ENDIAN
+  S2_LOG(FATAL) << "Not implemented on big-endian architectures";
+#endif
+
+  // This function always uses the UNCOMPRESSED encoding.  The header consists
+  // of a varint64 in the following format:
+  //
+  //   bits 0-2:  encoding format (UNCOMPRESSED)
+  //   bits 3-63: vector size
+  //
+  // This is followed by an array of S2Points in little-endian order.
+  encoder->Ensure(Varint::kMax64 + points.size() * sizeof(S2Point));
+  uint64 size_format = (points.size() << kEncodingFormatBits |
+                        EncodedS2PointVector::UNCOMPRESSED);
+  encoder->put_varint64(size_format);
+  encoder->putn(points.data(), points.size() * sizeof(S2Point));
+}
+
+bool EncodedS2PointVector::InitUncompressedFormat(Decoder* decoder) {
+#if !defined(IS_LITTLE_ENDIAN) || defined(__arm__) || \
+  defined(ABSL_INTERNAL_NEED_ALIGNED_LOADS)
+  // TODO(ericv): Make this work on platforms that don't support unaligned
+  // 64-bit little-endian reads, e.g. by falling back to
+  //
+  //   bit_cast<double>(little_endian::Load64()).
+  //
+  // Maybe the compiler is smart enough that we can do this all the time,
+  // but more likely we will need two cases using the #ifdef above.
+  // (Note that even ARMv7 does not support unaligned 64-bit loads.)
+  S2_LOG(DFATAL) << "Needs architecture with 64-bit little-endian unaligned loads";
+  return false;
+#endif
+
+  uint64 size;
+  if (!decoder->get_varint64(&size)) return false;
+  size >>= kEncodingFormatBits;
+
+  // Note that the encoding format supports up to 2**59 vertices, but we
+  // currently only support decoding up to 2**32 vertices.
+  if (size > std::numeric_limits<uint32>::max()) return false;
+  size_ = size;
+
+  size_t bytes = size_t{size_} * sizeof(S2Point);
+  if (decoder->avail() < bytes) return false;
+
+  uncompressed_.points = reinterpret_cast<const S2Point*>(decoder->ptr());
+  decoder->skip(bytes);
+  return true;
+}
+
+
+//////////////////////////////////////////////////////////////////////////////
+//                     CELL_IDS Encoding Format
+//////////////////////////////////////////////////////////////////////////////
+
+// Represents a point that can be encoded as an S2CellId center.
+// (If such an encoding is not possible then level < 0.)
+struct CellPoint {
+  // Constructor necessary in order to narrow "int" arguments to "int8".
+  CellPoint(int level, int face, uint32 si, uint32 ti)
+    : level(level), face(face), si(si), ti(ti) {}
+
+  int8 level, face;
+  uint32 si, ti;
+};
+
+// S2CellIds are represented in a special 64-bit format and are encoded in
+// fixed-size blocks.  kBlockSize represents the number of values per block.
+// Block sizes of 4, 8, 16, and 32 were tested and kBlockSize == 16 seems to
+// offer the best compression.  (Note that kBlockSize == 32 requires some code
+// modifications which have since been removed.)
+constexpr int kBlockShift = 4;
+constexpr size_t kBlockSize = 1 << kBlockShift;
+
+// Used to indicate that a point must be encoded as an exception (a 24-byte
+// S2Point) rather than as an S2CellId.
+constexpr uint64 kException = ~0ULL;
+
+// Represents the encoding parameters to be used for a given block (consisting
+// of kBlockSize encodable 64-bit values).  See below.
+struct BlockCode {
+  int delta_bits;     // Delta length in bits (multiple of 4)
+  int offset_bits;    // Offset length in bits (multiple of 8)
+  int overlap_bits;   // {Delta, Offset} overlap in bits (0 or 4)
+};
+
+// Returns a bit mask with "n" low-order 1 bits, for 0 <= n <= 64.
+inline uint64 BitMask(int n) {
+  return (n == 0) ? 0 : (~0ULL >> (64 - n));
+}
+
+// Returns the maximum number of bits per value at the given S2CellId level.
+inline int MaxBitsForLevel(int level) {
+  return 2 * level + 3;
+}
+
+// Returns the number of bits that "base" should be right-shifted in order to
+// encode only its leading "base_bits" bits, assuming that all points are
+// encoded at the given S2CellId level.
+inline int BaseShift(int level, int base_bits) {
+  return max(0, MaxBitsForLevel(level) - base_bits);
+}
+
+// Forward declarations.
+int ChooseBestLevel(Span<const S2Point> points, vector<CellPoint>* cell_points);
+vector<uint64> ConvertCellsToValues(const vector<CellPoint>& cell_points,
+                                    int level, bool* have_exceptions);
+uint64 ChooseBase(const vector<uint64>& values, int level, bool have_exceptions,
+                  int* base_bits);
+BlockCode GetBlockCode(Span<const uint64> values, uint64 base,
+                       bool have_exceptions);
+
+// Encodes a vector of points, optimizing for space.
+void EncodeS2PointVectorCompact(Span<const S2Point> points, Encoder* encoder) {
+  // OVERVIEW
+  // --------
+  //
+  // We attempt to represent each S2Point as the center of an S2CellId.  All
+  // S2CellIds must be at the same level.  Any points that cannot be encoded
+  // exactly as S2CellId centers are stored as exceptions using 24 bytes each.
+  // If there are so many exceptions that the CELL_IDS encoding does not save
+  // significant space, we give up and use the uncompressed encoding.
+  //
+  // The first step is to choose the best S2CellId level.  This requires
+  // converting each point to (face, si, ti) coordinates and checking whether
+  // the point can be represented exactly as an S2CellId center at some level.
+  // We then build a histogram of S2CellId levels (just like the similar code
+  // in S2Polygon::Encode) and choose the best level (or give up, if there are
+  // not enough S2CellId-encodable points).
+  //
+  // The simplest approach would then be to take all the S2CellIds and
+  // right-shift them to remove all the constant bits at the chosen level.
+  // This would give the best spatial locality and hence the smallest deltas.
+  // However instead we give up some spatial locality and use the similar but
+  // faster transformation described below.
+  //
+  // Each encodable point is first converted to the (sj, tj) representation
+  // defined below:
+  //
+  //   sj = (((face & 3) << 30) | (si >> 1)) >> (30 - level);
+  //   tj = (((face & 4) << 29) | ti) >> (31 - level);
+  //
+  // These two values encode the (face, si, ti) tuple using (2 * level + 3)
+  // bits.  To see this, recall that "si" and "ti" are 31-bit values that all
+  // share a common suffix consisting of a "1" bit followed by (30 - level)
+  // "0" bits.  The code above right-shifts these values to remove the
+  // constant bits and then prepends the bits for "face", yielding a total of
+  // (level + 2) bits for "sj" and (level + 1) bits for "tj".
+  //
+  // We then combine (sj, tj) into one 64-bit value by interleaving bit pairs:
+  //
+  //   v = InterleaveBitPairs(sj, tj);
+  //
+  // (We could also interleave individual bits, but it is faster this way.)
+  // The result is similar to right-shifting an S2CellId by (61 - 2 * level),
+  // except that it is faster to decode and the spatial locality is not quite
+  // as good.
+  //
+  // The 64-bit values are divided into blocks of size 8, and then each value is
+  // encoded as the sum of a base value, a per-block offset, and a per-value
+  // delta within that block:
+  //
+  //   v[i,j] = base + offset[i] + delta[i, j]
+  //
+  // where "i" represents a block and "j" represents an entry in that block.
+  //
+  // The deltas for each block are encoded using a fixed number of 4-bit nibbles
+  // (1-16 nibbles per delta).  This allows any delta to be accessed in constant
+  // time.
+  //
+  // The "offset" for each block is a 64-bit value encoded in 0-8 bytes.  The
+  // offset is left-shifted such that it overlaps the deltas by a configurable
+  // number of bits (either 0 or 4), called the "overlap".  The overlap and
+  // offset length (0-8 bytes) are specified per block.  The reason for the
+  // overlap is that it allows fewer delta bits to be used in some cases.  For
+  // example if base == 0 and the range within a block is 0xf0 to 0x110, then
+  // rather than using 12-bits deltas with an offset of 0, the overlap lets us
+  // use 8-bits deltas with an offset of 0xf0 (saving 7 bytes per block).
+  //
+  // The global minimum value "base" is encoded using 0-7 bytes starting with
+  // the most-significant non-zero bit possible for the chosen level.  For
+  // example, if (level == 7) then the encoded values have at most 17 bits, so
+  // if "base" is encoded in 1 byte then it is shifted to occupy bits 9-16.
+  //
+  // Example: at level == 15, there are at most 33 non-zero value bits.  The
+  // following shows the bit positions covered by "base", "offset", and "delta"
+  // assuming that "base" and "offset" are encoded in 2 bytes each, deltas are
+  // encoded in 2 nibbles (1 byte) each, and "overlap" is 4 bits:
+  //
+  //   Base:             1111111100000000-----------------
+  //   Offset:           -------------1111111100000000----
+  //   Delta:            -------------------------00000000
+  //   Overlap:                                   ^^^^
+  //
+  // The numbers (0 or 1) in this diagram denote the byte number of the encoded
+  // value.  Notice that "base" is shifted so that it starts at the leftmost
+  // possible bit, "delta" always starts at the rightmost possible bit (bit 0),
+  // and "offset" is shifted so that it overlaps "delta" by the chosen "overlap"
+  // (either 0 or 4 bits).  Also note that all of these values are summed, and
+  // therefore each value can affect higher-order bits due to carries.
+  //
+  // NOTE(ericv): Encoding deltas in 4-bit rather than 8-bit length increments
+  // reduces encoded sizes by about 7%.  Allowing a 4-bit overlap between the
+  // offset and deltas reduces encoded sizes by about 1%.  Both optimizations
+  // make the code more complex but don't affect running times significantly.
+  //
+  // ENCODING DETAILS
+  // ----------------
+  //
+  // Now we can move on to the actual encodings.  First, there is a 2 byte
+  // header encoded as follows:
+  //
+  //  Byte 0, bits 0-2: encoding_format (CELL_IDS)
+  //  Byte 0, bit  3:   have_exceptions
+  //  Byte 0, bits 4-7: (last_block_size - 1)
+  //  Byte 1, bits 0-2: base_bytes
+  //  Byte 1, bits 3-7: level (0-30)
+  //
+  // This is followed by an EncodedStringVector containing the encoded blocks.
+  // Each block contains kBlockSize (8) values.  The total size of the
+  // EncodeS2PointVector is not stored explicity, but instead is calculated as
+  //
+  //     num_values == kBlockSize * (num_blocks - 1) + last_block_size .
+  //
+  // (An empty vector has num_blocks == 0 and last_block_size == kBlockSize.)
+  //
+  // Each block starts with a 1 byte header containing the following:
+  //
+  //  Byte 0, bits 0-2: (offset_bytes - overlap_nibbles)
+  //  Byte 0, bit  3:   overlap_nibbles
+  //  Byte 0, bits 4-7: (delta_nibbles - 1)
+  //
+  // "overlap_nibbles" is either 0 or 1 (indicating an overlap of 0 or 4 bits),
+  // while "offset_bytes" is in the range 0-8 (indicating the number of bytes
+  // used to encode the offset for this block).  Note that some combinations
+  // cannot be encoded: in particular, offset_bytes == 0 can only be encoded
+  // with an overlap of 0 bits, and offset_bytes == 8 can only be encoded with
+  // an overlap of 4 bits.  This allows us to encode offset lengths of 0-8
+  // rather than just 0-7 without using an extra bit.  (Note that the
+  // combinations that can't be encoded are not useful anyway.)
+  //
+  // The header is followed by "offset_bytes" bytes for the offset, and then
+  // (4 * delta_nibbles) bytes for the deltas.
+  //
+  // If there are any points that could not be represented as S2CellIds, then
+  // "have_exceptions" in the header is true.  In that case the delta values
+  // within each block are encoded as (delta + 8), and values 0-7 are used to
+  // represent exceptions.  If a block has exceptions, they are encoded
+  // immediately following the array of deltas, and are referenced by encoding
+  // the corresponding exception index (0-7) as the delta.
+  //
+  // TODO(ericv): A vector containing a single leaf cell is currently encoded as
+  // 13 bytes (2 byte header, 7 byte base, 1 byte block count, 1 byte block
+  // length, 1 byte block header, 1 byte delta).  However if this case occurs
+  // often, a better solution would be implement a separate format that encodes
+  // the leading k bytes of an S2CellId.  It would have a one-byte header
+  // consisting of the encoding format (3 bits) and the number of bytes encoded
+  // (3 bits), followed by the S2CellId bytes.  The extra 2 header bits could be
+  // used to store single points using other encodings, e.g. E7.
+  //
+  // If we wind up using 8-value blocks, we could also use the extra bit in the
+  // first byte of the header to indicate that there is only one value, and
+  // then skip the 2nd byte of header and the EncodedStringVector.  But this
+  // would be messy because it also requires special cases while decoding.
+  // Essentially this would be a sub-format within the CELL_IDS format.
+
+  // 1. Compute (level, face, si, ti) for each point, build a histogram of
+  // levels, and determine the optimal level to use for encoding (if any).
+  vector<CellPoint> cell_points;
+  int level = ChooseBestLevel(points, &cell_points);
+  if (level < 0) {
+    return EncodeS2PointVectorFast(points, encoder);
+  }
+
+  // 2. Convert the points into encodable 64-bit values.  We don't use the
+  // S2CellId itself because it requires a somewhat more complicated bit
+  // interleaving operation.
+  //
+  // TODO(ericv): Benchmark using shifted S2CellIds instead.
+  bool have_exceptions;
+  vector<uint64> values = ConvertCellsToValues(cell_points, level,
+                                               &have_exceptions);
+
+  // 3. Choose the global encoding parameter "base" (consisting of the bit
+  // prefix shared by all values to be encoded).
+  int base_bits;
+  uint64 base = ChooseBase(values, level, have_exceptions, &base_bits);
+
+  // Now encode the output, starting with the 2-byte header (see above).
+  int num_blocks = (values.size() + kBlockSize - 1) >> kBlockShift;
+  int base_bytes = base_bits >> 3;
+  encoder->Ensure(2 + base_bytes);
+  int last_block_count = values.size() - kBlockSize * (num_blocks - 1);
+  S2_DCHECK_GE(last_block_count, 0);
+  S2_DCHECK_LE(last_block_count, kBlockSize);
+  S2_DCHECK_LE(base_bytes, 7);
+  S2_DCHECK_LE(level, 30);
+  encoder->put8(EncodedS2PointVector::CELL_IDS |
+                (have_exceptions << 3) |
+                ((last_block_count - 1) << 4));
+  encoder->put8(base_bytes | (level << 3));
+
+  // Next we encode 0-7 bytes of "base".
+  int base_shift = BaseShift(level, base_bits);
+  EncodeUintWithLength(base >> base_shift, base_bytes, encoder);
+
+  // Now we encode the contents of each block.
+  StringVectorEncoder blocks;
+  vector<S2Point> exceptions;
+  uint64 offset_bytes_sum = 0;
+  uint64 delta_nibbles_sum = 0;
+  uint64 exceptions_sum = 0;
+  for (int i = 0; i < values.size(); i += kBlockSize) {
+    int block_size = min(kBlockSize, values.size() - i);
+    BlockCode code = GetBlockCode(MakeSpan(&values[i], block_size),
+                                  base, have_exceptions);
+
+    // Encode the one-byte block header (see above).
+    Encoder* block = blocks.AddViaEncoder();
+    int offset_bytes = code.offset_bits >> 3;
+    int delta_nibbles = code.delta_bits >> 2;
+    int overlap_nibbles = code.overlap_bits >> 2;
+    block->Ensure(1 + offset_bytes + (kBlockSize / 2) * delta_nibbles);
+    S2_DCHECK_LE(offset_bytes - overlap_nibbles, 7);
+    S2_DCHECK_LE(overlap_nibbles, 1);
+    S2_DCHECK_LE(delta_nibbles, 16);
+    block->put8((offset_bytes - overlap_nibbles) |
+                (overlap_nibbles << 3) | (delta_nibbles - 1) << 4);
+
+    // Determine the offset for this block, and whether there are exceptions.
+    uint64 offset = ~0ULL;
+    int num_exceptions = 0;
+    for (int j = 0; j < block_size; ++j) {
+      if (values[i + j] == kException) {
+        num_exceptions += 1;
+      } else {
+        S2_DCHECK_GE(values[i + j], base);
+        offset = min(offset, values[i + j] - base);
+      }
+    }
+    if (num_exceptions == block_size) offset = 0;
+
+    // Encode the offset.
+    int offset_shift = code.delta_bits - code.overlap_bits;
+    offset &= ~BitMask(offset_shift);
+    S2_DCHECK_EQ(offset == 0, offset_bytes == 0);
+    if (offset > 0) {
+      EncodeUintWithLength(offset >> offset_shift, offset_bytes, block);
+    }
+
+    // Encode the deltas, and also gather any exceptions present.
+    int delta_bytes = (delta_nibbles + 1) >> 1;
+    exceptions.clear();
+    for (int j = 0; j < block_size; ++j) {
+      uint64 delta;
+      if (values[i + j] == kException) {
+        delta = exceptions.size();
+        exceptions.push_back(points[i + j]);
+      } else {
+        S2_DCHECK_GE(values[i + j], offset + base);
+        delta = values[i + j] - (offset + base);
+        if (have_exceptions) {
+          S2_DCHECK_LE(delta, ~0ULL - kBlockSize);
+          delta += kBlockSize;
+        }
+      }
+      S2_DCHECK_LE(delta, BitMask(code.delta_bits));
+      if ((delta_nibbles & 1) && (j & 1)) {
+        // Combine this delta with the high-order 4 bits of the previous delta.
+        uint8 last_byte = *(block->base() + block->length() - 1);
+        block->RemoveLast(1);
+        delta = (delta << 4) | (last_byte & 0xf);
+      }
+      EncodeUintWithLength(delta, delta_bytes, block);
+    }
+    // Append any exceptions to the end of the block.
+    if (num_exceptions > 0) {
+      int exceptions_bytes = exceptions.size() * sizeof(S2Point);
+      block->Ensure(exceptions_bytes);
+      block->putn(exceptions.data(), exceptions_bytes);
+    }
+    offset_bytes_sum += offset_bytes;
+    delta_nibbles_sum += delta_nibbles;
+    exceptions_sum += num_exceptions;
+  }
+  blocks.Encode(encoder);
+}
+
+// Returns the S2CellId level for which the greatest number of the given points
+// can be represented as the center of an S2CellId.  Initializes "cell_points"
+// to contain the S2CellId representation of each point (if any).  Returns -1
+// if there is no S2CellId that would result in significant space savings.
+int ChooseBestLevel(Span<const S2Point> points,
+                    vector<CellPoint>* cell_points) {
+  cell_points->clear();
+  cell_points->reserve(points.size());
+
+  // Count the number of points at each level.
+  int level_counts[S2CellId::kMaxLevel + 1] = { 0 };
+  for (const S2Point& point : points) {
+    int face;
+    uint32 si, ti;
+    int level = S2::XYZtoFaceSiTi(point, &face, &si, &ti);
+    cell_points->push_back(CellPoint(level, face, si, ti));
+    if (level >= 0) ++level_counts[level];
+  }
+  // Choose the level for which the most points can be encoded.
+  int best_level = 0;
+  for (int level = 1; level <= S2CellId::kMaxLevel; ++level) {
+    if (level_counts[level] > level_counts[best_level]) {
+      best_level = level;
+    }
+  }
+  // The uncompressed encoding is smaller *and* faster when very few of the
+  // points are encodable as S2CellIds.  The CELL_IDS encoding uses about 1
+  // extra byte per point in this case, consisting of up to a 3 byte
+  // EncodedStringVector offset for each block, a 1 byte block header, and 4
+  // bits per delta (encoding an exception number from 0-7), for a total of 8
+  // bytes per block.  This represents a space overhead of about 4%, so we
+  // require that at least 5% of the input points should be encodable as
+  // S2CellIds in order for the CELL_IDS format to be worthwhile.
+  constexpr double kMinEncodableFraction = 0.05;
+  if (level_counts[best_level] <= kMinEncodableFraction * points.size()) {
+    return -1;
+  }
+  return best_level;
+}
+
+// Given a vector of points in CellPoint format and an S2CellId level that has
+// been chosen for encoding, returns a vector of 64-bit values that should be
+// encoded in order to represent these points.  Points that cannot be
+// represented losslessly as the center of an S2CellId at the chosen level are
+// indicated by the value "kException".  "have_exceptions" is set to indicate
+// whether any exceptions were present.
+vector<uint64> ConvertCellsToValues(const vector<CellPoint>& cell_points,
+                                    int level, bool* have_exceptions) {
+  vector<uint64> values;
+  values.reserve(cell_points.size());
+  *have_exceptions = false;
+  int shift = S2CellId::kMaxLevel - level;
+  for (CellPoint cp : cell_points) {
+    if (cp.level != level) {
+      values.push_back(kException);
+      *have_exceptions = true;
+    } else {
+      // Note that bit 31 of tj is always zero, and that bits are interleaved in
+      // such a way that bit 63 of the result is always zero.
+      //
+      // The S2CellId version of the following code is:
+      // uint64 v = S2CellId::FromFaceIJ(cp.face, cp.si >> 1, cp.ti >> 1).
+      //            parent(level).id() >> (2 * shift + 1);
+      uint32 sj = (((cp.face & 3) << 30) | (cp.si >> 1)) >> shift;
+      uint32 tj = (((cp.face & 4) << 29) | cp.ti) >> (shift + 1);
+      uint64 v = InterleaveUint32BitPairs(sj, tj);
+      S2_DCHECK_LE(v, BitMask(MaxBitsForLevel(level)));
+      values.push_back(v);
+    }
+  }
+  return values;
+}
+
+uint64 ChooseBase(const vector<uint64>& values, int level, bool have_exceptions,
+                  int* base_bits) {
+  // Find the minimum and maximum non-exception values to be represented.
+  uint64 v_min = kException, v_max = 0;
+  for (auto v : values) {
+    if (v != kException) {
+      v_min = min(v_min, v);
+      v_max = max(v_max, v);
+    }
+  }
+  if (v_min == kException) return 0;
+
+  // Generally "base" is chosen as the bit prefix shared by v_min and v_max.
+  // However there are a few adjustments we need to make.
+  //
+  // 1. Encodings are usually smaller if the bits represented by "base" and
+  // "delta" do not overlap.  Usually the shared prefix rule does this
+  // automatically, but if v_min == v_max or there are special circumstances
+  // that increase delta_bits (such as values.size() == 1) then we need to
+  // make an adjustment.
+  //
+  // 2. The format only allows us to represent up to 7 bytes (56 bits) of
+  // "base", so we need to ensure that "base" conforms to this requirement.
+  int min_delta_bits = (have_exceptions || values.size() == 1) ? 8 : 4;
+  int excluded_bits = max(Bits::Log2Floor64(v_min ^ v_max) + 1,
+                          max(min_delta_bits, BaseShift(level, 56)));
+  uint64 base = v_min & ~BitMask(excluded_bits);
+
+  // Determine how many bytes are needed to represent this prefix.
+  if (base == 0) {
+    *base_bits = 0;
+  } else {
+    int low_bit = Bits::FindLSBSetNonZero64(base);
+    *base_bits = (MaxBitsForLevel(level) - low_bit + 7) & ~7;
+  }
+
+  // Since base_bits has been rounded up to a multiple of 8, we may now be
+  // able to represent additional bits of v_min.  In general this reduces the
+  // final encoded size.
+  //
+  // NOTE(ericv): A different strategy for choosing "base" is to encode all
+  // blocks under the assumption that "base" equals v_min exactly, and then
+  // set base equal to the minimum-length prefix of "v_min" that allows these
+  // encodings to be used.  This strategy reduces the encoded sizes by
+  // about 0.2% relative to the strategy here, but is more complicated.
+  return v_min & ~BitMask(BaseShift(level, *base_bits));
+}
+
+// Returns true if the range of values [d_min, d_max] can be encoded using the
+// specified parameters (delta_bits, overlap_bits, and have_exceptions).
+bool CanEncode(uint64 d_min, uint64 d_max, int delta_bits,
+               int overlap_bits, bool have_exceptions) {
+  // "offset" can't represent the lowest (delta_bits - overlap_bits) of d_min.
+  d_min &= ~BitMask(delta_bits - overlap_bits);
+
+  // The maximum delta is reduced by kBlockSize if any exceptions exist, since
+  // deltas 0..kBlockSize-1 are used to indicate exceptions.
+  uint64 max_delta = BitMask(delta_bits);
+  if (have_exceptions) {
+    if (max_delta < kBlockSize) return false;
+    max_delta -= kBlockSize;
+  }
+  // The first test below is necessary to avoid 64-bit overflow.
+  return (d_min > ~max_delta) || (d_min + max_delta >= d_max);
+}
+
+// Given a vector of 64-bit values to be encoded and an S2CellId level, returns
+// the optimal encoding parameters that should be used to encode each block.
+// Also returns the global minimum value "base" and the number of bits that
+// should be used to encode it ("base_bits").
+BlockCode GetBlockCode(Span<const uint64> values, uint64 base,
+                       bool have_exceptions) {
+  // "b_min" and "b_max"n are the minimum and maximum values within this block.
+  uint64 b_min = kException, b_max = 0;
+  for (uint64 v : values) {
+    if (v != kException) {
+      b_min = min(b_min, v);
+      b_max = max(b_max, v);
+    }
+  }
+  if (b_min == kException) {
+    // All values in this block are exceptions.
+    return BlockCode{4, 0, 0};
+  }
+
+  // Adjust the min/max values so that they are relative to "base".
+  b_min -= base;
+  b_max -= base;
+
+  // Determine the minimum possible delta length and overlap that can be used
+  // to encode this block.  The block will usually be encodable using the
+  // number of bits in (b_max - b_min) rounded up to a multiple of 4.  If this
+  // is not possible, the preferred solution is to shift "offset" so that the
+  // delta and offset values overlap by 4 bits (since this only costs an
+  // average of 4 extra bits per block).  Otherwise we increase the delta size
+  // by 4 bits.  Certain cases require that both of these techniques are used.
+  //
+  // Example 1: b_min = 0x72, b_max = 0x7e.  The range is 0x0c.  This can be
+  // encoded using delta_bits = 4 and overlap_bits = 0, which allows us to
+  // represent an offset of 0x70 and a maximum delta of 0x0f, so that we can
+  // encode values up to 0x7f.
+  //
+  // Example 2: b_min = 0x78, b_max = 0x84.  The range is 0x0c, but in this
+  // case it is not sufficient to use delta_bits = 4 and overlap_bits = 0
+  // because we can again only represent an offset of 0x70, so the maximum
+  // delta of 0x0f only lets us encode values up to 0x7f.  However if we
+  // increase the overlap to 4 bits then we can represent an offset of 0x78,
+  // which lets us encode values up to 0x78 + 0x0f = 0x87.
+  //
+  // Example 3: b_min = 0x08, b_max = 0x104.  The range is 0xfc, so we should
+  // be able to use 8-bit deltas.  But even with a 4-bit overlap, we can still
+  // only encode offset = 0 and a maximum value of 0xff.  (We don't allow
+  // bigger overlaps because statistically they are not worthwhile.)  Instead
+  // we increase the delta size to 12 bits, which handles this case easily.
+  //
+  // Example 4: b_min = 0xf08, b_max = 0x1004.  The range is 0xfc, so we
+  // should be able to use 8-bit deltas.  With 8-bit deltas and no overlap, we
+  // have offset = 0xf00 and a maximum encodable value of 0xfff.  With 8-bit
+  // deltas and a 4-bit overlap, we still have offset = 0xf00 and a maximum
+  // encodable value of 0xfff.  Even with 12-bit deltas, we have offset = 0
+  // and we can still only represent 0xfff.  However with delta_bits = 12 and
+  // overlap_bits = 4, we can represent offset = 0xf00 and a maximum encodable
+  // value of 0xf00 + 0xfff = 0x1eff.
+  //
+  // It is possible to show that this last example is the worst case, i.e.  we
+  // do not need to consider increasing delta_bits or overlap_bits further.
+  int delta_bits = (max(1, Bits::Log2Floor64(b_max - b_min)) + 3) & ~3;
+  int overlap_bits = 0;
+  if (!CanEncode(b_min, b_max, delta_bits, 0, have_exceptions)) {
+    if (CanEncode(b_min, b_max, delta_bits, 4, have_exceptions)) {
+      overlap_bits = 4;
+    } else {
+      S2_DCHECK_LE(delta_bits, 60);
+      delta_bits += 4;
+      if (!CanEncode(b_min, b_max, delta_bits, 0, have_exceptions)) {
+        S2_DCHECK(CanEncode(b_min, b_max, delta_bits, 4, have_exceptions));
+        overlap_bits = 4;
+      }
+    }
+  }
+
+  // Avoid wasting 4 bits of delta when the block size is 1.  This reduces the
+  // encoding size for single leaf cells by one byte.
+  if (values.size() == 1) {
+    S2_DCHECK(delta_bits == 4 && overlap_bits == 0);
+    delta_bits = 8;
+  }
+
+  // Now determine the number of bytes needed to encode "offset", given the
+  // chosen delta length.
+  uint64 max_delta = BitMask(delta_bits) - (have_exceptions ? kBlockSize : 0);
+  int offset_bits = 0;
+  if (b_max > max_delta) {
+    // At least one byte of offset is required.  Round up the minimum offset
+    // to the next encodable value, and determine how many bits it has.
+    int offset_shift = delta_bits - overlap_bits;
+    uint64 mask = BitMask(offset_shift);
+    uint64 min_offset = (b_max - max_delta + mask) & ~mask;
+    S2_DCHECK_GT(min_offset, 0);
+    offset_bits =
+        (Bits::FindMSBSetNonZero64(min_offset) + 1 - offset_shift + 7) & ~7;
+    // A 64-bit offset can only be encoded with an overlap of 4 bits.
+    if (offset_bits == 64) overlap_bits = 4;
+  }
+  return BlockCode{delta_bits, offset_bits, overlap_bits};
+}
+
+bool EncodedS2PointVector::InitCellIdsFormat(Decoder* decoder) {
+  // This function inverts the encodings documented above.
+  // First we decode the two-byte header.
+  if (decoder->avail() < 2) return false;
+  uint8 header1 = decoder->get8();
+  uint8 header2 = decoder->get8();
+  S2_DCHECK_EQ(header1 & 7, CELL_IDS);
+  int last_block_count, base_bytes;
+  cell_ids_.have_exceptions = (header1 & 8) != 0;
+  last_block_count = (header1 >> 4) + 1;
+  base_bytes = header2 & 7;
+  cell_ids_.level = header2 >> 3;
+
+  // Decode the base value (if any).
+  uint64 base;
+  if (!DecodeUintWithLength(base_bytes, decoder, &base)) return false;
+  cell_ids_.base = base << BaseShift(cell_ids_.level, base_bytes << 3);
+
+  // Initialize the vector of encoded blocks.
+  if (!cell_ids_.blocks.Init(decoder)) return false;
+  size_ = kBlockSize * (cell_ids_.blocks.size() - 1) + last_block_count;
+  return true;
+}
+
+S2Point EncodedS2PointVector::DecodeCellIdsFormat(int i) const {
+  // This function inverts the encodings documented above.
+
+  // First we decode the block header.
+  const char* ptr = cell_ids_.blocks.GetStart(i >> kBlockShift);
+  uint8 header = *ptr++;
+  int overlap_nibbles = (header >> 3) & 1;
+  int offset_bytes = (header & 7) + overlap_nibbles;
+  int delta_nibbles = (header >> 4) + 1;
+
+  // Decode the offset for this block.
+  int offset_shift = (delta_nibbles - overlap_nibbles) << 2;
+  uint64 offset = GetUintWithLength<uint64>(ptr, offset_bytes) << offset_shift;
+  ptr += offset_bytes;
+
+  // Decode the delta for the requested value.
+  int delta_nibble_offset = (i & (kBlockSize - 1)) * delta_nibbles;
+  int delta_bytes = (delta_nibbles + 1) >> 1;
+  const char* delta_ptr = ptr + (delta_nibble_offset >> 1);
+  uint64 delta = GetUintWithLength<uint64>(delta_ptr, delta_bytes);
+  delta >>= (delta_nibble_offset & 1) << 2;
+  delta &= BitMask(delta_nibbles << 2);
+
+  // Test whether this point is encoded as an exception.
+  if (cell_ids_.have_exceptions) {
+    if (delta < kBlockSize) {
+      int block_size = min(kBlockSize, size_ - (i & ~(kBlockSize - 1)));
+      ptr += (block_size * delta_nibbles + 1) >> 1;
+      ptr += delta * sizeof(S2Point);
+      return *reinterpret_cast<const S2Point*>(ptr);
+    }
+    delta -= kBlockSize;
+  }
+
+  // Otherwise convert the 64-bit value back to an S2Point.
+  uint64 value = cell_ids_.base + offset + delta;
+  int shift = S2CellId::kMaxLevel - cell_ids_.level;
+
+  // The S2CellId version of the following code is:
+  //   return S2CellId(((value << 1) | 1) << (2 * shift)).ToPoint();
+  uint32 sj, tj;
+  DeinterleaveUint32BitPairs(value, &sj, &tj);
+  int si = (((sj << 1) | 1) << shift) & 0x7fffffff;
+  int ti = (((tj << 1) | 1) << shift) & 0x7fffffff;
+  int face = ((sj << shift) >> 30) | (((tj << (shift + 1)) >> 29) & 4);
+  return S2::FaceUVtoXYZ(face, S2::STtoUV(S2::SiTitoST(si)),
+                         S2::STtoUV(S2::SiTitoST(ti))).Normalize();
+}
+
+}  // namespace s2coding
diff --git a/src/s2/encoded_s2point_vector.h b/src/s2/encoded_s2point_vector.h
new file mode 100644 (file)
index 0000000..44ce5eb
--- /dev/null
@@ -0,0 +1,149 @@
+// Copyright 2018 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// Author: ericv@google.com (Eric Veach)
+
+#ifndef S2_ENCODED_S2POINT_VECTOR_H_
+#define S2_ENCODED_S2POINT_VECTOR_H_
+
+#include <atomic>
+#include "absl/types/span.h"
+#include "s2/encoded_string_vector.h"
+#include "s2/encoded_uint_vector.h"
+#include "s2/s2point.h"
+
+namespace s2coding {
+
+// Controls whether to optimize for speed or size when encoding points.  (Note
+// that encoding is always lossless, and that currently compact encodings are
+// only possible when points have been snapped to S2CellId centers.)
+enum class CodingHint : uint8 { FAST, COMPACT };
+
+// Encodes a vector of S2Points in a format that can later be decoded as an
+// EncodedS2PointVector.
+//
+// REQUIRES: "encoder" uses the default constructor, so that its buffer
+//           can be enlarged as necessary by calling Ensure(int).
+void EncodeS2PointVector(absl::Span<const S2Point> points, CodingHint hint,
+                         Encoder* encoder);
+
+// This class represents an encoded vector of S2Points.  Values are decoded
+// only when they are accessed.  This allows for very fast initialization and
+// no additional memory use beyond the encoded data.  The encoded data is not
+// owned by this class; typically it points into a large contiguous buffer
+// that contains other encoded data as well.
+//
+// This is one of several helper classes that allow complex data structures to
+// be initialized from an encoded format in constant time and then decoded on
+// demand.  This can be a big performance advantage when only a small part of
+// the data structure is actually used.
+class EncodedS2PointVector {
+ public:
+  // Constructs an uninitialized object; requires Init() to be called.
+  EncodedS2PointVector() {}
+
+  // Initializes the EncodedS2PointVector.
+  //
+  // REQUIRES: The Decoder data buffer must outlive this object.
+  bool Init(Decoder* decoder);
+
+  // Returns the size of the original vector.
+  size_t size() const;
+
+  // Returns the element at the given index.
+  S2Point operator[](int i) const;
+
+  // Decodes and returns the entire original vector.
+  std::vector<S2Point> Decode() const;
+
+  // TODO(ericv): Consider adding a method that returns an adjacent pair of
+  // points.  This would save some decoding overhead.
+
+ private:
+  friend void EncodeS2PointVector(absl::Span<const S2Point>, CodingHint,
+                                  Encoder*);
+  friend void EncodeS2PointVectorFast(absl::Span<const S2Point>, Encoder*);
+  friend void EncodeS2PointVectorCompact(absl::Span<const S2Point>, Encoder*);
+
+  bool InitUncompressedFormat(Decoder* decoder);
+  bool InitCellIdsFormat(Decoder* decoder);
+  S2Point DecodeCellIdsFormat(int i) const;
+
+  // We use a tagged union to represent multiple formats, as opposed to an
+  // abstract base class or templating.  This represents the best compromise
+  // between performance, space, and convenience.  Note that the overhead of
+  // checking the tag is trivial and will typically be branch-predicted
+  // perfectly.
+  //
+  // TODO(ericv): Once additional formats have been implemented, consider
+  // using std::variant<> instead.  It's unclear whether this would have
+  // better or worse performance than the current approach.
+
+  // dd: These structs are anonymous in the upstream S2 code; however,
+  // this generates CMD-check failure due to the [-Wnested-anon-types]
+  // (anonymous types declared in an anonymous union are an extension)
+  // The approach here just names the types.
+  struct CellIDStruct {
+    EncodedStringVector blocks;
+    uint64 base;
+    uint8 level;
+    bool have_exceptions;
+
+    // TODO(ericv): Use std::atomic_flag to cache the last point decoded in
+    // a thread-safe way.  This reduces benchmark times for actual polygon
+    // operations (e.g. S2ClosestEdgeQuery) by about 15%.
+  };
+
+  struct UncompressedStruct {
+    const S2Point* points;
+  };
+
+  enum Format : uint8 {
+    UNCOMPRESSED = 0,
+    CELL_IDS = 1,
+  };
+  Format format_;
+  uint32 size_;
+  union {
+    struct UncompressedStruct uncompressed_;
+    struct CellIDStruct cell_ids_;
+  };
+};
+
+
+//////////////////   Implementation details follow   ////////////////////
+
+
+inline size_t EncodedS2PointVector::size() const {
+  return size_;
+}
+
+inline S2Point EncodedS2PointVector::operator[](int i) const {
+  switch (format_) {
+    case Format::UNCOMPRESSED:
+      return uncompressed_.points[i];
+
+    case Format::CELL_IDS:
+      return DecodeCellIdsFormat(i);
+
+    default:
+      S2_LOG(DFATAL) << "Unrecognized format";
+      return S2Point();
+  }
+}
+
+}  // namespace s2coding
+
+#endif  // S2_ENCODED_S2POINT_VECTOR_H_
diff --git a/src/s2/encoded_s2shape_index.cc b/src/s2/encoded_s2shape_index.cc
new file mode 100644 (file)
index 0000000..e68f2e4
--- /dev/null
@@ -0,0 +1,181 @@
+// Copyright 2018 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// Author: ericv@google.com (Eric Veach)
+
+#include "s2/encoded_s2shape_index.h"
+
+#include <memory>
+#include "absl/memory/memory.h"
+#include "s2/mutable_s2shape_index.h"
+
+using absl::make_unique;
+using std::unique_ptr;
+using std::vector;
+
+bool EncodedS2ShapeIndex::Iterator::Locate(const S2Point& target) {
+  return LocateImpl(target, this);
+}
+
+EncodedS2ShapeIndex::CellRelation EncodedS2ShapeIndex::Iterator::Locate(
+    S2CellId target) {
+  return LocateImpl(target, this);
+}
+
+unique_ptr<EncodedS2ShapeIndex::IteratorBase>
+EncodedS2ShapeIndex::Iterator::Clone() const {
+  return make_unique<Iterator>(*this);
+}
+
+void EncodedS2ShapeIndex::Iterator::Copy(const IteratorBase& other)  {
+  *this = *down_cast<const Iterator*>(&other);
+}
+
+S2Shape* EncodedS2ShapeIndex::GetShape(int id) const {
+  // This method is called when a shape has not been decoded yet.
+  unique_ptr<S2Shape> shape = (*shape_factory_)[id];
+  if (shape) shape->id_ = id;
+  S2Shape* expected = kUndecodedShape();
+  if (shapes_[id].compare_exchange_strong(expected, shape.get(),
+                                          std::memory_order_relaxed)) {
+    return shape.release();  // Ownership has been transferred to shapes_.
+  }
+  return shapes_[id].load(std::memory_order_relaxed);
+}
+
+inline const S2ShapeIndexCell* EncodedS2ShapeIndex::GetCell(int i) const {
+  if (cell_decoded(i)) {
+    auto cell = cells_[i].load(std::memory_order_acquire);
+    if (cell != nullptr) return cell;
+  }
+  // We decode the cell before acquiring the spinlock in order to minimize the
+  // time that the lock is held.
+  auto cell = make_unique<S2ShapeIndexCell>();
+  Decoder decoder = encoded_cells_.GetDecoder(i);
+  if (!cell->Decode(num_shape_ids(), &decoder)) {
+    return nullptr;
+  }
+  SpinLockHolder l(&cells_lock_);
+  if (test_and_set_cell_decoded(i)) {
+    // This cell has already been decoded.
+    return cells_[i].load(std::memory_order_relaxed);
+  }
+  if (cell_cache_.size() < max_cell_cache_size()) {
+    cell_cache_.push_back(i);
+  }
+  cells_[i].store(cell.get(), std::memory_order_relaxed);
+  return cell.release();  // Ownership has been transferred to cells_.
+}
+
+const S2ShapeIndexCell* EncodedS2ShapeIndex::Iterator::GetCell() const {
+  return index_->GetCell(cell_pos_);
+}
+
+EncodedS2ShapeIndex::EncodedS2ShapeIndex() {
+}
+
+EncodedS2ShapeIndex::~EncodedS2ShapeIndex() {
+  // Although Minimize() does slightly more than required for destruction
+  // (i.e., it resets vector elements to their default values), this does not
+  // affect benchmark times.
+  Minimize();
+}
+
+bool EncodedS2ShapeIndex::Init(Decoder* decoder,
+                               const ShapeFactory& shape_factory) {
+  Minimize();
+  uint64 max_edges_version;
+  if (!decoder->get_varint64(&max_edges_version)) return false;
+  int version = max_edges_version & 3;
+  if (version != MutableS2ShapeIndex::kCurrentEncodingVersionNumber) {
+    return false;
+  }
+  options_.set_max_edges_per_cell(max_edges_version >> 2);
+
+  // AtomicShape is a subtype of std::atomic<S2Shape*> that changes the
+  // default constructor value to kUndecodedShape().  This saves the effort of
+  // initializing all the elements twice.
+  shapes_ = std::vector<AtomicShape>(shape_factory.size());
+  shape_factory_ = shape_factory.Clone();
+  if (!cell_ids_.Init(decoder)) return false;
+
+  // The cells_ elements are *uninitialized memory*.  Instead we have bit
+  // vector (cells_decoded_) to indicate which elements of cells_ are valid.
+  // This reduces constructor times by more than a factor of 50, since rather
+  // than needing to initialize one 64-bit pointer per cell to zero, we only
+  // need to initialize one bit per cell to zero.
+  //
+  // For very large S2ShapeIndexes the internal memset() call to initialize
+  // cells_decoded_ still takes about 4 microseconds per million cells, but
+  // this seems reasonable relative to other likely costs (I/O, etc).
+  //
+  // NOTE(ericv): DO NOT use make_unique<> here!  make_unique<> allocates memory
+  // using "new T[n]()", which initializes all elements of the array.  This
+  // slows down some benchmarks by over 100x.
+  //
+  // cells_ = make_unique<std::atomic<S2ShapeIndexCell*>[]>(cell_ids_.size());
+  // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+  //                                NO NO NO
+  cells_.reset(new std::atomic<S2ShapeIndexCell*>[cell_ids_.size()]);
+  cells_decoded_ = vector<std::atomic<uint64>>((cell_ids_.size() + 63) >> 6);
+
+  return encoded_cells_.Init(decoder);
+}
+
+void EncodedS2ShapeIndex::Minimize() {
+  if (cells_ == nullptr) return;  // Not initialized yet.
+
+  for (auto& atomic_shape : shapes_) {
+    S2Shape* shape = atomic_shape.load(std::memory_order_relaxed);
+    if (shape != kUndecodedShape() && shape != nullptr) {
+      atomic_shape.store(kUndecodedShape(), std::memory_order_relaxed);
+      delete shape;
+    }
+  }
+  if (cell_cache_.size() < max_cell_cache_size()) {
+    // When only a tiny fraction of the cells are decoded, we keep track of
+    // those cells in cell_cache_ to avoid the cost of scanning the
+    // cells_decoded_ vector.  (The cost is only about 1 cycle per 64 cells,
+    // but for a huge polygon with 1 million cells that's still 16000 cycles.)
+    for (int pos : cell_cache_) {
+      cells_decoded_[pos >> 6].store(0, std::memory_order_relaxed);
+      delete cells_[pos].load(std::memory_order_relaxed);
+    }
+  } else {
+    // Scan the cells_decoded_ vector looking for cells that must be deleted.
+    for (int i = cells_decoded_.size(), base = 0; --i >= 0; base += 64) {
+      uint64 bits = cells_decoded_[i].load(std::memory_order_relaxed);
+      if (bits == 0) continue;
+      do {
+        int offset = Bits::FindLSBSetNonZero64(bits);
+        delete cells_[(i << 6) + offset].load(std::memory_order_relaxed);
+        bits &= bits - 1;
+      } while (bits != 0);
+      cells_decoded_[i].store(0, std::memory_order_relaxed);
+    }
+  }
+  cell_cache_.clear();
+}
+
+size_t EncodedS2ShapeIndex::SpaceUsed() const {
+  // TODO(ericv): Add SpaceUsed() method to S2Shape base class,and Include
+  // memory owned by the allocated S2Shapes (here and in S2ShapeIndex).
+  size_t size = sizeof(*this);
+  size += shapes_.capacity() * sizeof(std::atomic<S2Shape*>);
+  size += cell_ids_.size() * sizeof(std::atomic<S2ShapeIndexCell*>);  // cells_
+  size += cells_decoded_.capacity() * sizeof(std::atomic<uint64>);
+  size += cell_cache_.capacity() * sizeof(int);
+  return size;
+}
diff --git a/src/s2/encoded_s2shape_index.h b/src/s2/encoded_s2shape_index.h
new file mode 100644 (file)
index 0000000..3232474
--- /dev/null
@@ -0,0 +1,276 @@
+// Copyright 2018 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// Author: ericv@google.com (Eric Veach)
+
+#ifndef S2_ENCODED_S2SHAPE_INDEX_H_
+#define S2_ENCODED_S2SHAPE_INDEX_H_
+
+#include "s2/encoded_s2cell_id_vector.h"
+#include "s2/encoded_string_vector.h"
+#include "s2/mutable_s2shape_index.h"
+
+class EncodedS2ShapeIndex final : public S2ShapeIndex {
+ public:
+  using Options = MutableS2ShapeIndex::Options;
+  using ShapeFactory = S2ShapeIndex::ShapeFactory;
+
+  // Creates an index that must be initialized by calling Init().
+  EncodedS2ShapeIndex();
+
+  ~EncodedS2ShapeIndex() override;
+
+  // Initializes the EncodedS2ShapeIndex, returning true on success.
+  //
+  // This method does not decode the S2Shape objects in the index; this is
+  // the responsibility of the client-provided function "shape_factory"
+  // (see s2shapeutil_coding.h).  Example usage:
+  //
+  //   index.Init(decoder, s2shapeutil::LazyDecodeShapeFactory(decoder));
+  //
+  // Note that the encoded shape vector must *precede* the encoded S2ShapeIndex
+  // in the Decoder's data buffer in this example.
+  bool Init(Decoder* decoder, const ShapeFactory& shape_factory);
+
+  const Options& options() const { return options_; }
+
+  // The number of distinct shape ids in the index.  This equals the number of
+  // shapes in the index provided that no shapes have ever been removed.
+  // (Shape ids are not reused.)
+  int num_shape_ids() const override { return shapes_.size(); }
+
+  // Return a pointer to the shape with the given id, or nullptr if the shape
+  // has been removed from the index.
+  S2Shape* shape(int id) const override;
+
+  // Minimizes memory usage by requesting that any data structures that can be
+  // rebuilt should be discarded.  This method invalidates all iterators.
+  //
+  // Like all non-const methods, this method is not thread-safe.
+  void Minimize() override;
+
+  class Iterator final : public IteratorBase {
+   public:
+    // Default constructor; must be followed by a call to Init().
+    Iterator();
+
+    // Constructs an iterator positioned as specified.  By default iterators
+    // are unpositioned, since this avoids an extra seek in this situation
+    // where one of the seek methods (such as Locate) is immediately called.
+    //
+    // If you want to position the iterator at the beginning, e.g. in order to
+    // loop through the entire index, do this instead:
+    //
+    //   for (EncodedS2ShapeIndex::Iterator it(&index, S2ShapeIndex::BEGIN);
+    //        !it.done(); it.Next()) { ... }
+    explicit Iterator(const EncodedS2ShapeIndex* index,
+                      InitialPosition pos = UNPOSITIONED);
+
+    // Initializes an iterator for the given EncodedS2ShapeIndex.
+    void Init(const EncodedS2ShapeIndex* index,
+              InitialPosition pos = UNPOSITIONED);
+
+    // Inherited non-virtual methods:
+    //   S2CellId id() const;
+    //   const S2ShapeIndexCell& cell() const;
+    //   bool done() const;
+    //   S2Point center() const;
+
+    // IteratorBase API:
+    void Begin() override;
+    void Finish() override;
+    void Next() override;
+    bool Prev() override;
+    void Seek(S2CellId target) override;
+    bool Locate(const S2Point& target) override;
+    CellRelation Locate(S2CellId target) override;
+
+   protected:
+    const S2ShapeIndexCell* GetCell() const override;
+    std::unique_ptr<IteratorBase> Clone() const override;
+    void Copy(const IteratorBase& other) override;
+
+   private:
+    void Refresh();  // Updates the IteratorBase fields.
+    const EncodedS2ShapeIndex* index_;
+    int32 cell_pos_;  // Current position in the vector of index cells.
+    int32 num_cells_;
+  };
+
+  // Returns the number of bytes currently occupied by the index (including any
+  // unused space at the end of vectors, etc). It has the same thread safety
+  // as the other "const" methods (see introduction).
+  size_t SpaceUsed() const override;
+
+ protected:
+  std::unique_ptr<IteratorBase> NewIterator(InitialPosition pos) const override;
+
+ private:
+  friend class Iterator;
+
+  // Returns a value indicating that a shape has not been decoded yet.
+  inline static S2Shape* kUndecodedShape() {
+    return reinterpret_cast<S2Shape*>(1);
+  }
+
+  // Like std::atomic<S2Shape*>, but defaults to kUndecodedShape().
+  class AtomicShape : public std::atomic<S2Shape*> {
+   public:
+    AtomicShape() : std::atomic<S2Shape*>(kUndecodedShape()) {}
+  };
+
+  S2Shape* GetShape(int id) const;
+  const S2ShapeIndexCell* GetCell(int i) const;
+  bool cell_decoded(int i) const;
+  bool test_and_set_cell_decoded(int i) const;
+  int max_cell_cache_size() const;
+
+  std::unique_ptr<ShapeFactory> shape_factory_;
+
+  // The options specified for this index.
+  Options options_;
+
+  // A vector containing all shapes in the index.  Initially all shapes are
+  // set to kUndecodedShape(); as shapes are decoded, they are added to the
+  // vector using std::atomic::compare_exchange_strong.
+  mutable std::vector<AtomicShape> shapes_;
+
+  // A vector containing the S2CellIds of each cell in the index.
+  s2coding::EncodedS2CellIdVector cell_ids_;
+
+  // A vector containing the encoded contents of each cell in the index.
+  s2coding::EncodedStringVector encoded_cells_;
+
+  // A raw array containing the decoded contents of each cell in the index.
+  // Initially all values are *uninitialized memory*.  The cells_decoded_
+  // field below keeps track of which elements are present.
+  mutable std::unique_ptr<std::atomic<S2ShapeIndexCell*>[]> cells_;
+
+  // A bit vector indicating which elements of cells_ have been decoded.
+  // All other elements of cells_ contain uninitialized (random) memory.
+  mutable std::vector<std::atomic<uint64>> cells_decoded_;
+
+  // In order to minimize destructor time when very few cells of a large
+  // S2ShapeIndex are needed, we keep track of the indices of the first few
+  // cells to be decoded.  This lets us avoid scanning the cells_decoded_
+  // vector when the number of cells decoded is very small.
+  mutable std::vector<int> cell_cache_;
+
+  // Protects all updates to cells_ and cells_decoded_.
+  mutable SpinLock cells_lock_;
+
+  EncodedS2ShapeIndex(const EncodedS2ShapeIndex&) = delete;
+  void operator=(const EncodedS2ShapeIndex&) = delete;
+};
+
+
+//////////////////   Implementation details follow   ////////////////////
+
+
+inline EncodedS2ShapeIndex::Iterator::Iterator() : index_(nullptr) {
+}
+
+inline EncodedS2ShapeIndex::Iterator::Iterator(
+    const EncodedS2ShapeIndex* index, InitialPosition pos) {
+  Init(index, pos);
+}
+
+inline void EncodedS2ShapeIndex::Iterator::Init(
+    const EncodedS2ShapeIndex* index, InitialPosition pos) {
+  index_ = index;
+  num_cells_ = index->cell_ids_.size();
+  cell_pos_ = (pos == BEGIN) ? 0 : num_cells_;
+  Refresh();
+}
+
+inline void EncodedS2ShapeIndex::Iterator::Refresh() {
+  if (cell_pos_ == num_cells_) {
+    set_finished();
+  } else {
+    // It's faster to initialize the cell to nullptr even if it has already
+    // been decoded, since algorithms frequently don't need it (i.e., based on
+    // the S2CellId they might not need to look at the cell contents).
+    set_state(index_->cell_ids_[cell_pos_], nullptr);
+  }
+}
+
+inline void EncodedS2ShapeIndex::Iterator::Begin() {
+  cell_pos_ = 0;
+  Refresh();
+}
+
+inline void EncodedS2ShapeIndex::Iterator::Finish() {
+  cell_pos_ = num_cells_;
+  Refresh();
+}
+
+inline void EncodedS2ShapeIndex::Iterator::Next() {
+  S2_DCHECK(!done());
+  ++cell_pos_;
+  Refresh();
+}
+
+inline bool EncodedS2ShapeIndex::Iterator::Prev() {
+  if (cell_pos_ == 0) return false;
+  --cell_pos_;
+  Refresh();
+  return true;
+}
+
+inline void EncodedS2ShapeIndex::Iterator::Seek(S2CellId target) {
+  cell_pos_ = index_->cell_ids_.lower_bound(target);
+  Refresh();
+}
+
+inline std::unique_ptr<EncodedS2ShapeIndex::IteratorBase>
+EncodedS2ShapeIndex::NewIterator(InitialPosition pos) const {
+  return absl::make_unique<Iterator>(this, pos);
+}
+
+inline S2Shape* EncodedS2ShapeIndex::shape(int id) const {
+  S2Shape* shape = shapes_[id].load(std::memory_order_relaxed);
+  if (shape != kUndecodedShape()) return shape;
+  return GetShape(id);
+}
+
+// Returns true if the given cell has been decoded yet.
+inline bool EncodedS2ShapeIndex::cell_decoded(int i) const {
+  uint64 group_bits = cells_decoded_[i >> 6].load(std::memory_order_relaxed);
+  return (group_bits & (1ULL << (i & 63))) != 0;
+}
+
+// Marks the given cell as decoded and returns true if it was already marked.
+inline bool EncodedS2ShapeIndex::test_and_set_cell_decoded(int i) const {
+  std::atomic<uint64>* group = &cells_decoded_[i >> 6];
+  uint64 group_bits = group->load(std::memory_order_relaxed);
+  uint64 test_bit = 1ULL << (i & 63);
+  group->store(group_bits | test_bit, std::memory_order_relaxed);
+  return (group_bits & test_bit) != 0;
+}
+
+inline int EncodedS2ShapeIndex::max_cell_cache_size() const {
+  // The cell cache is sized so that scanning decoded_cells_ in the destructor
+  // costs about 30 cycles per decoded cell in the worst case.  (This overhead
+  // is acceptable relative to the other costs of decoding each cell.)
+  //
+  // For example, if there are 65,536 cells then we won't need to scan
+  // encoded_cells_ unless we decode at least (65536/2048) == 32 cells.  It
+  // takes about 1 cycle per 64 cells to scan encoded_cells_, so that works
+  // out to (65536/64) == 1024 cycles.  However this cost is amortized over
+  // the 32 cells decoded, which works out to 32 cycles per cell.
+  return cell_ids_.size() >> 11;
+}
+
+#endif  // S2_ENCODED_S2SHAPE_INDEX_H_
diff --git a/src/s2/encoded_string_vector.cc b/src/s2/encoded_string_vector.cc
new file mode 100644 (file)
index 0000000..2a6d7a5
--- /dev/null
@@ -0,0 +1,66 @@
+// Copyright 2018 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// Author: ericv@google.com (Eric Veach)
+
+#include "s2/encoded_string_vector.h"
+
+using absl::MakeSpan;
+using absl::Span;
+using absl::string_view;
+using std::vector;
+
+namespace s2coding {
+
+StringVectorEncoder::StringVectorEncoder() {
+}
+
+void StringVectorEncoder::Encode(Encoder* encoder) {
+  offsets_.push_back(data_.length());
+  // We don't encode the first element of "offsets_", which is always zero.
+  EncodeUintVector<uint64>(
+      MakeSpan(offsets_.data() + 1, offsets_.data() + offsets_.size()),
+      encoder);
+  encoder->Ensure(data_.length());
+  encoder->putn(data_.base(), data_.length());
+}
+
+void StringVectorEncoder::Encode(Span<const std::string> v, Encoder* encoder) {
+  StringVectorEncoder string_vector;
+  for (const auto& str : v) string_vector.Add(str);
+  string_vector.Encode(encoder);
+}
+
+bool EncodedStringVector::Init(Decoder* decoder) {
+  if (!offsets_.Init(decoder)) return false;
+  data_ = reinterpret_cast<const char*>(decoder->ptr());
+  if (offsets_.size() > 0) {
+    uint64 length = offsets_[offsets_.size() - 1];
+    if (decoder->avail() < length) return false;
+    decoder->skip(length);
+  }
+  return true;
+}
+
+vector<string_view> EncodedStringVector::Decode() const {
+  size_t n = size();
+  vector<string_view> result(n);
+  for (int i = 0; i < n; ++i) {
+    result[i] = (*this)[i];
+  }
+  return result;
+}
+
+}  // namespace s2coding
diff --git a/src/s2/encoded_string_vector.h b/src/s2/encoded_string_vector.h
new file mode 100644 (file)
index 0000000..bef1697
--- /dev/null
@@ -0,0 +1,164 @@
+// Copyright 2018 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// Author: ericv@google.com (Eric Veach)
+
+#ifndef S2_ENCODED_STRING_VECTOR_H_
+#define S2_ENCODED_STRING_VECTOR_H_
+
+#include <memory>
+#include <string>
+#include "absl/strings/string_view.h"
+#include "absl/types/span.h"
+#include "s2/encoded_uint_vector.h"
+
+namespace s2coding {
+
+// This class allows an EncodedStringVector to be created by adding strings
+// incrementally.  It also supports adding strings that are the output of
+// another Encoder.  For example, to create a vector of encoded S2Polygons,
+// you can do this:
+//
+// void EncodePolygons(const vector<S2Polygon*>& polygons, Encoder* encoder) {
+//   StringVectorEncoder encoded_polygons;
+//   for (auto polygon : polygons) {
+//     polygon->Encode(encoded_polygons.AddViaEncoder());
+//   }
+//   encoded_polygons.Encode(encoder);
+// }
+class StringVectorEncoder {
+ public:
+  StringVectorEncoder();
+
+  // Adds a string to the encoded vector.
+  void Add(const std::string& str);
+
+  // Adds a string to the encoded vector by means of the given Encoder.  The
+  // string consists of all output added to the encoder before the next call
+  // to any method of this class (after which the encoder is no longer valid).
+  Encoder* AddViaEncoder();
+
+  // Appends the EncodedStringVector representation to the given Encoder.
+  //
+  // REQUIRES: "encoder" uses the default constructor, so that its buffer
+  //           can be enlarged as necessary by calling Ensure(int).
+  void Encode(Encoder* encoder);
+
+  // Encodes a vector of strings in a format that can later be decoded as an
+  // EncodedStringVector.
+  //
+  // REQUIRES: "encoder" uses the default constructor, so that its buffer
+  //           can be enlarged as necessary by calling Ensure(int).
+  static void Encode(absl::Span<const std::string> v, Encoder* encoder);
+
+ private:
+  // A vector consisting of the starting offset of each string in the
+  // encoder's data buffer, plus a final entry pointing just past the end of
+  // the last string.
+  std::vector<uint64> offsets_;
+  Encoder data_;
+};
+
+// This class represents an encoded vector of strings.  Values are decoded
+// only when they are accessed.  This allows for very fast initialization and
+// no additional memory use beyond the encoded data.  The encoded data is not
+// owned by this class; typically it points into a large contiguous buffer
+// that contains other encoded data as well.
+//
+// This is one of several helper classes that allow complex data structures to
+// be initialized from an encoded format in constant time and then decoded on
+// demand.  This can be a big performance advantage when only a small part of
+// the data structure is actually used.
+class EncodedStringVector {
+ public:
+  // Constructs an uninitialized object; requires Init() to be called.
+  EncodedStringVector() {}
+
+  // Initializes the EncodedStringVector.  Returns false on errors, leaving
+  // the vector in an unspecified state.
+  //
+  // REQUIRES: The Decoder data buffer must outlive this object.
+  bool Init(Decoder* decoder);
+
+  // Resets the vector to be empty.
+  void Clear();
+
+  // Returns the size of the original vector.
+  size_t size() const;
+
+  // Returns the string at the given index.
+  absl::string_view operator[](int i) const;
+
+  // Returns a Decoder initialized with the string at the given index.
+  Decoder GetDecoder(int i) const;
+
+  // Returns a pointer to the start of the string at the given index.  This is
+  // faster than operator[] but returns an unbounded string.
+  const char* GetStart(int i) const;
+
+  // Returns the entire vector of original strings.  Requires that the
+  // data buffer passed to the constructor persists until the result vector is
+  // no longer needed.
+  std::vector<absl::string_view> Decode() const;
+
+ private:
+  EncodedUintVector<uint64> offsets_;
+  const char* data_;
+};
+
+
+//////////////////   Implementation details follow   ////////////////////
+
+
+inline void StringVectorEncoder::Add(const std::string& str) {
+  offsets_.push_back(data_.length());
+  data_.Ensure(str.size());
+  data_.putn(str.data(), str.size());
+}
+
+inline Encoder* StringVectorEncoder::AddViaEncoder() {
+  offsets_.push_back(data_.length());
+  return &data_;
+}
+
+inline void EncodedStringVector::Clear() {
+  offsets_.Clear();
+  data_ = nullptr;
+}
+
+inline size_t EncodedStringVector::size() const {
+  return offsets_.size();
+}
+
+inline absl::string_view EncodedStringVector::operator[](int i) const {
+  uint64 start = (i == 0) ? 0 : offsets_[i - 1];
+  uint64 limit = offsets_[i];
+  return absl::string_view(data_ + start, limit - start);
+}
+
+inline Decoder EncodedStringVector::GetDecoder(int i) const {
+  uint64 start = (i == 0) ? 0 : offsets_[i - 1];
+  uint64 limit = offsets_[i];
+  return Decoder(data_ + start, limit - start);
+}
+
+inline const char* EncodedStringVector::GetStart(int i) const {
+  uint64 start = (i == 0) ? 0 : offsets_[i - 1];
+  return data_ + start;
+}
+
+}  // namespace s2coding
+
+#endif  // S2_ENCODED_STRING_VECTOR_H_
diff --git a/src/s2/encoded_uint_vector.h b/src/s2/encoded_uint_vector.h
new file mode 100644 (file)
index 0000000..9ca50ba
--- /dev/null
@@ -0,0 +1,299 @@
+// Copyright 2018 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// Author: ericv@google.com (Eric Veach)
+
+#ifndef S2_ENCODED_UINT_VECTOR_H_
+#define S2_ENCODED_UINT_VECTOR_H_
+
+#include <type_traits>
+#include <vector>
+#include "absl/base/internal/unaligned_access.h"
+#include "absl/types/span.h"
+#include "s2/util/coding/coder.h"
+
+namespace s2coding {
+
+// Encodes a vector of unsigned integers in a format that can later be
+// decoded as an EncodedUintVector.
+//
+// REQUIRES: T is an unsigned integer type.
+// REQUIRES: 2 <= sizeof(T) <= 8
+// REQUIRES: "encoder" uses the default constructor, so that its buffer
+//           can be enlarged as necessary by calling Ensure(int).
+template <class T>
+void EncodeUintVector(absl::Span<const T> v, Encoder* encoder);
+
+// This class represents an encoded vector of unsigned integers of type T.
+// Values are decoded only when they are accessed.  This allows for very fast
+// initialization and no additional memory use beyond the encoded data.
+// The encoded data is not owned by this class; typically it points into a
+// large contiguous buffer that contains other encoded data as well.
+//
+// This is one of several helper classes that allow complex data structures to
+// be initialized from an encoded format in constant time and then decoded on
+// demand.  This can be a big performance advantage when only a small part of
+// the data structure is actually used.
+//
+// Values are encoded using a fixed number of bytes per value, where the
+// number of bytes depends on the largest value present.
+//
+// REQUIRES: T is an unsigned integer type.
+// REQUIRES: 2 <= sizeof(T) <= 8
+template <class T>
+class EncodedUintVector {
+ public:
+  static_assert(std::is_unsigned<T>::value, "Unsupported signed integer");
+  static_assert(sizeof(T) & 0xe, "Unsupported integer length");
+
+  // Constructs an uninitialized object; requires Init() to be called.
+  EncodedUintVector() {}
+
+  // Initializes the EncodedUintVector.  Returns false on errors, leaving the
+  // vector in an unspecified state.
+  //
+  // REQUIRES: The Decoder data buffer must outlive this object.
+  bool Init(Decoder* decoder);
+
+  // Resets the vector to be empty.
+  void Clear();
+
+  // Returns the size of the original vector.
+  size_t size() const;
+
+  // Returns the element at the given index.
+  T operator[](int i) const;
+
+  // Returns the index of the first element x such that (x >= target), or
+  // size() if no such element exists.
+  //
+  // REQUIRES: The vector elements are sorted in non-decreasing order.
+  size_t lower_bound(T target) const;
+
+  // Decodes and returns the entire original vector.
+  std::vector<T> Decode() const;
+
+ private:
+  template <int length> size_t lower_bound(T target) const;
+
+  const char* data_;
+  uint32 size_;
+  uint8 len_;
+};
+
+// Encodes an unsigned integer in little-endian format using "length" bytes.
+// (The client must ensure that the encoder's buffer is large enough.)
+//
+// REQUIRES: T is an unsigned integer type.
+// REQUIRES: 2 <= sizeof(T) <= 8
+// REQUIRES: 0 <= length <= sizeof(T)
+// REQUIRES: value < 256 ** length
+// REQUIRES: encoder->avail() >= length
+template <class T>
+void EncodeUintWithLength(T value, int length, Encoder* encoder);
+
+// Decodes a variable-length integer consisting of "length" bytes starting at
+// "ptr" in little-endian format.
+//
+// REQUIRES: T is an unsigned integer type.
+// REQUIRES: 2 <= sizeof(T) <= 8
+// REQUIRES: 0 <= length <= sizeof(T)
+template <class T>
+T GetUintWithLength(const void* ptr, int length);
+
+// Decodes and consumes a variable-length integer consisting of "length" bytes
+// in little-endian format.  Returns false if not enough bytes are available.
+//
+// REQUIRES: T is an unsigned integer type.
+// REQUIRES: 2 <= sizeof(T) <= 8
+// REQUIRES: 0 <= length <= sizeof(T)
+template <class T>
+bool DecodeUintWithLength(int length, Decoder* decoder, T* result);
+
+
+//////////////////   Implementation details follow   ////////////////////
+
+
+template <class T>
+inline void EncodeUintWithLength(T value, int length, Encoder* encoder) {
+  static_assert(std::is_unsigned<T>::value, "Unsupported signed integer");
+  static_assert(sizeof(T) & 0xe, "Unsupported integer length");
+  S2_DCHECK(length >= 0 && length <= sizeof(T));
+  S2_DCHECK_GE(encoder->avail(), length);
+
+  while (--length >= 0) {
+    encoder->put8(value);
+    value >>= 8;
+  }
+  S2_DCHECK_EQ(value, 0);
+}
+
+template <class T>
+inline T GetUintWithLength(const char* ptr, int length) {
+  static_assert(std::is_unsigned<T>::value, "Unsupported signed integer");
+  static_assert(sizeof(T) & 0xe, "Unsupported integer length");
+  S2_DCHECK(length >= 0 && length <= sizeof(T));
+
+  // Note that the following code is faster than any of the following:
+  //
+  //  - A loop that repeatedly loads and shifts one byte.
+  //  - memcpying "length" bytes to a local variable of type T.
+  //  - A switch statement that handles each length optimally.
+  //
+  // The following code is slightly faster:
+  //
+  //   T mask = (length == 0) ? 0 : ~T{0} >> 8 * (sizeof(T) - length);
+  //   return *reinterpret_cast<const T*>(ptr) & mask;
+  //
+  // However this technique is unsafe because in extremely rare cases it might
+  // access out-of-bounds heap memory.  (This can only happen if "ptr" is
+  // within (sizeof(T) - length) bytes of the end of a memory page and the
+  // following page in the address space is unmapped.)
+
+  if (length & sizeof(T)) {
+    if (sizeof(T) == 8) return ABSL_INTERNAL_UNALIGNED_LOAD64(ptr);
+    if (sizeof(T) == 4) return ABSL_INTERNAL_UNALIGNED_LOAD32(ptr);
+    if (sizeof(T) == 2) return ABSL_INTERNAL_UNALIGNED_LOAD16(ptr);
+    S2_DCHECK_EQ(sizeof(T), 1);
+    return *ptr;
+  }
+  T x = 0;
+  ptr += length;
+  if (sizeof(T) > 4 && (length & 4)) {
+    x = ABSL_INTERNAL_UNALIGNED_LOAD32(ptr -= sizeof(uint32));
+  }
+  if (sizeof(T) > 2 && (length & 2)) {
+    x = (x << 16) + ABSL_INTERNAL_UNALIGNED_LOAD16(ptr -= sizeof(uint16));
+  }
+  if (sizeof(T) > 1 && (length & 1)) {
+    x = (x << 8) + static_cast<uint8>(*--ptr);
+  }
+  return x;
+}
+
+template <class T>
+bool DecodeUintWithLength(int length, Decoder* decoder, T* result) {
+  if (decoder->avail() < length) return false;
+  const char* ptr = reinterpret_cast<const char*>(decoder->ptr());
+  *result = GetUintWithLength<T>(ptr, length);
+  decoder->skip(length);
+  return true;
+}
+
+template <class T>
+void EncodeUintVector(absl::Span<const T> v, Encoder* encoder) {
+  // The encoding is as follows:
+  //
+  //   varint64: (v.size() * sizeof(T)) | (len - 1)
+  //   array of v.size() elements ["len" bytes each]
+  //
+  // Note that we don't allow (len == 0) since this would require an extra bit
+  // to encode the length.
+
+  T one_bits = 1;  // Ensures len >= 1.
+  for (auto x : v) one_bits |= x;
+  int len = (Bits::FindMSBSetNonZero64(one_bits) >> 3) + 1;
+  S2_DCHECK(len >= 1 && len <= 8);
+
+  // Note that the multiplication is optimized into a bit shift.
+  encoder->Ensure(Varint::kMax64 + v.size() * len);
+  uint64 size_len = (uint64{v.size()} * sizeof(T)) | (len - 1);
+  encoder->put_varint64(size_len);
+  for (auto x : v) {
+    EncodeUintWithLength(x, len, encoder);
+  }
+}
+
+template <class T>
+bool EncodedUintVector<T>::Init(Decoder* decoder) {
+  uint64 size_len;
+  if (!decoder->get_varint64(&size_len)) return false;
+  size_ = size_len / sizeof(T);  // Optimized into bit shift.
+  len_ = (size_len & (sizeof(T) - 1)) + 1;
+  if (size_ > std::numeric_limits<size_t>::max() / sizeof(T)) return false;
+  size_t bytes = size_ * len_;
+  if (decoder->avail() < bytes) return false;
+  data_ = reinterpret_cast<const char*>(decoder->ptr());
+  decoder->skip(bytes);
+  return true;
+}
+
+template <class T>
+void EncodedUintVector<T>::Clear() {
+  size_ = 0;
+  data_ = nullptr;
+}
+
+template <class T>
+inline size_t EncodedUintVector<T>::size() const {
+  return size_;
+}
+
+template <class T>
+inline T EncodedUintVector<T>::operator[](int i) const {
+  S2_DCHECK(i >= 0 && i < size_);
+  return GetUintWithLength<T>(data_ + i * len_, len_);
+}
+
+template <class T>
+size_t EncodedUintVector<T>::lower_bound(T target) const {
+  static_assert(sizeof(T) & 0xe, "Unsupported integer length");
+  S2_DCHECK(len_ >= 1 && len_ <= sizeof(T));
+
+  // TODO(ericv): Consider using the unused 28 bits of "len_" to store the
+  // last result of lower_bound() to be used as a hint.  This should help in
+  // common situation where the same element is looked up repeatedly.  This
+  // would require declaring the new field (length_lower_bound_hint_) as
+  // mutable std::atomic<uint32> (accessed using std::memory_order_relaxed)
+  // with a custom copy constructor that resets the hint component to zero.
+  switch (len_) {
+    case 1: return lower_bound<1>(target);
+    case 2: return lower_bound<2>(target);
+    case 3: return lower_bound<3>(target);
+    case 4: return lower_bound<4>(target);
+    case 5: return lower_bound<5>(target);
+    case 6: return lower_bound<6>(target);
+    case 7: return lower_bound<7>(target);
+    default: return lower_bound<8>(target);
+  }
+}
+
+template <class T> template <int length>
+inline size_t EncodedUintVector<T>::lower_bound(T target) const {
+  size_t lo = 0, hi = size_;
+  while (lo < hi) {
+    size_t mid = (lo + hi) >> 1;
+    T value = GetUintWithLength<T>(data_ + mid * length, length);
+    if (value < target) {
+      lo = mid + 1;
+    } else {
+      hi = mid;
+    }
+  }
+  return lo;
+}
+
+template <class T>
+std::vector<T> EncodedUintVector<T>::Decode() const {
+  std::vector<T> result(size_);
+  for (int i = 0; i < size_; ++i) {
+    result[i] = (*this)[i];
+  }
+  return result;
+}
+
+}  // namespace s2coding
+
+#endif  // S2_ENCODED_UINT_VECTOR_H_
diff --git a/src/s2/id_set_lexicon.cc b/src/s2/id_set_lexicon.cc
new file mode 100644 (file)
index 0000000..f4dd911
--- /dev/null
@@ -0,0 +1,81 @@
+// Copyright 2016 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// Author: ericv@google.com (Eric Veach)
+
+#include "s2/id_set_lexicon.h"
+
+#include <algorithm>
+#include <vector>
+
+#include "s2/base/logging.h"
+
+IdSetLexicon::IdSetLexicon() {
+}
+
+IdSetLexicon::~IdSetLexicon() {
+}
+
+// We define the copy/move constructors and assignment operators explicitly
+// in order to avoid copying/moving the temporary storage vector "tmp_".
+
+IdSetLexicon::IdSetLexicon(const IdSetLexicon& x) : id_sets_(x.id_sets_) {
+}
+
+IdSetLexicon::IdSetLexicon(IdSetLexicon&& x) : id_sets_(std::move(x.id_sets_)) {
+}
+
+IdSetLexicon& IdSetLexicon::operator=(const IdSetLexicon& x) {
+  id_sets_ = x.id_sets_;
+  return *this;
+}
+
+IdSetLexicon& IdSetLexicon::operator=(IdSetLexicon&& x) {
+  id_sets_ = std::move(x.id_sets_);
+  return *this;
+}
+
+void IdSetLexicon::Clear() {
+  id_sets_.Clear();
+}
+
+int32 IdSetLexicon::AddInternal(std::vector<int32>* ids) {
+  if (ids->empty()) {
+    // Empty sets have a special id chosen not to conflict with other ids.
+    return kEmptySetId;
+  } else if (ids->size() == 1) {
+    // Singleton sets are represented by their element.
+    return (*ids)[0];
+  } else {
+    // Canonicalize the set by sorting and removing duplicates.
+    std::sort(ids->begin(), ids->end());
+    ids->erase(std::unique(ids->begin(), ids->end()), ids->end());
+    // Non-singleton sets are represented by the bitwise complement of the id
+    // returned by SequenceLexicon.
+    return ~id_sets_.Add(*ids);
+  }
+}
+
+IdSetLexicon::IdSet IdSetLexicon::id_set(int32 set_id) const {
+  if (set_id >= 0) {
+    return IdSet(set_id);
+  } else if (set_id == kEmptySetId) {
+    return IdSet();
+  } else {
+    auto sequence = id_sets_.sequence(~set_id);
+    S2_DCHECK_NE(0, sequence.size());
+    return IdSet(&*sequence.begin(), &*sequence.begin() + sequence.size());
+  }
+}
diff --git a/src/s2/id_set_lexicon.h b/src/s2/id_set_lexicon.h
new file mode 100644 (file)
index 0000000..25ace84
--- /dev/null
@@ -0,0 +1,199 @@
+// Copyright 2016 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// Author: ericv@google.com (Eric Veach)
+
+#ifndef S2_ID_SET_LEXICON_H_
+#define S2_ID_SET_LEXICON_H_
+
+#include <limits>
+#include <vector>
+
+#include "s2/base/integral_types.h"
+#include "s2/base/logging.h"
+#include "s2/sequence_lexicon.h"
+
+// IdSetLexicon is a class for compactly representing sets of non-negative
+// integers such as array indices ("id sets").  It is especially suitable when
+// either (1) there are many duplicate sets, or (2) there are many singleton
+// or empty sets.  See also ValueLexicon and SequenceLexicon.
+//
+// Each distinct id set is mapped to a 32-bit integer.  Empty and singleton
+// sets take up no additional space whatsoever; the set itself is represented
+// by the unique id assigned to the set. Sets of size 2 or more occupy about
+// 11 bytes per set plus 4 bytes per element (as compared to 24 bytes per set
+// plus 4 bytes per element for std::vector).  Duplicate sets are
+// automatically eliminated.  Note also that id sets are referred to using
+// 32-bit integers rather than 64-bit pointers.
+//
+// This class is especially useful in conjunction with ValueLexicon<T>.  For
+// example, suppose that you want to label objects with a set of strings.  You
+// could use a ValueLexicon<string> to map the strings to "label ids" (32-bit
+// integers), and then use IdSetLexicon to map each set of labels to a "label
+// set id".  Each reference to that label set then takes up only 4 bytes.
+//
+// Example usage:
+//
+//   ValueLexicon<string> labels_;
+//   IdSetLexicon label_sets_;
+//
+//   int32 GetLabelSet(const vector<string>& label_strings) {
+//     vector<int32> label_ids;
+//     for (const auto& str : label_strings) {
+//       label_ids.push_back(labels_.Add(str));
+//     }
+//     return label_sets_.Add(label_ids);
+//   }
+//
+//   int label_set_id = GetLabelSet(...);
+//   for (auto id : label_sets_.id_set(label_set_id)) {
+//     S2_LOG(INFO) << id;
+//   }
+//
+// This class is similar to SequenceLexicon, except:
+//
+// 1. Empty and singleton sets are represented implicitly; they use no space.
+// 2. Sets are represented rather than sequences; the ordering of values is
+//    not important and duplicates are removed.
+// 3. The values must be 32-bit non-negative integers (only).
+class IdSetLexicon {
+ public:
+  IdSetLexicon();
+  ~IdSetLexicon();
+
+  // IdSetLexicon is movable and copyable.
+  IdSetLexicon(const IdSetLexicon&);
+  IdSetLexicon& operator=(const IdSetLexicon&);
+  IdSetLexicon(IdSetLexicon&&);
+  IdSetLexicon& operator=(IdSetLexicon&&);
+
+  // Clears all data from the lexicon.
+  void Clear();
+
+  // Add the given set of integers to the lexicon if it is not already
+  // present, and return the unique id for this set.  "begin" and "end" are
+  // forward iterators over a sequence of values that can be converted to
+  // non-negative 32-bit integers.  The values are automatically sorted and
+  // duplicates are removed.  Returns a signed integer representing this set.
+  //
+  // REQUIRES: All values in [begin, end) are non-negative 32-bit integers.
+  template <class FwdIterator>
+  int32 Add(FwdIterator begin, FwdIterator end);
+
+  // Add the given set of integers to the lexicon if it is not already
+  // present, and return the unique id for this set.  This is a convenience
+  // method equivalent to Add(std::begin(container), std::end(container)).
+  template <class Container>
+  int32 Add(const Container& container);
+
+  // Convenience method that returns the unique id for a singleton set.
+  // Note that because singleton sets take up no space, this method is
+  // const.  Equivalent to calling Add(&id, &id + 1).
+  int32 AddSingleton(int32 id) const;
+
+  // Convenience method that returns the unique id for the empty set.  Note
+  // that because the empty set takes up no space and has a fixed id, this
+  // method is static.  Equivalent to calling Add() with an empty container.
+  static int32 EmptySetId();
+
+  // Iterator type; please treat this as an opaque forward iterator.
+  using Iterator = const int32*;
+
+  // This class represents a set of integers stored in the IdSetLexicon.
+  class IdSet {
+   public:
+    Iterator begin() const;
+    Iterator end() const;
+    size_t size() const;
+
+   private:
+    friend class IdSetLexicon;
+    IdSet();
+    IdSet(Iterator begin, Iterator end);
+    explicit IdSet(int32 singleton_id);
+    Iterator begin_, end_;
+    int32 singleton_id_;
+  };
+  // Return the set of integers corresponding to an id returned by Add().
+  IdSet id_set(int32 set_id) const;
+
+ private:
+  // Choose kEmptySetId to be the last id that will ever be generated.
+  // (Non-negative ids are reserved for singleton sets.)
+  static const int32 kEmptySetId = std::numeric_limits<int32>::min();
+  int32 AddInternal(std::vector<int32>* ids);
+
+  SequenceLexicon<int32> id_sets_;
+
+  std::vector<int32> tmp_;  // temporary storage used during Add()
+};
+
+
+//////////////////   Implementation details follow   ////////////////////
+
+
+inline IdSetLexicon::Iterator IdSetLexicon::IdSet::begin() const {
+  return begin_;
+}
+
+inline IdSetLexicon::Iterator IdSetLexicon::IdSet::end() const {
+  return end_;
+}
+
+inline size_t IdSetLexicon::IdSet::size() const {
+  return end_ - begin_;
+}
+
+inline IdSetLexicon::IdSet::IdSet()
+    : begin_(&singleton_id_), end_(begin_) {
+}
+
+inline IdSetLexicon::IdSet::IdSet(Iterator begin, Iterator end)
+    : begin_(begin), end_(end) {
+}
+
+inline IdSetLexicon::IdSet::IdSet(int32 singleton_id)
+    : begin_(&singleton_id_), end_(&singleton_id_ + 1),
+      singleton_id_(singleton_id) {
+}
+
+inline int32 IdSetLexicon::AddSingleton(int32 id) const {
+  S2_DCHECK_GE(id, 0);
+  S2_DCHECK_LE(id, std::numeric_limits<int32>::max());
+  // Singleton sets are represented by their element.
+  return id;
+}
+
+/*static*/ inline int32 IdSetLexicon::EmptySetId() {
+  return kEmptySetId;
+}
+
+template <class FwdIterator>
+int32 IdSetLexicon::Add(FwdIterator begin, FwdIterator end) {
+  tmp_.clear();
+  for (; begin != end; ++begin) {
+    S2_DCHECK_GE(*begin, 0);
+    S2_DCHECK_LE(*begin, std::numeric_limits<int32>::max());
+    tmp_.push_back(*begin);
+  }
+  return AddInternal(&tmp_);
+}
+
+template <class Container>
+int32 IdSetLexicon::Add(const Container& container) {
+  return Add(std::begin(container), std::end(container));
+}
+
+#endif  // S2_ID_SET_LEXICON_H_
diff --git a/src/s2/mutable_s2shape_index.cc b/src/s2/mutable_s2shape_index.cc
new file mode 100644 (file)
index 0000000..a81ee9c
--- /dev/null
@@ -0,0 +1,1585 @@
+// Copyright 2012 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// Author: ericv@google.com (Eric Veach)
+
+#include "s2/mutable_s2shape_index.h"
+
+#include <algorithm>
+#include <atomic>
+#include <cmath>
+
+#include "s2/base/casts.h"
+#include "s2/base/commandlineflags.h"
+#include "s2/base/spinlock.h"
+#include "s2/encoded_s2cell_id_vector.h"
+#include "s2/encoded_string_vector.h"
+#include "s2/r1interval.h"
+#include "s2/r2.h"
+#include "s2/r2rect.h"
+#include "s2/s2cell_id.h"
+#include "s2/s2cell_union.h"
+#include "s2/s2coords.h"
+#include "s2/s2edge_clipping.h"
+#include "s2/s2edge_crosser.h"
+#include "s2/s2metrics.h"
+#include "s2/s2padded_cell.h"
+#include "s2/s2pointutil.h"
+#include "s2/s2shapeutil_contains_brute_force.h"
+
+using std::fabs;
+using std::max;
+using std::unique_ptr;
+using std::vector;
+
+// FLAGS_s2shape_index_default_max_edges_per_cell
+//
+// The default maximum number of edges per cell (not counting "long" edges).
+// If a cell has more than this many edges, and it is not a leaf cell, then it
+// is subdivided.  This flag can be overridden via MutableS2ShapeIndex::Options.
+// Reasonable values range from 10 to about 50 or so.
+DEFINE_int32(
+    s2shape_index_default_max_edges_per_cell, 10,
+    "Default maximum number of edges (not counting 'long' edges) per cell; "
+    "reasonable values range from 10 to 50.  Small values makes queries "
+    "faster, while large values make construction faster and use less "
+    "memory.");
+
+// FLAGS_s2shape_index_tmp_memory_budget_mb
+//
+// Attempt to limit the amount of temporary memory allocated while building or
+// updating a MutableS2ShapeIndex to at most this value.  This is achieved by
+// splitting the updates into multiple batches when necessary.  (The memory
+// required is proportional to the number of edges being updated at once.)
+//
+// Note that this limit is not a hard guarantee, for several reasons:
+//  (1) the memory estimates are only approximations;
+//  (2) all edges in a given shape are added or removed at once, so shapes
+//      with huge numbers of edges may exceed the budget;
+//  (3) shapes being removed are always processed in a single batch.  (This
+//      could be fixed, but it seems better to keep the code simpler for now.)
+DEFINE_int32(
+    s2shape_index_tmp_memory_budget_mb, 100,
+    "Attempts to limit the amount of temporary memory used by "
+    "MutableS2ShapeIndex when creating or updating very large indexes "
+    "to at most this value.  If more memory than this is needed, updates "
+    "will automatically be split into batches internally.");
+
+// FLAGS_s2shape_index_cell_size_to_long_edge_ratio
+//
+// The cell size relative to the length of an edge at which it is first
+// considered to be "long".  Long edges do not contribute toward the decision
+// to subdivide a cell further.  For example, a value of 2.0 means that the
+// cell must be at least twice the size of the edge in order for that edge to
+// be counted.  There are two reasons for not counting long edges: (1) such
+// edges typically need to be propagated to several children, which increases
+// time and memory costs without much benefit, and (2) in pathological cases,
+// many long edges close together could force subdivision to continue all the
+// way to the leaf cell level.
+DEFINE_double(
+    s2shape_index_cell_size_to_long_edge_ratio, 1.0,
+    "The cell size relative to the length of an edge at which it is first "
+    "considered to be 'long'.  Long edges do not contribute to the decision "
+    "to subdivide a cell further.  The size and speed of the index are "
+    "typically not very sensitive to this parameter.  Reasonable values range "
+    "from 0.1 to 10, with smaller values causing more aggressive subdivision "
+    "of long edges grouped closely together.");
+
+// The total error when clipping an edge comes from two sources:
+// (1) Clipping the original spherical edge to a cube face (the "face edge").
+//     The maximum error in this step is S2::kFaceClipErrorUVCoord.
+// (2) Clipping the face edge to the u- or v-coordinate of a cell boundary.
+//     The maximum error in this step is S2::kEdgeClipErrorUVCoord.
+// Finally, since we encounter the same errors when clipping query edges, we
+// double the total error so that we only need to pad edges during indexing
+// and not at query time.
+const double MutableS2ShapeIndex::kCellPadding =
+    2 * (S2::kFaceClipErrorUVCoord + S2::kEdgeClipErrorUVCoord);
+
+MutableS2ShapeIndex::Options::Options()
+    : max_edges_per_cell_(FLAGS_s2shape_index_default_max_edges_per_cell) {
+}
+
+void MutableS2ShapeIndex::Options::set_max_edges_per_cell(
+    int max_edges_per_cell) {
+  max_edges_per_cell_ = max_edges_per_cell;
+}
+
+bool MutableS2ShapeIndex::Iterator::Locate(const S2Point& target) {
+  return LocateImpl(target, this);
+}
+
+MutableS2ShapeIndex::CellRelation MutableS2ShapeIndex::Iterator::Locate(
+    S2CellId target) {
+  return LocateImpl(target, this);
+}
+
+const S2ShapeIndexCell* MutableS2ShapeIndex::Iterator::GetCell() const {
+  S2_LOG(DFATAL) << "Should never be called";
+  return nullptr;
+}
+
+unique_ptr<MutableS2ShapeIndex::IteratorBase>
+MutableS2ShapeIndex::Iterator::Clone() const {
+  return absl::make_unique<Iterator>(*this);
+}
+
+void MutableS2ShapeIndex::Iterator::Copy(const IteratorBase& other)  {
+  *this = *down_cast<const Iterator*>(&other);
+}
+
+// Defines the initial focus point of MutableS2ShapeIndex::InteriorTracker
+// (the start of the S2CellId space-filling curve).
+//
+// TODO(ericv): Move InteriorTracker here to avoid the need for this method.
+static S2Point kInteriorTrackerOrigin() {
+  return S2::FaceUVtoXYZ(0, -1, -1).Normalize();
+}
+
+MutableS2ShapeIndex::MutableS2ShapeIndex()
+    : index_status_(FRESH) {
+}
+
+MutableS2ShapeIndex::MutableS2ShapeIndex(const Options& options)
+    : options_(options),
+      index_status_(FRESH) {
+}
+
+void MutableS2ShapeIndex::Init(const Options& options) {
+  S2_DCHECK(shapes_.empty());
+  options_ = options;
+}
+
+MutableS2ShapeIndex::~MutableS2ShapeIndex() {
+  Clear();
+}
+
+void MutableS2ShapeIndex::Minimize() {
+  // TODO(ericv): Implement.  In theory we should be able to discard the
+  // entire index and rebuild it the next time it is needed.
+}
+
+int MutableS2ShapeIndex::Add(unique_ptr<S2Shape> shape) {
+  // Additions are processed lazily by ApplyUpdates().
+  const int id = shapes_.size();
+  shape->id_ = id;
+  shapes_.push_back(std::move(shape));
+  index_status_.store(STALE, std::memory_order_relaxed);
+  return id;
+}
+
+unique_ptr<S2Shape> MutableS2ShapeIndex::Release(int shape_id) {
+  // This class updates itself lazily, because it is much more efficient to
+  // process additions and removals in batches.  However this means that when
+  // a shape is removed, we need to make a copy of all its edges, since the
+  // client is free to delete "shape" once this call is finished.
+
+  S2_DCHECK(shapes_[shape_id] != nullptr);
+  auto shape = std::move(shapes_[shape_id]);
+  if (shape_id >= pending_additions_begin_) {
+    // We are removing a shape that has not yet been added to the index,
+    // so there is nothing else to do.
+  } else {
+    if (!pending_removals_) {
+      pending_removals_.reset(new vector<RemovedShape>);
+    }
+    // We build the new RemovedShape in place, since it includes a potentially
+    // large vector of edges that might be expensive to copy.
+    pending_removals_->push_back(RemovedShape());
+    RemovedShape* removed = &pending_removals_->back();
+    removed->shape_id = shape->id();
+    removed->has_interior = (shape->dimension() == 2);
+    removed->contains_tracker_origin =
+        s2shapeutil::ContainsBruteForce(*shape, kInteriorTrackerOrigin());
+    int num_edges = shape->num_edges();
+    removed->edges.reserve(num_edges);
+    for (int e = 0; e < num_edges; ++e) {
+      removed->edges.push_back(shape->edge(e));
+    }
+  }
+  index_status_.store(STALE, std::memory_order_relaxed);
+  return shape;
+}
+
+vector<unique_ptr<S2Shape>> MutableS2ShapeIndex::ReleaseAll() {
+  Iterator it;
+  for (it.InitStale(this, S2ShapeIndex::BEGIN); !it.done(); it.Next()) {
+    delete &it.cell();
+  }
+  cell_map_.clear();
+  pending_additions_begin_ = 0;
+  pending_removals_.reset();
+  S2_DCHECK(update_state_ == nullptr);
+  index_status_.store(FRESH, std::memory_order_relaxed);
+  vector<unique_ptr<S2Shape>> result;
+  result.swap(shapes_);
+  return result;
+}
+
+void MutableS2ShapeIndex::Clear() {
+  ReleaseAll();
+}
+
+// FaceEdge and ClippedEdge store temporary edge data while the index is being
+// updated.  FaceEdge represents an edge that has been projected onto a given
+// face, while ClippedEdge represents the portion of that edge that has been
+// clipped to a given S2Cell.
+//
+// While it would be possible to combine all the edge information into one
+// structure, there are two good reasons for separating it:
+//
+//  - Memory usage.  Separating the two classes means that we only need to
+//    store one copy of the per-face data no matter how many times an edge is
+//    subdivided, and it also lets us delay computing bounding boxes until
+//    they are needed for processing each face (when the dataset spans
+//    multiple faces).
+//
+//  - Performance.  UpdateEdges is significantly faster on large polygons when
+//    the data is separated, because it often only needs to access the data in
+//    ClippedEdge and this data is cached more successfully.
+
+struct MutableS2ShapeIndex::FaceEdge {
+  int32 shape_id;      // The shape that this edge belongs to
+  int32 edge_id;       // Edge id within that shape
+  int32 max_level;     // Not desirable to subdivide this edge beyond this level
+  bool has_interior;   // Belongs to a shape of dimension 2.
+  R2Point a, b;        // The edge endpoints, clipped to a given face
+  S2Shape::Edge edge;  // The edge endpoints
+};
+
+struct MutableS2ShapeIndex::ClippedEdge {
+  const FaceEdge* face_edge;  // The original unclipped edge
+  R2Rect bound;               // Bounding box for the clipped portion
+};
+
+// Given a set of shapes, InteriorTracker keeps track of which shapes contain
+// a particular point (the "focus").  It provides an efficient way to move the
+// focus from one point to another and incrementally update the set of shapes
+// which contain it.  We use this to compute which shapes contain the center
+// of every S2CellId in the index, by advancing the focus from one cell center
+// to the next.
+//
+// Initially the focus is at the start of the S2CellId space-filling curve.
+// We then visit all the cells that are being added to the MutableS2ShapeIndex
+// in increasing order of S2CellId.  For each cell, we draw two edges: one
+// from the entry vertex to the center, and another from the center to the
+// exit vertex (where "entry" and "exit" refer to the points where the
+// space-filling curve enters and exits the cell).  By counting edge crossings
+// we can incrementally compute which shapes contain the cell center.  Note
+// that the same set of shapes will always contain the exit point of one cell
+// and the entry point of the next cell in the index, because either (a) these
+// two points are actually the same, or (b) the intervening cells in S2CellId
+// order are all empty, and therefore there are no edge crossings if we follow
+// this path from one cell to the other.
+class MutableS2ShapeIndex::InteriorTracker {
+ public:
+  // Constructs the InteriorTracker.  You must call AddShape() for each shape
+  // that will be tracked before calling MoveTo() or DrawTo().
+  InteriorTracker();
+
+  // Returns the initial focus point when the InteriorTracker is constructed
+  // (corresponding to the start of the S2CellId space-filling curve).
+  static S2Point Origin();
+
+  // Returns the current focus point (see above).
+  const S2Point& focus() { return b_; }
+
+  // Returns true if any shapes are being tracked.
+  bool is_active() const { return is_active_; }
+
+  // Adds a shape whose interior should be tracked.  "is_inside" indicates
+  // whether the current focus point is inside the shape.  Alternatively, if
+  // the focus point is in the process of being moved (via MoveTo/DrawTo), you
+  // can also specify "is_inside" at the old focus point and call TestEdge()
+  // for every edge of the shape that might cross the current DrawTo() line.
+  // This updates the state to correspond to the new focus point.
+  //
+  // REQUIRES: shape->dimension() == 2
+  void AddShape(int32 shape_id, bool is_inside);
+
+  // Moves the focus to the given point.  This method should only be used when
+  // it is known that there are no edge crossings between the old and new
+  // focus locations; otherwise use DrawTo().
+  void MoveTo(const S2Point& b) { b_ = b; }
+
+  // Moves the focus to the given point.  After this method is called,
+  // TestEdge() should be called with all edges that may cross the line
+  // segment between the old and new focus locations.
+  void DrawTo(const S2Point& b);
+
+  // Indicates that the given edge of the given shape may cross the line
+  // segment between the old and new focus locations (see DrawTo).
+  // REQUIRES: shape->dimension() == 2
+  inline void TestEdge(int32 shape_id, const S2Shape::Edge& edge);
+
+  // The set of shape ids that contain the current focus.
+  const ShapeIdSet& shape_ids() const { return shape_ids_; }
+
+  // Indicates that the last argument to MoveTo() or DrawTo() was the entry
+  // vertex of the given S2CellId, i.e. the tracker is positioned at the start
+  // of this cell.  By using this method together with at_cellid(), the caller
+  // can avoid calling MoveTo() in cases where the exit vertex of the previous
+  // cell is the same as the entry vertex of the current cell.
+  void set_next_cellid(S2CellId next_cellid) {
+    next_cellid_ = next_cellid.range_min();
+  }
+
+  // Returns true if the focus is already at the entry vertex of the given
+  // S2CellId (provided that the caller calls set_next_cellid() as each cell
+  // is processed).
+  bool at_cellid(S2CellId cellid) const {
+    return cellid.range_min() == next_cellid_;
+  }
+
+  // Makes an internal copy of the state for shape ids below the given limit,
+  // and then clear the state for those shapes.  This is used during
+  // incremental updates to track the state of added and removed shapes
+  // separately.
+  void SaveAndClearStateBefore(int32 limit_shape_id);
+
+  // Restores the state previously saved by SaveAndClearStateBefore().  This
+  // only affects the state for shape_ids below "limit_shape_id".
+  void RestoreStateBefore(int32 limit_shape_id);
+
+ private:
+  // Removes "shape_id" from shape_ids_ if it exists, otherwise insert it.
+  void ToggleShape(int shape_id);
+
+  // Returns a pointer to the first entry "x" where x >= shape_id.
+  ShapeIdSet::iterator lower_bound(int32 shape_id);
+
+  bool is_active_;
+  S2Point a_, b_;
+  S2CellId next_cellid_;
+  S2EdgeCrosser crosser_;
+  ShapeIdSet shape_ids_;
+
+  // Shape ids saved by SaveAndClearStateBefore().  The state is never saved
+  // recursively so we don't need to worry about maintaining a stack.
+  ShapeIdSet saved_ids_;
+};
+
+// As shapes are added, we compute which ones contain the start of the
+// S2CellId space-filling curve by drawing an edge from S2::Origin() to this
+// point and counting how many shape edges cross this edge.
+MutableS2ShapeIndex::InteriorTracker::InteriorTracker()
+    : is_active_(false), b_(Origin()),
+      next_cellid_(S2CellId::Begin(S2CellId::kMaxLevel)) {
+}
+
+S2Point MutableS2ShapeIndex::InteriorTracker::Origin() {
+  // The start of the S2CellId space-filling curve.
+  return S2::FaceUVtoXYZ(0, -1, -1).Normalize();
+}
+
+void MutableS2ShapeIndex::InteriorTracker::AddShape(int32 shape_id,
+                                                    bool contains_focus) {
+  is_active_ = true;
+  if (contains_focus) {
+    ToggleShape(shape_id);
+  }
+}
+
+void MutableS2ShapeIndex::InteriorTracker::ToggleShape(int shape_id) {
+  // Since shape_ids_.size() is typically *very* small (0, 1, or 2), it turns
+  // out to be significantly faster to maintain a sorted array rather than
+  // using an STL set or btree_set.
+  if (shape_ids_.empty()) {
+    shape_ids_.push_back(shape_id);
+  } else if (shape_ids_[0] == shape_id) {
+    shape_ids_.erase(shape_ids_.begin());
+  } else {
+    ShapeIdSet::iterator pos = shape_ids_.begin();
+    while (*pos < shape_id) {
+      if (++pos == shape_ids_.end()) {
+        shape_ids_.push_back(shape_id);
+        return;
+      }
+    }
+    if (*pos == shape_id) {
+      shape_ids_.erase(pos);
+    } else {
+      shape_ids_.insert(pos, shape_id);
+    }
+  }
+}
+
+void MutableS2ShapeIndex::InteriorTracker::DrawTo(const S2Point& b) {
+  a_ = b_;
+  b_ = b;
+  crosser_.Init(&a_, &b_);
+}
+
+inline void MutableS2ShapeIndex::InteriorTracker::TestEdge(
+    int32 shape_id, const S2Shape::Edge& edge) {
+  if (crosser_.EdgeOrVertexCrossing(&edge.v0, &edge.v1)) {
+    ToggleShape(shape_id);
+  }
+}
+
+// Like std::lower_bound(shape_ids_.begin(), shape_ids_.end(), shape_id), but
+// implemented with linear rather than binary search because the number of
+// shapes being tracked is typically very small.
+inline MutableS2ShapeIndex::ShapeIdSet::iterator
+MutableS2ShapeIndex::InteriorTracker::lower_bound(int32 shape_id) {
+  ShapeIdSet::iterator pos = shape_ids_.begin();
+  while (pos != shape_ids_.end() && *pos < shape_id) { ++pos; }
+  return pos;
+}
+
+void MutableS2ShapeIndex::InteriorTracker::SaveAndClearStateBefore(
+    int32 limit_shape_id) {
+  S2_DCHECK(saved_ids_.empty());
+  ShapeIdSet::iterator limit = lower_bound(limit_shape_id);
+  saved_ids_.assign(shape_ids_.begin(), limit);
+  shape_ids_.erase(shape_ids_.begin(), limit);
+}
+
+void MutableS2ShapeIndex::InteriorTracker::RestoreStateBefore(
+    int32 limit_shape_id) {
+  shape_ids_.erase(shape_ids_.begin(), lower_bound(limit_shape_id));
+  shape_ids_.insert(shape_ids_.begin(), saved_ids_.begin(), saved_ids_.end());
+  saved_ids_.clear();
+}
+
+// Apply any pending updates in a thread-safe way.
+void MutableS2ShapeIndex::ApplyUpdatesThreadSafe() {
+  lock_.Lock();
+  if (index_status_.load(std::memory_order_relaxed) == FRESH) {
+    lock_.Unlock();
+  } else if (index_status_.load(std::memory_order_relaxed) == UPDATING) {
+    // Wait until the updating thread is finished.  We do this by attempting
+    // to lock a mutex that is held by the updating thread.  When this mutex
+    // is unlocked the index_status_ is guaranteed to be FRESH.
+    ++update_state_->num_waiting;
+    lock_.Unlock();
+    update_state_->wait_mutex.Lock();
+    lock_.Lock();
+    --update_state_->num_waiting;
+    UnlockAndSignal();  // Notify other waiting threads.
+  } else {
+    S2_DCHECK_EQ(STALE, index_status_);
+    index_status_.store(UPDATING, std::memory_order_relaxed);
+    // Allocate the extra state needed for thread synchronization.  We keep
+    // the spinlock held while doing this, because (1) memory allocation is
+    // fast, so the chance of a context switch while holding the lock is low;
+    // (2) by far the most common situation is that there is no contention,
+    // and this saves an extra lock and unlock step; (3) even in the rare case
+    // where there is contention, the main side effect is that some other
+    // thread will burn a few CPU cycles rather than sleeping.
+    update_state_.reset(new UpdateState);
+    // lock_.Lock wait_mutex *before* calling Unlock() to ensure that all other
+    // threads will block on it.
+    update_state_->wait_mutex.Lock();
+    // Release the spinlock before doing any real work.
+    lock_.Unlock();
+    ApplyUpdatesInternal();
+    lock_.Lock();
+    // index_status_ can be updated to FRESH only while locked *and* using
+    // an atomic store operation, so that MaybeApplyUpdates() can check
+    // whether the index is FRESH without acquiring the spinlock.
+    index_status_.store(FRESH, std::memory_order_release);
+    UnlockAndSignal();  // Notify any waiting threads.
+  }
+}
+
+// Releases lock_ and wakes up any waiting threads by releasing wait_mutex.
+// If this was the last waiting thread, also deletes update_state_.
+// REQUIRES: lock_ is held.
+// REQUIRES: wait_mutex is held.
+inline void MutableS2ShapeIndex::UnlockAndSignal() {
+  S2_DCHECK_EQ(FRESH, index_status_);
+  int num_waiting = update_state_->num_waiting;
+  lock_.Unlock();
+  // Allow another waiting thread to proceed.  Note that no new threads can
+  // start waiting because the index_status_ is now FRESH, and the caller is
+  // required to prevent any new mutations from occurring while these const
+  // methods are running.
+  //
+  // We need to unlock wait_mutex before destroying it even if there are no
+  // waiting threads.
+  update_state_->wait_mutex.Unlock();
+  if (num_waiting == 0) {
+    update_state_.reset();
+  }
+}
+
+void MutableS2ShapeIndex::ForceBuild() {
+  // No locks required because this is not a const method.  It is the client's
+  // responsibility to ensure correct thread synchronization.
+  if (index_status_.load(std::memory_order_relaxed) != FRESH) {
+    ApplyUpdatesInternal();
+    index_status_.store(FRESH, std::memory_order_relaxed);
+  }
+}
+
+// A BatchDescriptor represents a set of pending updates that will be applied
+// at the same time.  The batch consists of all updates with shape ids between
+// the current value of "ShapeIndex::pending_additions_begin_" (inclusive) and
+// "additions_end" (exclusive).  The first batch to be processed also
+// implicitly includes all shapes being removed.  "num_edges" is the total
+// number of edges that will be added or removed in this batch.
+struct MutableS2ShapeIndex::BatchDescriptor {
+  BatchDescriptor(int _additions_end, int _num_edges)
+      : additions_end(_additions_end), num_edges(_num_edges) {
+  }
+  int additions_end;
+  int num_edges;
+};
+
+// This method updates the index by applying all pending additions and
+// removals.  It does *not* update index_status_ (see ApplyUpdatesThreadSafe).
+void MutableS2ShapeIndex::ApplyUpdatesInternal() {
+  // Check whether we have so many edges to process that we should process
+  // them in multiple batches to save memory.  Building the index can use up
+  // to 20x as much memory (per edge) as the final index size.
+  vector<BatchDescriptor> batches;
+  GetUpdateBatches(&batches);
+  int i = 0;
+  for (const BatchDescriptor& batch : batches) {
+    vector<FaceEdge> all_edges[6];
+    S2_VLOG(1) << "Batch " << i++ << ": shape_limit=" << batch.additions_end
+               << ", edges=" << batch.num_edges;
+
+    ReserveSpace(batch, all_edges);
+    InteriorTracker tracker;
+    if (pending_removals_) {
+      // The first batch implicitly includes all shapes being removed.
+      for (const auto& pending_removal : *pending_removals_) {
+        RemoveShape(pending_removal, all_edges, &tracker);
+      }
+      pending_removals_.reset(nullptr);
+    }
+    for (int id = pending_additions_begin_; id < batch.additions_end; ++id) {
+      AddShape(id, all_edges, &tracker);
+    }
+    for (int face = 0; face < 6; ++face) {
+      UpdateFaceEdges(face, all_edges[face], &tracker);
+      // Save memory by clearing vectors after we are done with them.
+      vector<FaceEdge>().swap(all_edges[face]);
+    }
+    pending_additions_begin_ = batch.additions_end;
+  }
+  // It is the caller's responsibility to update index_status_.
+}
+
+// Count the number of edges being updated, and break them into several
+// batches if necessary to reduce the amount of memory needed.  (See the
+// documentation for FLAGS_s2shape_index_tmp_memory_budget_mb.)
+void MutableS2ShapeIndex::GetUpdateBatches(vector<BatchDescriptor>* batches)
+    const {
+  // Count the edges being removed and added.
+  int num_edges_removed = 0;
+  if (pending_removals_) {
+    for (const auto& pending_removal : *pending_removals_) {
+      num_edges_removed += pending_removal.edges.size();
+    }
+  }
+  int num_edges_added = 0;
+  for (int id = pending_additions_begin_; id < shapes_.size(); ++id) {
+    const S2Shape* shape = this->shape(id);
+    if (shape == nullptr) continue;
+    num_edges_added += shape->num_edges();
+  }
+  int num_edges = num_edges_removed + num_edges_added;
+
+  // The following memory estimates are based on heap profiling.
+  //
+  // The final size of a MutableS2ShapeIndex depends mainly on how finely the
+  // index is subdivided, as controlled by Options::max_edges_per_cell() and
+  // --s2shape_index_default_max_edges_per_cell. For realistic values of
+  // max_edges_per_cell() and shapes with moderate numbers of edges, it is
+  // difficult to get much below 8 bytes per edge.  [The minimum possible size
+  // is 4 bytes per edge (to store a 32-bit edge id in an S2ClippedShape) plus
+  // 24 bytes per shape (for the S2ClippedShape itself plus a pointer in the
+  // shapes_ vector.]
+  //
+  // The temporary memory consists mainly of the FaceEdge and ClippedEdge
+  // structures plus a ClippedEdge pointer for every level of recursive
+  // subdivision.  For very large indexes this can be 200 bytes per edge.
+  const size_t kFinalBytesPerEdge = 8;
+  const size_t kTmpBytesPerEdge = 200;
+  const size_t kTmpMemoryBudgetBytes =
+      static_cast<size_t>(FLAGS_s2shape_index_tmp_memory_budget_mb) << 20;
+
+  // We arbitrarily limit the number of batches just as a safety measure.
+  // With the current default memory budget of 100 MB, this limit is not
+  // reached even when building an index of 350 million edges.
+  const int kMaxUpdateBatches = 100;
+
+  if (num_edges * kTmpBytesPerEdge <= kTmpMemoryBudgetBytes) {
+    // We can update all edges at once without exceeding kTmpMemoryBudgetBytes.
+    batches->push_back(BatchDescriptor(shapes_.size(), num_edges));
+    return;
+  }
+  // Otherwise, break the updates into up to several batches, where the size
+  // of each batch is chosen so that all batches use approximately the same
+  // high-water memory.  GetBatchSizes() returns the recommended number of
+  // edges in each batch.
+  vector<int> batch_sizes;
+  GetBatchSizes(num_edges, kMaxUpdateBatches, kFinalBytesPerEdge,
+                kTmpBytesPerEdge, kTmpMemoryBudgetBytes, &batch_sizes);
+
+  // We always process removed edges in a single batch, since (1) they already
+  // take up a lot of memory because we have copied all their edges, and (2)
+  // AbsorbIndexCell() uses (shapes_[id] == nullptr) to detect when a shape is
+  // being removed, so in order to split the removals into batches we would
+  // need a different approach (e.g., temporarily add fake entries to shapes_
+  // and restore them back to nullptr as shapes are actually removed).
+  num_edges = 0;
+  if (pending_removals_) {
+    num_edges += num_edges_removed;
+    if (num_edges >= batch_sizes[0]) {
+      batches->push_back(BatchDescriptor(pending_additions_begin_, num_edges));
+      num_edges = 0;
+    }
+  }
+  // Keep adding shapes to each batch until the recommended number of edges
+  // for that batch is reached, then move on to the next batch.
+  for (int id = pending_additions_begin_; id < shapes_.size(); ++id) {
+    const S2Shape* shape = this->shape(id);
+    if (shape == nullptr) continue;
+    num_edges += shape->num_edges();
+    if (num_edges >= batch_sizes[batches->size()]) {
+      batches->push_back(BatchDescriptor(id + 1, num_edges));
+      num_edges = 0;
+    }
+  }
+  // Some shapes have no edges.  If a shape with no edges is the last shape to
+  // be added or removed, then the final batch may not include it, so we fix
+  // that problem here.
+  batches->back().additions_end = shapes_.size();
+  S2_DCHECK_LE(batches->size(), kMaxUpdateBatches);
+}
+
+// Given "num_items" items, each of which uses "tmp_bytes_per_item" while it
+// is being updated but only "final_bytes_per_item" in the end, divide the
+// items into batches that have approximately the same *total* memory usage
+// consisting of the temporary memory needed for the items in the current
+// batch plus the final size of all the items that have already been
+// processed.  Use the fewest number of batches (but never more than
+// "max_batches") such that the total memory usage does not exceed the
+// combined final size of all the items plus "tmp_memory_budget_bytes".
+/* static */
+void MutableS2ShapeIndex::GetBatchSizes(int num_items, int max_batches,
+                                        double final_bytes_per_item,
+                                        double tmp_bytes_per_item,
+                                        double tmp_memory_budget_bytes,
+                                        vector<int>* batch_sizes) {
+  // This code tries to fit all the data into the same memory space
+  // ("total_budget_bytes") at every iteration.  The data consists of some
+  // number of processed items (at "final_bytes_per_item" each), plus some
+  // number being updated (at "tmp_bytes_per_item" each).  The space occupied
+  // by the items being updated is the "free space".  At each iteration, the
+  // free space is multiplied by (1 - final_bytes_per_item/tmp_bytes_per_item)
+  // as the items are converted into their final form.
+  double final_bytes = num_items * final_bytes_per_item;
+  double final_bytes_ratio = final_bytes_per_item / tmp_bytes_per_item;
+  double free_space_multiplier = 1 - final_bytes_ratio;
+
+  // The total memory budget is the greater of the final size plus the allowed
+  // temporary memory, or the minimum amount of memory required to limit the
+  // number of batches to "max_batches".
+  double total_budget_bytes = max(
+      final_bytes + tmp_memory_budget_bytes,
+      final_bytes / (1 - pow(free_space_multiplier, max_batches)));
+
+  // "max_batch_items" is the number of items in the current batch.
+  double max_batch_items = total_budget_bytes / tmp_bytes_per_item;
+  batch_sizes->clear();
+  for (int i = 0; i + 1 < max_batches && num_items > 0; ++i) {
+    int batch_items =
+        std::min(num_items, static_cast<int>(max_batch_items + 1));
+    batch_sizes->push_back(batch_items);
+    num_items -= batch_items;
+    max_batch_items *= free_space_multiplier;
+  }
+  S2_DCHECK_LE(batch_sizes->size(), max_batches);
+}
+
+// Reserve an appropriate amount of space for the top-level face edges in the
+// current batch.  This data structure uses about half of the temporary memory
+// needed during index construction.  Furthermore, if the arrays are grown via
+// push_back() then up to 10% of the total run time consists of copying data
+// as these arrays grow, so it is worthwhile to preallocate space for them.
+void MutableS2ShapeIndex::ReserveSpace(const BatchDescriptor& batch,
+                                       vector<FaceEdge> all_edges[6]) const {
+  // If the number of edges is relatively small, then the fastest approach is
+  // to simply reserve space on every face for the maximum possible number of
+  // edges.  We use a different threshold for this calculation than for
+  // deciding when to break updates into batches, because the cost/benefit
+  // ratio is different.  (Here the only extra expense is that we need to
+  // sample the edges to estimate how many edges per face there are.)
+  const size_t kMaxCheapBytes = 30 << 20;  // 30 MB
+  const int kMaxCheapEdges = kMaxCheapBytes / (6 * sizeof(FaceEdge));
+  if (batch.num_edges <= kMaxCheapEdges) {
+    for (int face = 0; face < 6; ++face) {
+      all_edges[face].reserve(batch.num_edges);
+    }
+    return;
+  }
+  // Otherwise we estimate the number of edges on each face by taking a random
+  // sample.  The goal is to come up with an estimate that is fast and
+  // accurate for non-pathological geometry.  If our estimates happen to be
+  // wrong, the vector will still grow automatically - the main side effects
+  // are that memory usage will be larger (by up to a factor of 3), and
+  // constructing the index will be about 10% slower.
+  //
+  // Given a desired sample size, we choose equally spaced edges from
+  // throughout the entire data set.  We use a Bresenham-type algorithm to
+  // choose the samples.
+  const int kDesiredSampleSize = 10000;
+  const int sample_interval = max(1, batch.num_edges / kDesiredSampleSize);
+
+  // Initialize "edge_id" to be midway through the first sample interval.
+  // Because samples are equally spaced the actual sample size may differ
+  // slightly from the desired sample size.
+  int edge_id = sample_interval / 2;
+  const int actual_sample_size = (batch.num_edges + edge_id) / sample_interval;
+  int face_count[6] = { 0, 0, 0, 0, 0, 0 };
+  if (pending_removals_) {
+    for (const RemovedShape& removed : *pending_removals_) {
+      edge_id += removed.edges.size();
+      while (edge_id >= sample_interval) {
+        edge_id -= sample_interval;
+        face_count[S2::GetFace(removed.edges[edge_id].v0)] += 1;
+      }
+    }
+  }
+  for (int id = pending_additions_begin_; id < batch.additions_end; ++id) {
+    const S2Shape* shape = this->shape(id);
+    if (shape == nullptr) continue;
+    edge_id += shape->num_edges();
+    while (edge_id >= sample_interval) {
+      edge_id -= sample_interval;
+      // For speed, we only count the face containing one endpoint of the
+      // edge.  In general the edge could span all 6 faces (with padding), but
+      // it's not worth the expense to compute this more accurately.
+      face_count[S2::GetFace(shape->edge(edge_id).v0)] += 1;
+    }
+  }
+  // Now given the raw face counts, compute a confidence interval such that we
+  // will be unlikely to allocate too little space.  Computing accurate
+  // binomial confidence intervals is expensive and not really necessary.
+  // Instead we use a simple approximation:
+  //  - For any face with at least 1 sample, we use at least a 4-sigma
+  //    confidence interval.  (The chosen width is adequate for the worst case
+  //    accuracy, which occurs when the face contains approximately 50% of the
+  //    edges.)  Assuming that our sample is representative, the probability of
+  //    reserving too little space is approximately 1 in 30,000.
+  //  - For faces with no samples at all, we don't bother reserving space.
+  //    It is quite likely that such faces are truly empty, so we save time
+  //    and memory this way.  If the face does contain some edges, there will
+  //    only be a few so it is fine to let the vector grow automatically.
+  // On average, we reserve 2% extra space for each face that has geometry.
+
+  // kMaxSemiWidth is the maximum semi-width over all probabilities p of a
+  // 4-sigma binomial confidence interval with a sample size of 10,000.
+  const double kMaxSemiWidth = 0.02;
+  const double sample_ratio = 1.0 / actual_sample_size;
+  for (int face = 0; face < 6; ++face) {
+    if (face_count[face] == 0) continue;
+    double fraction = sample_ratio * face_count[face] + kMaxSemiWidth;
+    all_edges[face].reserve(fraction * batch.num_edges);
+  }
+}
+
+// Clip all edges of the given shape to the six cube faces, add the clipped
+// edges to "all_edges", and start tracking its interior if necessary.
+void MutableS2ShapeIndex::AddShape(int id, vector<FaceEdge> all_edges[6],
+                                   InteriorTracker* tracker) const {
+  const S2Shape* shape = this->shape(id);
+  if (shape == nullptr) {
+    return;  // This shape has already been removed.
+  }
+  // Construct a template for the edges to be added.
+  FaceEdge edge;
+  edge.shape_id = id;
+  edge.has_interior = (shape->dimension() == 2);
+  if (edge.has_interior) {
+    tracker->AddShape(id, s2shapeutil::ContainsBruteForce(*shape,
+                                                          tracker->focus()));
+  }
+  int num_edges = shape->num_edges();
+  for (int e = 0; e < num_edges; ++e) {
+    edge.edge_id = e;
+    edge.edge = shape->edge(e);
+    edge.max_level = GetEdgeMaxLevel(edge.edge);
+    AddFaceEdge(&edge, all_edges);
+  }
+}
+
+void MutableS2ShapeIndex::RemoveShape(const RemovedShape& removed,
+                                      vector<FaceEdge> all_edges[6],
+                                      InteriorTracker* tracker) const {
+  FaceEdge edge;
+  edge.edge_id = -1;  // Not used or needed for removed edges.
+  edge.shape_id = removed.shape_id;
+  edge.has_interior = removed.has_interior;
+  if (edge.has_interior) {
+    tracker->AddShape(edge.shape_id, removed.contains_tracker_origin);
+  }
+  for (const auto& removed_edge : removed.edges) {
+    edge.edge = removed_edge;
+    edge.max_level = GetEdgeMaxLevel(edge.edge);
+    AddFaceEdge(&edge, all_edges);
+  }
+}
+
+inline void MutableS2ShapeIndex::AddFaceEdge(
+    FaceEdge* edge, vector<FaceEdge> all_edges[6]) const {
+  // Fast path: both endpoints are on the same face, and are far enough from
+  // the edge of the face that don't intersect any (padded) adjacent face.
+  int a_face = S2::GetFace(edge->edge.v0);
+  if (a_face == S2::GetFace(edge->edge.v1)) {
+    S2::ValidFaceXYZtoUV(a_face, edge->edge.v0, &edge->a);
+    S2::ValidFaceXYZtoUV(a_face, edge->edge.v1, &edge->b);
+    const double kMaxUV = 1 - kCellPadding;
+    if (fabs(edge->a[0]) <= kMaxUV && fabs(edge->a[1]) <= kMaxUV &&
+        fabs(edge->b[0]) <= kMaxUV && fabs(edge->b[1]) <= kMaxUV) {
+      all_edges[a_face].push_back(*edge);
+      return;
+    }
+  }
+  // Otherwise we simply clip the edge to all six faces.
+  for (int face = 0; face < 6; ++face) {
+    if (S2::ClipToPaddedFace(edge->edge.v0, edge->edge.v1, face,
+                             kCellPadding, &edge->a, &edge->b)) {
+      all_edges[face].push_back(*edge);
+    }
+  }
+}
+
+// Return the first level at which the edge will *not* contribute towards
+// the decision to subdivide.
+int MutableS2ShapeIndex::GetEdgeMaxLevel(const S2Shape::Edge& edge) const {
+  // Compute the maximum cell size for which this edge is considered "long".
+  // The calculation does not need to be perfectly accurate, so we use Norm()
+  // rather than Angle() for speed.
+  double cell_size = ((edge.v0 - edge.v1).Norm() *
+                      FLAGS_s2shape_index_cell_size_to_long_edge_ratio);
+  // Now return the first level encountered during subdivision where the
+  // average cell size is at most "cell_size".
+  return S2::kAvgEdge.GetLevelForMaxValue(cell_size);
+}
+
+// EdgeAllocator provides temporary storage for new ClippedEdges that are
+// created during indexing.  It is essentially a stack model, where edges are
+// allocated as the recursion does down and freed as it comes back up.
+//
+// It also provides a mutable vector of FaceEdges that is used when
+// incrementally updating the index (see AbsorbIndexCell).
+class MutableS2ShapeIndex::EdgeAllocator {
+ public:
+  EdgeAllocator() : size_(0) {}
+
+  // Return a pointer to a newly allocated edge.  The EdgeAllocator
+  // retains ownership.
+  ClippedEdge* NewClippedEdge() {
+    if (size_ == clipped_edges_.size()) {
+      clipped_edges_.emplace_back(new ClippedEdge);
+    }
+    return clipped_edges_[size_++].get();
+  }
+  // Return the number of allocated edges.
+  size_t size() const { return size_; }
+
+  // Reset the allocator to only contain the first "size" allocated edges.
+  void Reset(size_t size) { size_ = size; }
+
+  vector<FaceEdge>* mutable_face_edges() {
+    return &face_edges_;
+  }
+
+ private:
+  // We can't use vector<ClippedEdge> because edges are not allowed to move
+  // once they have been allocated.  Instead we keep a pool of allocated edges
+  // that are all deleted together at the end.
+  size_t size_;
+  vector<unique_ptr<ClippedEdge>> clipped_edges_;
+
+  // On the other hand, we can use vector<FaceEdge> because they are allocated
+  // only at one level during the recursion (namely, the level at which we
+  // absorb an existing index cell).
+  vector<FaceEdge> face_edges_;
+
+  EdgeAllocator(const EdgeAllocator&) = delete;
+  void operator=(const EdgeAllocator&) = delete;
+};
+
+// Given a face and a vector of edges that intersect that face, add or remove
+// all the edges from the index.  (An edge is added if shapes_[id] is not
+// nullptr, and removed otherwise.)
+void MutableS2ShapeIndex::UpdateFaceEdges(int face,
+                                          const vector<FaceEdge>& face_edges,
+                                          InteriorTracker* tracker) {
+  int num_edges = face_edges.size();
+  if (num_edges == 0 && tracker->shape_ids().empty()) return;
+
+  // Create the initial ClippedEdge for each FaceEdge.  Additional clipped
+  // edges are created when edges are split between child cells.  We create
+  // two arrays, one containing the edge data and another containing pointers
+  // to those edges, so that during the recursion we only need to copy
+  // pointers in order to propagate an edge to the correct child.
+  vector<ClippedEdge> clipped_edge_storage;
+  vector<const ClippedEdge*> clipped_edges;
+  clipped_edge_storage.reserve(num_edges);
+  clipped_edges.reserve(num_edges);
+  R2Rect bound = R2Rect::Empty();
+  for (int e = 0; e < num_edges; ++e) {
+    ClippedEdge clipped;
+    clipped.face_edge = &face_edges[e];
+    clipped.bound = R2Rect::FromPointPair(face_edges[e].a, face_edges[e].b);
+    clipped_edge_storage.push_back(clipped);
+    clipped_edges.push_back(&clipped_edge_storage.back());
+    bound.AddRect(clipped.bound);
+  }
+  // Construct the initial face cell containing all the edges, and then update
+  // all the edges in the index recursively.
+  EdgeAllocator alloc;
+  S2CellId face_id = S2CellId::FromFace(face);
+  S2PaddedCell pcell(face_id, kCellPadding);
+
+  // "disjoint_from_index" means that the current cell being processed (and
+  // all its descendants) are not already present in the index.
+  bool disjoint_from_index = is_first_update();
+  if (num_edges > 0) {
+    S2CellId shrunk_id = ShrinkToFit(pcell, bound);
+    if (shrunk_id != pcell.id()) {
+      // All the edges are contained by some descendant of the face cell.  We
+      // can save a lot of work by starting directly with that cell, but if we
+      // are in the interior of at least one shape then we need to create
+      // index entries for the cells we are skipping over.
+      SkipCellRange(face_id.range_min(), shrunk_id.range_min(),
+                    tracker, &alloc, disjoint_from_index);
+      pcell = S2PaddedCell(shrunk_id, kCellPadding);
+      UpdateEdges(pcell, &clipped_edges, tracker, &alloc, disjoint_from_index);
+      SkipCellRange(shrunk_id.range_max().next(), face_id.range_max().next(),
+                    tracker, &alloc, disjoint_from_index);
+      return;
+    }
+  }
+  // Otherwise (no edges, or no shrinking is possible), subdivide normally.
+  UpdateEdges(pcell, &clipped_edges, tracker, &alloc, disjoint_from_index);
+}
+
+inline S2CellId MutableS2ShapeIndex::ShrinkToFit(const S2PaddedCell& pcell,
+                                                 const R2Rect& bound) const {
+  S2CellId shrunk_id = pcell.ShrinkToFit(bound);
+  if (!is_first_update() && shrunk_id != pcell.id()) {
+    // Don't shrink any smaller than the existing index cells, since we need
+    // to combine the new edges with those cells.
+    // Use InitStale() to avoid applying updated recursively.
+    Iterator iter;
+    iter.InitStale(this);
+    CellRelation r = iter.Locate(shrunk_id);
+    if (r == INDEXED) { shrunk_id = iter.id(); }
+  }
+  return shrunk_id;
+}
+
+// Skip over the cells in the given range, creating index cells if we are
+// currently in the interior of at least one shape.
+void MutableS2ShapeIndex::SkipCellRange(S2CellId begin, S2CellId end,
+                                        InteriorTracker* tracker,
+                                        EdgeAllocator* alloc,
+                                        bool disjoint_from_index) {
+  // If we aren't in the interior of a shape, then skipping over cells is easy.
+  if (tracker->shape_ids().empty()) return;
+
+  // Otherwise generate the list of cell ids that we need to visit, and create
+  // an index entry for each one.
+  for (S2CellId skipped_id : S2CellUnion::FromBeginEnd(begin, end)) {
+    vector<const ClippedEdge*> clipped_edges;
+    UpdateEdges(S2PaddedCell(skipped_id, kCellPadding),
+                &clipped_edges, tracker, alloc, disjoint_from_index);
+  }
+}
+
+// Given a cell and a set of ClippedEdges whose bounding boxes intersect that
+// cell, add or remove all the edges from the index.  Temporary space for
+// edges that need to be subdivided is allocated from the given EdgeAllocator.
+// "disjoint_from_index" is an optimization hint indicating that cell_map_
+// does not contain any entries that overlap the given cell.
+void MutableS2ShapeIndex::UpdateEdges(const S2PaddedCell& pcell,
+                                      vector<const ClippedEdge*>* edges,
+                                      InteriorTracker* tracker,
+                                      EdgeAllocator* alloc,
+                                      bool disjoint_from_index) {
+  // Cases where an index cell is not needed should be detected before this.
+  S2_DCHECK(!edges->empty() || !tracker->shape_ids().empty());
+
+  // This function is recursive with a maximum recursion depth of 30
+  // (S2CellId::kMaxLevel).  Note that using an explicit stack does not seem
+  // to be any faster based on profiling.
+
+  // Incremental updates are handled as follows.  All edges being added or
+  // removed are combined together in "edges", and all shapes with interiors
+  // are tracked using "tracker".  We subdivide recursively as usual until we
+  // encounter an existing index cell.  At this point we "absorb" the index
+  // cell as follows:
+  //
+  //   - Edges and shapes that are being removed are deleted from "edges" and
+  //     "tracker".
+  //   - All remaining edges and shapes from the index cell are added to
+  //     "edges" and "tracker".
+  //   - Continue subdividing recursively, creating new index cells as needed.
+  //   - When the recursion gets back to the cell that was absorbed, we
+  //     restore "edges" and "tracker" to their previous state.
+  //
+  // Note that the only reason that we include removed shapes in the recursive
+  // subdivision process is so that we can find all of the index cells that
+  // contain those shapes efficiently, without maintaining an explicit list of
+  // index cells for each shape (which would be expensive in terms of memory).
+  bool index_cell_absorbed = false;
+  if (!disjoint_from_index) {
+    // There may be existing index cells contained inside "pcell".  If we
+    // encounter such a cell, we need to combine the edges being updated with
+    // the existing cell contents by "absorbing" the cell.
+    // Use InitStale() to avoid applying updated recursively.
+    Iterator iter;
+    iter.InitStale(this);
+    CellRelation r = iter.Locate(pcell.id());
+    if (r == DISJOINT) {
+      disjoint_from_index = true;
+    } else if (r == INDEXED) {
+      // Absorb the index cell by transferring its contents to "edges" and
+      // deleting it.  We also start tracking the interior of any new shapes.
+      AbsorbIndexCell(pcell, iter, edges, tracker, alloc);
+      index_cell_absorbed = true;
+      disjoint_from_index = true;
+    } else {
+      S2_DCHECK_EQ(SUBDIVIDED, r);
+    }
+  }
+
+  // If there are existing index cells below us, then we need to keep
+  // subdividing so that we can merge with those cells.  Otherwise,
+  // MakeIndexCell checks if the number of edges is small enough, and creates
+  // an index cell if possible (returning true when it does so).
+  if (!disjoint_from_index || !MakeIndexCell(pcell, *edges, tracker)) {
+    // Reserve space for the edges that will be passed to each child.  This is
+    // important since otherwise the running time is dominated by the time
+    // required to grow the vectors.  The amount of memory involved is
+    // relatively small, so we simply reserve the maximum space for every child.
+    vector<const ClippedEdge*> child_edges[2][2];  // [i][j]
+    int num_edges = edges->size();
+    for (int i = 0; i < 2; ++i) {
+      for (int j = 0; j < 2; ++j) {
+        child_edges[i][j].reserve(num_edges);
+      }
+    }
+
+    // Remember the current size of the EdgeAllocator so that we can free any
+    // edges that are allocated during edge splitting.
+    size_t alloc_size = alloc->size();
+
+    // Compute the middle of the padded cell, defined as the rectangle in
+    // (u,v)-space that belongs to all four (padded) children.  By comparing
+    // against the four boundaries of "middle" we can determine which children
+    // each edge needs to be propagated to.
+    const R2Rect& middle = pcell.middle();
+
+    // Build up a vector edges to be passed to each child cell.  The (i,j)
+    // directions are left (i=0), right (i=1), lower (j=0), and upper (j=1).
+    // Note that the vast majority of edges are propagated to a single child.
+    // This case is very fast, consisting of between 2 and 4 floating-point
+    // comparisons and copying one pointer.  (ClipVAxis is inline.)
+    for (int e = 0; e < num_edges; ++e) {
+      const ClippedEdge* edge = (*edges)[e];
+      if (edge->bound[0].hi() <= middle[0].lo()) {
+        // Edge is entirely contained in the two left children.
+        ClipVAxis(edge, middle[1], child_edges[0], alloc);
+      } else if (edge->bound[0].lo() >= middle[0].hi()) {
+        // Edge is entirely contained in the two right children.
+        ClipVAxis(edge, middle[1], child_edges[1], alloc);
+      } else if (edge->bound[1].hi() <= middle[1].lo()) {
+        // Edge is entirely contained in the two lower children.
+        child_edges[0][0].push_back(ClipUBound(edge, 1, middle[0].hi(), alloc));
+        child_edges[1][0].push_back(ClipUBound(edge, 0, middle[0].lo(), alloc));
+      } else if (edge->bound[1].lo() >= middle[1].hi()) {
+        // Edge is entirely contained in the two upper children.
+        child_edges[0][1].push_back(ClipUBound(edge, 1, middle[0].hi(), alloc));
+        child_edges[1][1].push_back(ClipUBound(edge, 0, middle[0].lo(), alloc));
+      } else {
+        // The edge bound spans all four children.  The edge itself intersects
+        // either three or four (padded) children.
+        const ClippedEdge* left = ClipUBound(edge, 1, middle[0].hi(), alloc);
+        ClipVAxis(left, middle[1], child_edges[0], alloc);
+        const ClippedEdge* right = ClipUBound(edge, 0, middle[0].lo(), alloc);
+        ClipVAxis(right, middle[1], child_edges[1], alloc);
+      }
+    }
+    // Free any memory reserved for children that turned out to be empty.  This
+    // step is cheap and reduces peak memory usage by about 10% when building
+    // large indexes (> 10M edges).
+    for (int i = 0; i < 2; ++i) {
+      for (int j = 0; j < 2; ++j) {
+        if (child_edges[i][j].empty()) {
+          vector<const ClippedEdge*>().swap(child_edges[i][j]);
+        }
+      }
+    }
+    // Now recursively update the edges in each child.  We call the children in
+    // increasing order of S2CellId so that when the index is first constructed,
+    // all insertions into cell_map_ are at the end (which is much faster).
+    for (int pos = 0; pos < 4; ++pos) {
+      int i, j;
+      pcell.GetChildIJ(pos, &i, &j);
+      if (!child_edges[i][j].empty() || !tracker->shape_ids().empty()) {
+        UpdateEdges(S2PaddedCell(pcell, i, j), &child_edges[i][j],
+                    tracker, alloc, disjoint_from_index);
+      }
+    }
+    // Free any temporary edges that were allocated during clipping.
+    alloc->Reset(alloc_size);
+  }
+  if (index_cell_absorbed) {
+    // Restore the state for any edges being removed that we are tracking.
+    tracker->RestoreStateBefore(pending_additions_begin_);
+  }
+}
+
+// Given an edge and an interval "middle" along the v-axis, clip the edge
+// against the boundaries of "middle" and add the edge to the corresponding
+// children.
+/* static */
+inline void MutableS2ShapeIndex::ClipVAxis(
+    const ClippedEdge* edge,
+    const R1Interval& middle,
+    vector<const ClippedEdge*> child_edges[2],
+    EdgeAllocator* alloc) {
+  if (edge->bound[1].hi() <= middle.lo()) {
+    // Edge is entirely contained in the lower child.
+    child_edges[0].push_back(edge);
+  } else if (edge->bound[1].lo() >= middle.hi()) {
+    // Edge is entirely contained in the upper child.
+    child_edges[1].push_back(edge);
+  } else {
+    // The edge bound spans both children.
+    child_edges[0].push_back(ClipVBound(edge, 1, middle.hi(), alloc));
+    child_edges[1].push_back(ClipVBound(edge, 0, middle.lo(), alloc));
+  }
+}
+
+// Given an edge, clip the given endpoint (lo=0, hi=1) of the u-axis so that
+// it does not extend past the given value.
+/* static */
+const MutableS2ShapeIndex::ClippedEdge*
+MutableS2ShapeIndex::ClipUBound(const ClippedEdge* edge, int u_end, double u,
+                                EdgeAllocator* alloc) {
+  // First check whether the edge actually requires any clipping.  (Sometimes
+  // this method is called when clipping is not necessary, e.g. when one edge
+  // endpoint is in the overlap area between two padded child cells.)
+  if (u_end == 0) {
+    if (edge->bound[0].lo() >= u) return edge;
+  } else {
+    if (edge->bound[0].hi() <= u) return edge;
+  }
+  // We interpolate the new v-value from the endpoints of the original edge.
+  // This has two advantages: (1) we don't need to store the clipped endpoints
+  // at all, just their bounding box; and (2) it avoids the accumulation of
+  // roundoff errors due to repeated interpolations.  The result needs to be
+  // clamped to ensure that it is in the appropriate range.
+  const FaceEdge& e = *edge->face_edge;
+  double v = edge->bound[1].Project(
+      S2::InterpolateDouble(u, e.a[0], e.b[0], e.a[1], e.b[1]));
+
+  // Determine which endpoint of the v-axis bound to update.  If the edge
+  // slope is positive we update the same endpoint, otherwise we update the
+  // opposite endpoint.
+  int v_end = u_end ^ ((e.a[0] > e.b[0]) != (e.a[1] > e.b[1]));
+  return UpdateBound(edge, u_end, u, v_end, v, alloc);
+}
+
+// Given an edge, clip the given endpoint (lo=0, hi=1) of the v-axis so that
+// it does not extend past the given value.
+/* static */
+const MutableS2ShapeIndex::ClippedEdge*
+MutableS2ShapeIndex::ClipVBound(const ClippedEdge* edge, int v_end, double v,
+                                EdgeAllocator* alloc) {
+  // See comments in ClipUBound.
+  if (v_end == 0) {
+    if (edge->bound[1].lo() >= v) return edge;
+  } else {
+    if (edge->bound[1].hi() <= v) return edge;
+  }
+  const FaceEdge& e = *edge->face_edge;
+  double u = edge->bound[0].Project(
+      S2::InterpolateDouble(v, e.a[1], e.b[1], e.a[0], e.b[0]));
+  int u_end = v_end ^ ((e.a[0] > e.b[0]) != (e.a[1] > e.b[1]));
+  return UpdateBound(edge, u_end, u, v_end, v, alloc);
+}
+
+// Given an edge and two bound endpoints that need to be updated, allocate and
+// return a new edge with the updated bound.
+/* static */
+inline const MutableS2ShapeIndex::ClippedEdge*
+MutableS2ShapeIndex::UpdateBound(const ClippedEdge* edge, int u_end, double u,
+                                 int v_end, double v, EdgeAllocator* alloc) {
+  ClippedEdge* clipped = alloc->NewClippedEdge();
+  clipped->face_edge = edge->face_edge;
+  clipped->bound[0][u_end] = u;
+  clipped->bound[1][v_end] = v;
+  clipped->bound[0][1-u_end] = edge->bound[0][1-u_end];
+  clipped->bound[1][1-v_end] = edge->bound[1][1-v_end];
+  S2_DCHECK(!clipped->bound.is_empty());
+  S2_DCHECK(edge->bound.Contains(clipped->bound));
+  return clipped;
+}
+
+// Absorb an index cell by transferring its contents to "edges" and/or
+// "tracker", and then delete this cell from the index.  If "edges" includes
+// any edges that are being removed, this method also updates their
+// InteriorTracker state to correspond to the exit vertex of this cell, and
+// saves the InteriorTracker state by calling SaveAndClearStateBefore().  It
+// is the caller's responsibility to restore this state by calling
+// RestoreStateBefore() when processing of this cell is finished.
+void MutableS2ShapeIndex::AbsorbIndexCell(const S2PaddedCell& pcell,
+                                          const Iterator& iter,
+                                          vector<const ClippedEdge*>* edges,
+                                          InteriorTracker* tracker,
+                                          EdgeAllocator* alloc) {
+  S2_DCHECK_EQ(pcell.id(), iter.id());
+
+  // When we absorb a cell, we erase all the edges that are being removed.
+  // However when we are finished with this cell, we want to restore the state
+  // of those edges (since that is how we find all the index cells that need
+  // to be updated).  The edges themselves are restored automatically when
+  // UpdateEdges returns from its recursive call, but the InteriorTracker
+  // state needs to be restored explicitly.
+  //
+  // Here we first update the InteriorTracker state for removed edges to
+  // correspond to the exit vertex of this cell, and then save the
+  // InteriorTracker state.  This state will be restored by UpdateEdges when
+  // it is finished processing the contents of this cell.
+  if (tracker->is_active() && !edges->empty() &&
+      is_shape_being_removed((*edges)[0]->face_edge->shape_id)) {
+    // We probably need to update the InteriorTracker.  ("Probably" because
+    // it's possible that all shapes being removed do not have interiors.)
+    if (!tracker->at_cellid(pcell.id())) {
+      tracker->MoveTo(pcell.GetEntryVertex());
+    }
+    tracker->DrawTo(pcell.GetExitVertex());
+    tracker->set_next_cellid(pcell.id().next());
+    for (const ClippedEdge* edge : *edges) {
+      const FaceEdge* face_edge = edge->face_edge;
+      if (!is_shape_being_removed(face_edge->shape_id)) {
+        break;  // All shapes being removed come first.
+      }
+      if (face_edge->has_interior) {
+        tracker->TestEdge(face_edge->shape_id, face_edge->edge);
+      }
+    }
+  }
+  // Save the state of the edges being removed, so that it can be restored
+  // when we are finished processing this cell and its children.  We don't
+  // need to save the state of the edges being added because they aren't being
+  // removed from "edges" and will therefore be updated normally as we visit
+  // this cell and its children.
+  tracker->SaveAndClearStateBefore(pending_additions_begin_);
+
+  // Create a FaceEdge for each edge in this cell that isn't being removed.
+  vector<FaceEdge>* face_edges = alloc->mutable_face_edges();
+  face_edges->clear();
+  bool tracker_moved = false;
+  const S2ShapeIndexCell& cell = iter.cell();
+  for (int s = 0; s < cell.num_clipped(); ++s) {
+    const S2ClippedShape& clipped = cell.clipped(s);
+    int shape_id = clipped.shape_id();
+    const S2Shape* shape = this->shape(shape_id);
+    if (shape == nullptr) continue;  // This shape is being removed.
+    int num_edges = clipped.num_edges();
+
+    // If this shape has an interior, start tracking whether we are inside the
+    // shape.  UpdateEdges() wants to know whether the entry vertex of this
+    // cell is inside the shape, but we only know whether the center of the
+    // cell is inside the shape, so we need to test all the edges against the
+    // line segment from the cell center to the entry vertex.
+    FaceEdge edge;
+    edge.shape_id = shape->id();
+    edge.has_interior = (shape->dimension() == 2);
+    if (edge.has_interior) {
+      tracker->AddShape(shape_id, clipped.contains_center());
+      // There might not be any edges in this entire cell (i.e., it might be
+      // in the interior of all shapes), so we delay updating the tracker
+      // until we see the first edge.
+      if (!tracker_moved && num_edges > 0) {
+        tracker->MoveTo(pcell.GetCenter());
+        tracker->DrawTo(pcell.GetEntryVertex());
+        tracker->set_next_cellid(pcell.id());
+        tracker_moved = true;
+      }
+    }
+    for (int i = 0; i < num_edges; ++i) {
+      int e = clipped.edge(i);
+      edge.edge_id = e;
+      edge.edge = shape->edge(e);
+      edge.max_level = GetEdgeMaxLevel(edge.edge);
+      if (edge.has_interior) tracker->TestEdge(shape_id, edge.edge);
+      if (!S2::ClipToPaddedFace(edge.edge.v0, edge.edge.v1, pcell.id().face(),
+                                kCellPadding, &edge.a, &edge.b)) {
+        S2_LOG(DFATAL) << "Invariant failure in MutableS2ShapeIndex";
+      }
+      face_edges->push_back(edge);
+    }
+  }
+  // Now create a ClippedEdge for each FaceEdge, and put them in "new_edges".
+  vector<const ClippedEdge*> new_edges;
+  for (const FaceEdge& face_edge : *face_edges) {
+    ClippedEdge* clipped = alloc->NewClippedEdge();
+    clipped->face_edge = &face_edge;
+    clipped->bound = S2::GetClippedEdgeBound(face_edge.a, face_edge.b,
+                                                     pcell.bound());
+    new_edges.push_back(clipped);
+  }
+  // Discard any edges from "edges" that are being removed, and append the
+  // remainder to "new_edges".  (This keeps the edges sorted by shape id.)
+  for (int i = 0; i < edges->size(); ++i) {
+    const ClippedEdge* clipped = (*edges)[i];
+    if (!is_shape_being_removed(clipped->face_edge->shape_id)) {
+      new_edges.insert(new_edges.end(), edges->begin() + i, edges->end());
+      break;
+    }
+  }
+  // Update the edge list and delete this cell from the index.
+  edges->swap(new_edges);
+  cell_map_.erase(pcell.id());
+  delete &cell;
+}
+
+// Attempt to build an index cell containing the given edges, and return true
+// if successful.  (Otherwise the edges should be subdivided further.)
+bool MutableS2ShapeIndex::MakeIndexCell(const S2PaddedCell& pcell,
+                                        const vector<const ClippedEdge*>& edges,
+                                        InteriorTracker* tracker) {
+  if (edges.empty() && tracker->shape_ids().empty()) {
+    // No index cell is needed.  (In most cases this situation is detected
+    // before we get to this point, but this can happen when all shapes in a
+    // cell are removed.)
+    return true;
+  }
+
+  // Count the number of edges that have not reached their maximum level yet.
+  // Return false if there are too many such edges.
+  int count = 0;
+  for (const ClippedEdge* edge : edges) {
+    count += (pcell.level() < edge->face_edge->max_level);
+    if (count > options_.max_edges_per_cell())
+      return false;
+  }
+
+  // Possible optimization: Continue subdividing as long as exactly one child
+  // of "pcell" intersects the given edges.  This can be done by finding the
+  // bounding box of all the edges and calling ShrinkToFit():
+  //
+  // S2CellId cellid = pcell.ShrinkToFit(GetRectBound(edges));
+  //
+  // Currently this is not beneficial; it slows down construction by 4-25%
+  // (mainly computing the union of the bounding rectangles) and also slows
+  // down queries (since more recursive clipping is required to get down to
+  // the level of a spatial index cell).  But it may be worth trying again
+  // once "contains_center" is computed and all algorithms are modified to
+  // take advantage of it.
+
+  // We update the InteriorTracker as follows.  For every S2Cell in the index
+  // we construct two edges: one edge from entry vertex of the cell to its
+  // center, and one from the cell center to its exit vertex.  Here "entry"
+  // and "exit" refer the S2CellId ordering, i.e. the order in which points
+  // are encountered along the S2 space-filling curve.  The exit vertex then
+  // becomes the entry vertex for the next cell in the index, unless there are
+  // one or more empty intervening cells, in which case the InteriorTracker
+  // state is unchanged because the intervening cells have no edges.
+
+  // Shift the InteriorTracker focus point to the center of the current cell.
+  if (tracker->is_active() && !edges.empty()) {
+    if (!tracker->at_cellid(pcell.id())) {
+      tracker->MoveTo(pcell.GetEntryVertex());
+    }
+    tracker->DrawTo(pcell.GetCenter());
+    TestAllEdges(edges, tracker);
+  }
+  // Allocate and fill a new index cell.  To get the total number of shapes we
+  // need to merge the shapes associated with the intersecting edges together
+  // with the shapes that happen to contain the cell center.
+  const ShapeIdSet& cshape_ids = tracker->shape_ids();
+  int num_shapes = CountShapes(edges, cshape_ids);
+  S2ShapeIndexCell* cell = new S2ShapeIndexCell;
+  S2ClippedShape* base = cell->add_shapes(num_shapes);
+
+  // To fill the index cell we merge the two sources of shapes: "edge shapes"
+  // (those that have at least one edge that intersects this cell), and
+  // "containing shapes" (those that contain the cell center).  We keep track
+  // of the index of the next intersecting edge and the next containing shape
+  // as we go along.  Both sets of shape ids are already sorted.
+  int enext = 0;
+  ShapeIdSet::const_iterator cnext = cshape_ids.begin();
+  for (int i = 0; i < num_shapes; ++i) {
+    S2ClippedShape* clipped = base + i;
+    int eshape_id = num_shape_ids(), cshape_id = eshape_id;  // Sentinels
+    if (enext != edges.size()) {
+      eshape_id = edges[enext]->face_edge->shape_id;
+    }
+    if (cnext != cshape_ids.end()) {
+      cshape_id = *cnext;
+    }
+    int ebegin = enext;
+    if (cshape_id < eshape_id) {
+      // The entire cell is in the shape interior.
+      clipped->Init(cshape_id, 0);
+      clipped->set_contains_center(true);
+      ++cnext;
+    } else {
+      // Count the number of edges for this shape and allocate space for them.
+      while (enext < edges.size() &&
+             edges[enext]->face_edge->shape_id == eshape_id) {
+        ++enext;
+      }
+      clipped->Init(eshape_id, enext - ebegin);
+      for (int e = ebegin; e < enext; ++e) {
+        clipped->set_edge(e - ebegin, edges[e]->face_edge->edge_id);
+      }
+      if (cshape_id == eshape_id) {
+        clipped->set_contains_center(true);
+        ++cnext;
+      }
+    }
+  }
+  // UpdateEdges() visits cells in increasing order of S2CellId, so during
+  // initial construction of the index all insertions happen at the end.  It
+  // is much faster to give an insertion hint in this case.  Otherwise the
+  // hint doesn't do much harm.  With more effort we could provide a hint even
+  // during incremental updates, but this is probably not worth the effort.
+  cell_map_.insert(cell_map_.end(), std::make_pair(pcell.id(), cell));
+
+  // Shift the InteriorTracker focus point to the exit vertex of this cell.
+  if (tracker->is_active() && !edges.empty()) {
+    tracker->DrawTo(pcell.GetExitVertex());
+    TestAllEdges(edges, tracker);
+    tracker->set_next_cellid(pcell.id().next());
+  }
+  return true;
+}
+
+// Call tracker->TestEdge() on all edges from shapes that have interiors.
+/* static */
+void MutableS2ShapeIndex::TestAllEdges(const vector<const ClippedEdge*>& edges,
+                                       InteriorTracker* tracker) {
+  for (const ClippedEdge* edge : edges) {
+    const FaceEdge* face_edge = edge->face_edge;
+    if (face_edge->has_interior) {
+      tracker->TestEdge(face_edge->shape_id, face_edge->edge);
+    }
+  }
+}
+
+// Return the number of distinct shapes that are either associated with the
+// given edges, or that are currently stored in the InteriorTracker.
+/* static */
+int MutableS2ShapeIndex::CountShapes(const vector<const ClippedEdge*>& edges,
+                                     const ShapeIdSet& cshape_ids) {
+  int count = 0;
+  int last_shape_id = -1;
+  ShapeIdSet::const_iterator cnext = cshape_ids.begin();  // Next shape
+  for (const ClippedEdge* edge : edges) {
+    if (edge->face_edge->shape_id != last_shape_id) {
+      ++count;
+      last_shape_id = edge->face_edge->shape_id;
+      // Skip over any containing shapes up to and including this one,
+      // updating "count" appropriately.
+      for (; cnext != cshape_ids.end(); ++cnext) {
+        if (*cnext > last_shape_id) break;
+        if (*cnext < last_shape_id) ++count;
+      }
+    }
+  }
+  // Count any remaining containing shapes.
+  count += (cshape_ids.end() - cnext);
+  return count;
+}
+
+size_t MutableS2ShapeIndex::SpaceUsed() const {
+  size_t size = sizeof(*this);
+  size += shapes_.capacity() * sizeof(std::unique_ptr<S2Shape>);
+  // cell_map_ itself is already included in sizeof(*this).
+  size += cell_map_.bytes_used() - sizeof(cell_map_);
+  size += cell_map_.size() * sizeof(S2ShapeIndexCell);
+  Iterator it;
+  for (it.InitStale(this, S2ShapeIndex::BEGIN); !it.done(); it.Next()) {
+    const S2ShapeIndexCell& cell = it.cell();
+    size += cell.shapes_.capacity() * sizeof(S2ClippedShape);
+    for (int s = 0; s < cell.num_clipped(); ++s) {
+      const S2ClippedShape& clipped = cell.clipped(s);
+      if (!clipped.is_inline()) {
+        size += clipped.num_edges() * sizeof(int32);
+      }
+    }
+  }
+  if (pending_removals_ != nullptr) {
+    size += pending_removals_->capacity() * sizeof(RemovedShape);
+  }
+
+  return size;
+}
+
+void MutableS2ShapeIndex::Encode(Encoder* encoder) const {
+  // The version number is encoded in 2 bits, under the assumption that by the
+  // time we need 5 versions the first version can be permanently retired.
+  // This only saves 1 byte, but that's significant for very small indexes.
+  encoder->Ensure(Varint::kMax64);
+  uint64 max_edges = options_.max_edges_per_cell();
+  encoder->put_varint64(max_edges << 2 | kCurrentEncodingVersionNumber);
+
+  vector<S2CellId> cell_ids;
+  cell_ids.reserve(cell_map_.size());
+  s2coding::StringVectorEncoder encoded_cells;
+  for (Iterator it(this, S2ShapeIndex::BEGIN); !it.done(); it.Next()) {
+    cell_ids.push_back(it.id());
+    it.cell().Encode(num_shape_ids(), encoded_cells.AddViaEncoder());
+  }
+  s2coding::EncodeS2CellIdVector(cell_ids, encoder);
+  encoded_cells.Encode(encoder);
+}
+
+bool MutableS2ShapeIndex::Init(Decoder* decoder,
+                               const ShapeFactory& shape_factory) {
+  Clear();
+  uint64 max_edges_version;
+  if (!decoder->get_varint64(&max_edges_version)) return false;
+  int version = max_edges_version & 3;
+  if (version != kCurrentEncodingVersionNumber) return false;
+  options_.set_max_edges_per_cell(max_edges_version >> 2);
+  uint32 num_shapes = shape_factory.size();
+  shapes_.reserve(num_shapes);
+  for (int shape_id = 0; shape_id < num_shapes; ++shape_id) {
+    auto shape = shape_factory[shape_id];
+    if (shape) shape->id_ = shape_id;
+    shapes_.push_back(std::move(shape));
+  }
+
+  s2coding::EncodedS2CellIdVector cell_ids;
+  s2coding::EncodedStringVector encoded_cells;
+  if (!cell_ids.Init(decoder)) return false;
+  if (!encoded_cells.Init(decoder)) return false;
+
+  for (int i = 0; i < cell_ids.size(); ++i) {
+    S2CellId id = cell_ids[i];
+    S2ShapeIndexCell* cell = new S2ShapeIndexCell;
+    Decoder decoder = encoded_cells.GetDecoder(i);
+    if (!cell->Decode(num_shapes, &decoder)) return false;
+    cell_map_.insert(cell_map_.end(), std::make_pair(id, cell));
+  }
+  return true;
+}
diff --git a/src/s2/mutable_s2shape_index.h b/src/s2/mutable_s2shape_index.h
new file mode 100644 (file)
index 0000000..2585e8f
--- /dev/null
@@ -0,0 +1,609 @@
+// Copyright 2012 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// Author: ericv@google.com (Eric Veach)
+
+#ifndef S2_MUTABLE_S2SHAPE_INDEX_H_
+#define S2_MUTABLE_S2SHAPE_INDEX_H_
+
+#include <array>
+#include <atomic>
+#include <cstddef>
+#include <memory>
+#include <utility>
+#include <vector>
+
+
+#include "s2/base/integral_types.h"
+#include "s2/base/logging.h"
+#include "s2/base/mutex.h"
+#include "s2/base/spinlock.h"
+#include "s2/_fp_contract_off.h"
+#include "s2/s2cell_id.h"
+#include "s2/s2pointutil.h"
+#include "s2/s2shape.h"
+#include "s2/s2shape_index.h"
+#include "absl/base/macros.h"
+#include "absl/base/thread_annotations.h"
+#include "absl/memory/memory.h"
+#include "absl/container/btree_map.h"
+
+namespace s2internal {
+// Hack to expose bytes_used.
+template <typename Key, typename Value>
+class BTreeMap : public absl::btree_map<Key, Value> {
+public:
+  size_t bytes_used() const { return this->tree_.bytes_used(); }
+};
+}  // namespace s2internal
+
+// MutableS2ShapeIndex is a class for in-memory indexing of polygonal geometry.
+// The objects in the index are known as "shapes", and may consist of points,
+// polylines, and/or polygons, possibly overlapping.  The index makes it very
+// fast to answer queries such as finding nearby shapes, measuring distances,
+// testing for intersection and containment, etc.
+//
+// MutableS2ShapeIndex allows not only building an index, but also updating it
+// incrementally by adding or removing shapes (hence its name).  It is one of
+// several implementations of the S2ShapeIndex interface.  MutableS2ShapeIndex
+// is designed to be compact; usually it is smaller than the underlying
+// geometry being indexed.  It is capable of indexing up to hundreds of
+// millions of edges.  The index is also fast to construct.
+//
+// There are a number of built-in classes that work with S2ShapeIndex objects.
+// Generally these classes accept any collection of geometry that can be
+// represented by an S2ShapeIndex, i.e. any combination of points, polylines,
+// and polygons.  Such classes include:
+//
+// - S2ContainsPointQuery: returns the shape(s) that contain a given point.
+//
+// - S2ClosestEdgeQuery: returns the closest edge(s) to a given point, edge,
+//                       S2CellId, or S2ShapeIndex.
+//
+// - S2CrossingEdgeQuery: returns the edge(s) that cross a given edge.
+//
+// - S2BooleanOperation: computes boolean operations such as union,
+//                       and boolean predicates such as containment.
+//
+// - S2ShapeIndexRegion: computes approximations for a collection of geometry.
+//
+// - S2ShapeIndexBufferedRegion: computes approximations that have been
+//                               expanded by a given radius.
+//
+// Here is an example showing how to build an index for a set of polygons, and
+// then then determine which polygon(s) contain each of a set of query points:
+//
+//   void TestContainment(const vector<S2Point>& points,
+//                        const vector<S2Polygon*>& polygons) {
+//     MutableS2ShapeIndex index;
+//     for (auto polygon : polygons) {
+//       index.Add(absl::make_unique<S2Polygon::Shape>(polygon));
+//     }
+//     auto query = MakeS2ContainsPointQuery(&index);
+//     for (const auto& point : points) {
+//       for (S2Shape* shape : query.GetContainingShapes(point)) {
+//         S2Polygon* polygon = polygons[shape->id()];
+//         ... do something with (point, polygon) ...
+//       }
+//     }
+//   }
+//
+// This example uses S2Polygon::Shape, which is one example of an S2Shape
+// object.  S2Polyline and S2Loop also have nested Shape classes, and there are
+// additional S2Shape types defined in *_shape.h.
+//
+// Internally, MutableS2ShapeIndex is essentially a map from S2CellIds to the
+// set of shapes that intersect each S2CellId.  It is adaptively refined to
+// ensure that no cell contains more than a small number of edges.
+//
+// For efficiency, updates are batched together and applied lazily on the
+// first subsequent query.  Locking is used to ensure that MutableS2ShapeIndex
+// has the same thread-safety properties as "vector": const methods are
+// thread-safe, while non-const methods are not thread-safe.  This means that
+// if one thread updates the index, you must ensure that no other thread is
+// reading or updating the index at the same time.
+//
+// TODO(ericv): MutableS2ShapeIndex has an Encode() method that allows the
+// index to be serialized.  An encoded S2ShapeIndex can be decoded either into
+// its original form (MutableS2ShapeIndex) or into an EncodedS2ShapeIndex.
+// The key property of EncodedS2ShapeIndex is that it can be constructed
+// instantaneously, since the index is kept in its original encoded form.
+// Data is decoded only when an operation needs it.  For example, to determine
+// which shapes(s) contain a given query point only requires decoding the data
+// in the S2ShapeIndexCell that contains that point.
+class MutableS2ShapeIndex final : public S2ShapeIndex {
+ private:
+  using CellMap = s2internal::BTreeMap<S2CellId, S2ShapeIndexCell*>;
+
+ public:
+  // Options that affect construction of the MutableS2ShapeIndex.
+  class Options {
+   public:
+    Options();
+
+    // The maximum number of edges per cell.  If a cell has more than this
+    // many edges that are not considered "long" relative to the cell size,
+    // then it is subdivided.  (Whether an edge is considered "long" is
+    // controlled by --s2shape_index_cell_size_to_long_edge_ratio flag.)
+    //
+    // Values between 10 and 50 represent a reasonable balance between memory
+    // usage, construction time, and query time.  Small values make queries
+    // faster, while large values make construction faster and use less memory.
+    // Values higher than 50 do not save significant additional memory, and
+    // query times can increase substantially, especially for algorithms that
+    // visit all pairs of potentially intersecting edges (such as polygon
+    // validation), since this is quadratic in the number of edges per cell.
+    //
+    // Note that the *average* number of edges per cell is generally slightly
+    // less than half of the maximum value defined here.
+    //
+    // Defaults to value given by --s2shape_index_default_max_edges_per_cell.
+    int max_edges_per_cell() const { return max_edges_per_cell_; }
+    void set_max_edges_per_cell(int max_edges_per_cell);
+
+   private:
+    int max_edges_per_cell_;
+  };
+
+  // Creates a MutableS2ShapeIndex that uses the default option settings.
+  // Option values may be changed by calling Init().
+  MutableS2ShapeIndex();
+
+  // Create a MutableS2ShapeIndex with the given options.
+  explicit MutableS2ShapeIndex(const Options& options);
+
+  ~MutableS2ShapeIndex() override;
+
+  // Initialize a MutableS2ShapeIndex with the given options.  This method may
+  // only be called when the index is empty (i.e. newly created or Reset() has
+  // just been called).
+  void Init(const Options& options);
+
+  const Options& options() const { return options_; }
+
+  // The number of distinct shape ids that have been assigned.  This equals
+  // the number of shapes in the index provided that no shapes have ever been
+  // removed.  (Shape ids are not reused.)
+  int num_shape_ids() const override {
+    return static_cast<int>(shapes_.size());
+  }
+
+  // Returns a pointer to the shape with the given id, or nullptr if the shape
+  // has been removed from the index.
+  S2Shape* shape(int id) const override { return shapes_[id].get(); }
+
+  // Minimizes memory usage by requesting that any data structures that can be
+  // rebuilt should be discarded.  This method invalidates all iterators.
+  //
+  // Like all non-const methods, this method is not thread-safe.
+  void Minimize() override;
+
+  // Appends an encoded representation of the S2ShapeIndex to "encoder".
+  //
+  // This method does not encode the S2Shapes in the index; it is the client's
+  // responsibility to encode them separately.  For example:
+  //
+  //   s2shapeutil::CompactEncodeTaggedShapes(index, encoder);
+  //   index.Encode(encoder);
+  //
+  // REQUIRES: "encoder" uses the default constructor, so that its buffer
+  //           can be enlarged as necessary by calling Ensure(int).
+  void Encode(Encoder* encoder) const;
+
+  // Decodes an S2ShapeIndex, returning true on success.
+  //
+  // This method does not decode the S2Shape objects in the index; this is
+  // the responsibility of the client-provided function "shape_factory"
+  // (see s2shapeutil_coding.h).  Example usage:
+  //
+  //   index.Init(decoder, s2shapeutil::LazyDecodeShapeFactory(decoder));
+  //
+  // Note that the S2Shape vector must be encoded *before* the S2ShapeIndex in
+  // this example.
+  bool Init(Decoder* decoder, const ShapeFactory& shape_factory);
+
+  class Iterator final : public IteratorBase {
+   public:
+    // Default constructor; must be followed by a call to Init().
+    Iterator();
+
+    // Constructs an iterator positioned as specified.  By default iterators
+    // are unpositioned, since this avoids an extra seek in this situation
+    // where one of the seek methods (such as Locate) is immediately called.
+    //
+    // If you want to position the iterator at the beginning, e.g. in order to
+    // loop through the entire index, do this instead:
+    //
+    //   for (MutableS2ShapeIndex::Iterator it(&index, S2ShapeIndex::BEGIN);
+    //        !it.done(); it.Next()) { ... }
+    explicit Iterator(const MutableS2ShapeIndex* index,
+                      InitialPosition pos = UNPOSITIONED);
+
+    // Initializes an iterator for the given MutableS2ShapeIndex.  This method
+    // may also be called in order to restore an iterator to a valid state
+    // after the underlying index has been updated (although it is usually
+    // easier just to declare a new iterator whenever required, since iterator
+    // construction is cheap).
+    void Init(const MutableS2ShapeIndex* index,
+              InitialPosition pos = UNPOSITIONED);
+
+    // Initialize an iterator for the given MutableS2ShapeIndex without
+    // applying any pending updates.  This can be used to observe the actual
+    // current state of the index without modifying it in any way.
+    void InitStale(const MutableS2ShapeIndex* index,
+                   InitialPosition pos = UNPOSITIONED);
+
+    // Inherited non-virtual methods:
+    //   S2CellId id() const;
+    //   bool done() const;
+    //   S2Point center() const;
+    const S2ShapeIndexCell& cell() const;
+
+    // IteratorBase API:
+    void Begin() override;
+    void Finish() override;
+    void Next() override;
+    bool Prev() override;
+    void Seek(S2CellId target) override;
+    bool Locate(const S2Point& target) override;
+    CellRelation Locate(S2CellId target) override;
+
+   protected:
+    const S2ShapeIndexCell* GetCell() const override;
+    std::unique_ptr<IteratorBase> Clone() const override;
+    void Copy(const IteratorBase& other) override;
+
+   private:
+    void Refresh();  // Updates the IteratorBase fields.
+    const MutableS2ShapeIndex* index_;
+    CellMap::const_iterator iter_, end_;
+  };
+
+  // Takes ownership of the given shape and adds it to the index.  Also
+  // assigns a unique id to the shape (shape->id()) and returns that id.
+  // Shape ids are assigned sequentially starting from 0 in the order shapes
+  // are added.  Invalidates all iterators and their associated data.
+  int Add(std::unique_ptr<S2Shape> shape);
+
+  // Removes the given shape from the index and return ownership to the caller.
+  // Invalidates all iterators and their associated data.
+  std::unique_ptr<S2Shape> Release(int shape_id);
+
+  // Resets the index to its original state and returns ownership of all
+  // shapes to the caller.  This method is much more efficient than removing
+  // all shapes one at a time.
+  std::vector<std::unique_ptr<S2Shape>> ReleaseAll();
+
+  // Resets the index to its original state and deletes all shapes.  Any
+  // options specified via Init() are preserved.
+  void Clear();
+
+  // Returns the number of bytes currently occupied by the index (including any
+  // unused space at the end of vectors, etc). It has the same thread safety
+  // as the other "const" methods (see introduction).
+  size_t SpaceUsed() const override;
+
+  // Calls to Add() and Release() are normally queued and processed on the
+  // first subsequent query (in a thread-safe way).  This has many advantages,
+  // the most important of which is that sometimes there *is* no subsequent
+  // query, which lets us avoid building the index completely.
+  //
+  // This method forces any pending updates to be applied immediately.
+  // Calling this method is rarely a good idea.  (One valid reason is to
+  // exclude the cost of building the index from benchmark results.)
+  void ForceBuild();
+
+  // Returns true if there are no pending updates that need to be applied.
+  // This can be useful to avoid building the index unnecessarily, or for
+  // choosing between two different algorithms depending on whether the index
+  // is available.
+  //
+  // The returned index status may be slightly out of date if the index was
+  // built in a different thread.  This is fine for the intended use (as an
+  // efficiency hint), but it should not be used by internal methods  (see
+  // MaybeApplyUpdates).
+  bool is_fresh() const;
+
+ protected:
+  std::unique_ptr<IteratorBase> NewIterator(InitialPosition pos) const override;
+
+ private:
+  friend class EncodedS2ShapeIndex;
+  friend class Iterator;
+  friend class MutableS2ShapeIndexTest;
+  friend class S2Stats;
+
+  struct BatchDescriptor;
+  struct ClippedEdge;
+  class EdgeAllocator;
+  struct FaceEdge;
+  class InteriorTracker;
+  struct RemovedShape;
+
+  using ShapeIdSet = std::vector<int>;
+
+  // When adding a new encoding, be aware that old binaries will not be able
+  // to decode it.
+  static const unsigned char kCurrentEncodingVersionNumber = 0;
+
+  // Internal methods are documented with their definitions.
+  bool is_first_update() const;
+  bool is_shape_being_removed(int shape_id) const;
+  void MaybeApplyUpdates() const;
+  void ApplyUpdatesThreadSafe();
+  void ApplyUpdatesInternal();
+  void GetUpdateBatches(std::vector<BatchDescriptor>* batches) const;
+  static void GetBatchSizes(int num_items, int max_batches,
+                            double final_bytes_per_item,
+                            double high_water_bytes_per_item,
+                            double preferred_max_bytes_per_batch,
+                            std::vector<int>* batch_sizes);
+  void ReserveSpace(const BatchDescriptor& batch,
+                    std::vector<FaceEdge> all_edges[6]) const;
+  void AddShape(int id, std::vector<FaceEdge> all_edges[6],
+                InteriorTracker* tracker) const;
+  void RemoveShape(const RemovedShape& removed,
+                   std::vector<FaceEdge> all_edges[6],
+                   InteriorTracker* tracker) const;
+  void AddFaceEdge(FaceEdge* edge, std::vector<FaceEdge> all_edges[6]) const;
+  void UpdateFaceEdges(int face, const std::vector<FaceEdge>& face_edges,
+                       InteriorTracker* tracker);
+  S2CellId ShrinkToFit(const S2PaddedCell& pcell, const R2Rect& bound) const;
+  void SkipCellRange(S2CellId begin, S2CellId end, InteriorTracker* tracker,
+                     EdgeAllocator* alloc, bool disjoint_from_index);
+  void UpdateEdges(const S2PaddedCell& pcell,
+                   std::vector<const ClippedEdge*>* edges,
+                   InteriorTracker* tracker, EdgeAllocator* alloc,
+                   bool disjoint_from_index);
+  void AbsorbIndexCell(const S2PaddedCell& pcell,
+                       const Iterator& iter,
+                       std::vector<const ClippedEdge*>* edges,
+                       InteriorTracker* tracker,
+                       EdgeAllocator* alloc);
+  int GetEdgeMaxLevel(const S2Shape::Edge& edge) const;
+  static int CountShapes(const std::vector<const ClippedEdge*>& edges,
+                         const ShapeIdSet& cshape_ids);
+  bool MakeIndexCell(const S2PaddedCell& pcell,
+                     const std::vector<const ClippedEdge*>& edges,
+                     InteriorTracker* tracker);
+  static void TestAllEdges(const std::vector<const ClippedEdge*>& edges,
+                           InteriorTracker* tracker);
+  inline static const ClippedEdge* UpdateBound(const ClippedEdge* edge,
+                                               int u_end, double u,
+                                               int v_end, double v,
+                                               EdgeAllocator* alloc);
+  static const ClippedEdge* ClipUBound(const ClippedEdge* edge,
+                                       int u_end, double u,
+                                       EdgeAllocator* alloc);
+  static const ClippedEdge* ClipVBound(const ClippedEdge* edge,
+                                       int v_end, double v,
+                                       EdgeAllocator* alloc);
+  static void ClipVAxis(const ClippedEdge* edge, const R1Interval& middle,
+                        std::vector<const ClippedEdge*> child_edges[2],
+                        EdgeAllocator* alloc);
+
+  // The amount by which cells are "padded" to compensate for numerical errors
+  // when clipping line segments to cell boundaries.
+  static const double kCellPadding;
+
+  // The shapes in the index, accessed by their shape id.  Removed shapes are
+  // replaced by nullptr pointers.
+  std::vector<std::unique_ptr<S2Shape>> shapes_;
+
+  // A map from S2CellId to the set of clipped shapes that intersect that
+  // cell.  The cell ids cover a set of non-overlapping regions on the
+  // sphere.  Note that this field is updated lazily (see below).  Const
+  // methods *must* call MaybeApplyUpdates() before accessing this field.
+  // (The easiest way to achieve this is simply to use an Iterator.)
+  CellMap cell_map_;
+
+  // The options supplied for this index.
+  Options options_;
+
+  // The id of the first shape that has been queued for addition but not
+  // processed yet.
+  int pending_additions_begin_ = 0;
+
+  // The representation of an edge that has been queued for removal.
+  struct RemovedShape {
+    int32 shape_id;
+    bool has_interior;  // Belongs to a shape of dimension 2.
+    bool contains_tracker_origin;
+    std::vector<S2Shape::Edge> edges;
+  };
+
+  // The set of shapes that have been queued for removal but not processed
+  // yet.  Note that we need to copy the edge data since the caller is free to
+  // destroy the shape once Release() has been called.  This field is present
+  // only when there are removed shapes to process (to save memory).
+  std::unique_ptr<std::vector<RemovedShape>> pending_removals_;
+
+  // Additions and removals are queued and processed on the first subsequent
+  // query.  There are several reasons to do this:
+  //
+  //  - It is significantly more efficient to process updates in batches.
+  //  - Often the index will never be queried, in which case we can save both
+  //    the time and memory required to build it.  Examples:
+  //     + S2Loops that are created simply to pass to an S2Polygon.  (We don't
+  //       need the S2Loop index, because S2Polygon builds its own index.)
+  //     + Applications that load a database of geometry and then query only
+  //       a small fraction of it.
+  //     + Applications that only read and write geometry (Decode/Encode).
+  //
+  // The main drawback is that we need to go to some extra work to ensure that
+  // "const" methods are still thread-safe.  Note that the goal is *not* to
+  // make this class thread-safe in general, but simply to hide the fact that
+  // we defer some of the indexing work until query time.
+  //
+  // The textbook approach to this problem would be to use a mutex and a
+  // condition variable.  Unfortunately pthread mutexes are huge (40 bytes).
+  // Instead we use spinlock (which is only 4 bytes) to guard a few small
+  // fields representing the current update status, and only create additional
+  // state while the update is actually occurring.
+  mutable SpinLock lock_;
+
+  enum IndexStatus {
+    STALE,     // There are pending updates.
+    UPDATING,  // Updates are currently being applied.
+    FRESH,     // There are no pending updates.
+  };
+  // Reads and writes to this field are guarded by "lock_".
+  std::atomic<IndexStatus> index_status_;
+
+  // UpdateState holds temporary data related to thread synchronization.  It
+  // is only allocated while updates are being applied.
+  struct UpdateState {
+    // This mutex is used as a condition variable.  It is locked by the
+    // updating thread for the entire duration of the update; other threads
+    // lock it in order to wait until the update is finished.
+    absl::Mutex wait_mutex;
+
+    // The number of threads currently waiting on "wait_mutex_".  The
+    // UpdateState can only be freed when this number reaches zero.
+    //
+    // Reads and writes to this field are guarded by "lock_".
+    int num_waiting;
+
+    UpdateState() : num_waiting(0) {
+    }
+
+    ~UpdateState() {
+      S2_DCHECK_EQ(0, num_waiting);
+    }
+  };
+  std::unique_ptr<UpdateState> update_state_;
+
+  // Documented in the .cc file.
+  void UnlockAndSignal()
+      UNLOCK_FUNCTION(lock_)
+      UNLOCK_FUNCTION(update_state_->wait_mutex);
+
+  MutableS2ShapeIndex(const MutableS2ShapeIndex&) = delete;
+  void operator=(const MutableS2ShapeIndex&) = delete;
+};
+
+
+//////////////////   Implementation details follow   ////////////////////
+
+
+inline MutableS2ShapeIndex::Iterator::Iterator() : index_(nullptr) {
+}
+
+inline MutableS2ShapeIndex::Iterator::Iterator(
+    const MutableS2ShapeIndex* index, InitialPosition pos) {
+  Init(index, pos);
+}
+
+inline void MutableS2ShapeIndex::Iterator::Init(
+    const MutableS2ShapeIndex* index, InitialPosition pos) {
+  index->MaybeApplyUpdates();
+  InitStale(index, pos);
+}
+
+inline void MutableS2ShapeIndex::Iterator::InitStale(
+    const MutableS2ShapeIndex* index, InitialPosition pos) {
+  index_ = index;
+  end_ = index_->cell_map_.end();
+  if (pos == BEGIN) {
+    iter_ = index_->cell_map_.begin();
+  } else {
+    iter_ = end_;
+  }
+  Refresh();
+}
+
+inline const S2ShapeIndexCell& MutableS2ShapeIndex::Iterator::cell() const {
+  // Since MutableS2ShapeIndex always sets the "cell_" field, we can skip the
+  // logic in the base class that conditionally calls GetCell().
+  return *raw_cell();
+}
+
+inline void MutableS2ShapeIndex::Iterator::Refresh() {
+  if (iter_ == end_) {
+    set_finished();
+  } else {
+    set_state(iter_->first, iter_->second);
+  }
+}
+
+inline void MutableS2ShapeIndex::Iterator::Begin() {
+  // Make sure that the index has not been modified since Init() was called.
+  S2_DCHECK(index_->is_fresh());
+  iter_ = index_->cell_map_.begin();
+  Refresh();
+}
+
+inline void MutableS2ShapeIndex::Iterator::Finish() {
+  iter_ = end_;
+  Refresh();
+}
+
+inline void MutableS2ShapeIndex::Iterator::Next() {
+  S2_DCHECK(!done());
+  ++iter_;
+  Refresh();
+}
+
+inline bool MutableS2ShapeIndex::Iterator::Prev() {
+  if (iter_ == index_->cell_map_.begin()) return false;
+  --iter_;
+  Refresh();
+  return true;
+}
+
+inline void MutableS2ShapeIndex::Iterator::Seek(S2CellId target) {
+  iter_ = index_->cell_map_.lower_bound(target);
+  Refresh();
+}
+
+inline std::unique_ptr<MutableS2ShapeIndex::IteratorBase>
+MutableS2ShapeIndex::NewIterator(InitialPosition pos) const {
+  return absl::make_unique<Iterator>(this, pos);
+}
+
+inline bool MutableS2ShapeIndex::is_fresh() const {
+  return index_status_.load(std::memory_order_relaxed) == FRESH;
+}
+
+// Return true if this is the first update to the index.
+inline bool MutableS2ShapeIndex::is_first_update() const {
+  // Note that it is not sufficient to check whether cell_map_ is empty, since
+  // entries are added during the update process.
+  return pending_additions_begin_ == 0;
+}
+
+// Given that the given shape is being updated, return true if it is being
+// removed (as opposed to being added).
+inline bool MutableS2ShapeIndex::is_shape_being_removed(int shape_id) const {
+  // All shape ids being removed are less than all shape ids being added.
+  return shape_id < pending_additions_begin_;
+}
+
+// Ensure that any pending updates have been applied.  This method must be
+// called before accessing the cell_map_ field, even if the index_status_
+// appears to be FRESH, because a memory barrier is required in order to
+// ensure that all the index updates are visible if the updates were done in
+// another thread.
+inline void MutableS2ShapeIndex::MaybeApplyUpdates() const {
+  // To avoid acquiring and releasing the spinlock on every query, we use
+  // atomic operations when testing whether the status is FRESH and when
+  // updating the status to be FRESH.  This guarantees that any thread that
+  // sees a status of FRESH will also see the corresponding index updates.
+  if (index_status_.load(std::memory_order_acquire) != FRESH) {
+    const_cast<MutableS2ShapeIndex*>(this)->ApplyUpdatesThreadSafe();
+  }
+}
+
+#endif  // S2_MUTABLE_S2SHAPE_INDEX_H_
diff --git a/src/s2/r1interval.h b/src/s2/r1interval.h
new file mode 100644 (file)
index 0000000..f120803
--- /dev/null
@@ -0,0 +1,220 @@
+// Copyright 2005 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// Author: ericv@google.com (Eric Veach)
+
+#ifndef S2_R1INTERVAL_H_
+#define S2_R1INTERVAL_H_
+
+#include <algorithm>
+#include <cmath>
+#include <iosfwd>
+#include <iostream>
+
+#include "s2/base/logging.h"
+#include "s2/_fp_contract_off.h"
+#include "s2/util/math/vector.h"  // IWYU pragma: export
+
+// An R1Interval represents a closed, bounded interval on the real line.
+// It is capable of representing the empty interval (containing no points)
+// and zero-length intervals (containing a single point).
+//
+// This class is intended to be copied by value as desired.  It uses
+// the default copy constructor and assignment operator.
+class R1Interval {
+ public:
+  // Constructor.  If lo > hi, the interval is empty.
+  R1Interval(double lo, double hi) : bounds_(lo, hi) {}
+
+  // The default constructor creates an empty interval.  (Any interval where
+  // lo > hi is considered to be empty.)
+  //
+  // Note: Don't construct an interval using the default constructor and
+  // set_lo()/set_hi(), since this technique doesn't work with S1Interval and
+  // is bad programming style anyways.  If you need to set both endpoints, use
+  // the constructor above:
+  //
+  //   lat_bounds_ = R1Interval(lat_lo, lat_hi);
+  R1Interval() : bounds_(1, 0) {}
+
+  // Returns an empty interval.
+  static R1Interval Empty() { return R1Interval(); }
+
+  // Convenience method to construct an interval containing a single point.
+  static R1Interval FromPoint(double p) { return R1Interval(p, p); }
+
+  // Convenience method to construct the minimal interval containing
+  // the two given points.  This is equivalent to starting with an empty
+  // interval and calling AddPoint() twice, but it is more efficient.
+  static R1Interval FromPointPair(double p1, double p2) {
+    if (p1 <= p2) {
+      return R1Interval(p1, p2);
+    } else {
+      return R1Interval(p2, p1);
+    }
+  }
+
+  // Accessors methods.
+  double lo() const { return bounds_[0]; }
+  double hi() const { return bounds_[1]; }
+
+  // Methods to modify one endpoint of an existing R1Interval.  Do not use
+  // these methods if you want to replace both endpoints of the interval; use
+  // a constructor instead.  For example:
+  //
+  //   *lat_bounds = R1Interval(lat_lo, lat_hi);
+  void set_lo(double p) { bounds_[0] = p; }
+  void set_hi(double p) { bounds_[1] = p; }
+
+  // Methods that allow the R1Interval to be accessed as a vector.  (The
+  // recommended style is to use lo() and hi() whenever possible, but these
+  // methods are useful when the endpoint to be selected is not constant.)
+  double operator[](int i) const { return bounds_[i]; }
+  double& operator[](int i) { return bounds_[i]; }
+  const Vector2_d& bounds() const { return bounds_; }
+  Vector2_d* mutable_bounds() { return &bounds_; }
+
+  // Return true if the interval is empty, i.e. it contains no points.
+  bool is_empty() const { return lo() > hi(); }
+
+  // Return the center of the interval.  For empty intervals,
+  // the result is arbitrary.
+  double GetCenter() const { return 0.5 * (lo() + hi()); }
+
+  // Return the length of the interval.  The length of an empty interval
+  // is negative.
+  double GetLength() const { return hi() - lo(); }
+
+  bool Contains(double p) const {
+    return p >= lo() && p <= hi();
+  }
+
+  bool InteriorContains(double p) const {
+    return p > lo() && p < hi();
+  }
+
+  // Return true if this interval contains the interval 'y'.
+  bool Contains(const R1Interval& y) const {
+    if (y.is_empty()) return true;
+    return y.lo() >= lo() && y.hi() <= hi();
+  }
+
+  // Return true if the interior of this interval contains the entire
+  // interval 'y' (including its boundary).
+  bool InteriorContains(const R1Interval& y) const {
+    if (y.is_empty()) return true;
+    return y.lo() > lo() && y.hi() < hi();
+  }
+
+  // Return true if this interval intersects the given interval,
+  // i.e. if they have any points in common.
+  bool Intersects(const R1Interval& y) const {
+    if (lo() <= y.lo()) {
+      return y.lo() <= hi() && y.lo() <= y.hi();
+    } else {
+      return lo() <= y.hi() && lo() <= hi();
+    }
+  }
+
+  // Return true if the interior of this interval intersects
+  // any point of the given interval (including its boundary).
+  bool InteriorIntersects(const R1Interval& y) const {
+    return y.lo() < hi() && lo() < y.hi() && lo() < hi() && y.lo() <= y.hi();
+  }
+
+  // Return the Hausdorff distance to the given interval 'y'. For two
+  // R1Intervals x and y, this distance is defined as
+  //     h(x, y) = max_{p in x} min_{q in y} d(p, q).
+  double GetDirectedHausdorffDistance(const R1Interval& y) const {
+    if (is_empty()) return 0.0;
+    if (y.is_empty()) return HUGE_VAL;
+    return std::max(0.0, std::max(hi() - y.hi(), y.lo() - lo()));
+  }
+
+  // Expand the interval so that it contains the given point "p".
+  void AddPoint(double p) {
+    if (is_empty()) { set_lo(p); set_hi(p); }
+    else if (p < lo()) { set_lo(p); }  // NOLINT
+    else if (p > hi()) { set_hi(p); }  // NOLINT
+  }
+
+  // Expand the interval so that it contains the given interval "y".
+  void AddInterval(const R1Interval& y) {
+    if (y.is_empty()) return;
+    if (is_empty()) { *this = y; return; }
+    if (y.lo() < lo()) set_lo(y.lo());
+    if (y.hi() > hi()) set_hi(y.hi());
+  }
+
+  // Return the closest point in the interval to the given point "p".
+  // The interval must be non-empty.
+  double Project(double p) const {
+    S2_DCHECK(!is_empty());
+    return std::max(lo(), std::min(hi(), p));
+  }
+
+  // Return an interval that has been expanded on each side by the given
+  // distance "margin".  If "margin" is negative, then shrink the interval on
+  // each side by "margin" instead.  The resulting interval may be empty.  Any
+  // expansion of an empty interval remains empty.
+  R1Interval Expanded(double margin) const {
+    if (is_empty()) return *this;
+    return R1Interval(lo() - margin, hi() + margin);
+  }
+
+  // Return the smallest interval that contains this interval and the
+  // given interval "y".
+  R1Interval Union(const R1Interval& y) const {
+    if (is_empty()) return y;
+    if (y.is_empty()) return *this;
+    return R1Interval(std::min(lo(), y.lo()), std::max(hi(), y.hi()));
+  }
+
+  // Return the intersection of this interval with the given interval.
+  // Empty intervals do not need to be special-cased.
+  R1Interval Intersection(const R1Interval& y) const {
+    return R1Interval(std::max(lo(), y.lo()), std::min(hi(), y.hi()));
+  }
+
+  // Return true if two intervals contain the same set of points.
+  bool operator==(const R1Interval& y) const {
+    return (lo() == y.lo() && hi() == y.hi()) || (is_empty() && y.is_empty());
+  }
+
+  // Return true if two intervals do not contain the same set of points.
+  bool operator!=(const R1Interval& y) const {
+    return !operator==(y);
+  }
+
+  // Return true if this interval can be transformed into the given interval
+  // by moving each endpoint by at most "max_error".  The empty interval is
+  // considered to be positioned arbitrarily on the real line, thus any
+  // interval with (length <= 2*max_error) matches the empty interval.
+  bool ApproxEquals(const R1Interval& y, double max_error = 1e-15) const {
+    if (is_empty()) return y.GetLength() <= 2 * max_error;
+    if (y.is_empty()) return GetLength() <= 2 * max_error;
+    return (std::fabs(y.lo() - lo()) <= max_error &&
+            std::fabs(y.hi() - hi()) <= max_error);
+  }
+
+ private:
+  Vector2_d bounds_;
+};
+
+inline std::ostream& operator<<(std::ostream& os, const R1Interval& x) {
+  return os << "[" << x.lo() << ", " << x.hi() << "]";
+}
+
+#endif  // S2_R1INTERVAL_H_
diff --git a/src/s2/r2.h b/src/s2/r2.h
new file mode 100644 (file)
index 0000000..9336e14
--- /dev/null
@@ -0,0 +1,26 @@
+// Copyright 2012 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// Author: ericv@google.com (Eric Veach)
+
+#ifndef S2_R2_H_
+#define S2_R2_H_
+
+#include "s2/_fp_contract_off.h"
+#include "s2/util/math/vector.h"  // IWYU pragma: export
+
+using R2Point = Vector2_d;
+
+#endif  // S2_R2_H_
diff --git a/src/s2/r2rect.cc b/src/s2/r2rect.cc
new file mode 100644 (file)
index 0000000..030578a
--- /dev/null
@@ -0,0 +1,93 @@
+// Copyright 2012 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// Author: ericv@google.com (Eric Veach)
+
+#include "s2/r2rect.h"
+
+#include <iosfwd>
+
+#include "s2/base/logging.h"
+#include "s2/r1interval.h"
+#include "s2/r2.h"
+
+R2Rect R2Rect::FromCenterSize(const R2Point& center, const R2Point& size) {
+  return R2Rect(R1Interval(center.x() - 0.5 * size.x(),
+                           center.x() + 0.5 * size.x()),
+                R1Interval(center.y() - 0.5 * size.y(),
+                           center.y() + 0.5 * size.y()));
+}
+
+R2Rect R2Rect::FromPointPair(const R2Point& p1, const R2Point& p2) {
+  return R2Rect(R1Interval::FromPointPair(p1.x(), p2.x()),
+                R1Interval::FromPointPair(p1.y(), p2.y()));
+}
+
+bool R2Rect::Contains(const R2Rect& other) const {
+  return x().Contains(other.x()) && y().Contains(other.y());
+}
+
+bool R2Rect::InteriorContains(const R2Rect& other) const {
+  return x().InteriorContains(other.x()) && y().InteriorContains(other.y());
+}
+
+bool R2Rect::Intersects(const R2Rect& other) const {
+  return x().Intersects(other.x()) && y().Intersects(other.y());
+}
+
+bool R2Rect::InteriorIntersects(const R2Rect& other) const {
+  return x().InteriorIntersects(other.x()) && y().InteriorIntersects(other.y());
+}
+
+void R2Rect::AddPoint(const R2Point& p) {
+  bounds_[0].AddPoint(p[0]);
+  bounds_[1].AddPoint(p[1]);
+}
+
+void R2Rect::AddRect(const R2Rect& other) {
+  bounds_[0].AddInterval(other[0]);
+  bounds_[1].AddInterval(other[1]);
+}
+
+R2Point R2Rect::Project(const R2Point& p) const {
+  return R2Point(x().Project(p.x()), y().Project(p.y()));
+}
+
+R2Rect R2Rect::Expanded(const R2Point& margin) const {
+  R1Interval xx = x().Expanded(margin.x());
+  R1Interval yy = y().Expanded(margin.y());
+  if (xx.is_empty() || yy.is_empty()) return Empty();
+  return R2Rect(xx, yy);
+}
+
+R2Rect R2Rect::Union(const R2Rect& other) const {
+  return R2Rect(x().Union(other.x()), y().Union(other.y()));
+}
+
+R2Rect R2Rect::Intersection(const R2Rect& other) const {
+  R1Interval xx = x().Intersection(other.x());
+  R1Interval yy = y().Intersection(other.y());
+  if (xx.is_empty() || yy.is_empty()) return Empty();
+  return R2Rect(xx, yy);
+}
+
+bool R2Rect::ApproxEquals(const R2Rect& other, double max_error) const {
+  return (x().ApproxEquals(other.x(), max_error) &&
+          y().ApproxEquals(other.y(), max_error));
+}
+
+std::ostream& operator<<(std::ostream& os, const R2Rect& r) {
+  return os << "[Lo" << r.lo() << ", Hi" << r.hi() << "]";
+}
diff --git a/src/s2/r2rect.h b/src/s2/r2rect.h
new file mode 100644 (file)
index 0000000..7700fae
--- /dev/null
@@ -0,0 +1,234 @@
+// Copyright 2012 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// Author: ericv@google.com (Eric Veach)
+
+#ifndef S2_R2RECT_H_
+#define S2_R2RECT_H_
+
+#include <iosfwd>
+
+#include "s2/base/logging.h"
+#include "s2/_fp_contract_off.h"
+#include "s2/r1interval.h"
+#include "s2/r2.h"
+
+// An R2Rect represents a closed axis-aligned rectangle in the (x,y) plane.
+//
+// This class is intended to be copied by value as desired.  It uses
+// the default copy constructor and assignment operator, however it is
+// not a "plain old datatype" (POD) because it has virtual functions.
+class R2Rect {
+ public:
+  // Construct a rectangle from the given lower-left and upper-right points.
+  R2Rect(const R2Point& lo, const R2Point& hi);
+
+  // Construct a rectangle from the given intervals in x and y.  The two
+  // intervals must either be both empty or both non-empty.
+  R2Rect(const R1Interval& x, const R1Interval& y);
+
+  // The default constructor creates an empty R2Rect.
+  R2Rect();
+
+  // The canonical empty rectangle.  Use is_empty() to test for empty
+  // rectangles, since they have more than one representation.
+  static R2Rect Empty();
+
+  // Construct a rectangle from a center point and size in each dimension.
+  // Both components of size should be non-negative, i.e. this method cannot
+  // be used to create an empty rectangle.
+  static R2Rect FromCenterSize(const R2Point& center, const R2Point& size);
+
+  // Convenience method to construct a rectangle containing a single point.
+  static R2Rect FromPoint(const R2Point& p);
+
+  // Convenience method to construct the minimal bounding rectangle containing
+  // the two given points.  This is equivalent to starting with an empty
+  // rectangle and calling AddPoint() twice.  Note that it is different than
+  // the R2Rect(lo, hi) constructor, where the first point is always
+  // used as the lower-left corner of the resulting rectangle.
+  static R2Rect FromPointPair(const R2Point& p1, const R2Point& p2);
+
+  // Accessor methods.
+  const R1Interval& x() const { return bounds_[0]; }
+  const R1Interval& y() const { return bounds_[1]; }
+  R2Point lo() const { return R2Point(x().lo(), y().lo()); }
+  R2Point hi() const { return R2Point(x().hi(), y().hi()); }
+
+  // Methods that allow the R2Rect to be accessed as a vector.
+  const R1Interval& operator[](int i) const { return bounds_[i]; }
+  R1Interval& operator[](int i) { return bounds_[i]; }
+
+  // Return true if the rectangle is valid, which essentially just means
+  // that if the bound for either axis is empty then both must be.
+  bool is_valid() const;
+
+  // Return true if the rectangle is empty, i.e. it contains no points at all.
+  bool is_empty() const;
+
+  // Return the k-th vertex of the rectangle (k = 0,1,2,3) in CCW order.
+  // Vertex 0 is in the lower-left corner.  For convenience, the argument is
+  // reduced modulo 4 to the range [0..3].
+  R2Point GetVertex(int k) const;
+
+  // Return the vertex in direction "i" along the x-axis (0=left, 1=right) and
+  // direction "j" along the y-axis (0=down, 1=up).  Equivalently, return the
+  // vertex constructed by selecting endpoint "i" of the x-interval (0=lo,
+  // 1=hi) and vertex "j" of the y-interval.
+  R2Point GetVertex(int i, int j) const;
+
+  // Return the center of the rectangle in (x,y)-space.
+  R2Point GetCenter() const;
+
+  // Return the width and height of this rectangle in (x,y)-space.  Empty
+  // rectangles have a negative width and height.
+  R2Point GetSize() const;
+
+  // Return true if the rectangle contains the given point.  Note that
+  // rectangles are closed regions, i.e. they contain their boundary.
+  bool Contains(const R2Point& p) const;
+
+  // Return true if and only if the given point is contained in the interior
+  // of the region (i.e. the region excluding its boundary).
+  bool InteriorContains(const R2Point& p) const;
+
+  // Return true if and only if the rectangle contains the given other
+  // rectangle.
+  bool Contains(const R2Rect& other) const;
+
+  // Return true if and only if the interior of this rectangle contains all
+  // points of the given other rectangle (including its boundary).
+  bool InteriorContains(const R2Rect& other) const;
+
+  // Return true if this rectangle and the given other rectangle have any
+  // points in common.
+  bool Intersects(const R2Rect& other) const;
+
+  // Return true if and only if the interior of this rectangle intersects
+  // any point (including the boundary) of the given other rectangle.
+  bool InteriorIntersects(const R2Rect& other) const;
+
+  // Expand the rectangle to include the given point.  The rectangle is
+  // expanded by the minimum amount possible.
+  void AddPoint(const R2Point& p);
+
+  // Expand the rectangle to include the given other rectangle.  This is the
+  // same as replacing the rectangle by the union of the two rectangles, but
+  // is somewhat more efficient.
+  void AddRect(const R2Rect& other);
+
+  // Return the closest point in the rectangle to the given point "p".
+  // The rectangle must be non-empty.
+  R2Point Project(const R2Point& p) const;
+
+  // Return a rectangle that has been expanded on each side in the x-direction
+  // by margin.x(), and on each side in the y-direction by margin.y().  If
+  // either margin is empty, then shrink the interval on the corresponding
+  // sides instead.  The resulting rectangle may be empty.  Any expansion of
+  // an empty rectangle remains empty.
+  R2Rect Expanded(const R2Point& margin) const;
+  R2Rect Expanded(double margin) const;
+
+  // Return the smallest rectangle containing the union of this rectangle and
+  // the given rectangle.
+  R2Rect Union(const R2Rect& other) const;
+
+  // Return the smallest rectangle containing the intersection of this
+  // rectangle and the given rectangle.
+  R2Rect Intersection(const R2Rect& other) const;
+
+  // Return true if two rectangles contains the same set of points.
+  bool operator==(const R2Rect& other) const;
+
+  // Return true if the x- and y-intervals of the two rectangles are the same
+  // up to the given tolerance (see r1interval.h for details).
+  bool ApproxEquals(const R2Rect& other, double max_error = 1e-15) const;
+
+ private:
+  R1Interval bounds_[2];
+};
+
+inline R2Rect::R2Rect(const R2Point& lo, const R2Point& hi) {
+  bounds_[0] = R1Interval(lo.x(), hi.x());
+  bounds_[1] = R1Interval(lo.y(), hi.y());
+  S2_DCHECK(is_valid());
+}
+
+inline R2Rect::R2Rect(const R1Interval& x, const R1Interval& y) {
+  bounds_[0] = x;
+  bounds_[1] = y;
+  S2_DCHECK(is_valid());
+}
+
+inline R2Rect::R2Rect() {
+  // The default R1Interval constructor creates an empty interval.
+  S2_DCHECK(is_valid());
+}
+
+inline R2Rect R2Rect::Empty() {
+  return R2Rect(R1Interval::Empty(), R1Interval::Empty());
+}
+
+inline bool R2Rect::is_valid() const {
+  // The x/y ranges must either be both empty or both non-empty.
+  return x().is_empty() == y().is_empty();
+}
+
+inline bool R2Rect::is_empty() const {
+  return x().is_empty();
+}
+
+inline R2Rect R2Rect::FromPoint(const R2Point& p) {
+  return R2Rect(p, p);
+}
+
+inline R2Point R2Rect::GetVertex(int k) const {
+  // Twiddle bits to return the points in CCW order (lower left, lower right,
+  // upper right, upper left).
+  int j = (k >> 1) & 1;
+  return GetVertex(j ^ (k & 1), j);
+}
+
+inline R2Point R2Rect::GetVertex(int i, int j) const {
+  return R2Point(bounds_[0][i], bounds_[1][j]);
+}
+
+inline R2Point R2Rect::GetCenter() const {
+  return R2Point(x().GetCenter(), y().GetCenter());
+}
+
+inline R2Point R2Rect::GetSize() const {
+  return R2Point(x().GetLength(), y().GetLength());
+}
+
+inline bool R2Rect::Contains(const R2Point& p) const {
+  return x().Contains(p.x()) && y().Contains(p.y());
+}
+
+inline bool R2Rect::InteriorContains(const R2Point& p) const {
+  return x().InteriorContains(p.x()) && y().InteriorContains(p.y());
+}
+
+inline R2Rect R2Rect::Expanded(double margin) const {
+  return Expanded(R2Point(margin, margin));
+}
+
+inline bool R2Rect::operator==(const R2Rect& other) const {
+  return x() == other.x() && y() == other.y();
+}
+
+std::ostream& operator<<(std::ostream& os, const R2Rect& r);
+
+#endif  // S2_R2RECT_H_
diff --git a/src/s2/s1angle.cc b/src/s2/s1angle.cc
new file mode 100644 (file)
index 0000000..78cceda
--- /dev/null
@@ -0,0 +1,54 @@
+// Copyright 2005 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// Author: ericv@google.com (Eric Veach)
+
+#include "s2/s1angle.h"
+
+#include <cmath>
+#include <cstdio>
+#include <ostream>
+
+#include "s2/s2latlng.h"
+
+S1Angle::S1Angle(const S2Point& x, const S2Point& y)
+    : radians_(x.Angle(y)) {
+}
+
+S1Angle::S1Angle(const S2LatLng& x, const S2LatLng& y)
+    : radians_(x.GetDistance(y).radians()) {
+}
+
+S1Angle S1Angle::Normalized() const {
+  S1Angle a(radians_);
+  a.Normalize();
+  return a;
+}
+
+void S1Angle::Normalize() {
+  radians_ = remainder(radians_, 2.0 * M_PI);
+  if (radians_ <= -M_PI) radians_ = M_PI;
+}
+
+std::ostream& operator<<(std::ostream& os, S1Angle a) {
+  double degrees = a.degrees();
+  char buffer[13];
+  int sz = snprintf(buffer, sizeof(buffer), "%.7f", degrees);
+  if (sz >= 0 && sz < sizeof(buffer)) {
+    return os << buffer;
+  } else {
+    return os << degrees;
+  }
+}
diff --git a/src/s2/s1angle.h b/src/s2/s1angle.h
new file mode 100644 (file)
index 0000000..96291e9
--- /dev/null
@@ -0,0 +1,336 @@
+// Copyright 2005 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// Author: ericv@google.com (Eric Veach)
+
+#ifndef S2_S1ANGLE_H_
+#define S2_S1ANGLE_H_
+
+#include <cmath>
+#include <limits>
+#include <ostream>
+#include <type_traits>
+
+#include "s2/base/integral_types.h"
+#include "s2/_fp_contract_off.h"
+#include "s2/s2point.h"
+#include "s2/util/math/mathutil.h"
+#include "s2/util/math/vector.h"
+
+class S2LatLng;
+
+#ifndef SWIG
+#define IFNDEF_SWIG(x) x
+#else
+#define IFNDEF_SWIG(x)
+#endif
+
+// This class represents a one-dimensional angle (as opposed to a
+// two-dimensional solid angle).  It has methods for converting angles to
+// or from radians, degrees, and the E5/E6/E7 representations (i.e. degrees
+// multiplied by 1e5/1e6/1e7 and rounded to the nearest integer).
+//
+// The internal representation is a double-precision value in radians, so
+// conversion to and from radians is exact.  Conversions between E5, E6, E7,
+// and Degrees are not always exact; for example, Degrees(3.1) is different
+// from E6(3100000) or E7(310000000).  However, the following properties are
+// guaranteed for any integer "n", provided that "n" is in the input range of
+// both functions:
+//
+//     Degrees(n) == E6(1000000 * n)
+//     Degrees(n) == E7(10000000 * n)
+//          E6(n) == E7(10 * n)
+//
+// The corresponding properties are *not* true for E5, so if you use E5 then
+// don't test for exact equality when comparing to other formats such as
+// Degrees or E7.
+//
+// The following conversions between degrees and radians are exact:
+//
+//          Degrees(180) == Radians(M_PI)
+//       Degrees(45 * k) == Radians(k * M_PI / 4)  for k == 0..8
+//
+// These identities also hold when the arguments are scaled up or down by any
+// power of 2.  Some similar identities are also true, for example,
+// Degrees(60) == Radians(M_PI / 3), but be aware that this type of identity
+// does not hold in general.  For example, Degrees(3) != Radians(M_PI / 60).
+//
+// Similarly, the conversion to radians means that Angle::Degrees(x).degrees()
+// does not always equal "x".  For example,
+//
+//         S1Angle::Degrees(45 * k).degrees() == 45 * k      for k == 0..8
+//   but       S1Angle::Degrees(60).degrees() != 60.
+//
+// This means that when testing for equality, you should allow for numerical
+// errors (EXPECT_DOUBLE_EQ) or convert to discrete E5/E6/E7 values first.
+//
+// CAVEAT: All of the above properties depend on "double" being the usual
+// 64-bit IEEE 754 type (which is true on almost all modern platforms).
+//
+// This class is intended to be copied by value as desired.  It uses
+// the default copy constructor and assignment operator.
+class S1Angle {
+ public:
+  // These methods construct S1Angle objects from their measure in radians
+  // or degrees.
+  static constexpr S1Angle Radians(double radians);
+  static constexpr S1Angle Degrees(double degrees);
+  static constexpr S1Angle E5(int32 e5);
+  static constexpr S1Angle E6(int32 e6);
+  static constexpr S1Angle E7(int32 e7);
+
+  // Convenience functions -- to use when args have been fixed32s in protos.
+  //
+  // The arguments are static_cast into int32, so very large unsigned values
+  // are treated as negative numbers.
+  static constexpr S1Angle UnsignedE6(uint32 e6);
+  static constexpr S1Angle UnsignedE7(uint32 e7);
+
+  // The default constructor yields a zero angle.  This is useful for STL
+  // containers and class methods with output arguments.
+  IFNDEF_SWIG(constexpr) S1Angle() : radians_(0) {}
+
+  // Return an angle larger than any finite angle.
+  static constexpr S1Angle Infinity();
+
+  // A explicit shorthand for the default constructor.
+  static constexpr S1Angle Zero();
+
+  // Return the angle between two points, which is also equal to the distance
+  // between these points on the unit sphere.  The points do not need to be
+  // normalized.  This function has a maximum error of 3.25 * DBL_EPSILON (or
+  // 2.5 * DBL_EPSILON for angles up to 1 radian). If either point is
+  // zero-length (e.g. an uninitialized S2Point), or almost zero-length, the
+  // resulting angle will be zero.
+  S1Angle(const S2Point& x, const S2Point& y);
+
+  // Like the constructor above, but return the angle (i.e., distance) between
+  // two S2LatLng points.  This function has about 15 digits of accuracy for
+  // small distances but only about 8 digits of accuracy as the distance
+  // approaches 180 degrees (i.e., nearly-antipodal points).
+  S1Angle(const S2LatLng& x, const S2LatLng& y);
+
+  constexpr double radians() const;
+  constexpr double degrees() const;
+
+  int32 e5() const;
+  int32 e6() const;
+  int32 e7() const;
+
+  // Return the absolute value of an angle.
+  S1Angle abs() const;
+
+  // Comparison operators.
+  friend bool operator==(S1Angle x, S1Angle y);
+  friend bool operator!=(S1Angle x, S1Angle y);
+  friend bool operator<(S1Angle x, S1Angle y);
+  friend bool operator>(S1Angle x, S1Angle y);
+  friend bool operator<=(S1Angle x, S1Angle y);
+  friend bool operator>=(S1Angle x, S1Angle y);
+
+  // Simple arithmetic operators for manipulating S1Angles.
+  friend S1Angle operator-(S1Angle a);
+  friend S1Angle operator+(S1Angle a, S1Angle b);
+  friend S1Angle operator-(S1Angle a, S1Angle b);
+  friend S1Angle operator*(double m, S1Angle a);
+  friend S1Angle operator*(S1Angle a, double m);
+  friend S1Angle operator/(S1Angle a, double m);
+  friend double operator/(S1Angle a, S1Angle b);
+  S1Angle& operator+=(S1Angle a);
+  S1Angle& operator-=(S1Angle a);
+  S1Angle& operator*=(double m);
+  S1Angle& operator/=(double m);
+
+  // Trigonmetric functions (not necessary but slightly more convenient).
+  friend double sin(S1Angle a);
+  friend double cos(S1Angle a);
+  friend double tan(S1Angle a);
+
+  // Return the angle normalized to the range (-180, 180] degrees.
+  S1Angle Normalized() const;
+
+  // Normalize this angle to the range (-180, 180] degrees.
+  void Normalize();
+
+  // When S1Angle is used as a key in one of the btree container types
+  // (util/btree), indicate that linear rather than binary search should be
+  // used.  This is much faster when the comparison function is cheap.
+  typedef std::true_type absl_btree_prefer_linear_node_search;
+
+ private:
+  explicit IFNDEF_SWIG(constexpr) S1Angle(double radians) : radians_(radians) {}
+  double radians_;
+};
+
+
+//////////////////   Implementation details follow   ////////////////////
+
+
+inline constexpr S1Angle S1Angle::Infinity() {
+  return S1Angle(std::numeric_limits<double>::infinity());
+}
+
+inline constexpr S1Angle S1Angle::Zero() {
+  return S1Angle(0);
+}
+
+inline constexpr double S1Angle::radians() const {
+  return radians_;
+}
+
+inline constexpr double S1Angle::degrees() const {
+  return (180 / M_PI) * radians_;
+}
+
+// Note that the E5, E6, and E7 conversion involve two multiplications rather
+// than one.  This is mainly for backwards compatibility (changing this would
+// break many tests), but it does have the nice side effect that conversions
+// between Degrees, E6, and E7 are exact when the arguments are integers.
+
+inline int32 S1Angle::e5() const {
+  return MathUtil::FastIntRound(1e5 * degrees());
+}
+
+inline int32 S1Angle::e6() const {
+  return MathUtil::FastIntRound(1e6 * degrees());
+}
+
+inline int32 S1Angle::e7() const {
+  return MathUtil::FastIntRound(1e7 * degrees());
+}
+
+inline S1Angle S1Angle::abs() const {
+  return S1Angle(std::fabs(radians_));
+}
+
+inline bool operator==(S1Angle x, S1Angle y) {
+  return x.radians() == y.radians();
+}
+
+inline bool operator!=(S1Angle x, S1Angle y) {
+  return x.radians() != y.radians();
+}
+
+inline bool operator<(S1Angle x, S1Angle y) {
+  return x.radians() < y.radians();
+}
+
+inline bool operator>(S1Angle x, S1Angle y) {
+  return x.radians() > y.radians();
+}
+
+inline bool operator<=(S1Angle x, S1Angle y) {
+  return x.radians() <= y.radians();
+}
+
+inline bool operator>=(S1Angle x, S1Angle y) {
+  return x.radians() >= y.radians();
+}
+
+inline S1Angle operator-(S1Angle a) {
+  return S1Angle::Radians(-a.radians());
+}
+
+inline S1Angle operator+(S1Angle a, S1Angle b) {
+  return S1Angle::Radians(a.radians() + b.radians());
+}
+
+inline S1Angle operator-(S1Angle a, S1Angle b) {
+  return S1Angle::Radians(a.radians() - b.radians());
+}
+
+inline S1Angle operator*(double m, S1Angle a) {
+  return S1Angle::Radians(m * a.radians());
+}
+
+inline S1Angle operator*(S1Angle a, double m) {
+  return S1Angle::Radians(m * a.radians());
+}
+
+inline S1Angle operator/(S1Angle a, double m) {
+  return S1Angle::Radians(a.radians() / m);
+}
+
+inline double operator/(S1Angle a, S1Angle b) {
+  return a.radians() / b.radians();
+}
+
+inline S1Angle& S1Angle::operator+=(S1Angle a) {
+  radians_ += a.radians();
+  return *this;
+}
+
+inline S1Angle& S1Angle::operator-=(S1Angle a) {
+  radians_ -= a.radians();
+  return *this;
+}
+
+inline S1Angle& S1Angle::operator*=(double m) {
+  radians_ *= m;
+  return *this;
+}
+
+inline S1Angle& S1Angle::operator/=(double m) {
+  radians_ /= m;
+  return *this;
+}
+
+inline double sin(S1Angle a) {
+  return sin(a.radians());
+}
+
+inline double cos(S1Angle a) {
+  return cos(a.radians());
+}
+
+inline double tan(S1Angle a) {
+  return tan(a.radians());
+}
+
+inline constexpr S1Angle S1Angle::Radians(double radians) {
+  return S1Angle(radians);
+}
+
+inline constexpr S1Angle S1Angle::Degrees(double degrees) {
+  return S1Angle((M_PI / 180) * degrees);
+}
+
+inline constexpr S1Angle S1Angle::E5(int32 e5) {
+  return Degrees(1e-5 * e5);
+}
+
+inline constexpr S1Angle S1Angle::E6(int32 e6) {
+  return Degrees(1e-6 * e6);
+}
+
+inline constexpr S1Angle S1Angle::E7(int32 e7) {
+  return Degrees(1e-7 * e7);
+}
+
+inline constexpr S1Angle S1Angle::UnsignedE6(uint32 e6) {
+  return E6(static_cast<int32>(e6));
+}
+
+inline constexpr S1Angle S1Angle::UnsignedE7(uint32 e7) {
+  return E7(static_cast<int32>(e7));
+}
+
+// Writes the angle in degrees with 7 digits of precision after the
+// decimal point, e.g. "17.3745904".
+std::ostream& operator<<(std::ostream& os, S1Angle a);
+
+#undef IFNDEF_SWIG
+
+#endif  // S2_S1ANGLE_H_
diff --git a/src/s2/s1chord_angle.cc b/src/s2/s1chord_angle.cc
new file mode 100644 (file)
index 0000000..eb5fccc
--- /dev/null
@@ -0,0 +1,159 @@
+// Copyright 2013 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// Author: ericv@google.com (Eric Veach)
+
+#include "s2/s1chord_angle.h"
+
+#include <cfloat>
+#include <cmath>
+
+#include "s2/s1angle.h"
+#include "s2/s2pointutil.h"
+
+using std::max;
+using std::min;
+// Android with gnustl has ::nextafter but not std::nextafter.
+// https://github.com/android-ndk/ndk/issues/82
+// Check for gnustl with _GLIBCXX_CMATH, which is its cmath include
+// guard.
+#if !defined(__ANDROID__) || !defined(_GLIBCXX_CMATH)
+using std::nextafter;
+#endif
+
+static constexpr double kMaxLength2 = 4.0;
+
+S1ChordAngle::S1ChordAngle(S1Angle angle) {
+  if (angle.radians() < 0) {
+    *this = Negative();
+  } else if (angle == S1Angle::Infinity()) {
+    *this = Infinity();
+  } else {
+    // The chord length is 2 * sin(angle / 2).
+    double length = 2 * sin(0.5 * min(M_PI, angle.radians()));
+    length2_ = length * length;
+  }
+  S2_DCHECK(is_valid());
+}
+
+S1Angle S1ChordAngle::ToAngle() const {
+  if (is_negative()) return S1Angle::Radians(-1);
+  if (is_infinity()) return S1Angle::Infinity();
+  return S1Angle::Radians(2 * asin(0.5 * sqrt(length2_)));
+}
+
+bool S1ChordAngle::is_valid() const {
+  return (length2_ >= 0 && length2_ <= kMaxLength2) || is_special();
+}
+
+S1ChordAngle S1ChordAngle::Successor() const {
+  if (length2_ >= kMaxLength2) return Infinity();
+  if (length2_ < 0.0) return Zero();
+  return S1ChordAngle(nextafter(length2_, 10.0));
+}
+
+S1ChordAngle S1ChordAngle::Predecessor() const {
+  if (length2_ <= 0.0) return Negative();
+  if (length2_ > kMaxLength2) return Straight();
+  return S1ChordAngle(nextafter(length2_, -10.0));
+}
+
+S1ChordAngle S1ChordAngle::PlusError(double error) const {
+  // If angle is Negative() or Infinity(), don't change it.
+  // Otherwise clamp it to the valid range.
+  if (is_special()) return *this;
+  return S1ChordAngle(max(0.0, min(kMaxLength2, length2_ + error)));
+}
+
+double S1ChordAngle::GetS2PointConstructorMaxError() const {
+  // There is a relative error of 2.5 * DBL_EPSILON when computing the squared
+  // distance, plus a relative error of 2 * DBL_EPSILON and an absolute error
+  // of (16 * DBL_EPSILON**2) because the lengths of the input points may
+  // differ from 1 by up to (2 * DBL_EPSILON) each.  (This is the maximum
+  // length error in S2Point::Normalize.)
+  return 4.5 * DBL_EPSILON * length2_ + 16 * DBL_EPSILON * DBL_EPSILON;
+}
+
+double S1ChordAngle::GetS1AngleConstructorMaxError() const {
+  // Assuming that an accurate math library is being used, the sin() call and
+  // the multiply each have a relative error of 0.5 * DBL_EPSILON.
+  return DBL_EPSILON * length2_;
+}
+
+S1ChordAngle operator+(S1ChordAngle a, S1ChordAngle b) {
+  // Note that this method is much more efficient than converting the chord
+  // angles to S1Angles and adding those.  It requires only one square root
+  // plus a few additions and multiplications.
+  S2_DCHECK(!a.is_special());
+  S2_DCHECK(!b.is_special());
+
+  // Optimization for the common case where "b" is an error tolerance
+  // parameter that happens to be set to zero.
+  double a2 = a.length2(), b2 = b.length2();
+  if (b2 == 0) return a;
+
+  // Clamp the angle sum to at most 180 degrees.
+  if (a2 + b2 >= kMaxLength2) return S1ChordAngle::Straight();
+
+  // Let "a" and "b" be the (non-squared) chord lengths, and let c = a+b.
+  // Let A, B, and C be the corresponding half-angles (a = 2*sin(A), etc).
+  // Then the formula below can be derived from c = 2 * sin(A+B) and the
+  // relationships   sin(A+B) = sin(A)*cos(B) + sin(B)*cos(A)
+  //                 cos(X) = sqrt(1 - sin^2(X)) .
+
+  double x = a2 * (1 - 0.25 * b2);  // is_valid() => non-negative
+  double y = b2 * (1 - 0.25 * a2);  // is_valid() => non-negative
+  return S1ChordAngle(min(kMaxLength2, x + y + 2 * sqrt(x * y)));
+}
+
+S1ChordAngle operator-(S1ChordAngle a, S1ChordAngle b) {
+  // See comments in operator+().
+  S2_DCHECK(!a.is_special());
+  S2_DCHECK(!b.is_special());
+  double a2 = a.length2(), b2 = b.length2();
+  if (b2 == 0) return a;
+  if (a2 <= b2) return S1ChordAngle::Zero();
+  double x = a2 * (1 - 0.25 * b2);
+  double y = b2 * (1 - 0.25 * a2);
+  return S1ChordAngle(max(0.0, x + y - 2 * sqrt(x * y)));
+}
+
+double sin2(S1ChordAngle a) {
+  S2_DCHECK(!a.is_special());
+  // Let "a" be the (non-squared) chord length, and let A be the corresponding
+  // half-angle (a = 2*sin(A)).  The formula below can be derived from:
+  //   sin(2*A) = 2 * sin(A) * cos(A)
+  //   cos^2(A) = 1 - sin^2(A)
+  // This is much faster than converting to an angle and computing its sine.
+  return a.length2() * (1 - 0.25 * a.length2());
+}
+
+double sin(S1ChordAngle a) {
+  return sqrt(sin2(a));
+}
+
+double cos(S1ChordAngle a) {
+  // cos(2*A) = cos^2(A) - sin^2(A) = 1 - 2*sin^2(A)
+  S2_DCHECK(!a.is_special());
+  return 1 - 0.5 * a.length2();
+}
+
+double tan(S1ChordAngle a) {
+  return sin(a) / cos(a);
+}
+
+std::ostream& operator<<(std::ostream& os, S1ChordAngle a) {
+  return os << a.ToAngle();
+}
diff --git a/src/s2/s1chord_angle.h b/src/s2/s1chord_angle.h
new file mode 100644 (file)
index 0000000..4077221
--- /dev/null
@@ -0,0 +1,369 @@
+// Copyright 2013 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// Author: ericv@google.com (Eric Veach)
+
+#ifndef S2_S1CHORD_ANGLE_H_
+#define S2_S1CHORD_ANGLE_H_
+
+#include <cmath>
+#include <limits>
+#include <ostream>
+#include <type_traits>
+
+#include "s2/_fp_contract_off.h"
+#include "s2/s1angle.h"
+#include "s2/s2pointutil.h"
+
+// S1ChordAngle represents the angle subtended by a chord (i.e., the straight
+// line segment connecting two points on the sphere).  Its representation
+// makes it very efficient for computing and comparing distances, but unlike
+// S1Angle it is only capable of representing angles between 0 and Pi radians.
+// Generally, S1ChordAngle should only be used in loops where many angles need
+// to be calculated and compared.  Otherwise it is simpler to use S1Angle.
+//
+// S1ChordAngle also loses some accuracy as the angle approaches Pi radians.
+// Specifically, the representation of (Pi - x) radians has an error of about
+// (1e-15 / x), with a maximum error of about 2e-8 radians (about 13cm on the
+// Earth's surface).  For comparison, for angles up to 90 degrees (10000km)
+// the worst-case representation error is about 2e-16 radians (1 nanometer),
+// which is about the same as S1Angle.
+//
+// This class is intended to be copied by value as desired.  It uses
+// the default copy constructor and assignment operator.
+class S1ChordAngle {
+ public:
+  // The default constructor yields a zero angle.  This is useful for STL
+  // containers and class methods with output arguments.
+  S1ChordAngle() : length2_(0) {}
+
+  // Construct the S1ChordAngle corresponding to the distance between the two
+  // given points.  The points must be unit length.
+  S1ChordAngle(const S2Point& x, const S2Point& y);
+
+  // Return the zero chord angle.
+  static S1ChordAngle Zero();
+
+  // Return a chord angle of 90 degrees (a "right angle").
+  static S1ChordAngle Right();
+
+  // Return a chord angle of 180 degrees (a "straight angle").  This is the
+  // maximum finite chord angle.
+  static S1ChordAngle Straight();
+
+  // Return a chord angle larger than any finite chord angle.  The only valid
+  // operations on Infinity() are comparisons, S1Angle conversions, and
+  // Successor() / Predecessor().
+  static S1ChordAngle Infinity();
+
+  // Return a chord angle smaller than Zero().  The only valid operations on
+  // Negative() are comparisons, S1Angle conversions, and Successor() /
+  // Predecessor().
+  static S1ChordAngle Negative();
+
+  // Conversion from an S1Angle.  Angles outside the range [0, Pi] are handled
+  // as follows: Infinity() is mapped to Infinity(), negative angles are
+  // mapped to Negative(), and finite angles larger than Pi are mapped to
+  // Straight().
+  //
+  // Note that this operation is relatively expensive and should be avoided.
+  // To use S1ChordAngle effectively, you should structure your code so that
+  // input arguments are converted to S1ChordAngles at the beginning of your
+  // algorithm, and results are converted back to S1Angles only at the end.
+  explicit S1ChordAngle(S1Angle angle);
+
+  // Convenience methods implemented by converting from an S1Angle.
+  static S1ChordAngle Radians(double radians);
+  static S1ChordAngle Degrees(double degrees);
+  static S1ChordAngle E5(int32 e5);
+  static S1ChordAngle E6(int32 e6);
+  static S1ChordAngle E7(int32 e7);
+
+  // Construct an S1ChordAngle that is an upper bound on the given S1Angle,
+  // i.e. such that FastUpperBoundFrom(x).ToAngle() >= x.  Unlike the S1Angle
+  // constructor above, this method is very fast, and the bound is accurate to
+  // within 1% for distances up to about 3100km on the Earth's surface.
+  static S1ChordAngle FastUpperBoundFrom(S1Angle angle);
+
+  // Construct an S1ChordAngle from the squared chord length.  Note that the
+  // argument is automatically clamped to a maximum of 4.0 to handle possible
+  // roundoff errors.  The argument must be non-negative.
+  static S1ChordAngle FromLength2(double length2);
+
+  // Converts to an S1Angle.  Can be used just like an S1Angle constructor:
+  //
+  //   S1ChordAngle x = ...;
+  //   return S1Angle(x);
+  //
+  // Infinity() is converted to S1Angle::Infinity(), and Negative() is
+  // converted to an unspecified negative S1Angle.
+  //
+  // Note that the conversion uses trigonometric functions and therefore
+  // should be avoided in inner loops.
+  explicit operator S1Angle() const;
+
+  // Converts to an S1Angle (equivalent to the operator above).
+  S1Angle ToAngle() const;
+
+  // Convenience methods implemented by calling ToAngle() first.  Note that
+  // because of the S1Angle conversion these methods are relatively expensive
+  // (despite their lowercase names), so the results should be cached if they
+  // are needed inside loops.
+  double radians() const;
+  double degrees() const;
+  int32 e5() const;
+  int32 e6() const;
+  int32 e7() const;
+
+  // All operators and functions are declared here so that we can put them all
+  // in one place.  (The compound assignment operators must be put here.)
+
+  // Comparison operators.
+  friend bool operator==(S1ChordAngle x, S1ChordAngle y);
+  friend bool operator!=(S1ChordAngle x, S1ChordAngle y);
+  friend bool operator<(S1ChordAngle x, S1ChordAngle y);
+  friend bool operator>(S1ChordAngle x, S1ChordAngle y);
+  friend bool operator<=(S1ChordAngle x, S1ChordAngle y);
+  friend bool operator>=(S1ChordAngle x, S1ChordAngle y);
+
+  // Comparison predicates.
+  bool is_zero() const;
+  bool is_negative() const;
+  bool is_infinity() const;
+  bool is_special() const;  // Negative or infinity.
+
+  // Only addition and subtraction of S1ChordAngles is supported.  These
+  // methods add or subtract the corresponding S1Angles, and clamp the result
+  // to the range [0, Pi].  Both arguments must be non-negative and
+  // non-infinite.
+  //
+  // REQUIRES: !a.is_special() && !b.is_special()
+  friend S1ChordAngle operator+(S1ChordAngle a, S1ChordAngle b);
+  friend S1ChordAngle operator-(S1ChordAngle a, S1ChordAngle b);
+  S1ChordAngle& operator+=(S1ChordAngle a);
+  S1ChordAngle& operator-=(S1ChordAngle a);
+
+  // Trigonmetric functions.  It is more accurate and efficient to call these
+  // rather than first converting to an S1Angle.
+  friend double sin(S1ChordAngle a);
+  friend double cos(S1ChordAngle a);
+  friend double tan(S1ChordAngle a);
+
+  // Returns sin(a)**2, but computed more efficiently.
+  friend double sin2(S1ChordAngle a);
+
+  // The squared length of the chord.  (Most clients will not need this.)
+  double length2() const { return length2_; }
+
+  // Returns the smallest representable S1ChordAngle larger than this object.
+  // This can be used to convert a "<" comparison to a "<=" comparison.  For
+  // example:
+  //
+  //   S2ClosestEdgeQuery query(...);
+  //   S1ChordAngle limit = ...;
+  //   if (query.IsDistanceLess(target, limit.Successor())) {
+  //     // Distance to "target" is less than or equal to "limit".
+  //   }
+  //
+  // Note the following special cases:
+  //   Negative().Successor() == Zero()
+  //   Straight().Successor() == Infinity()
+  //   Infinity().Successor() == Infinity()
+  S1ChordAngle Successor() const;
+
+  // Like Successor(), but returns the largest representable S1ChordAngle less
+  // than this object.
+  //
+  // Note the following special cases:
+  //   Infinity().Predecessor() == Straight()
+  //   Zero().Predecessor() == Negative()
+  //   Negative().Predecessor() == Negative()
+  S1ChordAngle Predecessor() const;
+
+  // Returns a new S1ChordAngle that has been adjusted by the given error
+  // bound (which can be positive or negative).  "error" should be the value
+  // returned by one of the error bound methods below.  For example:
+  //    S1ChordAngle a(x, y);
+  //    S1ChordAngle a1 = a.PlusError(a.GetS2PointConstructorMaxError());
+  S1ChordAngle PlusError(double error) const;
+
+  // Return the maximum error in length2() for the S1ChordAngle(x, y)
+  // constructor, assuming that "x" and "y" are normalized to within the
+  // bounds guaranteed by S2Point::Normalize().  (The error is defined with
+  // respect to the true distance after the points are projected to lie
+  // exactly on the sphere.)
+  double GetS2PointConstructorMaxError() const;
+
+  // Return the maximum error in length2() for the S1Angle constructor.
+  double GetS1AngleConstructorMaxError() const;
+
+  // Return true if the internal representation is valid.  Negative() and
+  // Infinity() are both considered valid.
+  bool is_valid() const;
+
+  // When S1ChordAngle is used as a key in one of the btree container types
+  // (util/btree), indicate that linear rather than binary search should be
+  // used.  This is much faster when the comparison function is cheap.
+  typedef std::true_type absl_btree_prefer_linear_node_search;
+
+ private:
+  // S1ChordAngles are represented by the squared chord length, which can
+  // range from 0 to 4.  Infinity() uses an infinite squared length.
+  explicit S1ChordAngle(double length2) : length2_(length2) {
+    S2_DCHECK(is_valid());
+  }
+  double length2_;
+};
+
+
+//////////////////   Implementation details follow   ////////////////////
+
+
+inline S1ChordAngle::S1ChordAngle(const S2Point& x, const S2Point& y) {
+  S2_DCHECK(S2::IsUnitLength(x));
+  S2_DCHECK(S2::IsUnitLength(y));
+  // The squared distance may slightly exceed 4.0 due to roundoff errors.
+  // The maximum error in the result is 2 * DBL_EPSILON * length2_.
+  length2_ = std::min(4.0, (x - y).Norm2());
+  S2_DCHECK(is_valid());
+}
+
+inline S1ChordAngle S1ChordAngle::FromLength2(double length2) {
+  return S1ChordAngle(std::min(4.0, length2));
+}
+
+inline S1ChordAngle S1ChordAngle::Zero() {
+  return S1ChordAngle(0);
+}
+
+inline S1ChordAngle S1ChordAngle::Right() {
+  return S1ChordAngle(2);
+}
+
+inline S1ChordAngle S1ChordAngle::Straight() {
+  return S1ChordAngle(4);
+}
+
+inline S1ChordAngle S1ChordAngle::Infinity() {
+  return S1ChordAngle(std::numeric_limits<double>::infinity());
+}
+
+inline S1ChordAngle S1ChordAngle::Negative() {
+  return S1ChordAngle(-1);
+}
+
+inline S1ChordAngle S1ChordAngle::Radians(double radians) {
+  return S1ChordAngle(S1Angle::Radians(radians));
+}
+
+inline S1ChordAngle S1ChordAngle::Degrees(double degrees) {
+  return S1ChordAngle(S1Angle::Degrees(degrees));
+}
+
+inline S1ChordAngle S1ChordAngle::E5(int32 e5) {
+  return S1ChordAngle(S1Angle::E5(e5));
+}
+
+inline S1ChordAngle S1ChordAngle::E6(int32 e6) {
+  return S1ChordAngle(S1Angle::E6(e6));
+}
+
+inline S1ChordAngle S1ChordAngle::E7(int32 e7) {
+  return S1ChordAngle(S1Angle::E7(e7));
+}
+
+inline S1ChordAngle S1ChordAngle::FastUpperBoundFrom(S1Angle angle) {
+  // This method uses the distance along the surface of the sphere as an upper
+  // bound on the distance through the sphere's interior.
+  return S1ChordAngle::FromLength2(angle.radians() * angle.radians());
+}
+
+inline S1ChordAngle::operator S1Angle() const {
+  return ToAngle();
+}
+
+inline double S1ChordAngle::radians() const {
+  return ToAngle().radians();
+}
+
+inline double S1ChordAngle::degrees() const {
+  return ToAngle().degrees();
+}
+
+inline int32 S1ChordAngle::e5() const {
+  return ToAngle().e5();
+}
+
+inline int32 S1ChordAngle::e6() const {
+  return ToAngle().e6();
+}
+
+inline int32 S1ChordAngle::e7() const {
+  return ToAngle().e7();
+}
+
+inline bool S1ChordAngle::is_zero() const {
+  return length2_ == 0;
+}
+
+inline bool S1ChordAngle::is_negative() const {
+  // TODO(ericv): Consider stricter check here -- only allow Negative().
+  return length2_ < 0;
+}
+
+inline bool S1ChordAngle::is_infinity() const {
+  return length2_ == std::numeric_limits<double>::infinity();
+}
+
+inline bool S1ChordAngle::is_special() const {
+  return is_negative() || is_infinity();
+}
+
+inline bool operator==(S1ChordAngle x, S1ChordAngle y) {
+  return x.length2() == y.length2();
+}
+
+inline bool operator!=(S1ChordAngle x, S1ChordAngle y) {
+  return x.length2() != y.length2();
+}
+
+inline bool operator<(S1ChordAngle x, S1ChordAngle y) {
+  return x.length2() < y.length2();
+}
+
+inline bool operator>(S1ChordAngle x, S1ChordAngle y) {
+  return x.length2() > y.length2();
+}
+
+inline bool operator<=(S1ChordAngle x, S1ChordAngle y) {
+  return x.length2() <= y.length2();
+}
+
+inline bool operator>=(S1ChordAngle x, S1ChordAngle y) {
+  return x.length2() >= y.length2();
+}
+
+inline S1ChordAngle& S1ChordAngle::operator+=(S1ChordAngle a) {
+  return (*this = *this + a);
+}
+
+inline S1ChordAngle& S1ChordAngle::operator-=(S1ChordAngle a) {
+  return (*this = *this - a);
+}
+
+// Outputs the chord angle as the equivalent S1Angle.
+std::ostream& operator<<(std::ostream& os, S1ChordAngle a);
+
+#endif  // S2_S1CHORD_ANGLE_H_
diff --git a/src/s2/s1interval.cc b/src/s2/s1interval.cc
new file mode 100644 (file)
index 0000000..d47875d
--- /dev/null
@@ -0,0 +1,296 @@
+// Copyright 2005 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// Author: ericv@google.com (Eric Veach)
+
+#include "s2/s1interval.h"
+
+#include <algorithm>
+#include <cfloat>
+#include <cmath>
+
+#include "s2/base/logging.h"
+
+using std::fabs;
+using std::max;
+
+S1Interval S1Interval::FromPoint(double p) {
+  if (p == -M_PI) p = M_PI;
+  return S1Interval(p, p, ARGS_CHECKED);
+}
+
+double S1Interval::GetCenter() const {
+  double center = 0.5 * (lo() + hi());
+  if (!is_inverted()) return center;
+  // Return the center in the range (-Pi, Pi].
+  return (center <= 0) ? (center + M_PI) : (center - M_PI);
+}
+
+double S1Interval::GetLength() const {
+  double length = hi() - lo();
+  if (length >= 0) return length;
+  length += 2 * M_PI;
+  // Empty intervals have a negative length.
+  return (length > 0) ? length : -1;
+}
+
+S1Interval S1Interval::Complement() const {
+  if (lo() == hi()) return Full();   // Singleton.
+  return S1Interval(hi(), lo(), ARGS_CHECKED);  // Handles empty and full.
+}
+
+double S1Interval::GetComplementCenter() const {
+  if (lo() != hi()) {
+    return Complement().GetCenter();
+  } else {  // Singleton.
+    return (hi() <= 0) ? (hi() + M_PI) : (hi() - M_PI);
+  }
+}
+
+bool S1Interval::FastContains(double p) const {
+  if (is_inverted()) {
+    return (p >= lo() || p <= hi()) && !is_empty();
+  } else {
+    return p >= lo() && p <= hi();
+  }
+}
+
+bool S1Interval::Contains(double p) const {
+  // Works for empty, full, and singleton intervals.
+  S2_DCHECK_LE(fabs(p), M_PI);
+  if (p == -M_PI) p = M_PI;
+  return FastContains(p);
+}
+
+bool S1Interval::InteriorContains(double p) const {
+  // Works for empty, full, and singleton intervals.
+  S2_DCHECK_LE(fabs(p), M_PI);
+  if (p == -M_PI) p = M_PI;
+
+  if (is_inverted()) {
+    return p > lo() || p < hi();
+  } else {
+    return (p > lo() && p < hi()) || is_full();
+  }
+}
+
+bool S1Interval::Contains(const S1Interval& y) const {
+  // It might be helpful to compare the structure of these tests to
+  // the simpler Contains(double) method above.
+
+  if (is_inverted()) {
+    if (y.is_inverted()) return y.lo() >= lo() && y.hi() <= hi();
+    return (y.lo() >= lo() || y.hi() <= hi()) && !is_empty();
+  } else {
+    if (y.is_inverted()) return is_full() || y.is_empty();
+    return y.lo() >= lo() && y.hi() <= hi();
+  }
+}
+
+bool S1Interval::InteriorContains(const S1Interval& y) const {
+  if (is_inverted()) {
+    if (!y.is_inverted()) return y.lo() > lo() || y.hi() < hi();
+    return (y.lo() > lo() && y.hi() < hi()) || y.is_empty();
+  } else {
+    if (y.is_inverted()) return is_full() || y.is_empty();
+    return (y.lo() > lo() && y.hi() < hi()) || is_full();
+  }
+}
+
+bool S1Interval::Intersects(const S1Interval& y) const {
+  if (is_empty() || y.is_empty()) return false;
+  if (is_inverted()) {
+    // Every non-empty inverted interval contains Pi.
+    return y.is_inverted() || y.lo() <= hi() || y.hi() >= lo();
+  } else {
+    if (y.is_inverted()) return y.lo() <= hi() || y.hi() >= lo();
+    return y.lo() <= hi() && y.hi() >= lo();
+  }
+}
+
+bool S1Interval::InteriorIntersects(const S1Interval& y) const {
+  if (is_empty() || y.is_empty() || lo() == hi()) return false;
+  if (is_inverted()) {
+    return y.is_inverted() || y.lo() < hi() || y.hi() > lo();
+  } else {
+    if (y.is_inverted()) return y.lo() < hi() || y.hi() > lo();
+    return (y.lo() < hi() && y.hi() > lo()) || is_full();
+  }
+}
+
+inline static double PositiveDistance(double a, double b) {
+  // Compute the distance from "a" to "b" in the range [0, 2*Pi).
+  // This is equivalent to (remainder(b - a - M_PI, 2 * M_PI) + M_PI),
+  // except that it is more numerically stable (it does not lose
+  // precision for very small positive distances).
+  double d = b - a;
+  if (d >= 0) return d;
+  // We want to ensure that if b == Pi and a == (-Pi + eps),
+  // the return result is approximately 2*Pi and not zero.
+  return (b + M_PI) - (a - M_PI);
+}
+
+double S1Interval::GetDirectedHausdorffDistance(const S1Interval& y) const {
+  if (y.Contains(*this)) return 0.0;  // this includes the case *this is empty
+  if (y.is_empty()) return M_PI;  // maximum possible distance on S1
+
+  double y_complement_center = y.GetComplementCenter();
+  if (Contains(y_complement_center)) {
+    return PositiveDistance(y.hi(), y_complement_center);
+  } else {
+    // The Hausdorff distance is realized by either two hi() endpoints or two
+    // lo() endpoints, whichever is farther apart.
+    double hi_hi = S1Interval(y.hi(), y_complement_center).Contains(hi()) ?
+        PositiveDistance(y.hi(), hi()) : 0;
+    double lo_lo = S1Interval(y_complement_center, y.lo()).Contains(lo()) ?
+        PositiveDistance(lo(), y.lo()) : 0;
+    S2_DCHECK(hi_hi > 0 || lo_lo > 0);
+    return max(hi_hi, lo_lo);
+  }
+}
+
+void S1Interval::AddPoint(double p) {
+  S2_DCHECK_LE(fabs(p), M_PI);
+  if (p == -M_PI) p = M_PI;
+
+  if (FastContains(p)) return;
+  if (is_empty()) {
+    set_hi(p);
+    set_lo(p);
+  } else {
+    // Compute distance from p to each endpoint.
+    double dlo = PositiveDistance(p, lo());
+    double dhi = PositiveDistance(hi(), p);
+    if (dlo < dhi) {
+      set_lo(p);
+    } else {
+      set_hi(p);
+    }
+    // Adding a point can never turn a non-full interval into a full one.
+  }
+}
+
+double S1Interval::Project(double p) const {
+  S2_DCHECK(!is_empty());
+  S2_DCHECK_LE(fabs(p), M_PI);
+  if (p == -M_PI) p = M_PI;
+  if (FastContains(p)) return p;
+  // Compute distance from p to each endpoint.
+  double dlo = PositiveDistance(p, lo());
+  double dhi = PositiveDistance(hi(), p);
+  return (dlo < dhi) ? lo() : hi();
+}
+
+S1Interval S1Interval::FromPointPair(double p1, double p2) {
+  S2_DCHECK_LE(fabs(p1), M_PI);
+  S2_DCHECK_LE(fabs(p2), M_PI);
+  if (p1 == -M_PI) p1 = M_PI;
+  if (p2 == -M_PI) p2 = M_PI;
+  if (PositiveDistance(p1, p2) <= M_PI) {
+    return S1Interval(p1, p2, ARGS_CHECKED);
+  } else {
+    return S1Interval(p2, p1, ARGS_CHECKED);
+  }
+}
+
+S1Interval S1Interval::Expanded(double margin) const {
+  if (margin >= 0) {
+    if (is_empty()) return *this;
+    // Check whether this interval will be full after expansion, allowing
+    // for a 1-bit rounding error when computing each endpoint.
+    if (GetLength() + 2 * margin + 2 * DBL_EPSILON >= 2 * M_PI) return Full();
+  } else {
+    if (is_full()) return *this;
+    // Check whether this interval will be empty after expansion, allowing
+    // for a 1-bit rounding error when computing each endpoint.
+    if (GetLength() + 2 * margin - 2 * DBL_EPSILON <= 0) return Empty();
+  }
+  S1Interval result(remainder(lo() - margin, 2*M_PI),
+                    remainder(hi() + margin, 2*M_PI));
+  if (result.lo() <= -M_PI) result.set_lo(M_PI);
+  return result;
+}
+
+S1Interval S1Interval::Union(const S1Interval& y) const {
+  // The y.is_full() case is handled correctly in all cases by the code
+  // below, but can follow three separate code paths depending on whether
+  // this interval is inverted, is non-inverted but contains Pi, or neither.
+
+  if (y.is_empty()) return *this;
+  if (FastContains(y.lo())) {
+    if (FastContains(y.hi())) {
+      // Either this interval contains y, or the union of the two
+      // intervals is the Full() interval.
+      if (Contains(y)) return *this;  // is_full() code path
+      return Full();
+    }
+    return S1Interval(lo(), y.hi(), ARGS_CHECKED);
+  }
+  if (FastContains(y.hi())) return S1Interval(y.lo(), hi(), ARGS_CHECKED);
+
+  // This interval contains neither endpoint of y.  This means that either y
+  // contains all of this interval, or the two intervals are disjoint.
+  if (is_empty() || y.FastContains(lo())) return y;
+
+  // Check which pair of endpoints are closer together.
+  double dlo = PositiveDistance(y.hi(), lo());
+  double dhi = PositiveDistance(hi(), y.lo());
+  if (dlo < dhi) {
+    return S1Interval(y.lo(), hi(), ARGS_CHECKED);
+  } else {
+    return S1Interval(lo(), y.hi(), ARGS_CHECKED);
+  }
+}
+
+S1Interval S1Interval::Intersection(const S1Interval& y) const {
+  // The y.is_full() case is handled correctly in all cases by the code
+  // below, but can follow three separate code paths depending on whether
+  // this interval is inverted, is non-inverted but contains Pi, or neither.
+
+  if (y.is_empty()) return Empty();
+  if (FastContains(y.lo())) {
+    if (FastContains(y.hi())) {
+      // Either this interval contains y, or the region of intersection
+      // consists of two disjoint subintervals.  In either case, we want
+      // to return the shorter of the two original intervals.
+      if (y.GetLength() < GetLength()) return y;  // is_full() code path
+      return *this;
+    }
+    return S1Interval(y.lo(), hi(), ARGS_CHECKED);
+  }
+  if (FastContains(y.hi())) return S1Interval(lo(), y.hi(), ARGS_CHECKED);
+
+  // This interval contains neither endpoint of y.  This means that either y
+  // contains all of this interval, or the two intervals are disjoint.
+
+  if (y.FastContains(lo())) return *this;  // is_empty() okay here
+  S2_DCHECK(!Intersects(y));
+  return Empty();
+}
+
+bool S1Interval::ApproxEquals(const S1Interval& y, double max_error) const {
+  // Full and empty intervals require special cases because the "endpoints"
+  // are considered to be positioned arbitrarily.
+  if (is_empty()) return y.GetLength() <= 2 * max_error;
+  if (y.is_empty()) return GetLength() <= 2 * max_error;
+  if (is_full()) return y.GetLength() >= 2 * (M_PI - max_error);
+  if (y.is_full()) return GetLength() >= 2 * (M_PI - max_error);
+
+  // The purpose of the last test below is to verify that moving the endpoints
+  // does not invert the interval, e.g. [-1e20, 1e20] vs. [1e20, -1e20].
+  return (fabs(remainder(y.lo() - lo(), 2 * M_PI)) <= max_error &&
+          fabs(remainder(y.hi() - hi(), 2 * M_PI)) <= max_error &&
+          fabs(GetLength() - y.GetLength()) <= 2 * max_error);
+}
diff --git a/src/s2/s1interval.h b/src/s2/s1interval.h
new file mode 100644 (file)
index 0000000..b37471a
--- /dev/null
@@ -0,0 +1,266 @@
+// Copyright 2005 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// Author: ericv@google.com (Eric Veach)
+
+#ifndef S2_S1INTERVAL_H_
+#define S2_S1INTERVAL_H_
+
+#include <cmath>
+#include <iosfwd>
+#include <iostream>
+
+#include "s2/base/logging.h"
+#include "s2/_fp_contract_off.h"
+#include "s2/util/math/vector.h"  // IWYU pragma: export
+
+// An S1Interval represents a closed interval on a unit circle (also known
+// as a 1-dimensional sphere).  It is capable of representing the empty
+// interval (containing no points), the full interval (containing all
+// points), and zero-length intervals (containing a single point).
+//
+// Points are represented by the angle they make with the positive x-axis in
+// the range [-Pi, Pi].  An interval is represented by its lower and upper
+// bounds (both inclusive, since the interval is closed).  The lower bound may
+// be greater than the upper bound, in which case the interval is "inverted"
+// (i.e. it passes through the point (-1, 0)).
+//
+// Note that the point (-1, 0) has two valid representations, Pi and -Pi.
+// The normalized representation of this point internally is Pi, so that
+// endpoints of normal intervals are in the range (-Pi, Pi].  However, we
+// take advantage of the point -Pi to construct two special intervals:
+// the Full() interval is [-Pi, Pi], and the Empty() interval is [Pi, -Pi].
+//
+// This class is intended to be copied by value as desired.  It uses
+// the default copy constructor and assignment operator.
+class S1Interval {
+ public:
+  // Constructor.  Both endpoints must be in the range -Pi to Pi inclusive.
+  // The value -Pi is converted internally to Pi except for the Full()
+  // and Empty() intervals.
+  S1Interval(double lo, double hi);
+
+  // The default constructor creates an empty interval.
+  //
+  // Note: Don't construct an interval using the default constructor and
+  // set_lo()/set_hi().  If you need to set both endpoints, use the
+  // constructor above:
+  //
+  //   lng_bounds_ = S1Interval(lng_lo, lng_hi);
+  S1Interval();
+
+  // Returns the empty interval.
+  static S1Interval Empty();
+
+  // Returns the full interval.
+  static S1Interval Full();
+
+  // Convenience method to construct an interval containing a single point.
+  static S1Interval FromPoint(double p);
+
+  // Convenience method to construct the minimal interval containing
+  // the two given points.  This is equivalent to starting with an empty
+  // interval and calling AddPoint() twice, but it is more efficient.
+  static S1Interval FromPointPair(double p1, double p2);
+
+  // Accessors methods.
+  double lo() const { return bounds_[0]; }
+  double hi() const { return bounds_[1]; }
+
+  // Methods that allow the S1Interval to be accessed as a vector.  (The
+  // recommended style is to use lo() and hi() whenever possible, but these
+  // methods are useful when the endpoint to be selected is not constant.)
+  //
+  // Only const versions of these methods are provided, since S1Interval
+  // has invariants that must be maintained after each update.
+  double operator[](int i) const { return bounds_[i]; }
+  const Vector2_d& bounds() const { return bounds_; }
+
+  // An interval is valid if neither bound exceeds Pi in absolute value,
+  // and the value -Pi appears only in the Empty() and Full() intervals.
+  bool is_valid() const;
+
+  // Return true if the interval contains all points on the unit circle.
+  bool is_full() const { return lo() == -M_PI && hi() == M_PI; }
+
+  // Return true if the interval is empty, i.e. it contains no points.
+  bool is_empty() const { return lo() == M_PI && hi() == -M_PI; }
+
+  // Return true if lo() > hi().  (This is true for empty intervals.)
+  bool is_inverted() const { return lo() > hi(); }
+
+  // Return the midpoint of the interval.  For full and empty intervals,
+  // the result is arbitrary.
+  double GetCenter() const;
+
+  // Return the length of the interval.  The length of an empty interval
+  // is negative.
+  double GetLength() const;
+
+  // Return the complement of the interior of the interval.  An interval and
+  // its complement have the same boundary but do not share any interior
+  // values.  The complement operator is not a bijection, since the complement
+  // of a singleton interval (containing a single value) is the same as the
+  // complement of an empty interval.
+  S1Interval Complement() const;
+
+  // Return the midpoint of the complement of the interval. For full and empty
+  // intervals, the result is arbitrary. For a singleton interval (containing a
+  // single point), the result is its antipodal point on S1.
+  double GetComplementCenter() const;
+
+  // Return true if the interval (which is closed) contains the point 'p'.
+  bool Contains(double p) const;
+
+  // Return true if the interior of the interval contains the point 'p'.
+  bool InteriorContains(double p) const;
+
+  // Return true if the interval contains the given interval 'y'.
+  // Works for empty, full, and singleton intervals.
+  bool Contains(const S1Interval& y) const;
+
+  // Returns true if the interior of this interval contains the entire
+  // interval 'y'.  Note that x.InteriorContains(x) is true only when
+  // x is the empty or full interval, and x.InteriorContains(S1Interval(p,p))
+  // is equivalent to x.InteriorContains(p).
+  bool InteriorContains(const S1Interval& y) const;
+
+  // Return true if the two intervals contain any points in common.
+  // Note that the point +/-Pi has two representations, so the intervals
+  // [-Pi,-3] and [2,Pi] intersect, for example.
+  bool Intersects(const S1Interval& y) const;
+
+  // Return true if the interior of this interval contains any point of the
+  // interval 'y' (including its boundary).  Works for empty, full, and
+  // singleton intervals.
+  bool InteriorIntersects(const S1Interval& y) const;
+
+  // Return the Hausdorff distance to the given interval 'y'. For two
+  // S1Intervals x and y, this distance is defined by
+  //     h(x, y) = max_{p in x} min_{q in y} d(p, q),
+  // where d(.,.) is measured along S1.
+  double GetDirectedHausdorffDistance(const S1Interval& y) const;
+
+  // Expand the interval by the minimum amount necessary so that it
+  // contains the given point "p" (an angle in the range [-Pi, Pi]).
+  void AddPoint(double p);
+
+  // Return the closest point in the interval to the given point "p".
+  // The interval must be non-empty.
+  double Project(double p) const;
+
+  // Return an interval that has been expanded on each side by the given
+  // distance "margin".  If "margin" is negative, then shrink the interval on
+  // each side by "margin" instead.  The resulting interval may be empty or
+  // full.  Any expansion (positive or negative) of a full interval remains
+  // full, and any expansion of an empty interval remains empty.
+  S1Interval Expanded(double margin) const;
+
+  // Return the smallest interval that contains this interval and the
+  // given interval "y".
+  S1Interval Union(const S1Interval& y) const;
+
+  // Return the smallest interval that contains the intersection of this
+  // interval with "y".  Note that the region of intersection may
+  // consist of two disjoint intervals.
+  S1Interval Intersection(const S1Interval& y) const;
+
+  // Return true if two intervals contains the same set of points.
+  bool operator==(const S1Interval& y) const;
+
+  // Return true if this interval can be transformed into the given interval by
+  // moving each endpoint by at most "max_error" (and without the endpoints
+  // crossing, which would invert the interval).  Empty and full intervals are
+  // considered to start at an arbitrary point on the unit circle, thus any
+  // interval with (length <= 2*max_error) matches the empty interval, and any
+  // interval with (length >= 2*Pi - 2*max_error) matches the full interval.
+  bool ApproxEquals(const S1Interval& y, double max_error = 1e-15) const;
+
+  // Low-level methods to modify one endpoint of an existing S1Interval.
+  // These methods should really be private because setting just one endpoint
+  // can violate the invariants maintained by S1Interval.  In particular:
+  //
+  //  - It is not valid to call these methods on an Empty() or Full()
+  //    interval, since these intervals do not have any endpoints.
+  //
+  //  - It is not allowed to set an endpoint to -Pi.  (When these methods are
+  //    used internally, values of -Pi have already been normalized to Pi.)
+  //
+  // The preferred way to modify both endpoints of an interval is to use a
+  // constructor, e.g. lng = S1Interval(lng_lo, lng_hi).
+  void set_lo(double p);
+  void set_hi(double p);
+
+ private:
+  enum ArgsChecked { ARGS_CHECKED };
+
+  // Internal constructor that assumes that both arguments are in the
+  // correct range, i.e. normalization from -Pi to Pi is already done.
+  S1Interval(double lo, double hi, ArgsChecked dummy);
+
+  // Return true if the interval (which is closed) contains the point 'p'.
+  // Skips the normalization of 'p' from -Pi to Pi.
+  bool FastContains(double p) const;
+
+  Vector2_d bounds_;
+};
+
+inline S1Interval::S1Interval(double lo, double hi) : bounds_(lo, hi) {
+  if (lo == -M_PI && hi != M_PI) set_lo(M_PI);
+  if (hi == -M_PI && lo != M_PI) set_hi(M_PI);
+  S2_DCHECK(is_valid());
+}
+
+inline S1Interval::S1Interval(double lo, double hi, ArgsChecked dummy)
+  : bounds_(lo, hi) {
+  S2_DCHECK(is_valid());
+}
+
+inline S1Interval::S1Interval() : bounds_(M_PI, -M_PI) {
+}
+
+inline S1Interval S1Interval::Empty() {
+  return S1Interval();
+}
+
+inline S1Interval S1Interval::Full() {
+  return S1Interval(-M_PI, M_PI, ARGS_CHECKED);
+}
+
+inline bool S1Interval::is_valid() const {
+  return (std::fabs(lo()) <= M_PI && std::fabs(hi()) <= M_PI &&
+          !(lo() == -M_PI && hi() != M_PI) &&
+          !(hi() == -M_PI && lo() != M_PI));
+}
+
+inline bool S1Interval::operator==(const S1Interval& y) const {
+  return lo() == y.lo() && hi() == y.hi();
+}
+
+inline void S1Interval::set_lo(double p) {
+  bounds_[0] = p;
+  S2_DCHECK(is_valid());
+}
+
+inline void S1Interval::set_hi(double p) {
+  bounds_[1] = p;
+  S2_DCHECK(is_valid());
+}
+
+inline std::ostream& operator<<(std::ostream& os, const S1Interval& x) {
+  return os << "[" << x.lo() << ", " << x.hi() << "]";
+}
+
+#endif  // S2_S1INTERVAL_H_
diff --git a/src/s2/s2boolean_operation.cc b/src/s2/s2boolean_operation.cc
new file mode 100644 (file)
index 0000000..4ef36c8
--- /dev/null
@@ -0,0 +1,2392 @@
+#include "cpp-compat.h"
+// Copyright 2017 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// Author: ericv@google.com (Eric Veach)
+//
+// Boolean operations are implemented by constructing the boundary of the
+// result and then using S2Builder to assemble the edges.  The boundary is
+// obtained by clipping each of the two input regions to the interior or
+// exterior of the other region.  For example, to compute the union of A and
+// B, we clip the boundary of A to the exterior of B and the boundary of B to
+// the exterior of A; the resulting set of edges defines the union of the two
+// regions.
+//
+// We use exact predicates, but inexact constructions (e.g. computing the
+// intersection point of two edges).  Nevertheless, the following algorithm is
+// guaranteed to be 100% robust, in that the computed boundary stays within a
+// small tolerance (snap_radius + S2::kIntersectionError) of the exact
+// result, and also preserves the correct topology (i.e., no crossing edges).
+//
+// Unfortunately this robustness cannot quite be achieved using the strategy
+// outlined above (clipping the two input regions and assembling the
+// resulting edges).  Since computed intersection points are not exact, the
+// input geometry passed to S2Builder might contain self-intersections, and
+// these self-intersections cannot be eliminated reliably by snap rounding.
+//
+// So instead, we pass S2Builder the entire set of input edges where at least
+// some portion of each edge belongs to the output boundary.  We allow
+// S2Builder to compute the intersection points and snap round the edges
+// (which it does in a way that is guaranteed to preserve the input topology).
+// Then once this is finished, we remove the portions of each edge that would
+// have been clipped if we had done the clipping first.  This step only
+// involves deciding whether to keep or discard each edge in the output, since
+// all intersection points have already been resolved, and therefore there is
+// no risk of creating new self-intersections.
+//
+// This is implemented using the following classes:
+//
+//  - S2BooleanOperation::Impl: the top-level class that clips each of
+//                              the two regions to the other region.
+//
+//  - CrossingProcessor: a class that processes edge crossings and maintains
+//                       the necessary state in order to clip the boundary
+//                       of one region to the interior or exterior of the
+//                       other region.
+//
+//  - EdgeClippingLayer: an S2Builder::Layer that removes graph edges that
+//                       correspond to clipped portions of input edges, and
+//                       passes the result to another layer for assembly.
+//
+//  - GraphEdgeClipper: a helper class that does the actual work of the
+//                      EdgeClippingLayer.
+
+#include "s2/s2boolean_operation.h"
+
+#include <algorithm>
+#include <limits>
+#include <memory>
+#include <utility>
+
+#include "absl/container/btree_map.h"
+#include "absl/memory/memory.h"
+#include "s2/s2builder.h"
+#include "s2/s2builder_layer.h"
+#include "s2/s2builderutil_snap_functions.h"
+#include "s2/s2contains_point_query.h"
+#include "s2/s2crossing_edge_query.h"
+#include "s2/s2edge_crosser.h"
+#include "s2/s2edge_crossings.h"
+#include "s2/s2measures.h"
+#include "s2/s2predicates.h"
+#include "s2/s2shape_index_measures.h"
+#include "s2/s2shapeutil_visit_crossing_edge_pairs.h"
+
+// TODO(ericv): Remove this debugging output at some point.
+extern bool s2builder_verbose;
+
+namespace {  // Anonymous namespace for helper classes.
+
+using absl::make_unique;
+using std::make_pair;
+using std::max;
+using std::min;
+using std::pair;
+using std::swap;
+using std::unique_ptr;
+using std::vector;
+
+using EdgeType = S2Builder::EdgeType;
+using SnapFunction = S2Builder::SnapFunction;
+using GraphOptions = S2Builder::GraphOptions;
+using DegenerateEdges = GraphOptions::DegenerateEdges;
+using DuplicateEdges = GraphOptions::DuplicateEdges;
+using SiblingPairs = GraphOptions::SiblingPairs;
+
+using Graph = S2Builder::Graph;
+using EdgeId = Graph::EdgeId;
+using VertexId = Graph::VertexId;
+using InputEdgeId = Graph::InputEdgeId;
+using InputEdgeIdSetId = Graph::InputEdgeIdSetId;
+
+using PolygonModel = S2BooleanOperation::PolygonModel;
+using PolylineModel = S2BooleanOperation::PolylineModel;
+using Precision = S2BooleanOperation::Precision;
+
+// A collection of special InputEdgeIds that allow the GraphEdgeClipper state
+// modifications to be inserted into the list of edge crossings.
+static const InputEdgeId kSetInside = -1;
+static const InputEdgeId kSetInvertB = -2;
+static const InputEdgeId kSetReverseA = -3;
+
+// CrossingInputEdge represents an input edge B that crosses some other input
+// edge A.  It stores the input edge id of edge B and also whether it crosses
+// edge A from left to right (or vice versa).
+class CrossingInputEdge {
+ public:
+  // Indicates that input edge "input_id" crosses another edge (from left to
+  // right if "left_to_right" is true).
+  CrossingInputEdge(InputEdgeId input_id, bool left_to_right)
+      : left_to_right_(left_to_right), input_id_(input_id) {
+  }
+
+  InputEdgeId input_id() const { return input_id_; }
+  bool left_to_right() const { return left_to_right_; }
+
+  bool operator<(const CrossingInputEdge& other) const {
+    return input_id_ < other.input_id_;
+  }
+  bool operator<(const InputEdgeId& other) const {
+    return input_id_ < other;
+  }
+
+ private:
+  bool left_to_right_ : 1;
+  InputEdgeId input_id_ : 31;
+};
+
+// InputEdgeCrossings represents all pairs of intersecting input edges.
+// It is sorted in lexicographic order.
+using InputEdgeCrossings = vector<pair<InputEdgeId, CrossingInputEdge>>;
+
+// Given two input edges A and B that intersect, suppose that A maps to a
+// chain of snapped edges A_0, A_1, ..., A_m and B maps to a chain of snapped
+// edges B_0, B_1, ..., B_n.  CrossingGraphEdge represents an edge from chain
+// B that shares a vertex with chain A.  It is used as a temporary data
+// representation while processing chain A.  The arguments are:
+//
+//   "id" - the Graph::EdgeId of an edge from chain B.
+//   "a_index" - the index of the vertex (A_i) that is shared with chain A.
+//   "outgoing" - true if the shared vertex is the first vertex of the B edge.
+//   "dst" - the Graph::VertexId of the vertex that is not shared with chain A.
+//
+// Note that if an edge from the B chain shares both vertices with the A
+// chain, there will be two entries: an outgoing edge that treats its first
+// vertex as being shared, and an incoming edge that treats its second vertex
+// as being shared.
+struct CrossingGraphEdge {
+  CrossingGraphEdge(EdgeId _id, int _a_index, bool _outgoing, VertexId _dst)
+      : id(_id), a_index(_a_index), outgoing(_outgoing), dst(_dst) {
+  }
+  EdgeId id;
+  int a_index;
+  bool outgoing;
+  VertexId dst;
+};
+using CrossingGraphEdgeVector = absl::InlinedVector<CrossingGraphEdge, 2>;
+
+// Returns a vector of EdgeIds sorted by input edge id.  When more than one
+// output edge has the same input edge id (i.e., the input edge snapped to a
+// chain of edges), the edges are sorted so that they form a directed edge
+// chain.
+//
+// This function could possibily be moved to S2Builder::Graph, but note that
+// it has special requirements.  Namely, duplicate edges and sibling pairs
+// must be kept in order to ensure that every output edge corresponds to
+// exactly one input edge.  (See also S2Builder::Graph::GetInputEdgeOrder.)
+static vector<EdgeId> GetInputEdgeChainOrder(
+    const Graph& g, const vector<InputEdgeId>& input_ids) {
+
+  S2_DCHECK(g.options().edge_type() == EdgeType::DIRECTED);
+  S2_DCHECK(g.options().duplicate_edges() == DuplicateEdges::KEEP);
+  S2_DCHECK(g.options().sibling_pairs() == SiblingPairs::KEEP);
+
+  // First, sort the edges so that the edges corresponding to each input edge
+  // are consecutive.  (Each input edge was snapped to a chain of output
+  // edges, or two chains in the case of undirected input edges.)
+  vector<EdgeId> order = g.GetInputEdgeOrder(input_ids);
+
+  // Now sort the group of edges corresponding to each input edge in edge
+  // chain order (e.g.  AB, BC, CD).
+  vector<pair<VertexId, EdgeId>> vmap;     // Map from source vertex to edge id.
+  vector<int> indegree(g.num_vertices());  // Restricted to current input edge.
+  for (int end, begin = 0; begin < order.size(); begin = end) {
+    // Gather the edges that came from a single input edge.
+    InputEdgeId input_id = input_ids[order[begin]];
+    for (end = begin; end < order.size(); ++end) {
+      if (input_ids[order[end]] != input_id) break;
+    }
+    if (end - begin == 1) continue;
+
+    // Build a map from the source vertex of each edge to its edge id,
+    // and also compute the indegree at each vertex considering only the edges
+    // that came from the current input edge.
+    for (int i = begin; i < end; ++i) {
+      EdgeId e = order[i];
+      vmap.push_back(make_pair(g.edge(e).first, e));
+      indegree[g.edge(e).second] += 1;
+    }
+    std::sort(vmap.begin(), vmap.end());
+
+    // Find the starting edge for building the edge chain.
+    EdgeId next = g.num_edges();
+    for (int i = begin; i < end; ++i) {
+      EdgeId e = order[i];
+      if (indegree[g.edge(e).first] == 0) next = e;
+    }
+    // Build the edge chain.
+    for (int i = begin; ;) {
+      order[i] = next;
+      VertexId v = g.edge(next).second;
+      indegree[v] = 0;  // Clear as we go along.
+      if (++i == end) break;
+      auto out = lower_bound(vmap.begin(), vmap.end(), make_pair(v, 0));
+      S2_DCHECK_EQ(v, out->first);
+      next = out->second;
+    }
+    vmap.clear();
+  }
+  return order;
+}
+
+// Given a set of clipping instructions encoded as a set of InputEdgeCrossings,
+// GraphEdgeClipper determines which graph edges correspond to clipped
+// portions of input edges and removes them.
+//
+// The clipping model is as follows.  The input consists of edge chains.  The
+// clipper maintains an "inside" boolean state as it clips each chain, and
+// toggles this state whenever an input edge is crossed.  Any edges that are
+// deemed to be "outside" after clipping are removed.
+//
+// The "inside" state can be reset when necessary (e.g., when jumping to the
+// start of a new chain) by adding a special crossing marked kSetInside.
+// There are also two other special "crossings" that modify the clipping
+// parameters: kSetInvertB specifies that edges should be clipped to the
+// exterior of the other region, and kSetReverseA specifies that edges should
+// be reversed before emitting them (which is needed to implement difference
+// operations).
+class GraphEdgeClipper {
+ public:
+  // "input_dimensions" is a vector specifying the dimension of each input
+  // edge (0, 1, or 2).  "input_crossings" is the set of all crossings to be
+  // used when clipping the edges of "g", sorted in lexicographic order.
+  //
+  // The clipped set of edges and their corresponding set of input edge ids
+  // are returned in "new_edges" and "new_input_edge_ids".  (These can be used
+  // to construct a new S2Builder::Graph.)
+  GraphEdgeClipper(const Graph& g, const vector<int8>& input_dimensions,
+                   const InputEdgeCrossings& input_crossings,
+                   vector<Graph::Edge>* new_edges,
+                   vector<InputEdgeIdSetId>* new_input_edge_ids);
+  void Run();
+
+ private:
+  void AddEdge(Graph::Edge edge, InputEdgeId input_edge_id);
+  void GatherIncidentEdges(
+      const vector<VertexId>& a, int ai,
+      const vector<CrossingInputEdge>& b_input_edges,
+      vector<CrossingGraphEdgeVector>* b_edges) const;
+  int GetCrossedVertexIndex(
+      const vector<VertexId>& a, const CrossingGraphEdgeVector& b,
+      bool left_to_right) const;
+  int GetVertexRank(const CrossingGraphEdge& e) const;
+  bool EdgeChainOnLeft(const vector<VertexId>& a,
+                       EdgeId b_first, EdgeId b_last) const;
+
+  const Graph& g_;
+  Graph::VertexInMap in_;
+  Graph::VertexOutMap out_;
+  const vector<int8>& input_dimensions_;
+  const InputEdgeCrossings& input_crossings_;
+  vector<Graph::Edge>* new_edges_;
+  vector<InputEdgeIdSetId>* new_input_edge_ids_;
+
+  // Every graph edge is associated with exactly one input edge in our case,
+  // which means that we can declare g_.input_edge_id_set_ids() as a vector of
+  // InputEdgeIds rather than a vector of InputEdgeIdSetIds.  (This also takes
+  // advantage of the fact that IdSetLexicon represents a singleton set as the
+  // value of its single element.)
+  const vector<InputEdgeId>& input_ids_;
+
+  vector<EdgeId> order_;  // Graph edges sorted in input edge id order.
+  vector<int> rank_;      // The rank of each graph edge within order_.
+};
+
+GraphEdgeClipper::GraphEdgeClipper(
+    const Graph& g, const vector<int8>& input_dimensions,
+    const InputEdgeCrossings& input_crossings,
+    vector<Graph::Edge>* new_edges,
+    vector<InputEdgeIdSetId>* new_input_edge_ids)
+    : g_(g), in_(g), out_(g),
+      input_dimensions_(input_dimensions),
+      input_crossings_(input_crossings),
+      new_edges_(new_edges),
+      new_input_edge_ids_(new_input_edge_ids),
+      input_ids_(g.input_edge_id_set_ids()),
+      order_(GetInputEdgeChainOrder(g_, input_ids_)),
+      rank_(order_.size()) {
+  for (int i = 0; i < order_.size(); ++i) {
+    rank_[order_[i]] = i;
+  }
+}
+
+inline void GraphEdgeClipper::AddEdge(Graph::Edge edge,
+                                      InputEdgeId input_edge_id) {
+  new_edges_->push_back(edge);
+  new_input_edge_ids_->push_back(input_edge_id);
+}
+
+void GraphEdgeClipper::Run() {
+  // Declare vectors here and reuse them to avoid reallocation.
+  vector<VertexId> a_vertices;
+  vector<int> a_num_crossings;
+  vector<bool> a_isolated;
+  vector<CrossingInputEdge> b_input_edges;
+  vector<CrossingGraphEdgeVector> b_edges;
+
+  bool inside = false;
+  bool invert_b = false;
+  bool reverse_a = false;
+  auto next = input_crossings_.begin();
+  for (int i = 0; i < order_.size(); ++i) {
+    // For each input edge (the "A" input edge), gather all the input edges
+    // that cross it (the "B" input edges).
+    InputEdgeId a_input_id = input_ids_[order_[i]];
+    const Graph::Edge& edge0 = g_.edge(order_[i]);
+    b_input_edges.clear();
+    for (; next != input_crossings_.end(); ++next) {
+      if (next->first != a_input_id) break;
+      if (next->second.input_id() >= 0) {
+        b_input_edges.push_back(next->second);
+      } else if (next->second.input_id() == kSetInside) {
+        inside = next->second.left_to_right();
+      } else if (next->second.input_id() == kSetInvertB) {
+        invert_b = next->second.left_to_right();
+      } else {
+        S2_DCHECK_EQ(next->second.input_id(), kSetReverseA);
+        reverse_a = next->second.left_to_right();
+      }
+    }
+    // Optimization for degenerate edges.
+    // TODO(ericv): If the output layer for this edge dimension specifies
+    // DegenerateEdges::DISCARD, then remove the edge here.
+    if (edge0.first == edge0.second) {
+      inside ^= (b_input_edges.size() & 1);
+      AddEdge(edge0, a_input_id);
+      continue;
+    }
+    // Optimization for the case where there are no crossings.
+    if (b_input_edges.empty()) {
+      // In general the caller only passes edges that are part of the output
+      // (i.e., we could S2_DCHECK(inside) here).  The one exception is for
+      // polyline/polygon operations, where the polygon edges are needed to
+      // compute the polyline output but are not emitted themselves.
+      if (inside) {
+        AddEdge(reverse_a ? Graph::reverse(edge0) : edge0, a_input_id);
+      }
+      continue;
+    }
+    // Walk along the chain of snapped edges for input edge A, and at each
+    // vertex collect all the incident edges that belong to one of the
+    // crossing edge chains (the "B" input edges).
+    a_vertices.clear();
+    a_vertices.push_back(edge0.first);
+    b_edges.clear();
+    b_edges.resize(b_input_edges.size());
+    GatherIncidentEdges(a_vertices, 0, b_input_edges, &b_edges);
+    for (; i < order_.size() && input_ids_[order_[i]] == a_input_id; ++i) {
+      a_vertices.push_back(g_.edge(order_[i]).second);
+      GatherIncidentEdges(a_vertices, a_vertices.size() - 1, b_input_edges,
+                          &b_edges);
+    }
+    --i;
+    if (s2builder_verbose) {
+      cpp_compat_cout << "input edge " << a_input_id << " (inside=" << inside << "):";
+      for (VertexId id : a_vertices) cpp_compat_cout << " " << id;
+    }
+    // Now for each B edge chain, decide which vertex of the A chain it
+    // crosses, and keep track of the number of signed crossings at each A
+    // vertex.  The sign of a crossing depends on whether the other edge
+    // crosses from left to right or right to left.
+    //
+    // This would not be necessary if all calculations were done in exact
+    // arithmetic, because crossings would have strictly alternating signs.
+    // But because we have already snapped the result, some crossing locations
+    // are ambiguous, and GetCrossedVertexIndex() handles this by choosing a
+    // candidate vertex arbitrarily.  The end result is that rarely, we may
+    // see two crossings in a row with the same sign.  We correct for this by
+    // adding extra output edges that essentially link up the crossings in the
+    // correct (alternating sign) order.  Compared to the "correct" behavior,
+    // the only difference is that we have added some extra sibling pairs
+    // (consisting of an edge and its corresponding reverse edge) which do not
+    // affect the result.
+    a_num_crossings.clear();
+    a_num_crossings.resize(a_vertices.size());
+    a_isolated.clear();
+    a_isolated.resize(a_vertices.size());
+    for (int bi = 0; bi < b_input_edges.size(); ++bi) {
+      bool left_to_right = b_input_edges[bi].left_to_right();
+      int a_index = GetCrossedVertexIndex(a_vertices, b_edges[bi],
+                                          left_to_right);
+      if (a_index >= 0) {
+        if (s2builder_verbose) {
+          cpp_compat_cout << std::endl << "  " << "b input edge "
+                    << b_input_edges[bi].input_id() << " (l2r=" << left_to_right
+                    << ", crossing=" << a_vertices[a_index] << ")";
+          for (const auto& x : b_edges[bi]) {
+            const Graph::Edge& e = g_.edge(x.id);
+            cpp_compat_cout << " (" << e.first << ", " << e.second << ")";
+          }
+        }
+        // Keep track of the number of signed crossings (see above).
+        bool is_line = input_dimensions_[b_input_edges[bi].input_id()] == 1;
+        int sign = is_line ? 0 : (left_to_right == invert_b) ? -1 : 1;
+        a_num_crossings[a_index] += sign;
+
+        // Any polyline or polygon vertex that has at least one crossing but no
+        // adjacent emitted edge may be emitted as an isolated vertex.
+        a_isolated[a_index] = true;
+      } else {
+        // TODO(b/112043775): fix this condition.
+        S2_LOG(DFATAL) << "Failed to get crossed vertex index.";
+      }
+    }
+    if (s2builder_verbose) cpp_compat_cout << std::endl;
+
+    // Finally, we iterate through the A edge chain, keeping track of the
+    // number of signed crossings as we go along.  The "multiplicity" is
+    // defined as the cumulative number of signed crossings, and indicates how
+    // many edges should be output (and in which direction) in order to link
+    // up the edge crossings in the correct order.  (The multiplicity is
+    // almost always either 0 or 1 except in very rare cases.)
+    int multiplicity = inside + a_num_crossings[0];
+    for (int ai = 1; ai < a_vertices.size(); ++ai) {
+      if (multiplicity != 0) {
+        a_isolated[ai - 1] = a_isolated[ai] = false;
+      }
+      int edge_count = reverse_a ? -multiplicity : multiplicity;
+      // Output any forward edges required.
+      for (int i = 0; i < edge_count; ++i) {
+        AddEdge(Graph::Edge(a_vertices[ai - 1], a_vertices[ai]), a_input_id);
+      }
+      // Output any reverse edges required.
+      for (int i = edge_count; i < 0; ++i) {
+        AddEdge(Graph::Edge(a_vertices[ai], a_vertices[ai - 1]), a_input_id);
+      }
+      multiplicity += a_num_crossings[ai];
+    }
+    // Multiplicities other than 0 or 1 can only occur in the edge interior.
+    S2_DCHECK(multiplicity == 0 || multiplicity == 1);
+    inside = (multiplicity != 0);
+
+    // Output any isolated polyline vertices.
+    // TODO(ericv): Only do this if an output layer wants degenerate edges.
+    if (input_dimensions_[a_input_id] != 0) {
+      for (int ai = 0; ai < a_vertices.size(); ++ai) {
+        if (a_isolated[ai]) {
+          AddEdge(Graph::Edge(a_vertices[ai], a_vertices[ai]), a_input_id);
+        }
+      }
+    }
+  }
+}
+
+// Given the vertices of the snapped edge chain for an input edge A and the
+// set of input edges B that cross input edge A, this method gathers all of
+// the snapped edges of B that are incident to a given snapped vertex of A.
+// The incident edges for each input edge of B are appended to a separate
+// output vector.  (A and B can refer to either the input edge or the
+// corresponding snapped edge chain.)
+void GraphEdgeClipper::GatherIncidentEdges(
+    const vector<VertexId>& a, int ai,
+    const vector<CrossingInputEdge>& b_input_edges,
+    vector<CrossingGraphEdgeVector>* b_edges) const {
+  // Examine all of the edges incident to the given vertex of A.  If any edge
+  // comes from a B input edge, append it to the appropriate vector.
+  S2_DCHECK_EQ(b_input_edges.size(), b_edges->size());
+  for (EdgeId e : in_.edge_ids(a[ai])) {
+    InputEdgeId id = input_ids_[e];
+    auto it = lower_bound(b_input_edges.begin(), b_input_edges.end(), id);
+    if (it != b_input_edges.end() && it->input_id() == id) {
+      auto& edges = (*b_edges)[it - b_input_edges.begin()];
+      edges.push_back(CrossingGraphEdge(e, ai, false, g_.edge(e).first));
+    }
+  }
+  for (EdgeId e : out_.edge_ids(a[ai])) {
+    InputEdgeId id = input_ids_[e];
+    auto it = lower_bound(b_input_edges.begin(), b_input_edges.end(), id);
+    if (it != b_input_edges.end() && it->input_id() == id) {
+      auto& edges = (*b_edges)[it - b_input_edges.begin()];
+      edges.push_back(CrossingGraphEdge(e, ai, true, g_.edge(e).second));
+    }
+  }
+}
+
+// Returns the "vertex rank" of the shared vertex associated with the given
+// CrossingGraphEdge.  Recall that graph edges are sorted in input edge order,
+// and that the rank of an edge is its position in this order (rank_[e]).
+// VertexRank(e) is defined such that VertexRank(e.src) == rank_[e] and
+// VertexRank(e.dst) == rank_[e] + 1.  Note that the concept of "vertex rank"
+// is only defined within a single edge chain (since different edge chains can
+// have overlapping vertex ranks).
+int GraphEdgeClipper::GetVertexRank(const CrossingGraphEdge& e) const {
+  return rank_[e.id] + !e.outgoing;
+}
+
+// Given an edge chain A that is crossed by another edge chain B (where
+// "left_to_right" indicates whether B crosses A from left to right), this
+// method decides which vertex of A the crossing takes place at.  The
+// parameters are the vertices of the A chain ("a") and the set of edges in
+// the B chain ("b") that are incident to vertices of A.  The B chain edges
+// are sorted in increasing order of (a_index, outgoing) tuple.
+int GraphEdgeClipper::GetCrossedVertexIndex(
+    const vector<VertexId>& a, const CrossingGraphEdgeVector& b,
+    bool left_to_right) const {
+  S2_DCHECK(!a.empty());
+  S2_DCHECK(!b.empty());
+
+  // The reason this calculation is tricky is that after snapping, the A and B
+  // chains may meet and separate several times.  For example, if B crosses A
+  // from left to right, then B may touch A, make an excursion to the left of
+  // A, come back to A, then make an excursion to the right of A and come back
+  // to A again, like this:
+  //
+  //  *--B--*-\             /-*-\
+  //           B-\       /-B     B-\      6     7     8     9
+  //  *--A--*--A--*-A,B-*--A--*--A--*-A,B-*--A--*--A--*-A,B-*
+  //  0     1     2     3     4     5      \-B     B-/
+  //                                          \-*-/
+  //
+  // (where "*" is a vertex, and "A" and "B" are edge labels).  Note that B
+  // may also follow A for one or more edges whenever they touch (e.g. between
+  // vertices 2 and 3).  In this case the only vertices of A where the
+  // crossing could take place are 5 and 6, i.e. after all excursions of B to
+  // the left of A, and before all excursions of B to the right of A.
+  //
+  // Other factors to consider are that the portion of B before and/or after
+  // the crossing may be degenerate, and some or all of the B edges may be
+  // reversed relative to the A edges.
+
+  // First, check whether edge A is degenerate.
+  int n = a.size();
+  if (n == 1) return 0;
+
+  // If edge chain B is incident to only one vertex of A, we're done.
+  if (b[0].a_index == b.back().a_index) return b[0].a_index;
+
+  // Determine whether the B chain visits the first and last vertices that it
+  // shares with the A chain in the same order or the reverse order.  This is
+  // only needed to implement one special case (see below).
+  bool b_reversed = GetVertexRank(b[0]) > GetVertexRank(b.back());
+
+  // Examine each incident B edge and use it to narrow the range of positions
+  // where the crossing could occur in the B chain.  Vertex positions are
+  // represented as a range [lo, hi] of vertex ranks in the B chain (see
+  // GetVertexRank).
+  //
+  // Note that if an edge of B is incident to the first or last vertex of A,
+  // we can't test which side of the A chain it is on.  (An s2pred::Sign test
+  // doesn't work; e.g. if the B edge is XY and the first edge of A is YZ,
+  // then snapping can change the sign of XYZ while maintaining topological
+  // guarantees.)  There can be up to 4 such edges (one incoming and one
+  // outgoing edge at each endpoint of A).  Two of these edges logically
+  // extend past the end of the A chain and place no restrictions on the
+  // crossing vertex.  The other two edges define the ends of the subchain
+  // where B shares vertices with A.  We save these edges in order to handle a
+  // special case (see below).
+  int lo = -1, hi = order_.size();   // Vertex ranks of acceptable crossings
+  EdgeId b_first = -1, b_last = -1;  // "b" subchain connecting "a" endpoints
+  for (const auto& e : b) {
+    int ai = e.a_index;
+    if (ai == 0) {
+      if (e.outgoing != b_reversed && e.dst != a[1]) b_first = e.id;
+    } else if (ai == n - 1) {
+      if (e.outgoing == b_reversed && e.dst != a[n - 2]) b_last = e.id;
+    } else {
+      // This B edge is incident to an interior vertex of the A chain.  First
+      // check whether this edge is identical (or reversed) to an edge in the
+      // A chain, in which case it does not create any restrictions.
+      if (e.dst == a[ai - 1] || e.dst == a[ai + 1]) continue;
+
+      // Otherwise we can test which side of the A chain the edge lies on.
+      bool on_left = s2pred::OrderedCCW(g_.vertex(a[ai + 1]), g_.vertex(e.dst),
+                                        g_.vertex(a[ai - 1]), g_.vertex(a[ai]));
+
+      // Every B edge that is incident to an interior vertex of the A chain
+      // places some restriction on where the crossing vertex could be.
+      if (left_to_right == on_left) {
+        // This is a pre-crossing edge, so the crossing cannot be before the
+        // destination vertex of this edge.  (For example, the input B edge
+        // crosses the input A edge from left to right and this edge of the B
+        // chain is to the left of the A chain.)
+        lo = max(lo, rank_[e.id] + 1);
+      } else {
+        // This is a post-crossing edge, so the crossing cannot be after the
+        // source vertex of this edge.
+        hi = min(hi, rank_[e.id]);
+      }
+    }
+  }
+  // There is one special case.  If a subchain of B connects the first and
+  // last vertices of A, then together with the edges of A this forms a loop
+  // whose orientation can be tested to determine whether B is on the left or
+  // right side of A.  This is only possible (and only necessary) if the B
+  // subchain does not include any interior vertices of A, since otherwise the
+  // B chain might cross from one side of A to the other.
+  //
+  // Note that it would be possible to avoid this test in some situations by
+  // checking whether either endpoint of the A chain has two incident B edges,
+  // in which case we could check which side of the B chain the A edge is on
+  // and use this to limit the possible crossing locations.
+  if (b_first >= 0 && b_last >= 0) {
+    // The B subchain connects the first and last vertices of A.  Test whether
+    // the chain includes any interior vertices of A.  We do this indirectly
+    // by testing whether any edge of B has restricted the range of allowable
+    // crossing vertices (since any interior edge of the B subchain incident
+    // to any interior edge of A is guaranteed to do so).
+    int min_rank = order_.size(), max_rank = -1;
+    for (const auto& e : b) {
+      min_rank = min(min_rank, GetVertexRank(e));
+      max_rank = max(max_rank, GetVertexRank(e));
+    }
+    if (lo <= min_rank && hi >= max_rank) {
+      // The B subchain is not incident to any interior vertex of A.
+      // Swap the edges if necessary so that they are in B chain order.
+      if (b_reversed) swap(b_first, b_last);
+      bool on_left = EdgeChainOnLeft(a, b_first, b_last);
+      if (left_to_right == on_left) {
+        lo = max(lo, rank_[b_last] + 1);
+      } else {
+        hi = min(hi, rank_[b_first]);
+      }
+    }
+  }
+
+  // Otherwise we choose the smallest shared VertexId in the acceptable range,
+  // in order to ensure that both chains choose the same crossing vertex.
+  int best = -1;
+  S2_DCHECK_LE(lo, hi);
+  for (const auto& e : b) {
+    int ai = e.a_index;
+    int vrank = GetVertexRank(e);
+    if (vrank >= lo && vrank <= hi && (best < 0 || a[ai] < a[best])) {
+      best = ai;
+    }
+  }
+  return best;
+}
+
+// Given edge chains A and B that form a loop (after possibly reversing the
+// direction of chain B), returns true if chain B is to the left of chain A.
+// Chain A is given as a sequence of vertices, while chain B is specified as
+// the first and last edges of the chain.
+bool GraphEdgeClipper::EdgeChainOnLeft(
+    const vector<VertexId>& a, EdgeId b_first, EdgeId b_last) const {
+  // Gather all the interior vertices of the B subchain.
+  vector<VertexId> loop;
+  for (int i = rank_[b_first]; i < rank_[b_last]; ++i) {
+    loop.push_back(g_.edge(order_[i]).second);
+  }
+  // Possibly reverse the chain so that it forms a loop when "a" is appended.
+  if (g_.edge(b_last).second != a[0]) std::reverse(loop.begin(), loop.end());
+  loop.insert(loop.end(), a.begin(), a.end());
+  // Duplicate the first two vertices to simplify vertex indexing.
+  for (int j = 0; j < 2; j++) {
+    loop.insert(loop.end(), *(loop.begin() + j));
+  }
+  // Now B is to the left of A if and only if the loop is counterclockwise.
+  double sum = 0;
+  for (int i = 2; i < loop.size(); ++i) {
+    sum += S2::TurnAngle(g_.vertex(loop[i - 2]), g_.vertex(loop[i - 1]),
+                         g_.vertex(loop[i]));
+  }
+  return sum > 0;
+}
+
+// Given a set of clipping instructions encoded as a set of intersections
+// between input edges, EdgeClippingLayer determines which graph edges
+// correspond to clipped portions of input edges and removes them.  It
+// assembles the remaining edges into a new S2Builder::Graph and passes the
+// result to the given output layer for assembly.
+class EdgeClippingLayer : public S2Builder::Layer {
+ public:
+  EdgeClippingLayer(const vector<unique_ptr<S2Builder::Layer>>* layers,
+                    const vector<int8>* input_dimensions,
+                    const InputEdgeCrossings* input_crossings)
+      : layers_(*layers),
+        input_dimensions_(*input_dimensions),
+        input_crossings_(*input_crossings) {
+  }
+
+  // Layer interface:
+  GraphOptions graph_options() const override;
+  void Build(const Graph& g, S2Error* error) override;
+
+ private:
+  const vector<unique_ptr<S2Builder::Layer>>& layers_;
+  const vector<int8>& input_dimensions_;
+  const InputEdgeCrossings& input_crossings_;
+};
+
+GraphOptions EdgeClippingLayer::graph_options() const {
+  // We keep all edges, including degenerate ones, so that we can figure out
+  // the correspondence between input edge crossings and output edge
+  // crossings.
+  return GraphOptions(EdgeType::DIRECTED, DegenerateEdges::KEEP,
+                      DuplicateEdges::KEEP, SiblingPairs::KEEP);
+}
+
+// Helper function (in anonymous namespace) to create an S2Builder::Graph from
+// a vector of edges.
+Graph MakeGraph(
+    const Graph& g, GraphOptions* options, vector<Graph::Edge>* new_edges,
+    vector<InputEdgeIdSetId>* new_input_edge_ids,
+    IdSetLexicon* new_input_edge_id_set_lexicon, S2Error* error) {
+  if (options->edge_type() == EdgeType::UNDIRECTED) {
+    // Create a reversed edge for every edge.
+    int n = new_edges->size();
+    new_edges->reserve(2 * n);
+    new_input_edge_ids->reserve(2 * n);
+    for (int i = 0; i < n; ++i) {
+      new_edges->push_back(Graph::reverse((*new_edges)[i]));
+      new_input_edge_ids->push_back(IdSetLexicon::EmptySetId());
+    }
+  }
+  Graph::ProcessEdges(options, new_edges, new_input_edge_ids,
+                      new_input_edge_id_set_lexicon, error);
+  return Graph(*options, &g.vertices(), new_edges, new_input_edge_ids,
+               new_input_edge_id_set_lexicon, &g.label_set_ids(),
+               &g.label_set_lexicon(), g.is_full_polygon_predicate());
+}
+
+void EdgeClippingLayer::Build(const Graph& g, S2Error* error) {
+  // The bulk of the work is handled by GraphEdgeClipper.
+  vector<Graph::Edge> new_edges;
+  vector<InputEdgeIdSetId> new_input_edge_ids;
+  // Destroy the GraphEdgeClipper immediately to save memory.
+  GraphEdgeClipper(g, input_dimensions_, input_crossings_,
+                   &new_edges, &new_input_edge_ids).Run();
+  if (s2builder_verbose) {
+    cpp_compat_cout << "Edges after clipping: " << std::endl;
+    for (int i = 0; i < new_edges.size(); ++i) {
+      cpp_compat_cout << "  " << new_input_edge_ids[i] << " (" << new_edges[i].first
+                << ", " << new_edges[i].second << ")" << std::endl;
+    }
+  }
+  // Construct one or more graphs from the clipped edges and pass them to the
+  // given output layer(s).
+  IdSetLexicon new_input_edge_id_set_lexicon;
+  if (layers_.size() == 1) {
+    GraphOptions options = layers_[0]->graph_options();
+    Graph new_graph = MakeGraph(g, &options, &new_edges, &new_input_edge_ids,
+                                &new_input_edge_id_set_lexicon, error);
+    layers_[0]->Build(new_graph, error);
+  } else {
+    // The Graph objects must be valid until the last Build() call completes,
+    // so we store all of the graph data in arrays with 3 elements.
+    S2_DCHECK_EQ(3, layers_.size());
+    vector<Graph::Edge> layer_edges[3];
+    vector<InputEdgeIdSetId> layer_input_edge_ids[3];
+    S2Builder::GraphOptions layer_options[3];
+    vector<S2Builder::Graph> layer_graphs;  // No default constructor.
+    layer_graphs.reserve(3);
+    // Separate the edges according to their dimension.
+    for (int i = 0; i < new_edges.size(); ++i) {
+      int d = input_dimensions_[new_input_edge_ids[i]];
+      layer_edges[d].push_back(new_edges[i]);
+      layer_input_edge_ids[d].push_back(new_input_edge_ids[i]);
+    }
+    // Clear variables to save space.
+    vector<Graph::Edge>().swap(new_edges);
+    vector<InputEdgeIdSetId>().swap(new_input_edge_ids);
+    for (int d = 0; d < 3; ++d) {
+      layer_options[d] = layers_[d]->graph_options();
+      layer_graphs.push_back(MakeGraph(
+          g, &layer_options[d], &layer_edges[d], &layer_input_edge_ids[d],
+          &new_input_edge_id_set_lexicon, error));
+      layers_[d]->Build(layer_graphs[d], error);
+    }
+  }
+}
+
+}  // namespace
+
+class S2BooleanOperation::Impl {
+ public:
+  explicit Impl(S2BooleanOperation* op)
+      : op_(op), index_crossings_first_region_id_(-1) {
+  }
+  bool Build(S2Error* error);
+
+ private:
+  class CrossingIterator;
+  class CrossingProcessor;
+  using ShapeEdge = s2shapeutil::ShapeEdge;
+  using ShapeEdgeId = s2shapeutil::ShapeEdgeId;
+
+  // An IndexCrossing represents a pair of intersecting S2ShapeIndex edges
+  // ("a_edge" and "b_edge").  We store all such intersections because the
+  // algorithm needs them twice, once when processing the boundary of region A
+  // and once when processing the boundary of region B.
+  struct IndexCrossing {
+    ShapeEdgeId a, b;
+
+    // True if S2::CrossingSign(a_edge, b_edge) > 0.
+    uint32 is_interior_crossing : 1;
+
+    // True if "a_edge" crosses "b_edge" from left to right.  Undefined if
+    // is_interior_crossing is false.
+    uint32 left_to_right: 1;
+
+    // Equal to S2::VertexCrossing(a_edge, b_edge).  Undefined if "a_edge" and
+    // "b_edge" do not share exactly one vertex or either edge is degenerate.
+    uint32 is_vertex_crossing : 1;
+
+    // All flags are "false" by default.
+    IndexCrossing(ShapeEdgeId _a, ShapeEdgeId _b)
+        : a(_a), b(_b), is_interior_crossing(false), left_to_right(false),
+          is_vertex_crossing(false) {
+    }
+
+    friend bool operator==(const IndexCrossing& x, const IndexCrossing& y) {
+      return x.a == y.a && x.b == y.b;
+    }
+    friend bool operator<(const IndexCrossing& x, const IndexCrossing& y) {
+      // The compiler (2017) doesn't optimize the following as well:
+      // return x.a < y.a || (x.a == y.a && x.b < y.b);
+      if (x.a.shape_id < y.a.shape_id) return true;
+      if (y.a.shape_id < x.a.shape_id) return false;
+      if (x.a.edge_id < y.a.edge_id) return true;
+      if (y.a.edge_id < x.a.edge_id) return false;
+      if (x.b.shape_id < y.b.shape_id) return true;
+      if (y.b.shape_id < x.b.shape_id) return false;
+      return x.b.edge_id < y.b.edge_id;
+    }
+  };
+  using IndexCrossings = vector<IndexCrossing>;
+
+  bool is_boolean_output() const { return op_->result_empty_ != nullptr; }
+
+  // All of the methods below support "early exit" in the case of boolean
+  // results by returning "false" as soon as the result is known to be
+  // non-empty.
+  bool AddBoundary(int a_region_id, bool invert_a, bool invert_b,
+                   bool invert_result,
+                   const vector<ShapeEdgeId>& a_chain_starts,
+                   CrossingProcessor* cp);
+  bool GetChainStarts(int a_region_id, bool invert_a, bool invert_b,
+                      bool invert_result, CrossingProcessor* cp,
+                      vector<ShapeEdgeId>* chain_starts);
+  bool ProcessIncidentEdges(const ShapeEdge& a,
+                            S2ContainsPointQuery<S2ShapeIndex>* query,
+                            CrossingProcessor* cp);
+  static bool HasInterior(const S2ShapeIndex& index);
+  static bool AddIndexCrossing(const ShapeEdge& a, const ShapeEdge& b,
+                               bool is_interior, IndexCrossings* crossings);
+  bool GetIndexCrossings(int region_id);
+  bool AddBoundaryPair(bool invert_a, bool invert_b, bool invert_result,
+                       CrossingProcessor* cp);
+  bool AreRegionsIdentical() const;
+  bool BuildOpType(OpType op_type);
+  bool IsFullPolygonResult(const S2Builder::Graph& g, S2Error* error) const;
+  bool IsFullPolygonUnion(const S2ShapeIndex& a,
+                          const S2ShapeIndex& b) const;
+  bool IsFullPolygonIntersection(const S2ShapeIndex& a,
+                                 const S2ShapeIndex& b) const;
+  bool IsFullPolygonDifference(const S2ShapeIndex& a,
+                               const S2ShapeIndex& b) const;
+  bool IsFullPolygonSymmetricDifference(const S2ShapeIndex& a,
+                                        const S2ShapeIndex& b) const;
+
+  // A bit mask representing all six faces of the S2 cube.
+  static constexpr uint8 kAllFacesMask = 0x3f;
+
+  S2BooleanOperation* op_;
+
+  // The S2Builder used to construct the output.
+  unique_ptr<S2Builder> builder_;
+
+  // A vector specifying the dimension of each edge added to S2Builder.
+  vector<int8> input_dimensions_;
+
+  // The set of all input edge crossings, which is used by EdgeClippingLayer
+  // to construct the clipped output polygon.
+  InputEdgeCrossings input_crossings_;
+
+  // kSentinel is a sentinel value used to mark the end of vectors.
+  static const ShapeEdgeId kSentinel;
+
+  // A vector containing all pairs of crossing edges from the two input
+  // regions (including edge pairs that share a common vertex).  The first
+  // element of each pair is an edge from "index_crossings_first_region_id_",
+  // while the second element of each pair is an edge from the other region.
+  IndexCrossings index_crossings_;
+
+  // Indicates that the first element of each crossing edge pair in
+  // "index_crossings_" corresponds to an edge from the given region.
+  // This field is negative if index_crossings_ has not been computed yet.
+  int index_crossings_first_region_id_;
+
+  // Temporary storage used in GetChainStarts(), declared here to avoid
+  // repeatedly allocating memory.
+  IndexCrossings tmp_crossings_;
+};
+
+const s2shapeutil::ShapeEdgeId S2BooleanOperation::Impl::kSentinel(
+    std::numeric_limits<int32>::max(), 0);
+
+// A helper class for iterating through the edges from region B that cross a
+// particular edge from region A.  It caches information from the current
+// shape, chain, and edge so that it doesn't need to be looked up repeatedly.
+// Typical usage:
+//
+//  void SomeFunction(ShapeEdgeId a_id, CrossingIterator *it) {
+//    // Iterate through the edges that cross edge "a_id".
+//    for (; !it->Done(a_id); it->Next()) {
+//      ... use it->b_shape(), it->b_edge(), etc ...
+//    }
+class S2BooleanOperation::Impl::CrossingIterator {
+ public:
+  // Creates an iterator over crossing edge pairs (a, b) where "b" is an edge
+  // from "b_index".  "crossings_complete" indicates that "crossings" contains
+  // all edge crossings between the two regions (rather than a subset).
+  CrossingIterator(const S2ShapeIndex* b_index,
+                   const IndexCrossings* crossings, bool crossings_complete)
+      : b_index_(*b_index), it_(crossings->begin()), b_shape_id_(-1),
+        crossings_complete_(crossings_complete) {
+    Update();
+  }
+  void Next() {
+    ++it_;
+    Update();
+  }
+  bool Done(ShapeEdgeId id) const { return a_id() != id; }
+
+  // True if all edge crossings are available (see above).
+  bool crossings_complete() const { return crossings_complete_; }
+
+  // True if this crossing occurs at a point interior to both edges.
+  bool is_interior_crossing() const { return it_->is_interior_crossing; }
+
+  // Equal to S2::VertexCrossing(a_edge, b_edge), provided that a_edge and
+  // b_edge have exactly one vertex in common and neither edge is degenerate.
+  bool is_vertex_crossing() const { return it_->is_vertex_crossing; }
+
+  // True if a_edge crosses b_edge from left to right (for interior crossings).
+  bool left_to_right() const { return it_->left_to_right; }
+
+  ShapeEdgeId a_id() const { return it_->a; }
+  ShapeEdgeId b_id() const { return it_->b; }
+  const S2ShapeIndex& b_index() const { return b_index_; }
+  const S2Shape& b_shape() const { return *b_shape_; }
+  int b_dimension() const { return b_dimension_; }
+  int b_shape_id() const { return b_shape_id_; }
+  int b_edge_id() const { return b_id().edge_id; }
+
+  S2Shape::Edge b_edge() const {
+    return b_shape_->edge(b_edge_id());  // Opportunity to cache this.
+  }
+
+  // Information about the chain to which an edge belongs.
+  struct ChainInfo {
+    int chain_id;  // chain id
+    int start;     // starting edge id
+    int limit;     // limit edge id
+  };
+  // Returns a description of the chain to which the current B edge belongs.
+  const ChainInfo& b_chain_info() const {
+    if (b_info_.chain_id < 0) {
+      b_info_.chain_id = b_shape().chain_position(b_edge_id()).chain_id;
+      auto chain = b_shape().chain(b_info_.chain_id);
+      b_info_.start = chain.start;
+      b_info_.limit = chain.start + chain.length;
+    }
+    return b_info_;
+  }
+
+ private:
+  // Updates information about the B shape whenever it changes.
+  void Update() {
+    if (a_id() != kSentinel && b_id().shape_id != b_shape_id_) {
+      b_shape_id_ = b_id().shape_id;
+      b_shape_ = b_index_.shape(b_shape_id_);
+      b_dimension_ = b_shape_->dimension();
+      b_info_.chain_id = -1;  // Computed on demand.
+    }
+  }
+
+  const S2ShapeIndex& b_index_;
+  IndexCrossings::const_iterator it_;
+  const S2Shape* b_shape_;
+  int b_shape_id_;
+  int b_dimension_;
+  mutable ChainInfo b_info_;  // Computed on demand.
+  bool crossings_complete_;
+};
+
+// CrossingProcessor is a helper class that processes all the edges from one
+// region that cross a specific edge of the other region.  It outputs the
+// appropriate edges to an S2Builder, and outputs other information required
+// by GraphEdgeClipper to the given vectors.
+class S2BooleanOperation::Impl::CrossingProcessor {
+ public:
+  // Prepares to build output for the given polygon and polyline boundary
+  // models.  Edges are emitted to "builder", while other auxiliary data is
+  // appended to the given vectors.
+  //
+  // If a predicate is being evaluated (i.e., we do not need to construct the
+  // actual result), then "builder" and the various output vectors should all
+  // be nullptr.
+  CrossingProcessor(const PolygonModel& polygon_model,
+                    const PolylineModel& polyline_model,
+                    bool polyline_loops_have_boundaries,
+                    S2Builder* builder,
+                    vector<int8>* input_dimensions,
+                    InputEdgeCrossings *input_crossings)
+      : polygon_model_(polygon_model), polyline_model_(polyline_model),
+        polyline_loops_have_boundaries_(polyline_loops_have_boundaries),
+        builder_(builder), input_dimensions_(input_dimensions),
+        input_crossings_(input_crossings), prev_inside_(false) {
+  }
+
+  // Starts processing edges from the given region.  "invert_a", "invert_b",
+  // and "invert_result" indicate whether region A, region B, and/or the
+  // result should be inverted, which allows operations such as union and
+  // difference to be implemented.  For example, union is ~(~A & ~B).
+  //
+  // This method should be called in pairs, once to process the edges from
+  // region A and once to process the edges from region B.
+  void StartBoundary(int a_region_id, bool invert_a, bool invert_b,
+                     bool invert_result);
+
+  // Starts processing edges from the given shape.
+  void StartShape(const S2Shape* a_shape);
+
+  // Starts processing edges from the given chain.
+  void StartChain(int chain_id, S2Shape::Chain chain, bool inside);
+
+  // Processes the given edge "a_id".  "it" should be positioned to the set of
+  // edges from the other region that cross "a_id" (if any).
+  //
+  // Supports "early exit" in the case of boolean results by returning false
+  // as soon as the result is known to be non-empty.
+  bool ProcessEdge(ShapeEdgeId a_id, CrossingIterator* it);
+
+  // This method should be called after each pair of calls to StartBoundary.
+  // (The only operation that processes more than one pair of boundaries is
+  // SYMMETRIC_DIFFERENCE, which computes the union of A-B and B-A.)
+  //
+  // Resets the state of the CrossingProcessor.
+  void DoneBoundaryPair();
+
+  // Indicates whether the point being processed along the current edge chain
+  // is in the polygonal interior of the opposite region, using semi-open
+  // boundaries.  If "invert_b_" is true then this field is inverted.
+  //
+  // This value along with the set of incident edges can be used to compute
+  // whether the opposite region contains this point under any of the
+  // supported boundary models (PolylineModel::CLOSED, etc).
+  bool inside() const { return inside_; }
+
+ private:
+  // SourceEdgeCrossing represents an input edge that crosses some other
+  // edge; it crosses the edge from left to right iff the second parameter
+  // is "true".
+  using SourceEdgeCrossing = pair<SourceId, bool>;
+  struct PointCrossingResult;
+  struct EdgeCrossingResult;
+
+  InputEdgeId input_edge_id() const { return input_dimensions_->size(); }
+
+  // Returns true if the edges on either side of the first vertex of the
+  // current edge have not been emitted.
+  //
+  // REQUIRES: This method is called just after updating "inside_" for "v0".
+  bool is_v0_isolated(ShapeEdgeId a_id) const {
+    return !inside_ && v0_emitted_max_edge_id_ < a_id.edge_id;
+  }
+
+  // Returns true if "a_id" is the last edge of the current chain, and the
+  // edges on either side of the last vertex have not been emitted (including
+  // the possibility that the chain forms a loop).
+  bool is_chain_last_vertex_isolated(ShapeEdgeId a_id) const {
+    return (a_id.edge_id == chain_limit_ - 1 && !chain_v0_emitted_ &&
+            v0_emitted_max_edge_id_ <= a_id.edge_id);
+  }
+
+  // Returns true if the given polyline edge contains "v0", taking into
+  // account the specified PolylineModel.
+  bool polyline_contains_v0(int edge_id, int chain_start) const {
+    return (polyline_model_ != PolylineModel::OPEN || edge_id > chain_start);
+  }
+
+  void AddCrossing(const SourceEdgeCrossing& crossing) {
+    source_edge_crossings_.push_back(make_pair(input_edge_id(), crossing));
+  }
+
+  void SetClippingState(InputEdgeId parameter, bool state) {
+    AddCrossing(SourceEdgeCrossing(SourceId(parameter), state));
+  }
+
+  // Supports "early exit" in the case of boolean results by returning false
+  // as soon as the result is known to be non-empty.
+  bool AddEdge(ShapeEdgeId a_id, const S2Shape::Edge& a,
+               int dimension, int interior_crossings) {
+    if (builder_ == nullptr) return false;  // Boolean output.
+    if (interior_crossings > 0) {
+      // Build a map that translates temporary edge ids (SourceId) to
+      // the representation used by EdgeClippingLayer (InputEdgeId).
+      SourceId src_id(a_region_id_, a_id.shape_id, a_id.edge_id);
+      source_id_map_[src_id] = input_edge_id();
+    }
+    // Set the GraphEdgeClipper's "inside" state to match ours.
+    if (inside_ != prev_inside_) SetClippingState(kSetInside, inside_);
+    input_dimensions_->push_back(dimension);
+    builder_->AddEdge(a.v0, a.v1);
+    inside_ ^= (interior_crossings & 1);
+    prev_inside_ = inside_;
+    return true;
+  }
+
+  // Supports "early exit" in the case of boolean results by returning false
+  // as soon as the result is known to be non-empty.
+  bool AddPointEdge(const S2Point& p, int dimension) {
+    if (builder_ == nullptr) return false;  // Boolean output.
+    if (!prev_inside_) SetClippingState(kSetInside, true);
+    input_dimensions_->push_back(dimension);
+    builder_->AddEdge(p, p);
+    prev_inside_ = true;
+    return true;
+  }
+
+  bool ProcessEdge0(ShapeEdgeId a_id, const S2Shape::Edge& a,
+                    CrossingIterator* it);
+  bool ProcessEdge1(ShapeEdgeId a_id, const S2Shape::Edge& a,
+                    CrossingIterator* it);
+  bool ProcessEdge2(ShapeEdgeId a_id, const S2Shape::Edge& a,
+                    CrossingIterator* it);
+
+  void SkipCrossings(ShapeEdgeId a_id, CrossingIterator* it);
+  PointCrossingResult ProcessPointCrossings(
+      ShapeEdgeId a_id, const S2Point& a0, CrossingIterator* it) const;
+  EdgeCrossingResult ProcessEdgeCrossings(
+      ShapeEdgeId a_id, const S2Shape::Edge& a, CrossingIterator* it);
+
+  bool IsPolylineVertexInside(bool matches_polyline,
+                              bool matches_polygon) const;
+  bool IsPolylineEdgeInside(const EdgeCrossingResult& r) const;
+  bool PolylineEdgeContainsVertex(const S2Point& v,
+                                  const CrossingIterator& it) const;
+
+  // Constructor parameters:
+
+  PolygonModel polygon_model_;
+  PolylineModel polyline_model_;
+  bool polyline_loops_have_boundaries_;
+
+  // The output of the CrossingProcessor consists of a subset of the input
+  // edges that are emitted to "builder_", and some auxiliary information
+  // that allows GraphEdgeClipper to determine which segments of those input
+  // edges belong to the output.  The auxiliary information consists of the
+  // dimension of each input edge, and set of input edges from the other
+  // region that cross each input input edge.
+  S2Builder* builder_;
+  vector<int8>* input_dimensions_;
+  InputEdgeCrossings* input_crossings_;
+
+  // Fields set by StartBoundary:
+
+  int a_region_id_, b_region_id_;
+  bool invert_a_, invert_b_, invert_result_;
+  bool is_union_;  // True if this is a UNION operation.
+
+  // Fields set by StartShape:
+
+  const S2Shape* a_shape_;
+  int a_dimension_;
+
+  // Fields set by StartChain:
+
+  int chain_id_;
+  int chain_start_;
+  int chain_limit_;
+
+  // Fields updated by ProcessEdge:
+
+  // A temporary representation of input_crossings_ that is used internally
+  // until all necessary edges from *both* polygons have been emitted to the
+  // S2Builder.  This field is then converted by DoneBoundaryPair() into
+  // the InputEdgeCrossings format expected by GraphEdgeClipper.
+  //
+  // The reason that we can't construct input_crossings_ directly is that it
+  // uses InputEdgeIds to identify the edges from both polygons, and when we
+  // are processing edges from the first polygon, InputEdgeIds have not yet
+  // been assigned to the second polygon.  So instead this field identifies
+  // edges from the first polygon using an InputEdgeId, and edges from the
+  // second polygon using a (region_id, shape_id, edge_id) tuple (i.e., a
+  // SourceId).
+  //
+  // All crossings are represented twice, once to indicate that an edge from
+  // polygon 0 is crossed by an edge from polygon 1, and once to indicate that
+  // an edge from polygon 1 is crossed by an edge from polygon 0.
+  using SourceEdgeCrossings = vector<pair<InputEdgeId, SourceEdgeCrossing>>;
+  SourceEdgeCrossings source_edge_crossings_;
+
+  // A map that translates from SourceId (the (region_id, shape_id,
+  // edge_id) triple that identifies an S2ShapeIndex edge) to InputEdgeId (the
+  // sequentially increasing numbers assigned to input edges by S2Builder).
+  using SourceIdMap = absl::btree_map<SourceId, InputEdgeId>;
+  SourceIdMap source_id_map_;
+
+  // Indicates whether the point being processed along the current edge chain
+  // is in the polygonal interior of the opposite region, using semi-open
+  // boundaries.  If "invert_b_" is true then this field is inverted.
+  //
+  // Equal to: b_index_.Contains(current point) ^ invert_b_
+  bool inside_;
+
+  // The value of that "inside_" would have just before the end of the
+  // previous edge added to S2Builder.  This value is used to determine
+  // whether the GraphEdgeClipper state needs to be updated when jumping from
+  // one edge chain to another.
+  bool prev_inside_;
+
+  // The maximum edge id of any edge in the current chain whose v0 vertex has
+  // already been emitted.  This is used to determine when an isolated vertex
+  // needs to be emitted, e.g. when two closed polygons share only a vertex.
+  int v0_emitted_max_edge_id_;
+
+  // True if the first vertex of the current chain has been emitted.  This is
+  // used when processing loops in order to determine whether the first/last
+  // vertex of the loop should be emitted as an isolated vertex.
+  bool chain_v0_emitted_;
+};
+
+// See documentation above.
+void S2BooleanOperation::Impl::CrossingProcessor::StartBoundary(
+    int a_region_id, bool invert_a, bool invert_b, bool invert_result) {
+  a_region_id_ = a_region_id;
+  b_region_id_ = 1 - a_region_id;
+  invert_a_ = invert_a;
+  invert_b_ = invert_b;
+  invert_result_ = invert_result;
+  is_union_ = invert_b && invert_result;
+
+  // Specify to GraphEdgeClipper how these edges should be clipped.
+  SetClippingState(kSetReverseA, invert_a != invert_result);
+  SetClippingState(kSetInvertB, invert_b);
+}
+
+// See documentation above.
+inline void S2BooleanOperation::Impl::CrossingProcessor::StartShape(
+    const S2Shape* a_shape) {
+  a_shape_ = a_shape;
+  a_dimension_ = a_shape->dimension();
+}
+
+// See documentation above.
+inline void S2BooleanOperation::Impl::CrossingProcessor::StartChain(
+    int chain_id, S2Shape::Chain chain, bool inside) {
+  chain_id_ = chain_id;
+  chain_start_ = chain.start;
+  chain_limit_ = chain.start + chain.length;
+  inside_ = inside;
+  v0_emitted_max_edge_id_ = chain.start - 1;  // No edges emitted yet.
+  chain_v0_emitted_ = false;
+}
+
+// See documentation above.
+bool S2BooleanOperation::Impl::CrossingProcessor::ProcessEdge(
+    ShapeEdgeId a_id, CrossingIterator* it) {
+  // chain_edge() is faster than edge() when there are multiple chains.
+  auto a = a_shape_->chain_edge(chain_id_, a_id.edge_id - chain_start_);
+  if (a_dimension_ == 0) {
+    return ProcessEdge0(a_id, a, it);
+  } else if (a_dimension_ == 1) {
+    return ProcessEdge1(a_id, a, it);
+  } else {
+    S2_DCHECK_EQ(2, a_dimension_);
+    return ProcessEdge2(a_id, a, it);
+  }
+}
+
+// PointCrossingResult describes the relationship between a point from region A
+// and a set of crossing edges from region B.  For example, "matches_polygon"
+// indicates whether a polygon vertex from region B matches the given point.
+struct S2BooleanOperation::Impl::CrossingProcessor::PointCrossingResult {
+  PointCrossingResult()
+      : matches_point(false), matches_polyline(false), matches_polygon(false) {
+  }
+  // Note that "matches_polyline" is true only if the point matches a polyline
+  // vertex of B *and* the polyline contains that vertex, whereas
+  // "matches_polygon" is true if the point matches any polygon vertex.
+  bool matches_point;     // Matches point.
+  bool matches_polyline;  // Matches contained polyline vertex.
+  bool matches_polygon;   // Matches polygon vertex.
+};
+
+// Processes an edge of dimension 0 (i.e., a point) from region A.
+//
+// Supports "early exit" in the case of boolean results by returning false
+// as soon as the result is known to be non-empty.
+bool S2BooleanOperation::Impl::CrossingProcessor::ProcessEdge0(
+    ShapeEdgeId a_id, const S2Shape::Edge& a, CrossingIterator* it) {
+  S2_DCHECK_EQ(a.v0, a.v1);
+  // When a region is inverted, all points and polylines are discarded.
+  if (invert_a_ != invert_result_) {
+    SkipCrossings(a_id, it);
+    return true;
+  }
+  PointCrossingResult r = ProcessPointCrossings(a_id, a.v0, it);
+
+  // "contained" indicates whether the current point is inside the polygonal
+  // interior of the opposite region, using semi-open boundaries.
+  bool contained = inside_ ^ invert_b_;
+  if (r.matches_polygon && polygon_model_ != PolygonModel::SEMI_OPEN) {
+    contained = (polygon_model_ == PolygonModel::CLOSED);
+  }
+  if (r.matches_polyline) contained = true;
+
+  // The output of UNION includes duplicate values, so ensure that points are
+  // not suppressed by other points.
+  if (r.matches_point && !is_union_) contained = true;
+
+  // Test whether the point is contained after region B is inverted.
+  if (contained == invert_b_) return true;  // Don't exit early.
+  return AddPointEdge(a.v0, 0);
+}
+
+// Skip any crossings that were not needed to determine the result.
+inline void S2BooleanOperation::Impl::CrossingProcessor::SkipCrossings(
+    ShapeEdgeId a_id, CrossingIterator* it) {
+  while (!it->Done(a_id)) it->Next();
+}
+
+// Returns a summary of the relationship between a point from region A and
+// a set of crossing edges from region B (see PointCrossingResult).
+S2BooleanOperation::Impl::CrossingProcessor::PointCrossingResult
+S2BooleanOperation::Impl::CrossingProcessor::ProcessPointCrossings(
+    ShapeEdgeId a_id, const S2Point& a0, CrossingIterator* it) const {
+  PointCrossingResult r;
+  for (; !it->Done(a_id); it->Next()) {
+    if (it->b_dimension() == 0) {
+      r.matches_point = true;
+    } else if (it->b_dimension() == 1) {
+      if (PolylineEdgeContainsVertex(a0, *it)) {
+        r.matches_polyline = true;
+      }
+    } else {
+      r.matches_polygon = true;
+    }
+  }
+  return r;
+}
+
+// EdgeCrossingResult describes the relationship between an edge from region A
+// ("a_edge") and a set of crossing edges from region B.  For example,
+// "matches_polygon" indicates whether "a_edge" matches a polygon edge from
+// region B.
+struct S2BooleanOperation::Impl::CrossingProcessor::EdgeCrossingResult {
+  EdgeCrossingResult()
+      : matches_polyline(false), matches_polygon(false), matches_sibling(false),
+        a0_matches_polyline(false), a1_matches_polyline(false),
+        a0_matches_polygon(false), a1_matches_polygon(false),
+        a0_crossings(0), a1_crossings(0), interior_crossings(0) {
+  }
+  // These fields indicate that "a_edge" exactly matches an edge of B.
+  bool matches_polyline;     // Matches polyline edge (either direction).
+  bool matches_polygon;      // Matches polygon edge (same direction).
+  bool matches_sibling;      // Matches polygon edge (reverse direction).
+
+  // These fields indicate that a vertex of "a_edge" matches a polyline vertex
+  // of B *and* the polyline contains that vertex.
+  bool a0_matches_polyline;  // Start vertex matches contained polyline vertex.
+  bool a1_matches_polyline;  // End vertex matches contained polyline vertex.
+
+  // These fields indicate that a vertex of "a_edge" matches a polygon vertex
+  // of B.  (Unlike with polylines, the polygon may not contain that vertex.)
+  bool a0_matches_polygon;   // Start vertex matches polygon vertex.
+  bool a1_matches_polygon;   // End vertex matches polygon vertex.
+
+  // These fields count the number of edge crossings at the start vertex, end
+  // vertex, and interior of "a_edge".
+  int a0_crossings;          // Count of polygon crossings at start vertex.
+  int a1_crossings;          // Count of polygon crossings at end vertex.
+  int interior_crossings;    // Count of polygon crossings in edge interior.
+};
+
+// Processes an edge of dimension 1 (i.e., a polyline edge) from region A.
+//
+// Supports "early exit" in the case of boolean results by returning false
+// as soon as the result is known to be non-empty.
+bool S2BooleanOperation::Impl::CrossingProcessor::ProcessEdge1(
+    ShapeEdgeId a_id, const S2Shape::Edge& a, CrossingIterator* it) {
+  // When a region is inverted, all points and polylines are discarded.
+  if (invert_a_ != invert_result_) {
+    SkipCrossings(a_id, it);
+    return true;
+  }
+  // Evaluate whether the start vertex should belong to the output, in case it
+  // needs to be emitted as an isolated vertex.
+  EdgeCrossingResult r = ProcessEdgeCrossings(a_id, a, it);
+  bool a0_inside = IsPolylineVertexInside(r.a0_matches_polyline,
+                                          r.a0_matches_polygon);
+
+  // Test whether the entire polyline edge should be emitted (or not emitted)
+  // because it matches a polyline or polygon edge.
+  inside_ ^= (r.a0_crossings & 1);
+  if (inside_ != IsPolylineEdgeInside(r)) {
+    inside_ ^= true;   // Invert the inside_ state.
+    ++r.a1_crossings;  // Restore the correct (semi-open) state later.
+  }
+
+  // If neither edge adjacent to v0 was emitted, and this polyline contains
+  // v0, and the other region contains v0, then emit an isolated vertex.
+  if (!polyline_loops_have_boundaries_ && a_id.edge_id == chain_start_ &&
+      a.v0 == a_shape_->chain_edge(chain_id_,
+                                   chain_limit_ - chain_start_ - 1).v1) {
+    // This is the first vertex of a polyline loop, so we can't decide if it
+    // is isolated until we process the last polyline edge.
+    chain_v0_emitted_ = inside_;
+  } else if (is_v0_isolated(a_id) &&
+             polyline_contains_v0(a_id.edge_id, chain_start_) && a0_inside) {
+    if (!AddPointEdge(a.v0, 1)) return false;
+  }
+
+  // Test whether the entire edge or any part of it belongs to the output.
+  if (inside_ || r.interior_crossings > 0) {
+    // Note: updates "inside_" to correspond to the state just before a1.
+    if (!AddEdge(a_id, a, 1 /*dimension*/, r.interior_crossings)) {
+      return false;
+    }
+  }
+  // Remember whether the edge portion just before "a1" was emitted, so that
+  // we can decide whether "a1" need to be emitted as an isolated vertex.
+  if (inside_) v0_emitted_max_edge_id_ = a_id.edge_id + 1;
+
+  // Verify that edge crossings are being counted correctly.
+  inside_ ^= (r.a1_crossings & 1);
+  if (it->crossings_complete()) {
+    S2_DCHECK_EQ(MakeS2ContainsPointQuery(&it->b_index()).Contains(a.v1),
+              inside_ ^ invert_b_);
+  }
+
+  // Special case to test whether the last vertex of a polyline should be
+  // emitted as an isolated vertex.
+  if (it->crossings_complete() && is_chain_last_vertex_isolated(a_id) &&
+      (polyline_model_ == PolylineModel::CLOSED ||
+       (!polyline_loops_have_boundaries_ &&
+        a.v1 == a_shape_->chain_edge(chain_id_, chain_start_).v0)) &&
+      IsPolylineVertexInside(r.a1_matches_polyline, r.a1_matches_polygon)) {
+    if (!AddPointEdge(a.v1, 1)) return false;
+  }
+  return true;
+}
+
+// Returns true if the current point being processed (which must be a polyline
+// vertex) is contained by the opposite region (after inversion if "invert_b_"
+// is true).  "matches_polyline" and "matches_polygon" indicate whether the
+// vertex matches a polyline/polygon vertex of the opposite region.
+bool S2BooleanOperation::Impl::CrossingProcessor::IsPolylineVertexInside(
+    bool matches_polyline, bool matches_polygon) const {
+  // "contained" indicates whether the current point is inside the polygonal
+  // interior of the opposite region using semi-open boundaries.
+  bool contained = inside_ ^ invert_b_;
+
+  // For UNION the output includes duplicate polylines.  The test below
+  // ensures that isolated polyline vertices are not suppressed by other
+  // polyline vertices in the output.
+  if (matches_polyline && !is_union_) {
+    contained = true;
+  } else if (matches_polygon && polygon_model_ != PolygonModel::SEMI_OPEN) {
+    contained = (polygon_model_ == PolygonModel::CLOSED);
+  }
+  // Finally, invert the result if the opposite region should be inverted.
+  return contained ^ invert_b_;
+}
+
+// Returns true if the current polyline edge is contained by the opposite
+// region (after inversion if "invert_b_" is true).
+inline bool S2BooleanOperation::Impl::CrossingProcessor::IsPolylineEdgeInside(
+    const EdgeCrossingResult& r) const {
+  // "contained" indicates whether the current point is inside the polygonal
+  // interior of the opposite region using semi-open boundaries.
+  bool contained = inside_ ^ invert_b_;
+  if (r.matches_polyline && !is_union_) {
+    contained = true;
+  } else if (r.matches_polygon) {
+    // In the SEMI_OPEN model, polygon sibling pairs cancel each other and
+    // have no effect on point or edge containment.
+    if (!(r.matches_sibling && polygon_model_ == PolygonModel::SEMI_OPEN)) {
+      contained = (polygon_model_ != PolygonModel::OPEN);
+    }
+  } else if (r.matches_sibling) {
+    contained = (polygon_model_ == PolygonModel::CLOSED);
+  }
+  // Finally, invert the result if the opposite region should be inverted.
+  return contained ^ invert_b_;
+}
+
+// Processes an edge of dimension 2 (i.e., a polygon edge) from region A.
+//
+// Supports "early exit" in the case of boolean results by returning false
+// as soon as the result is known to be non-empty.
+bool S2BooleanOperation::Impl::CrossingProcessor::ProcessEdge2(
+    ShapeEdgeId a_id, const S2Shape::Edge& a, CrossingIterator* it) {
+  // In order to keep only one copy of any shared polygon edges, we only
+  // output shared edges when processing the second region.
+  bool emit_shared = (a_region_id_ == 1);
+
+  // Degeneracies such as isolated vertices and sibling pairs can only be
+  // created by intersecting CLOSED polygons or unioning OPEN polygons.
+  bool emit_degenerate =
+      (polygon_model_ == PolygonModel::CLOSED && !invert_a_ && !invert_b_) ||
+      (polygon_model_ == PolygonModel::OPEN && invert_a_ && invert_b_);
+
+  EdgeCrossingResult r = ProcessEdgeCrossings(a_id, a, it);
+  S2_DCHECK(!r.matches_polyline);
+  inside_ ^= (r.a0_crossings & 1);
+
+  // If only one region is inverted, matching/sibling relations are reversed.
+  // TODO(ericv): Update the following code to handle degenerate loops.
+  S2_DCHECK(!r.matches_polygon || !r.matches_sibling);
+  if (invert_a_ != invert_b_) swap(r.matches_polygon, r.matches_sibling);
+
+  // Test whether the entire polygon edge should be emitted (or not emitted)
+  // because it matches a polygon edge or its sibling.
+  bool new_inside = inside_;
+
+  // Shared edge are emitted only while processing the second region.
+  if (r.matches_polygon) new_inside = emit_shared;
+
+  // Sibling pairs are emitted only when degeneracies are desired.
+  if (r.matches_sibling) new_inside = emit_degenerate;
+  if (inside_ != new_inside) {
+    inside_ ^= true;   // Invert the inside_ state.
+    ++r.a1_crossings;  // Restore the correct (semi-open) state later.
+  }
+
+  // Test whether the first vertex of this edge should be emitted as an
+  // isolated degenerate vertex.
+  if (a_id.edge_id == chain_start_) {
+    chain_v0_emitted_ = inside_;
+  } else if (emit_shared && emit_degenerate && r.a0_matches_polygon &&
+             is_v0_isolated(a_id)) {
+    if (!AddPointEdge(a.v0, 2)) return false;
+  }
+
+  // Test whether the entire edge or any part of it belongs to the output.
+  if (inside_ || r.interior_crossings > 0) {
+    // Note: updates "inside_" to correspond to the state just before a1.
+    if (!AddEdge(a_id, a, 2 /*dimension*/, r.interior_crossings)) {
+      return false;
+    }
+  }
+
+  // Remember whether the edge portion just before "a1" was emitted, so that
+  // we can decide whether "a1" need to be emitted as an isolated vertex.
+  if (inside_) v0_emitted_max_edge_id_ = a_id.edge_id + 1;
+  inside_ ^= (r.a1_crossings & 1);
+
+  // Verify that edge crossings are being counted correctly.
+  if (it->crossings_complete()) {
+    S2_DCHECK_EQ(MakeS2ContainsPointQuery(&it->b_index()).Contains(a.v1),
+              inside_ ^ invert_b_);
+  }
+
+  // Special case to test whether the last vertex of a loop should be emitted
+  // as an isolated degenerate vertex.
+  if (emit_shared && emit_degenerate && r.a1_matches_polygon &&
+      it->crossings_complete() && is_chain_last_vertex_isolated(a_id)) {
+    if (!AddPointEdge(a.v1, 2)) return false;
+  }
+  return true;
+}
+
+// Returns a summary of the relationship between a test edge from region A and
+// a set of crossing edges from region B (see EdgeCrossingResult).
+//
+// NOTE(ericv): We could save a bit of work when matching polygon vertices by
+// passing in a flag saying whether this information is needed.  For example
+// if is only needed in ProcessEdge2 when (emit_shared && emit_degenerate).
+S2BooleanOperation::Impl::CrossingProcessor::EdgeCrossingResult
+S2BooleanOperation::Impl::CrossingProcessor::ProcessEdgeCrossings(
+    ShapeEdgeId a_id, const S2Shape::Edge& a, CrossingIterator* it) {
+  EdgeCrossingResult r;
+  if (it->Done(a_id)) return r;
+
+  // TODO(ericv): bool a_degenerate = (a.v0 == a.v1);
+  for (; !it->Done(a_id); it->Next()) {
+    // Polylines and polygons are not affected by point geometry.
+    if (it->b_dimension() == 0) continue;
+    S2Shape::Edge b = it->b_edge();
+    if (it->is_interior_crossing()) {
+      // The crossing occurs in the edge interior.  The condition below says
+      // that (1) polyline crossings don't affect polygon output, and (2)
+      // subtracting a crossing polyline from a polyline has no effect.
+      if (a_dimension_ <= it->b_dimension() &&
+          !(invert_b_ != invert_result_ && it->b_dimension() == 1)) {
+        SourceId src_id(b_region_id_, it->b_shape_id(), it->b_edge_id());
+        AddCrossing(make_pair(src_id, it->left_to_right()));
+      }
+      r.interior_crossings += (it->b_dimension() == 1) ? 2 : 1;
+    } else if (it->b_dimension() == 1) {
+      // Polygons are not affected by polyline geometry.
+      if (a_dimension_ == 2) continue;
+      if ((a.v0 == b.v0 && a.v1 == b.v1) || (a.v0 == b.v1 && a.v1 == b.v0)) {
+        r.matches_polyline = true;
+      }
+      if ((a.v0 == b.v0 || a.v0 == b.v1) &&
+          PolylineEdgeContainsVertex(a.v0, *it)) {
+        r.a0_matches_polyline = true;
+      }
+      if ((a.v1 == b.v0 || a.v1 == b.v1) &&
+          PolylineEdgeContainsVertex(a.v1, *it)) {
+        r.a1_matches_polyline = true;
+      }
+    } else {
+      S2_DCHECK_EQ(2, it->b_dimension());
+      if (a.v0 == b.v0 && a.v1 == b.v1) {
+        ++r.a0_crossings;
+        r.matches_polygon = true;
+      } else if (a.v0 == b.v1 && a.v1 == b.v0) {
+        ++r.a0_crossings;
+        r.matches_sibling = true;
+      } else if (it->is_vertex_crossing()) {
+        if (a.v0 == b.v0 || a.v0 == b.v1) {
+          ++r.a0_crossings;
+        } else {
+          ++r.a1_crossings;
+        }
+      }
+      if (a.v0 == b.v0 || a.v0 == b.v1) {
+        r.a0_matches_polygon = true;
+      }
+      if (a.v1 == b.v0 || a.v1 == b.v1) {
+        r.a1_matches_polygon = true;
+      }
+    }
+  }
+  return r;
+}
+
+// Returns true if the vertex "v" is contained by the polyline edge referred
+// to by the CrossingIterator "it", taking into account the PolylineModel.
+//
+// REQUIRES: it.b_dimension() == 1
+// REQUIRES: "v" is an endpoint of it.b_edge()
+bool S2BooleanOperation::Impl::CrossingProcessor::PolylineEdgeContainsVertex(
+    const S2Point& v, const CrossingIterator& it) const {
+  S2_DCHECK_EQ(1, it.b_dimension());
+  S2_DCHECK(it.b_edge().v0 == v || it.b_edge().v1 == v);
+
+  // Closed polylines contain all their vertices.
+  if (polyline_model_ == PolylineModel::CLOSED) return true;
+
+  // Note that the code below is structured so that it.b_edge() is not usually
+  // needed (since accessing the edge can be relatively expensive).
+  const auto& b_chain = it.b_chain_info();
+  int b_edge_id = it.b_edge_id();
+
+  // The last polyline vertex is never contained.  (For polyline loops, it is
+  // sufficient to treat the first vertex as begin contained.)  This case also
+  // handles degenerate polylines (polylines with one edge where v0 == v1),
+  // which do not contain any points.
+  if (b_edge_id == b_chain.limit - 1 && v == it.b_edge().v1) return false;
+
+  // Otherwise all interior vertices are contained.  The first polyline
+  // vertex is contained if either the polyline model is not OPEN, or the
+  // polyline forms a loop and polyline_loops_have_boundaries_ is false.
+  if (polyline_contains_v0(b_edge_id, b_chain.start)) return true;
+  if (v != it.b_edge().v0) return true;
+  if (polyline_loops_have_boundaries_) return false;
+  return v == it.b_shape().chain_edge(b_chain.chain_id,
+                                      b_chain.limit - b_chain.start - 1).v1;
+}
+
+// Translates the temporary representation of crossing edges (SourceId) into
+// the format expected by EdgeClippingLayer (InputEdgeId).
+void S2BooleanOperation::Impl::CrossingProcessor::DoneBoundaryPair() {
+  // Add entries that translate the "special" crossings.
+  source_id_map_[SourceId(kSetInside)] = kSetInside;
+  source_id_map_[SourceId(kSetInvertB)] = kSetInvertB;
+  source_id_map_[SourceId(kSetReverseA)] = kSetReverseA;
+  input_crossings_->reserve(input_crossings_->size() +
+                            source_edge_crossings_.size());
+  for (const auto& tmp : source_edge_crossings_) {
+    auto it = source_id_map_.find(tmp.second.first);
+    S2_DCHECK(it != source_id_map_.end());
+    input_crossings_->push_back(make_pair(
+        tmp.first, CrossingInputEdge(it->second, tmp.second.second)));
+  }
+  source_edge_crossings_.clear();
+  source_id_map_.clear();
+}
+
+// Clips the boundary of A to the interior of the opposite region B and adds
+// the resulting edges to the output.  Optionally, any combination of region
+// A, region B, and the result may be inverted, which allows operations such
+// as union and difference to be implemented.
+//
+// Note that when an input region is inverted with respect to the output
+// (e.g., invert_a != invert_result), all polygon edges are reversed and all
+// points and polylines are discarded, since the complement of such objects
+// cannot be represented.  (If you want to compute the complement of points
+// or polylines, you can use S2LaxPolygonShape to represent your geometry as
+// degenerate polygons instead.)
+//
+// This method must be called an even number of times (first to clip A to B
+// and then to clip B to A), calling DoneBoundaryPair() after each pair.
+//
+// Supports "early exit" in the case of boolean results by returning false
+// as soon as the result is known to be non-empty.
+bool S2BooleanOperation::Impl::AddBoundary(
+    int a_region_id, bool invert_a, bool invert_b, bool invert_result,
+    const vector<ShapeEdgeId>& a_chain_starts, CrossingProcessor* cp) {
+  const S2ShapeIndex& a_index = *op_->regions_[a_region_id];
+  const S2ShapeIndex& b_index = *op_->regions_[1 - a_region_id];
+  if (!GetIndexCrossings(a_region_id)) return false;
+  cp->StartBoundary(a_region_id, invert_a, invert_b, invert_result);
+
+  // Walk the boundary of region A and build a list of all edge crossings.
+  // We also keep track of whether the current vertex is inside region B.
+  auto next_start = a_chain_starts.begin();
+  CrossingIterator next_crossing(&b_index, &index_crossings_,
+                                 true /*crossings_complete*/);
+  ShapeEdgeId next_id = min(*next_start, next_crossing.a_id());
+  while (next_id != kSentinel) {
+    int a_shape_id = next_id.shape_id;
+    const S2Shape& a_shape = *a_index.shape(a_shape_id);
+    cp->StartShape(&a_shape);
+    while (next_id.shape_id == a_shape_id) {
+      // TODO(ericv): Special handling of dimension 0?  Can omit most of this
+      // code, including the loop, since all chains are of length 1.
+      int edge_id = next_id.edge_id;
+      S2Shape::ChainPosition chain_position = a_shape.chain_position(edge_id);
+      int chain_id = chain_position.chain_id;
+      S2Shape::Chain chain = a_shape.chain(chain_id);
+      bool start_inside = (next_id == *next_start);
+      if (start_inside) ++next_start;
+      cp->StartChain(chain_id, chain, start_inside);
+      int chain_limit = chain.start + chain.length;
+      while (edge_id < chain_limit) {
+        ShapeEdgeId a_id(a_shape_id, edge_id);
+        S2_DCHECK(cp->inside() || next_crossing.a_id() == a_id);
+        if (!cp->ProcessEdge(a_id, &next_crossing)) {
+          return false;
+        }
+        if (cp->inside()) {
+          ++edge_id;
+        } else if (next_crossing.a_id().shape_id == a_shape_id &&
+                   next_crossing.a_id().edge_id < chain_limit) {
+          edge_id = next_crossing.a_id().edge_id;
+        } else {
+          break;
+        }
+      }
+      next_id = min(*next_start, next_crossing.a_id());
+    }
+  }
+  return true;
+}
+
+// Returns the first edge of each edge chain from "a_region_id" whose first
+// vertex is contained by opposite region's polygons (using the semi-open
+// boundary model).  Each input region and the result region are inverted as
+// specified (invert_a, invert_b, and invert_result) before testing for
+// containment.  The algorithm uses these "chain starts" in order to clip the
+// boundary of A to the interior of B in an output-senstive way.
+//
+// This method supports "early exit" in the case where a boolean predicate is
+// being evaluated and the algorithm discovers that the result region will be
+// non-empty.
+bool S2BooleanOperation::Impl::GetChainStarts(
+    int a_region_id, bool invert_a, bool invert_b, bool invert_result,
+    CrossingProcessor* cp, vector<ShapeEdgeId>* chain_starts) {
+  const S2ShapeIndex& a_index = *op_->regions_[a_region_id];
+  const S2ShapeIndex& b_index = *op_->regions_[1 - a_region_id];
+
+  if (is_boolean_output()) {
+    // If boolean output is requested, then we use the CrossingProcessor to
+    // determine whether the first edge of each chain will be emitted to the
+    // output region.  This lets us terminate the operation early in many
+    // cases.
+    cp->StartBoundary(a_region_id, invert_a, invert_b, invert_result);
+  }
+
+  // If region B has no two-dimensional shapes and is not inverted, then by
+  // definition no chain starts are contained.  However if boolean output is
+  // requested then we check for containment anyway, since as a side effect we
+  // may discover that the result region is non-empty and terminate the entire
+  // operation early.
+  bool b_has_interior = HasInterior(b_index);
+  if (b_has_interior || invert_b || is_boolean_output()) {
+    auto query = MakeS2ContainsPointQuery(&b_index);
+    int num_shape_ids = a_index.num_shape_ids();
+    for (int shape_id = 0; shape_id < num_shape_ids; ++shape_id) {
+      S2Shape* a_shape = a_index.shape(shape_id);
+      if (a_shape == nullptr) continue;
+
+      // If region A is being subtracted from region B, points and polylines
+      // in region A can be ignored since these shapes never contribute to the
+      // output (they can only remove edges from region B).
+      if (invert_a != invert_result && a_shape->dimension() < 2) continue;
+
+      if (is_boolean_output()) cp->StartShape(a_shape);
+      int num_chains = a_shape->num_chains();
+      for (int chain_id = 0; chain_id < num_chains; ++chain_id) {
+        S2Shape::Chain chain = a_shape->chain(chain_id);
+        if (chain.length == 0) continue;
+        ShapeEdge a(shape_id, chain.start, a_shape->chain_edge(chain_id, 0));
+        bool inside = (b_has_interior && query.Contains(a.v0())) != invert_b;
+        if (inside) {
+          chain_starts->push_back(ShapeEdgeId(shape_id, chain.start));
+        }
+        if (is_boolean_output()) {
+          cp->StartChain(chain_id, chain, inside);
+          if (!ProcessIncidentEdges(a, &query, cp)) return false;
+        }
+      }
+    }
+  }
+  chain_starts->push_back(kSentinel);
+  return true;
+}
+
+bool S2BooleanOperation::Impl::ProcessIncidentEdges(
+    const ShapeEdge& a, S2ContainsPointQuery<S2ShapeIndex>* query,
+    CrossingProcessor* cp) {
+  tmp_crossings_.clear();
+  query->VisitIncidentEdges(a.v0(), [&a, this](const ShapeEdge& b) {
+      return AddIndexCrossing(a, b, false /*is_interior*/, &tmp_crossings_);
+    });
+  // Fast path for the common case where there are no incident edges.  We
+  // return false (terminating early) if the first chain edge will be emitted.
+  if (tmp_crossings_.empty()) {
+    return !cp->inside();
+  }
+  // Otherwise we invoke the full CrossingProcessor logic to determine whether
+  // the first chain edge will be emitted.
+  if (tmp_crossings_.size() > 1) {
+    std::sort(tmp_crossings_.begin(), tmp_crossings_.end());
+    // VisitIncidentEdges() should not generate any duplicate values.
+    S2_DCHECK(std::adjacent_find(tmp_crossings_.begin(), tmp_crossings_.end()) ==
+           tmp_crossings_.end());
+  }
+  tmp_crossings_.push_back(IndexCrossing(kSentinel, kSentinel));
+  CrossingIterator next_crossing(&query->index(), &tmp_crossings_,
+                                 false /*crossings_complete*/);
+  return cp->ProcessEdge(a.id(),  &next_crossing);
+}
+
+bool S2BooleanOperation::Impl::HasInterior(const S2ShapeIndex& index) {
+  for (int s = index.num_shape_ids(); --s >= 0; ) {
+    S2Shape* shape = index.shape(s);
+    if (shape && shape->dimension() == 2) return true;
+  }
+  return false;
+}
+
+inline bool S2BooleanOperation::Impl::AddIndexCrossing(
+    const ShapeEdge& a, const ShapeEdge& b, bool is_interior,
+    IndexCrossings* crossings) {
+  crossings->push_back(IndexCrossing(a.id(), b.id()));
+  IndexCrossing* crossing = &crossings->back();
+  if (is_interior) {
+    crossing->is_interior_crossing = true;
+    if (s2pred::Sign(a.v0(), a.v1(), b.v0()) > 0) {
+      crossing->left_to_right = true;
+    }
+  } else {
+    // TODO(ericv): This field isn't used unless one shape is a polygon and
+    // the other is a polyline or polygon, but we don't have the shape
+    // dimension information readily available here.
+    if (S2::VertexCrossing(a.v0(), a.v1(), b.v0(), b.v1())) {
+      crossing->is_vertex_crossing = true;
+    }
+  }
+  return true;  // Continue visiting.
+}
+
+// Initialize index_crossings_ to the set of crossing edge pairs such that the
+// first element of each pair is an edge from "region_id".
+//
+// Supports "early exit" in the case of boolean results by returning false
+// as soon as the result is known to be non-empty.
+bool S2BooleanOperation::Impl::GetIndexCrossings(int region_id) {
+  if (region_id == index_crossings_first_region_id_) return true;
+  if (index_crossings_first_region_id_ < 0) {
+    S2_DCHECK_EQ(region_id, 0);  // For efficiency, not correctness.
+    if (!s2shapeutil::VisitCrossingEdgePairs(
+            *op_->regions_[0], *op_->regions_[1],
+            s2shapeutil::CrossingType::ALL,
+            [this](const ShapeEdge& a, const ShapeEdge& b, bool is_interior) {
+              // For all supported operations (union, intersection, and
+              // difference), if the input edges have an interior crossing
+              // then the output is guaranteed to have at least one edge.
+              if (is_interior && is_boolean_output()) return false;
+              return AddIndexCrossing(a, b, is_interior, &index_crossings_);
+            })) {
+      return false;
+    }
+    if (index_crossings_.size() > 1) {
+      std::sort(index_crossings_.begin(), index_crossings_.end());
+      index_crossings_.erase(
+          std::unique(index_crossings_.begin(), index_crossings_.end()),
+          index_crossings_.end());
+    }
+    // Add a sentinel value to simplify the loop logic.
+    index_crossings_.push_back(IndexCrossing(kSentinel, kSentinel));
+    index_crossings_first_region_id_ = 0;
+  }
+  if (region_id != index_crossings_first_region_id_) {
+    for (auto& crossing : index_crossings_) {
+      swap(crossing.a, crossing.b);
+      // The following predicates get inverted when the edges are swapped.
+      crossing.left_to_right ^= true;
+      crossing.is_vertex_crossing ^= true;
+    }
+    std::sort(index_crossings_.begin(), index_crossings_.end());
+    index_crossings_first_region_id_ = region_id;
+  }
+  return true;
+}
+
+// Supports "early exit" in the case of boolean results by returning false
+// as soon as the result is known to be non-empty.
+bool S2BooleanOperation::Impl::AddBoundaryPair(
+    bool invert_a, bool invert_b, bool invert_result, CrossingProcessor* cp) {
+  // Optimization: if the operation is DIFFERENCE or SYMMETRIC_DIFFERENCE,
+  // it is worthwhile checking whether the two regions are identical (in which
+  // case the output is empty).
+  //
+  // TODO(ericv): When boolean output is requested there are other quick
+  // checks that could be done here, such as checking whether a full cell from
+  // one S2ShapeIndex intersects a non-empty cell of the other S2ShapeIndex.
+  auto type = op_->op_type();
+  if (type == OpType::DIFFERENCE || type == OpType::SYMMETRIC_DIFFERENCE) {
+    if (AreRegionsIdentical()) return true;
+  } else if (!is_boolean_output()) {
+  }
+  vector<ShapeEdgeId> a_starts, b_starts;
+  if (!GetChainStarts(0, invert_a, invert_b, invert_result, cp, &a_starts) ||
+      !GetChainStarts(1, invert_b, invert_a, invert_result, cp, &b_starts) ||
+      !AddBoundary(0, invert_a, invert_b, invert_result, a_starts, cp) ||
+      !AddBoundary(1, invert_b, invert_a, invert_result, b_starts, cp)) {
+    return false;
+  }
+  if (!is_boolean_output()) cp->DoneBoundaryPair();
+  return true;
+}
+
+// Supports "early exit" in the case of boolean results by returning false
+// as soon as the result is known to be non-empty.
+bool S2BooleanOperation::Impl::BuildOpType(OpType op_type) {
+  // CrossingProcessor does the real work of emitting the output edges.
+  CrossingProcessor cp(op_->options_.polygon_model(),
+                       op_->options_.polyline_model(),
+                       op_->options_.polyline_loops_have_boundaries(),
+                       builder_.get(), &input_dimensions_, &input_crossings_);
+  switch (op_type) {
+    case OpType::UNION:
+      // A | B == ~(~A & ~B)
+      return AddBoundaryPair(true, true, true, &cp);
+
+    case OpType::INTERSECTION:
+      // A & B
+      return AddBoundaryPair(false, false, false, &cp);
+
+    case OpType::DIFFERENCE:
+      // A - B = A & ~B
+      return AddBoundaryPair(false, true, false, &cp);
+
+    case OpType::SYMMETRIC_DIFFERENCE:
+      // Compute the union of (A - B) and (B - A).
+      return (AddBoundaryPair(false, true, false, &cp) &&
+              AddBoundaryPair(true, false, false, &cp));
+  }
+  S2_LOG(FATAL) << "Invalid S2BooleanOperation::OpType";
+  return false;
+}
+
+// Returns a bit mask indicating which of the 6 S2 cube faces intersect the
+// index contents.
+uint8 GetFaceMask(const S2ShapeIndex& index) {
+  uint8 mask = 0;
+  S2ShapeIndex::Iterator it(&index, S2ShapeIndex::BEGIN);
+  while (!it.done()) {
+    int face = it.id().face();
+    mask |= 1 << face;
+    it.Seek(S2CellId::FromFace(face + 1).range_min());
+  }
+  return mask;
+}
+
+// Given a polygon edge graph containing only degenerate edges and sibling edge
+// pairs, the purpose of this function is to decide whether the polygon is empty
+// or full except for the degeneracies, i.e. whether the degeneracies represent
+// shells or holes.
+bool S2BooleanOperation::Impl::IsFullPolygonResult(
+    const S2Builder::Graph& g, S2Error* error) const {
+  // If there are no edges of dimension 2, the result could be either the
+  // empty polygon or the full polygon.  Note that this is harder to determine
+  // than you might think due to snapping.  For example, the union of two
+  // non-empty polygons can be empty, because both polygons consist of tiny
+  // loops that are eliminated by snapping.  Similarly, even if two polygons
+  // both contain a common point their intersection can still be empty.
+  //
+  // We distinguish empty from full results using two heuristics:
+  //
+  //  1. We compute a bit mask representing the subset of the six S2 cube faces
+  //     intersected by each input geometry, and use this to determine if only
+  //     one of the two results is possible.  (This test is very fast.)  Note
+  //     that snapping will never cause the result to cover an entire extra
+  //     cube face because the maximum allowed snap radius is too small.
+  S2_DCHECK_LE(S2Builder::SnapFunction::kMaxSnapRadius().degrees(), 70);
+  //
+  //  2. We compute the area of each input geometry, and use this to bound the
+  //     minimum and maximum area of the result.  If only one of {0, 4*Pi} is
+  //     possible then we are done.  If neither is possible then we choose the
+  //     one that is closest to being possible (since snapping can change the
+  //     result area).  Both results are possible only when computing the
+  //     symmetric difference of two regions of area 2*Pi each, in which case we
+  //     must resort to additional heuristics (see below).
+  //
+  // TODO(ericv): Implement a predicate that uses the results of edge snapping
+  // directly, rather than computing areas.  This would not only be much faster
+  // but would also allows all cases to be handled 100% robustly.
+  const S2ShapeIndex& a = *op_->regions_[0];
+  const S2ShapeIndex& b = *op_->regions_[1];
+  switch (op_->op_type()) {
+    case OpType::UNION:
+      return IsFullPolygonUnion(a, b);
+
+    case OpType::INTERSECTION:
+      return IsFullPolygonIntersection(a, b);
+
+    case OpType::DIFFERENCE:
+      return IsFullPolygonDifference(a, b);
+
+    case OpType::SYMMETRIC_DIFFERENCE:
+      return IsFullPolygonSymmetricDifference(a, b);
+
+    default:
+      S2_LOG(FATAL) << "Invalid S2BooleanOperation::OpType";
+      return false;
+  }
+}
+
+bool S2BooleanOperation::Impl::IsFullPolygonUnion(
+    const S2ShapeIndex& a, const S2ShapeIndex& b) const {
+  // See comments in IsFullPolygonResult().  The most common case is that
+  // neither input polygon is empty but the result is empty due to snapping.
+
+  // The result can be full only if the union of the two input geometries
+  // intersects all six faces of the S2 cube.  This test is fast.
+  if ((GetFaceMask(a) | GetFaceMask(b)) != kAllFacesMask) return false;
+
+  // The union area satisfies:
+  //
+  //   max(A, B) <= Union(A, B) <= min(4*Pi, A + B)
+  //
+  // where A, B can refer to a polygon or its area.  We then choose the result
+  // that assumes the smallest amount of error.
+  double a_area = S2::GetArea(a), b_area = S2::GetArea(b);
+  double min_area = max(a_area, b_area);
+  double max_area = min(4 * M_PI, a_area + b_area);
+  return min_area > 4 * M_PI - max_area;
+}
+
+bool S2BooleanOperation::Impl::IsFullPolygonIntersection(
+    const S2ShapeIndex& a, const S2ShapeIndex& b) const {
+  // See comments in IsFullPolygonResult().  By far the most common case is
+  // that the result is empty.
+
+  // The result can be full only if each of the two input geometries
+  // intersects all six faces of the S2 cube.  This test is fast.
+  if ((GetFaceMask(a) & GetFaceMask(b)) != kAllFacesMask) return false;
+
+  // The intersection area satisfies:
+  //
+  //   max(0, A + B - 4*Pi) <= Intersection(A, B) <= min(A, B)
+  //
+  // where A, B can refer to a polygon or its area.  We then choose the result
+  // that assumes the smallest amount of error.
+  double a_area = S2::GetArea(a), b_area = S2::GetArea(b);
+  double min_area = max(0.0, a_area + b_area - 4 * M_PI);
+  double max_area = min(a_area, b_area);
+  return min_area > 4 * M_PI - max_area;
+}
+
+bool S2BooleanOperation::Impl::IsFullPolygonDifference(
+    const S2ShapeIndex& a, const S2ShapeIndex& b) const {
+  // See comments in IsFullPolygonResult().  By far the most common case is
+  // that the result is empty.
+
+  // The result can be full only if each cube face is intersected by the first
+  // geometry.  (The second geometry is irrelevant, since for example it could
+  // consist of a tiny loop on each S2 cube face.)  This test is fast.
+  if (GetFaceMask(a) != kAllFacesMask) return false;
+
+  // The difference area satisfies:
+  //
+  //   max(0, A - B) <= Difference(A, B) <= min(A, 4*Pi - B)
+  //
+  // where A, B can refer to a polygon or its area.  We then choose the result
+  // that assumes the smallest amount of error.
+  double a_area = S2::GetArea(a), b_area = S2::GetArea(b);
+  double min_area = max(0.0, a_area - b_area);
+  double max_area = min(a_area, 4 * M_PI - b_area);
+  return min_area > 4 * M_PI - max_area;
+}
+
+bool S2BooleanOperation::Impl::IsFullPolygonSymmetricDifference(
+    const S2ShapeIndex& a, const S2ShapeIndex& b) const {
+  // See comments in IsFullPolygonResult().  By far the most common case is
+  // that the result is empty.
+
+  // The result can be full only if the union of the two input geometries
+  // intersects all six faces of the S2 cube.  This test is fast.
+  uint8 a_mask = GetFaceMask(a);
+  uint8 b_mask = GetFaceMask(b);
+  if ((a_mask | b_mask) != kAllFacesMask) return false;
+
+  // The symmetric difference area satisfies:
+  //
+  //   |A - B| <= SymmetricDifference(A, B) <= 4*Pi - |4*Pi - (A + B)|
+  //
+  // where A, B can refer to a polygon or its area.
+  double a_area = S2::GetArea(a), b_area = S2::GetArea(b);
+  double min_area = fabs(a_area - b_area);
+  double max_area = 4 * M_PI - fabs(4 * M_PI - (a_area + b_area));
+
+  // Now we choose the result that assumes the smallest amount of error
+  // (min_area in the empty case, and (4*Pi - max_area) in the full case).
+  // However in the case of symmetric difference these two errors may be equal,
+  // meaning that the result is ambiguous.  This happens when both polygons have
+  // area 2*Pi.  Furthermore, this can happen even when the areas are not
+  // exactly 2*Pi due to snapping and area calculation errors.
+  //
+  // To determine whether the result is ambiguous, we compute a rough estimate
+  // of the maximum expected area error (including errors due to snapping),
+  // using the worst-case error bound for a hemisphere defined by 4 vertices.
+  auto edge_snap_radius = op_->options_.snap_function().snap_radius() +
+                          S2::kIntersectionError;  // split_crossing_edges
+  double hemisphere_area_error = 2 * M_PI * edge_snap_radius.radians() +
+                                 40 * DBL_EPSILON;  // GetCurvatureMaxError
+
+  // The following sign is the difference between the error needed for an empty
+  // result and the error needed for a full result.  It is negative if an
+  // empty result is possible, positive if a full result is possible, and zero
+  // if both results are possible.
+  double error_sign = min_area - (4 * M_PI - max_area);
+  if (fabs(error_sign) <= hemisphere_area_error) {
+    // Handling the ambiguous case correctly requires a more sophisticated
+    // algorithm (see below), but we can at least handle the simple cases by
+    // testing whether both input geometries intersect all 6 cube faces.  If
+    // not, then the result is definitely full.
+    if ((a_mask & b_mask) != kAllFacesMask) return true;
+
+    // Otherwise both regions have area 2*Pi and intersect all 6 cube faces.
+    // We choose "empty" in this case under the assumption that it is more
+    // likely that the user is computing the difference between two nearly
+    // identical polygons.
+    //
+    // TODO(ericv): Implement a robust algorithm based on examining the edge
+    // snapping results directly, or alternatively add another heuristic (such
+    // as testing containment of random points, or using a larger bit mask in
+    // the tests above, e.g. a 24-bit mask representing all level 1 cells).
+    return false;
+  }
+  return error_sign > 0;
+}
+
+bool S2BooleanOperation::Impl::AreRegionsIdentical() const {
+  const S2ShapeIndex* a = op_->regions_[0];
+  const S2ShapeIndex* b = op_->regions_[1];
+  if (a == b) return true;
+  int num_shape_ids = a->num_shape_ids();
+  if (num_shape_ids != b->num_shape_ids()) return false;
+  for (int s = 0; s < num_shape_ids; ++s) {
+    const S2Shape* a_shape = a->shape(s);
+    const S2Shape* b_shape = b->shape(s);
+    if (a_shape->dimension() != b_shape->dimension()) return false;
+    if (a_shape->dimension() == 2) {
+      auto a_ref = a_shape->GetReferencePoint();
+      auto b_ref = b_shape->GetReferencePoint();
+      if (a_ref.point != b_ref.point) return false;
+      if (a_ref.contained != b_ref.contained) return false;
+    }
+    int num_chains = a_shape->num_chains();
+    if (num_chains != b_shape->num_chains()) return false;
+    for (int c = 0; c < num_chains; ++c) {
+      S2Shape::Chain a_chain = a_shape->chain(c);
+      S2Shape::Chain b_chain = b_shape->chain(c);
+      S2_DCHECK_EQ(a_chain.start, b_chain.start);
+      if (a_chain.length != b_chain.length) return false;
+      for (int i = 0; i < a_chain.length; ++i) {
+        S2Shape::Edge a_edge = a_shape->chain_edge(c, i);
+        S2Shape::Edge b_edge = b_shape->chain_edge(c, i);
+        if (a_edge.v0 != b_edge.v0) return false;
+        if (a_edge.v1 != b_edge.v1) return false;
+      }
+    }
+  }
+  return true;
+}
+
+bool S2BooleanOperation::Impl::Build(S2Error* error) {
+  error->Clear();
+  if (is_boolean_output()) {
+    // BuildOpType() returns true if and only if the result has no edges.
+    S2Builder::Graph g;  // Unused by IsFullPolygonResult() implementation.
+    *op_->result_empty_ =
+        BuildOpType(op_->op_type()) && !IsFullPolygonResult(g, error);
+    return true;
+  }
+  // TODO(ericv): Rather than having S2Builder split the edges, it would be
+  // faster to call AddVertex() in this class and have a new S2Builder
+  // option that increases the edge_snap_radius_ to account for errors in
+  // the intersection point (the way that split_crossing_edges does).
+  S2Builder::Options options(op_->options_.snap_function());
+  options.set_split_crossing_edges(true);
+
+  // TODO(ericv): Ideally idempotent() should be true, but existing clients
+  // expect vertices closer than the full "snap_radius" to be snapped.
+  options.set_idempotent(false);
+  builder_ = make_unique<S2Builder>(options);
+  builder_->StartLayer(make_unique<EdgeClippingLayer>(
+      &op_->layers_, &input_dimensions_, &input_crossings_));
+
+  // Add a predicate that decides whether a result with no polygon edges should
+  // be interpreted as the empty polygon or the full polygon.
+  builder_->AddIsFullPolygonPredicate(
+      [this](const S2Builder::Graph& g, S2Error* error) {
+        return IsFullPolygonResult(g, error);
+      });
+  (void) BuildOpType(op_->op_type());
+  return builder_->Build(error);
+}
+
+S2BooleanOperation::Options::Options()
+    : snap_function_(make_unique<s2builderutil::IdentitySnapFunction>(
+          S1Angle::Zero())) {
+}
+
+S2BooleanOperation::Options::Options(const SnapFunction& snap_function)
+    : snap_function_(snap_function.Clone()) {
+}
+
+S2BooleanOperation::Options::Options(const Options& options)
+    :  snap_function_(options.snap_function_->Clone()),
+       polygon_model_(options.polygon_model_),
+       polyline_model_(options.polyline_model_),
+       polyline_loops_have_boundaries_(options.polyline_loops_have_boundaries_),
+       precision_(options.precision_),
+       conservative_output_(options.conservative_output_),
+       source_id_lexicon_(options.source_id_lexicon_) {
+}
+
+S2BooleanOperation::Options& S2BooleanOperation::Options::operator=(
+    const Options& options) {
+  snap_function_ = options.snap_function_->Clone();
+  polygon_model_ = options.polygon_model_;
+  polyline_model_ = options.polyline_model_;
+  polyline_loops_have_boundaries_ = options.polyline_loops_have_boundaries_;
+  precision_ = options.precision_;
+  conservative_output_ = options.conservative_output_;
+  source_id_lexicon_ = options.source_id_lexicon_;
+  return *this;
+}
+
+const SnapFunction& S2BooleanOperation::Options::snap_function() const {
+  return *snap_function_;
+}
+
+void S2BooleanOperation::Options::set_snap_function(
+    const SnapFunction& snap_function) {
+  snap_function_ = snap_function.Clone();
+}
+
+PolygonModel S2BooleanOperation::Options::polygon_model() const {
+  return polygon_model_;
+}
+
+void S2BooleanOperation::Options::set_polygon_model(PolygonModel model) {
+  polygon_model_ = model;
+}
+
+PolylineModel S2BooleanOperation::Options::polyline_model() const {
+  return polyline_model_;
+}
+
+void S2BooleanOperation::Options::set_polyline_model(PolylineModel model) {
+  polyline_model_ = model;
+}
+
+bool S2BooleanOperation::Options::polyline_loops_have_boundaries() const {
+  return polyline_loops_have_boundaries_;
+}
+
+void S2BooleanOperation::Options::set_polyline_loops_have_boundaries(
+    bool value) {
+  polyline_loops_have_boundaries_ = value;
+}
+
+Precision S2BooleanOperation::Options::precision() const {
+  return precision_;
+}
+
+bool S2BooleanOperation::Options::conservative_output() const {
+  return conservative_output_;
+}
+
+ValueLexicon<S2BooleanOperation::SourceId>*
+S2BooleanOperation::Options::source_id_lexicon() const {
+  return source_id_lexicon_;
+}
+
+const char* S2BooleanOperation::OpTypeToString(OpType op_type) {
+  switch (op_type) {
+    case OpType::UNION:                return "UNION";
+    case OpType::INTERSECTION:         return "INTERSECTION";
+    case OpType::DIFFERENCE:           return "DIFFERENCE";
+    case OpType::SYMMETRIC_DIFFERENCE: return "SYMMETRIC DIFFERENCE";
+    default:                           return "Unknown OpType";
+  }
+}
+
+S2BooleanOperation::S2BooleanOperation(OpType op_type,
+                                       const Options& options)
+    : op_type_(op_type), options_(options), result_empty_(nullptr) {
+}
+
+S2BooleanOperation::S2BooleanOperation(OpType op_type, bool* result_empty,
+                                       const Options& options)
+    : op_type_(op_type), options_(options),
+      result_empty_(result_empty) {
+}
+
+S2BooleanOperation::S2BooleanOperation(
+    OpType op_type, unique_ptr<S2Builder::Layer> layer, const Options& options)
+    : op_type_(op_type), options_(options), result_empty_(nullptr) {
+  layers_.push_back(std::move(layer));
+}
+
+S2BooleanOperation::S2BooleanOperation(
+    OpType op_type, vector<unique_ptr<S2Builder::Layer>> layers,
+    const Options& options)
+    : op_type_(op_type), options_(options), layers_(std::move(layers)),
+      result_empty_(nullptr) {
+}
+
+bool S2BooleanOperation::Build(const S2ShapeIndex& a,
+                               const S2ShapeIndex& b,
+                               S2Error* error) {
+  regions_[0] = &a;
+  regions_[1] = &b;
+  return Impl(this).Build(error);
+}
+
+bool S2BooleanOperation::IsEmpty(
+    OpType op_type, const S2ShapeIndex& a, const S2ShapeIndex& b,
+    const Options& options) {
+  bool result_empty;
+  S2BooleanOperation op(op_type, &result_empty, options);
+  S2Error error;
+  op.Build(a, b, &error);
+  S2_DCHECK(error.ok());
+  return result_empty;
+}
diff --git a/src/s2/s2boolean_operation.h b/src/s2/s2boolean_operation.h
new file mode 100644 (file)
index 0000000..acceb06
--- /dev/null
@@ -0,0 +1,501 @@
+// Copyright 2017 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// Author: ericv@google.com (Eric Veach)
+
+#ifndef S2_S2BOOLEAN_OPERATION_H_
+#define S2_S2BOOLEAN_OPERATION_H_
+
+#include <memory>
+#include <utility>
+#include <vector>
+#include "s2/s2builder.h"
+#include "s2/s2builder_graph.h"
+#include "s2/s2builder_layer.h"
+#include "s2/value_lexicon.h"
+
+// This class implements boolean operations (intersection, union, difference,
+// and symmetric difference) for regions whose boundaries are defined by
+// geodesic edges.
+//
+// S2BooleanOperation operates on exactly two input regions at a time.  Each
+// region is represented as an S2ShapeIndex and may contain any number of
+// points, polylines, and polygons.  The region is essentially the union of
+// these objects, except that polygon interiors must be disjoint from all
+// other geometry (including other polygon interiors).  If the input geometry
+// for a region does not meet this condition, it can be normalized by
+// computing its union first.  Note that points or polylines are allowed to
+// coincide with the boundaries of polygons.
+//
+// Degeneracies are supported.  A polygon loop or polyline may consist of a
+// single edge from a vertex to itself, and polygons may contain "sibling
+// pairs" consisting of an edge and its corresponding reverse edge.  Polygons
+// must not have any duplicate edges (due to the requirement that polygon
+// interiors are disjoint), but polylines may have duplicate edges or can even
+// be self-intersecting.
+//
+// Points and polyline edges are treated as multisets: if the same point or
+// polyline edge appears multiple times in the input, it will appear multiple
+// times in the output.  For example, the union of a point with an identical
+// point consists of two points.  This feature is useful for modeling large
+// sets of points or polylines as a single region while maintaining their
+// distinct identities, even when the points or polylines intersect each
+// other.  It is also useful for reconstructing polylines that loop back on
+// themselves.  If duplicate geometry is not desired, it can be merged by
+// GraphOptions::DuplicateEdges::MERGE in the S2Builder output layer.
+//
+// Polylines are always considered to be directed.  Polyline edges between the
+// same pair of vertices are defined to intersect even if the two edges are in
+// opposite directions.  (Undirected polylines can be modeled by specifying
+// GraphOptions::EdgeType::UNDIRECTED in the S2Builder output layer.)
+//
+// The output of each operation is sent to an S2Builder::Layer provided by the
+// client.  This allows clients to build any representation of the geometry
+// they choose.  It also allows the client to do additional postprocessing of
+// the output before building data structures; for example, the client can
+// easily discard degeneracies or convert them to another data type.
+//
+// The boundaries of polygons and polylines can be modeled as open, semi-open,
+// or closed.  Polyline boundaries are controlled by the PolylineModel class,
+// whose options are as follows:
+//
+//  - In the OPEN model, polylines do not contain their first or last vertex
+//    except for one special case: namely, if the polyline forms a loop and
+//    the polyline_loops_have_boundaries() option is set to false, then the
+//    first/last vertex is contained.
+//
+//  - In the SEMI_OPEN model, polylines contain all vertices except the last.
+//    Therefore if one polyline starts where another polyline stops, the two
+//    polylines do not intersect.
+//
+//  - In the CLOSED model, polylines contain all of their vertices.
+//
+// When multiple polylines are present, they are processed independently and
+// have no effect on each other.  For example, in the OPEN boundary model the
+// polyline ABC contains the vertex B, while set of polylines {AB, BC} does
+// not.  (If you want to treat the polylines as a union instead, with
+// boundaries merged according to the "mod 2" rule, this can be achieved by
+// reassembling the edges into maximal polylines using S2PolylineVectorLayer
+// with EdgeType::UNDIRECTED, DuplicateEdges::MERGE, and PolylineType::WALK.)
+//
+// Polygon boundaries are controlled by the PolygonModel class, which has the
+// following options:
+//
+//  - In the OPEN model, polygons do not contain their vertices or edges.
+//    This implies that a polyline that follows the boundary of a polygon will
+//    not intersect it.
+//
+//  - In the SEMI_OPEN model, polygon point containment is defined such that
+//    if several polygons tile the region around a vertex, then exactly one of
+//    those polygons contains that vertex.  Similarly polygons contain all of
+//    their edges, but none of their reversed edges.  This implies that a
+//    polyline and polygon edge with the same endpoints intersect if and only
+//    if they are in the same direction.  (This rule ensures that if a
+//    polyline is intersected with a polygon and its complement, the two
+//    resulting polylines do not have any edges in common.)
+//
+//  - In the CLOSED model, polygons contain all their vertices, edges, and
+//    reversed edges.  This implies that a polyline that shares an edge (in
+//    either direction) with a polygon is defined to intersect it.  Similarly,
+//    this is the only model where polygons that touch at a vertex or along an
+//    edge intersect.
+//
+// Note that PolylineModel and PolygonModel are defined as separate classes in
+// order to allow for possible future extensions.
+//
+// Operations between geometry of different dimensions are defined as follows:
+//
+//  - For UNION, the higher-dimensional shape always wins.  For example the
+//    union of a closed polygon A with a polyline B that coincides with the
+//    boundary of A consists only of the polygon A.
+//
+//  - For INTERSECTION, the lower-dimensional shape always wins.  For example,
+//    the intersection of a closed polygon A with a point B that coincides
+//    with a vertex of A consists only of the point B.
+//
+//  - For DIFFERENCE, higher-dimensional shapes are not affected by
+//    subtracting lower-dimensional shapes.  For example, subtracting a point
+//    or polyline from a polygon A yields the original polygon A.  This rule
+//    exists because in general, it is impossible to represent the output
+//    using the specified boundary model(s).  (Consider subtracting one vertex
+//    from a PolylineModel::CLOSED polyline, or subtracting one edge from a
+//    PolygonModel::CLOSED polygon.)  If you want to perform operations like
+//    this, consider representing all boundaries explicitly (topological
+//    boundaries) using OPEN boundary models.  Another option for polygons is
+//    to subtract a degenerate loop, which yields a polygon with a degenerate
+//    hole (see S2LaxPolygonShape).
+//
+// Note that in the case of Precision::EXACT operations, the above remarks
+// only apply to the output before snapping.  Snapping may cause nearby
+// distinct edges to become coincident, e.g. a polyline may become coincident
+// with a polygon boundary.  However also note that S2BooleanOperation is
+// perfectly happy to accept such geometry as input.
+//
+// Note the following differences between S2BooleanOperation and the similar
+// S2MultiBooleanOperation class:
+//
+//  - S2BooleanOperation operates on exactly two regions at a time, whereas
+//    S2MultiBooleanOperation operates on any number of regions.
+//
+//  - S2BooleanOperation is potentially much faster when the input is already
+//    represented as S2ShapeIndexes.  The algorithm is output sensitive and is
+//    often sublinear in the input size.  This can be a big advantage if, say,
+//
+//  - S2BooleanOperation supports exact predicates and the corresponding
+//    exact operations (i.e., operations that are equivalent to computing the
+//    exact result and then snap rounding it).
+//
+//  - S2MultiBooleanOperation has better error guarantees when there are many
+//    regions, since it requires only one snapping operation for any number of
+//    input regions.
+//
+// Example usage:
+//   S2ShapeIndex a, b;  // Input geometry, e.g. containing polygons.
+//   S2Polygon polygon;  // Output geometry.
+//   S2BooleanOperation::Options options;
+//   options.set_snap_function(snap_function);
+//   S2BooleanOperation op(S2BooleanOperation::OpType::INTERSECTION,
+//                         absl::make_unique<S2PolygonLayer>(&polygon),
+//                         options);
+//   S2Error error;
+//   if (!op.Build(a, b, &error)) {
+//     S2_LOG(ERROR) << error;
+//     ...
+//   }
+//
+// If the output includes objects of different dimensions, they can be
+// assembled into different layers with code like this:
+//
+//   vector<S2Point> points;
+//   vector<unique_ptr<S2Polyline>> polylines;
+//   S2Polygon polygon;
+//   S2BooleanOperation op(
+//       S2BooleanOperation::OpType::UNION,
+//       absl::make_unique<s2builderutil::PointVectorLayer>(&points),
+//       absl::make_unique<s2builderutil::S2PolylineVectorLayer>(&polylines),
+//       absl::make_unique<S2PolygonLayer>(&polygon));
+
+class S2BooleanOperation {
+ public:
+  // The supported operation types.
+  enum class OpType {
+    UNION,                // Contained by either region.
+    INTERSECTION,         // Contained by both regions.
+    DIFFERENCE,           // Contained by the first region but not the second.
+    SYMMETRIC_DIFFERENCE  // Contained by one region but not the other.
+  };
+  // Translates OpType to one of the strings above.
+  static const char* OpTypeToString(OpType op_type);
+
+  // Defines whether polygons are considered to contain their vertices and/or
+  // edges (see definitions above).
+  enum class PolygonModel { OPEN, SEMI_OPEN, CLOSED };
+
+  // Defines whether polylines are considered to contain their endpoints
+  // (see definitions above).
+  enum class PolylineModel { OPEN, SEMI_OPEN, CLOSED };
+
+  // With Precision::EXACT, the operation is evaluated using the exact input
+  // geometry.  Predicates that use this option will produce exact results;
+  // for example, they can distinguish between a polyline that barely
+  // intersects a polygon from one that barely misses it.  Constructive
+  // operations (ones that yield new geometry, as opposed to predicates) are
+  // implemented by computing the exact result and then snap rounding it
+  // according to the given snap_function() (see below).  This is as close as
+  // it is possible to get to the exact result while requiring that vertex
+  // coordinates have type "double".
+  //
+  // With Precision::SNAPPED, the input regions are snapped together *before*
+  // the operation is evaluated.  So for example, two polygons that overlap
+  // slightly will be treated as though they share a common boundary, and
+  // similarly two polygons that are slightly separated from each other will
+  // be treated as though they share a common boundary.  Snapped results are
+  // useful for dealing with points, since in S2 the only points that lie
+  // exactly on a polyline or polygon edge are the endpoints of that edge.
+  //
+  // Conceptually, the difference between these two options is that with
+  // Precision::SNAPPED, the inputs are snap rounded (together), whereas with
+  // Precision::EXACT only the result is snap rounded.
+  enum class Precision { EXACT, SNAPPED };
+
+  // SourceId identifies an edge from one of the two input S2ShapeIndexes.
+  // It consists of a region id (0 or 1), a shape id within that region's
+  // S2ShapeIndex, and an edge id within that shape.
+  class SourceId {
+   public:
+    SourceId();
+    SourceId(int region_id, int32 shape_id, int32 edge_id);
+    explicit SourceId(int32 special_edge_id);
+    int region_id() const { return region_id_; }
+    int32 shape_id() const { return shape_id_; }
+    int32 edge_id() const { return edge_id_; }
+    // TODO(ericv): Convert to functions, define all 6 comparisons.
+    bool operator==(SourceId other) const;
+    bool operator<(SourceId other) const;
+
+   private:
+    uint32 region_id_ : 1;
+    uint32 shape_id_ : 31;
+    int32 edge_id_;
+  };
+
+  class Options {
+   public:
+    Options();
+
+    // Convenience constructor that calls set_snap_function().
+    explicit Options(const S2Builder::SnapFunction& snap_function);
+
+    // Specifies the function to be used for snap rounding.
+    //
+    // DEFAULT: s2builderutil::IdentitySnapFunction(S1Angle::Zero())
+    //  - This does no snapping and preserves all input vertices exactly unless
+    //    there are crossing edges, in which case the snap radius is increased
+    //    to the maximum intersection point error (S2::kIntersectionError).
+    const S2Builder::SnapFunction& snap_function() const;
+    void set_snap_function(const S2Builder::SnapFunction& snap_function);
+
+    // Defines whether polygons are considered to contain their vertices
+    // and/or edges (see comments above).
+    //
+    // DEFAULT: PolygonModel::SEMI_OPEN
+    PolygonModel polygon_model() const;
+    void set_polygon_model(PolygonModel model);
+
+    // Defines whether polylines are considered to contain their vertices (see
+    // comments above).
+    //
+    // DEFAULT: PolylineModel::CLOSED
+    PolylineModel polyline_model() const;
+    void set_polyline_model(PolylineModel model);
+
+    // Specifies whether a polyline loop is considered to have a non-empty
+    // boundary.  By default this option is true, meaning that even if the
+    // first and last vertices of a polyline are the same, the polyline is
+    // considered to have a well-defined "start" and "end".  For example, if
+    // the polyline boundary model is OPEN then the polyline loop would not
+    // include the start/end vertices.  These are the best semantics for most
+    // applications, such as GPS tracks or road network segments.
+    //
+    // If the polyline forms a loop and this option is set to false, then
+    // instead the first and last vertices are considered to represent a
+    // single vertex in the interior of the polyline.  In this case the
+    // boundary of the polyline is empty, meaning that the first/last vertex
+    // will be contained by the polyline even if the boundary model is OPEN.
+    // (Note that this option also has a small effect on the CLOSED boundary
+    // model, because the first/last vertices of a polyline loop are
+    // considered to represent one vertex rather than two.)
+    //
+    // The main reason for this option is to implement the "mod 2 union"
+    // boundary semantics of the OpenGIS Simple Features spec.  This can be
+    // achieved by making sure that all polylines are constructed using
+    // S2Builder::Graph::PolylineType::WALK (which ensures that all polylines
+    // are as long as possible), and then setting this option to false.
+    //
+    // DEFAULT: true
+    bool polyline_loops_have_boundaries() const;
+    void set_polyline_loops_have_boundaries(bool value);
+
+    // Specifies whether the operation should use the exact input geometry
+    // (Precision::EXACT), or whether the two input regions should be snapped
+    // together first (Precision::SNAPPED).
+    //
+    // DEFAULT: Precision::EXACT
+    Precision precision() const;
+    // void set_precision(Precision precision);
+
+    // If true, the input geometry is interpreted as representing nearby
+    // geometry that has been snapped or simplified.  It then outputs a
+    // conservative result based on the value of polygon_model() and
+    // polyline_model().  For the most part, this only affects the handling of
+    // degeneracies.
+    //
+    // - If the model is OPEN, the result is as open as possible.  For
+    //   example, the intersection of two identical degenerate shells is empty
+    //   under PolygonModel::OPEN because they could have been disjoint before
+    //   snapping.  Similarly, two identical degenerate polylines have an
+    //   empty intersection under PolylineModel::OPEN.
+    //
+    // - If the model is CLOSED, the result is as closed as possible.  In the
+    //   case of the DIFFERENCE operation, this is equivalent to evaluating
+    //   A - B as Closure(A) - Interior(B).  For other operations, it affects
+    //   only the handling of degeneracies.  For example, the union of two
+    //   identical degenerate holes is empty under PolygonModel::CLOSED
+    //   (i.e., the hole disappears) because the holes could have been
+    //   disjoint before snapping.
+    //
+    // - If the model is SEMI_OPEN, the result is as degenerate as possible.
+    //   New degeneracies will not be created, but all degeneracies that
+    //   coincide with the opposite region's boundary are retained unless this
+    //   would cause a duplicate polygon edge to be created.  This model is
+    //   is very useful for working with input data that has both positive and
+    //   negative degeneracies (i.e., degenerate shells and holes).
+    //
+    // DEFAULT: false
+    bool conservative_output() const;
+    // void set_conservative_output(bool conservative);
+
+    // If specified, then each output edge will be labelled with one or more
+    // SourceIds indicating which input edge(s) it corresponds to.  This
+    // can be useful if your input geometry has additional data that needs to
+    // be propagated from the input to the output (e.g., elevations).
+    //
+    // You can access the labels by using an S2Builder::Layer type that
+    // supports labels, such as S2PolygonLayer.  The layer outputs a
+    // "label_set_lexicon" and an "label_set_id" for each edge.  You can then
+    // look up the source information for each edge like this:
+    //
+    // for (int32 label : label_set_lexicon.id_set(label_set_id)) {
+    //   const SourceId& src = source_id_lexicon.value(label);
+    //   // region_id() specifies which S2ShapeIndex the edge is from (0 or 1).
+    //   DoSomething(src.region_id(), src.shape_id(), src.edge_id());
+    // }
+    //
+    // DEFAULT: nullptr
+    ValueLexicon<SourceId>* source_id_lexicon() const;
+    // void set_source_id_lexicon(ValueLexicon<SourceId>* source_id_lexicon);
+
+    // Options may be assigned and copied.
+    Options(const Options& options);
+    Options& operator=(const Options& options);
+
+   private:
+    std::unique_ptr<S2Builder::SnapFunction> snap_function_;
+    PolygonModel polygon_model_ = PolygonModel::SEMI_OPEN;
+    PolylineModel polyline_model_ = PolylineModel::CLOSED;
+    bool polyline_loops_have_boundaries_ = true;
+    Precision precision_ = Precision::EXACT;
+    bool conservative_output_ = false;
+    ValueLexicon<SourceId>* source_id_lexicon_ = nullptr;
+  };
+
+  S2BooleanOperation(OpType op_type,
+                     std::unique_ptr<S2Builder::Layer> layer,
+                     const Options& options = Options());
+
+  // Specifies that the output boundary edges should be sent to three
+  // different layers according to their dimension.  Points (represented by
+  // degenerate edges) are sent to layer 0, polyline edges are sent to
+  // layer 1, and polygon edges are sent to layer 2.
+  //
+  // The dimension of an edge is defined as the minimum dimension of the two
+  // input edges that produced it.  For example, the intersection of two
+  // crossing polyline edges is a considered to be a degenerate polyline
+  // rather than a point, so it is sent to layer 1.  Clients can easily
+  // reclassify such polylines as points if desired, but this rule makes it
+  // easier for clients that want to process point, polyline, and polygon
+  // inputs differently.
+  //
+  // The layers are always built in the order 0, 1, 2, and all arguments to
+  // the Build() calls are guaranteed to be valid until the last call returns.
+  // All Graph objects have the same set of vertices and the same lexicon
+  // objects, in order to make it easier to write classes that process all the
+  // edges in parallel.
+  S2BooleanOperation(OpType op_type,
+                     std::vector<std::unique_ptr<S2Builder::Layer>> layers,
+                     const Options& options = Options());
+
+  OpType op_type() const { return op_type_; }
+
+  // Executes the given operation.  Returns true on success, and otherwise
+  // sets "error" appropriately.  (This class does not generate any errors
+  // itself, but the S2Builder::Layer might.)
+  bool Build(const S2ShapeIndex& a, const S2ShapeIndex& b,
+             S2Error* error);
+
+  // Convenience method that returns true if the result of the given operation
+  // is empty.
+  static bool IsEmpty(OpType op_type,
+                      const S2ShapeIndex& a, const S2ShapeIndex& b,
+                      const Options& options = Options());
+
+  // Convenience method that returns true if A intersects B.
+  static bool Intersects(const S2ShapeIndex& a, const S2ShapeIndex& b,
+                         const Options& options = Options()) {
+    return !IsEmpty(OpType::INTERSECTION, b, a, options);
+  }
+
+  // Convenience method that returns true if A contains B, i.e., if the
+  // difference (B - A) is empty.
+  static bool Contains(const S2ShapeIndex& a, const S2ShapeIndex& b,
+                       const Options& options = Options()) {
+    return IsEmpty(OpType::DIFFERENCE, b, a, options);
+  }
+
+  // Convenience method that returns true if the symmetric difference of A and
+  // B is empty.  (Note that A and B may still not be identical, e.g. A may
+  // contain two copies of a polyline while B contains one.)
+  static bool Equals(const S2ShapeIndex& a, const S2ShapeIndex& b,
+                     const Options& options = Options()) {
+    return IsEmpty(OpType::SYMMETRIC_DIFFERENCE, b, a, options);
+  }
+
+ private:
+  class Impl;  // The actual implementation.
+
+  // Internal constructor to reduce code duplication.
+  S2BooleanOperation(OpType op_type, const Options& options);
+
+  // Specifies that "result_empty" should be set to indicate whether the exact
+  // result of the operation is empty.  This constructor is used to efficiently
+  // test boolean relationships (see IsEmpty above).
+  S2BooleanOperation(OpType op_type, bool* result_empty,
+                     const Options& options = Options());
+
+  OpType op_type_;
+  Options options_;
+
+  // The input regions.
+  const S2ShapeIndex* regions_[2];
+
+  // The output consists either of zero layers, one layer, or three layers.
+  std::vector<std::unique_ptr<S2Builder::Layer>> layers_;
+
+  // The following field is set if and only if there are no output layers.
+  bool* result_empty_;
+};
+
+
+//////////////////   Implementation details follow   ////////////////////
+
+
+inline S2BooleanOperation::SourceId::SourceId()
+    : region_id_(0), shape_id_(0), edge_id_(-1) {
+}
+
+inline S2BooleanOperation::SourceId::SourceId(
+    int region_id, int32 shape_id, int32 edge_id)
+    : region_id_(region_id), shape_id_(shape_id), edge_id_(edge_id) {
+}
+
+inline S2BooleanOperation::SourceId::SourceId(int special_edge_id)
+    : region_id_(0), shape_id_(0), edge_id_(special_edge_id) {
+}
+
+inline bool S2BooleanOperation::SourceId::operator==(SourceId other) const {
+  return (region_id_ == other.region_id_ &&
+          shape_id_ == other.shape_id_ &&
+          edge_id_ == other.edge_id_);
+}
+
+inline bool S2BooleanOperation::SourceId::operator<(SourceId other) const {
+  if (region_id_ < other.region_id_) return true;
+  if (region_id_ > other.region_id_) return false;
+  if (shape_id_ < other.shape_id_) return true;
+  if (shape_id_ > other.shape_id_) return false;
+  return edge_id_ < other.edge_id_;
+}
+
+#endif  // S2_S2BOOLEAN_OPERATION_H_
diff --git a/src/s2/s2builder.cc b/src/s2/s2builder.cc
new file mode 100644 (file)
index 0000000..7781e7b
--- /dev/null
@@ -0,0 +1,1829 @@
+#include "cpp-compat.h"
+// Copyright 2016 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// Author: ericv@google.com (Eric Veach)
+//
+// The algorithm is based on the idea of choosing a set of sites and computing
+// their "limited radius Voronoi diagram", which is obtained by intersecting
+// each Voronoi region with a disc of fixed radius (the "snap radius")
+// centered around the corresponding site.
+//
+// For each input edge, we then determine the sequence of Voronoi regions
+// crossed by that edge, and snap the edge to the corresponding sequence of
+// sites.  (In other words, each input edge is replaced by an edge chain.)
+//
+// The sites are chosen by starting with the set of input vertices, optionally
+// snapping them to discrete point set (such as S2CellId centers or lat/lng E7
+// coordinates), and then choosing a subset such that no two sites are closer
+// than the given "snap_radius".  Note that the sites do not need to be spaced
+// regularly -- their positions are completely arbitrary.
+//
+// Rather than computing the full limited radius Voronoi diagram, instead we
+// compute on demand the sequence of Voronoi regions intersected by each edge.
+// We do this by first finding all the sites that are within "snap_radius" of
+// the edge, sorting them by distance from the edge origin, and then using an
+// incremental algorithm.
+//
+// We implement the minimum edge-vertex separation property by snapping all
+// the input edges and checking whether any site (the "site to avoid") would
+// then be too close to the edge.  If so we add another site (the "separation
+// site") along the input edge, positioned so that the new snapped edge is
+// guaranteed to be far enough away from the site to avoid.  We then find all
+// the input edges that are within "snap_radius" of the new site, and resnap
+// those edges.  (It is very rare that we need to add a separation site, even
+// when sites are densely spaced.)
+//
+// Idempotency is implemented by explicitly checking whether the input
+// geometry already meets the output criteria.  This is not as sophisticated
+// as Stable Snap Rounding (Hershberger); I have worked out the details and it
+// is possible to adapt those ideas here, but it would make the implementation
+// significantly more complex.
+//
+// The only way that different output layers interact is in the choice of
+// Voronoi sites:
+//
+//  - Vertices from all layers contribute to the initial selection of sites.
+//
+//  - Edges in any layer that pass too close to a site can cause new sites to
+//    be added (which affects snapping in all layers).
+//
+//  - Simplification can be thought of as removing sites.  A site can be
+//    removed only if the snapped edges stay within the error bounds of the
+//    corresponding input edges in all layers.
+//
+// Otherwise all layers are processed independently.  For example, sibling
+// edge pairs can only cancel each other within a single layer (if desired).
+
+#include "s2/s2builder.h"
+
+#include <algorithm>
+#include <cfloat>
+#include <cmath>
+#include <iostream>
+#include <memory>
+#include <numeric>
+#include <string>
+#include <vector>
+
+#include "s2/base/casts.h"
+#include "s2/base/logging.h"
+#include "absl/memory/memory.h"
+#include "s2/util/bits/bits.h"
+#include "s2/id_set_lexicon.h"
+#include "s2/mutable_s2shape_index.h"
+#include "s2/s1angle.h"
+#include "s2/s1chord_angle.h"
+#include "s2/s2builder_graph.h"
+#include "s2/s2builder_layer.h"
+#include "s2/s2builderutil_snap_functions.h"
+#include "s2/s2closest_edge_query.h"
+#include "s2/s2closest_point_query.h"
+#include "s2/s2edge_crossings.h"
+#include "s2/s2edge_distances.h"
+#include "s2/s2error.h"
+#include "s2/s2loop.h"
+#include "s2/s2point_index.h"
+#include "s2/s2pointutil.h"
+#include "s2/s2polygon.h"
+#include "s2/s2polyline.h"
+#include "s2/s2polyline_simplifier.h"
+#include "s2/s2predicates.h"
+#include "s2/s2shapeutil_visit_crossing_edge_pairs.h"
+#include "s2/s2text_format.h"
+
+using absl::make_unique;
+using gtl::compact_array;
+using std::max;
+using std::pair;
+using std::unique_ptr;
+using std::vector;
+
+// Internal flag intended to be set from within a debugger.
+bool s2builder_verbose = false;
+
+S1Angle S2Builder::SnapFunction::max_edge_deviation() const {
+  // We want max_edge_deviation() to be large enough compared to snap_radius()
+  // such that edge splitting is rare.
+  //
+  // Using spherical trigonometry, if the endpoints of an edge of length L
+  // move by at most a distance R, the center of the edge moves by at most
+  // asin(sin(R) / cos(L / 2)).  Thus the (max_edge_deviation / snap_radius)
+  // ratio increases with both the snap radius R and the edge length L.
+  //
+  // We arbitrarily limit the edge deviation to be at most 10% more than the
+  // snap radius.  With the maximum allowed snap radius of 70 degrees, this
+  // means that edges up to 30.6 degrees long are never split.  For smaller
+  // snap radii, edges up to 49 degrees long are never split.  (Edges of any
+  // length are not split unless their endpoints move far enough so that the
+  // actual edge deviation exceeds the limit; in practice, splitting is rare
+  // even with long edges.)  Note that it is always possible to split edges
+  // when max_edge_deviation() is exceeded; see MaybeAddExtraSites().
+  S2_DCHECK_LE(snap_radius(), kMaxSnapRadius());
+  const double kMaxEdgeDeviationRatio = 1.1;
+  return kMaxEdgeDeviationRatio * snap_radius();
+}
+
+S2Builder::Options::Options()
+    : snap_function_(
+          make_unique<s2builderutil::IdentitySnapFunction>(S1Angle::Zero())) {
+}
+
+S2Builder::Options::Options(const SnapFunction& snap_function)
+    : snap_function_(snap_function.Clone()) {
+}
+
+S2Builder::Options::Options(const Options& options)
+    :  snap_function_(options.snap_function_->Clone()),
+       split_crossing_edges_(options.split_crossing_edges_),
+       simplify_edge_chains_(options.simplify_edge_chains_),
+       idempotent_(options.idempotent_) {
+}
+
+S2Builder::Options& S2Builder::Options::operator=(const Options& options) {
+  snap_function_ = options.snap_function_->Clone();
+  split_crossing_edges_ = options.split_crossing_edges_;
+  simplify_edge_chains_ = options.simplify_edge_chains_;
+  idempotent_ = options.idempotent_;
+  return *this;
+}
+
+bool operator==(const S2Builder::GraphOptions& x,
+                const S2Builder::GraphOptions& y) {
+  return (x.edge_type() == y.edge_type() &&
+          x.degenerate_edges() == y.degenerate_edges() &&
+          x.duplicate_edges() == y.duplicate_edges() &&
+          x.sibling_pairs() == y.sibling_pairs() &&
+          x.allow_vertex_filtering() == y.allow_vertex_filtering());
+}
+
+// Helper functions for computing error bounds:
+
+static S1ChordAngle RoundUp(S1Angle a) {
+  S1ChordAngle ca(a);
+  return ca.PlusError(ca.GetS1AngleConstructorMaxError());
+}
+
+static S1ChordAngle AddPointToPointError(S1ChordAngle ca) {
+  return ca.PlusError(ca.GetS2PointConstructorMaxError());
+}
+
+static S1ChordAngle AddPointToEdgeError(S1ChordAngle ca) {
+  return ca.PlusError(S2::GetUpdateMinDistanceMaxError(ca));
+}
+
+S2Builder::S2Builder() {
+}
+
+S2Builder::S2Builder(const Options& options) {
+  Init(options);
+}
+
+void S2Builder::Init(const Options& options) {
+  options_ = options;
+  const SnapFunction& snap_function = options.snap_function();
+  S1Angle snap_radius = snap_function.snap_radius();
+  S2_DCHECK_LE(snap_radius, SnapFunction::kMaxSnapRadius());
+
+  // Convert the snap radius to an S1ChordAngle.  This is the "true snap
+  // radius" used when evaluating exact predicates (s2predicates.h).
+  site_snap_radius_ca_ = S1ChordAngle(snap_radius);
+
+  // When split_crossing_edges() is true, we need to use a larger snap radius
+  // for edges than for vertices to ensure that both edges are snapped to the
+  // edge intersection location.  This is because the computed intersection
+  // point is not exact; it may be up to kIntersectionError away from its true
+  // position.  The computed intersection point might then be snapped to some
+  // other vertex up to snap_radius away.  So to ensure that both edges are
+  // snapped to a common vertex, we need to increase the snap radius for edges
+  // to at least the sum of these two values (calculated conservatively).
+  S1Angle edge_snap_radius = snap_radius;
+  if (!options.split_crossing_edges()) {
+    edge_snap_radius_ca_ = site_snap_radius_ca_;
+  } else {
+    edge_snap_radius += S2::kIntersectionError;
+    edge_snap_radius_ca_ = RoundUp(edge_snap_radius);
+  }
+  snapping_requested_ = (edge_snap_radius > S1Angle::Zero());
+
+  // Compute the maximum distance that a vertex can be separated from an
+  // edge while still affecting how that edge is snapped.
+  max_edge_deviation_ = snap_function.max_edge_deviation();
+  edge_site_query_radius_ca_ = S1ChordAngle(
+      max_edge_deviation_ + snap_function.min_edge_vertex_separation());
+
+  // Compute the maximum edge length such that even if both endpoints move by
+  // the maximum distance allowed (i.e., snap_radius), the center of the edge
+  // will still move by less than max_edge_deviation().  This saves us a lot
+  // of work since then we don't need to check the actual deviation.
+  min_edge_length_to_split_ca_ = S1ChordAngle::Radians(
+      2 * acos(sin(snap_radius) / sin(max_edge_deviation_)));
+
+  // If the condition below is violated, then AddExtraSites() needs to be
+  // modified to check that snapped edges pass on the same side of each "site
+  // to avoid" as the input edge.  Currently it doesn't need to do this
+  // because the condition below guarantees that if the snapped edge passes on
+  // the wrong side of the site then it is also too close, which will cause a
+  // separation site to be added.
+  //
+  // Currently max_edge_deviation() is at most 1.1 * snap_radius(), whereas
+  // min_edge_vertex_separation() is at least 0.219 * snap_radius() (based on
+  // S2CellIdSnapFunction, which is currently the worst case).
+  S2_DCHECK_LE(snap_function.max_edge_deviation(),
+            snap_function.snap_radius() +
+            snap_function.min_edge_vertex_separation());
+
+  // To implement idempotency, we check whether the input geometry could
+  // possibly be the output of a previous S2Builder invocation.  This involves
+  // testing whether any site/site or edge/site pairs are too close together.
+  // This is done using exact predicates, which require converting the minimum
+  // separation values to an S1ChordAngle.
+  min_site_separation_ = snap_function.min_vertex_separation();
+  min_site_separation_ca_ = S1ChordAngle(min_site_separation_);
+  min_edge_site_separation_ca_ =
+      S1ChordAngle(snap_function.min_edge_vertex_separation());
+
+  // This is an upper bound on the distance computed by S2ClosestPointQuery
+  // where the true distance might be less than min_edge_site_separation_ca_.
+  min_edge_site_separation_ca_limit_ =
+      AddPointToEdgeError(min_edge_site_separation_ca_);
+
+  // Compute the maximum possible distance between two sites whose Voronoi
+  // regions touch.  (The maximum radius of each Voronoi region is
+  // edge_snap_radius_.)  Then increase this bound to account for errors.
+  max_adjacent_site_separation_ca_ =
+      AddPointToPointError(RoundUp(2 * edge_snap_radius));
+
+  // Finally, we also precompute sin^2(edge_snap_radius), which is simply the
+  // squared distance between a vertex and an edge measured perpendicular to
+  // the plane containing the edge, and increase this value by the maximum
+  // error in the calculation to compare this distance against the bound.
+  double d = sin(edge_snap_radius);
+  edge_snap_radius_sin2_ = d * d;
+  edge_snap_radius_sin2_ += ((9.5 * d + 2.5 + 2 * sqrt(3.0)) * d +
+                             9 * DBL_EPSILON) * DBL_EPSILON;
+
+  // Initialize the current label set.
+  label_set_id_ = label_set_lexicon_.EmptySetId();
+  label_set_modified_ = false;
+
+  // If snapping was requested, we try to determine whether the input geometry
+  // already meets the output requirements.  This is necessary for
+  // idempotency, and can also save work.  If we discover any reason that the
+  // input geometry needs to be modified, snapping_needed_ is set to true.
+  snapping_needed_ = false;
+}
+
+void S2Builder::clear_labels() {
+  label_set_.clear();
+  label_set_modified_ = true;
+}
+
+void S2Builder::push_label(Label label) {
+  S2_DCHECK_GE(label, 0);
+  label_set_.push_back(label);
+  label_set_modified_ = true;
+}
+
+void S2Builder::pop_label() {
+  label_set_.pop_back();
+  label_set_modified_ = true;
+}
+
+void S2Builder::set_label(Label label) {
+  S2_DCHECK_GE(label, 0);
+  label_set_.resize(1);
+  label_set_[0] = label;
+  label_set_modified_ = true;
+}
+
+bool S2Builder::IsFullPolygonUnspecified(const S2Builder::Graph& g,
+                                         S2Error* error) {
+  error->Init(S2Error::BUILDER_IS_FULL_PREDICATE_NOT_SPECIFIED,
+              "A degenerate polygon was found, but no predicate was specified "
+              "to determine whether the polygon is empty or full.  Call "
+              "S2Builder::AddIsFullPolygonPredicate() to fix this problem.");
+  return false;  // Assumes the polygon is empty.
+}
+
+S2Builder::IsFullPolygonPredicate S2Builder::IsFullPolygon(bool is_full) {
+  return [is_full](const S2Builder::Graph& g, S2Error* error) {
+      return is_full;
+    };
+}
+
+void S2Builder::StartLayer(unique_ptr<Layer> layer) {
+  layer_options_.push_back(layer->graph_options());
+  layer_begins_.push_back(input_edges_.size());
+  layer_is_full_polygon_predicates_.push_back(IsFullPolygon(false));
+  layers_.push_back(std::move(layer));
+}
+
+// Input vertices are stored in a vector, with some removal of duplicates.
+// Edges are represented as (VertexId, VertexId) pairs.  All edges are stored
+// in a single vector; each layer corresponds to a contiguous range.
+
+S2Builder::InputVertexId S2Builder::AddVertex(const S2Point& v) {
+  // Remove duplicate vertices that follow the pattern AB, BC, CD.  If we want
+  // to do anything more sophisticated, either use a ValueLexicon, or sort the
+  // vertices once they have all been added, remove duplicates, and update the
+  // edges.
+  if (input_vertices_.empty() || v != input_vertices_.back()) {
+    input_vertices_.push_back(v);
+  }
+  return input_vertices_.size() - 1;
+}
+
+void S2Builder::AddEdge(const S2Point& v0, const S2Point& v1) {
+  S2_DCHECK(!layers_.empty()) << "Call StartLayer before adding any edges";
+
+  if (v0 == v1 && (layer_options_.back().degenerate_edges() ==
+                   GraphOptions::DegenerateEdges::DISCARD)) {
+    return;
+  }
+  InputVertexId j0 = AddVertex(v0);
+  InputVertexId j1 = AddVertex(v1);
+  input_edges_.push_back(InputEdge(j0, j1));
+
+  // If there are any labels, then attach them to this input edge.
+  if (label_set_modified_) {
+    if (label_set_ids_.empty()) {
+      // Populate the missing entries with empty label sets.
+      label_set_ids_.assign(input_edges_.size() - 1, label_set_id_);
+    }
+    label_set_id_ = label_set_lexicon_.Add(label_set_);
+    label_set_ids_.push_back(label_set_id_);
+    label_set_modified_ = false;
+  } else if (!label_set_ids_.empty()) {
+    label_set_ids_.push_back(label_set_id_);
+  }
+}
+
+void S2Builder::AddPolyline(const S2Polyline& polyline) {
+  const int n = polyline.num_vertices();
+  for (int i = 1; i < n; ++i) {
+    AddEdge(polyline.vertex(i - 1), polyline.vertex(i));
+  }
+}
+
+void S2Builder::AddLoop(const S2Loop& loop) {
+  // Ignore loops that do not have a boundary.
+  if (loop.is_empty_or_full()) return;
+
+  // For loops that represent holes, we add the edge from vertex n-1 to vertex
+  // n-2 first.  This is because these edges will be assembled into a
+  // clockwise loop, which will eventually be normalized in S2Polygon by
+  // calling S2Loop::Invert().  S2Loop::Invert() reverses the order of the
+  // vertices, so to end up with the original vertex order (0, 1, ..., n-1) we
+  // need to build a clockwise loop with vertex order (n-1, n-2, ..., 0).
+  // This is done by adding the edge (n-1, n-2) first, and then ensuring that
+  // Build() assembles loops starting from edges in the order they were added.
+  const int n = loop.num_vertices();
+  for (int i = 0; i < n; ++i) {
+    AddEdge(loop.oriented_vertex(i), loop.oriented_vertex(i + 1));
+  }
+}
+
+void S2Builder::AddPolygon(const S2Polygon& polygon) {
+  for (int i = 0; i < polygon.num_loops(); ++i) {
+    AddLoop(*polygon.loop(i));
+  }
+}
+
+void S2Builder::AddShape(const S2Shape& shape) {
+  for (int e = 0, n = shape.num_edges(); e < n; ++e) {
+    S2Shape::Edge edge = shape.edge(e);
+    AddEdge(edge.v0, edge.v1);
+  }
+}
+
+void S2Builder::AddIsFullPolygonPredicate(IsFullPolygonPredicate predicate) {
+  layer_is_full_polygon_predicates_.back() = std::move(predicate);
+}
+
+void S2Builder::ForceVertex(const S2Point& vertex) {
+  sites_.push_back(vertex);
+}
+
+// An S2Shape used to represent the entire collection of S2Builder input edges.
+// Vertices are specified as indices into a vertex vector to save space.
+namespace {
+class VertexIdEdgeVectorShape final : public S2Shape {
+ public:
+  // Requires that "edges" is constant for the lifetime of this object.
+  VertexIdEdgeVectorShape(const vector<pair<int32, int32>>& edges,
+                          const vector<S2Point>& vertices)
+      : edges_(edges), vertices_(vertices) {
+  }
+
+  const S2Point& vertex0(int e) const { return vertex(edges_[e].first); }
+  const S2Point& vertex1(int e) const { return vertex(edges_[e].second); }
+
+  // S2Shape interface:
+  int num_edges() const override { return edges_.size(); }
+  Edge edge(int e) const override {
+    return Edge(vertices_[edges_[e].first], vertices_[edges_[e].second]);
+  }
+  int dimension() const override { return 1; }
+  ReferencePoint GetReferencePoint() const override {
+    return ReferencePoint::Contained(false);
+  }
+  int num_chains() const override { return edges_.size(); }
+  Chain chain(int i) const override { return Chain(i, 1); }
+  Edge chain_edge(int i, int j) const override { return edge(i); }
+  ChainPosition chain_position(int e) const override {
+    return ChainPosition(e, 0);
+  }
+
+ private:
+  const S2Point& vertex(int i) const { return vertices_[i]; }
+
+  const vector<std::pair<int32, int32>>& edges_;
+  const vector<S2Point>& vertices_;
+};
+}  // namespace
+
+bool S2Builder::Build(S2Error* error) {
+  // S2_CHECK rather than S2_DCHECK because this is friendlier than crashing on the
+  // "error->ok()" call below.  It would be easy to allow (error == nullptr)
+  // by declaring a local "tmp_error", but it seems better to make clients
+  // think about error handling.
+  S2_CHECK(error != nullptr);
+  error->Clear();
+  error_ = error;
+
+  // Mark the end of the last layer.
+  layer_begins_.push_back(input_edges_.size());
+
+  // See the algorithm overview at the top of this file.
+  if (snapping_requested_ && !options_.idempotent()) {
+    snapping_needed_ = true;
+  }
+  ChooseSites();
+  BuildLayers();
+  Reset();
+  return error->ok();
+}
+
+void S2Builder::Reset() {
+  input_vertices_.clear();
+  input_edges_.clear();
+  layers_.clear();
+  layer_options_.clear();
+  layer_begins_.clear();
+  layer_is_full_polygon_predicates_.clear();
+  label_set_ids_.clear();
+  label_set_lexicon_.Clear();
+  label_set_.clear();
+  label_set_modified_ = false;
+  sites_.clear();
+  edge_sites_.clear();
+  snapping_needed_ = false;
+}
+
+void S2Builder::ChooseSites() {
+  if (input_vertices_.empty()) return;
+
+  MutableS2ShapeIndex input_edge_index;
+  input_edge_index.Add(make_unique<VertexIdEdgeVectorShape>(
+      input_edges_, input_vertices_));
+  if (options_.split_crossing_edges()) {
+    AddEdgeCrossings(input_edge_index);
+  }
+  if (snapping_requested_) {
+    S2PointIndex<SiteId> site_index;
+    AddForcedSites(&site_index);
+    ChooseInitialSites(&site_index);
+    CollectSiteEdges(site_index);
+  }
+  if (snapping_needed_) {
+    AddExtraSites(input_edge_index);
+  } else {
+    CopyInputEdges();
+  }
+}
+
+void S2Builder::CopyInputEdges() {
+  // Sort the input vertices, discard duplicates, and update the input edges
+  // to refer to the pruned vertex list.  (We sort in the same order used by
+  // ChooseInitialSites() to avoid inconsistencies in tests.)
+  vector<InputVertexKey> sorted = SortInputVertices();
+  vector<InputVertexId> vmap(input_vertices_.size());
+  sites_.clear();
+  sites_.reserve(input_vertices_.size());
+  for (int in = 0; in < sorted.size(); ) {
+    const S2Point& site = input_vertices_[sorted[in].second];
+    vmap[sorted[in].second] = sites_.size();
+    while (++in < sorted.size() && input_vertices_[sorted[in].second] == site) {
+      vmap[sorted[in].second] = sites_.size();
+    }
+    sites_.push_back(site);
+  }
+  input_vertices_ = sites_;
+  for (InputEdge& e : input_edges_) {
+    e.first = vmap[e.first];
+    e.second = vmap[e.second];
+  }
+}
+
+vector<S2Builder::InputVertexKey> S2Builder::SortInputVertices() {
+  // Sort all the input vertices in the order that we wish to consider them as
+  // candidate Voronoi sites.  Any sort order will produce correct output, so
+  // we have complete flexibility in choosing the sort key.  We could even
+  // leave them unsorted, although this would have the disadvantage that
+  // changing the order of the input edges could cause S2Builder to snap to a
+  // different set of Voronoi sites.
+  //
+  // We have chosen to sort them primarily by S2CellId since this improves the
+  // performance of many S2Builder phases (due to better spatial locality).
+  // It also allows the possibility of replacing the current S2PointIndex
+  // approach with a more efficient recursive divide-and-conquer algorithm.
+  //
+  // However, sorting by leaf S2CellId alone has two small disadvantages in
+  // the case where the candidate sites are densely spaced relative to the
+  // snap radius (e.g., when using the IdentitySnapFunction, or when snapping
+  // to E6/E7 near the poles, or snapping to S2CellId/E6/E7 using a snap
+  // radius larger than the minimum value required):
+  //
+  //  - First, it tends to bias the Voronoi site locations towards points that
+  //    are earlier on the S2CellId Hilbert curve.  For example, suppose that
+  //    there are two parallel rows of input vertices on opposite sides of the
+  //    edge between two large S2Cells, and the rows are separated by less
+  //    than the snap radius.  Then only vertices from the cell with the
+  //    smaller S2CellId are selected, because they are considered first and
+  //    prevent us from selecting the sites from the other cell (because they
+  //    are closer than "snap_radius" to an existing site).
+  //
+  //  - Second, it tends to choose more Voronoi sites than necessary, because
+  //    at each step we choose the first site along the Hilbert curve that is
+  //    at least "snap_radius" away from all previously selected sites.  This
+  //    tends to yield sites whose "coverage discs" overlap quite a bit,
+  //    whereas it would be better to cover all the input vertices with a
+  //    smaller set of coverage discs that don't overlap as much.  (This is
+  //    the "geometric set cover problem", which is NP-hard.)
+  //
+  // It is not worth going to much trouble to fix these problems, because they
+  // really aren't that important (and don't affect the guarantees made by the
+  // algorithm), but here are a couple of heuristics that might help:
+  //
+  // 1. Sort the input vertices by S2CellId at a coarse level (down to cells
+  // that are O(snap_radius) in size), and then sort by a fingerprint of the
+  // S2Point coordinates (i.e., quasi-randomly).  This would retain most of
+  // the advantages of S2CellId sorting, but makes it more likely that we will
+  // select sites that are further apart.
+  //
+  // 2. Rather than choosing the first uncovered input vertex and snapping it
+  // to obtain the next Voronoi site, instead look ahead through following
+  // candidates in S2CellId order and choose the furthest candidate whose
+  // snapped location covers all previous uncovered input vertices.
+  //
+  // TODO(ericv): Experiment with these approaches.
+
+  vector<InputVertexKey> keys;
+  keys.reserve(input_vertices_.size());
+  for (InputVertexId i = 0; i < input_vertices_.size(); ++i) {
+    keys.push_back(InputVertexKey(S2CellId(input_vertices_[i]), i));
+  }
+  std::sort(keys.begin(), keys.end(),
+            [this](const InputVertexKey& a, const InputVertexKey& b) {
+      if (a.first < b.first) return true;
+      if (b.first < a.first) return false;
+      return input_vertices_[a.second] < input_vertices_[b.second];
+    });
+  return keys;
+}
+
+// Check all edge pairs for crossings, and add the corresponding intersection
+// points to input_vertices_.  (The intersection points will be snapped and
+// merged with the other vertices during site selection.)
+void S2Builder::AddEdgeCrossings(const MutableS2ShapeIndex& input_edge_index) {
+  // We need to build a list of intersections and add them afterwards so that
+  // we don't reallocate vertices_ during the VisitCrossings() call.
+  vector<S2Point> new_vertices;
+  s2shapeutil::VisitCrossingEdgePairs(
+      input_edge_index, s2shapeutil::CrossingType::INTERIOR,
+      [&new_vertices](const s2shapeutil::ShapeEdge& a,
+                      const s2shapeutil::ShapeEdge& b, bool) {
+        new_vertices.push_back(
+            S2::GetIntersection(a.v0(), a.v1(), b.v0(), b.v1()));
+        return true;  // Continue visiting.
+      });
+  if (!new_vertices.empty()) {
+    snapping_needed_ = true;
+    for (const auto& vertex : new_vertices) AddVertex(vertex);
+  }
+}
+
+void S2Builder::AddForcedSites(S2PointIndex<SiteId>* site_index) {
+  // Sort the forced sites and remove duplicates.
+  std::sort(sites_.begin(), sites_.end());
+  sites_.erase(std::unique(sites_.begin(), sites_.end()), sites_.end());
+  // Add the forced sites to the index.
+  for (SiteId id = 0; id < sites_.size(); ++id) {
+    site_index->Add(sites_[id], id);
+  }
+  num_forced_sites_ = sites_.size();
+}
+
+void S2Builder::ChooseInitialSites(S2PointIndex<SiteId>* site_index) {
+  // Find all points whose distance is <= min_site_separation_ca_.
+  S2ClosestPointQueryOptions options;
+  options.set_conservative_max_distance(min_site_separation_ca_);
+  S2ClosestPointQuery<SiteId> site_query(site_index, options);
+  vector<S2ClosestPointQuery<SiteId>::Result> results;
+
+  // Apply the snap_function() to each input vertex, then check whether any
+  // existing site is closer than min_vertex_separation().  If not, then add a
+  // new site.
+  //
+  // NOTE(ericv): There are actually two reasonable algorithms, which we call
+  // "snap first" (the one above) and "snap last".  The latter checks for each
+  // input vertex whether any existing site is closer than snap_radius(), and
+  // only then applies the snap_function() and adds a new site.  "Snap last"
+  // can yield slightly fewer sites in some cases, but it is also more
+  // expensive and can produce surprising results.  For example, if you snap
+  // the polyline "0:0, 0:0.7" using IntLatLngSnapFunction(0), the result is
+  // "0:0, 0:0" rather than the expected "0:0, 0:1", because the snap radius
+  // is approximately sqrt(2) degrees and therefore it is legal to snap both
+  // input points to "0:0".  "Snap first" produces "0:0, 0:1" as expected.
+  for (const InputVertexKey& key : SortInputVertices()) {
+    const S2Point& vertex = input_vertices_[key.second];
+    S2Point site = SnapSite(vertex);
+    // If any vertex moves when snapped, the output cannot be idempotent.
+    snapping_needed_ = snapping_needed_ || site != vertex;
+
+    // FindClosestPoints() measures distances conservatively, so we need to
+    // recheck the distances using exact predicates.
+    //
+    // NOTE(ericv): When the snap radius is large compared to the average
+    // vertex spacing, we could possibly avoid the call the FindClosestPoints
+    // by checking whether sites_.back() is close enough.
+    S2ClosestPointQueryPointTarget target(site);
+    site_query.FindClosestPoints(&target, &results);
+    bool add_site = true;
+    for (const auto& result : results) {
+      if (s2pred::CompareDistance(site, result.point(),
+                                  min_site_separation_ca_) <= 0) {
+        add_site = false;
+        // This pair of sites is too close.  If the sites are distinct, then
+        // the output cannot be idempotent.
+        snapping_needed_ = snapping_needed_ || site != result.point();
+      }
+    }
+    if (add_site) {
+      site_index->Add(site, sites_.size());
+      sites_.push_back(site);
+      site_query.ReInit();
+    }
+  }
+}
+
+S2Point S2Builder::SnapSite(const S2Point& point) const {
+  if (!snapping_requested_) return point;
+  S2Point site = options_.snap_function().SnapPoint(point);
+S1ChordAngle dist_moved(site, point);
+  if (dist_moved > site_snap_radius_ca_) {
+    error_->Init(S2Error::BUILDER_SNAP_RADIUS_TOO_SMALL,
+                 "Snap function moved vertex (%.15g, %.15g, %.15g) "
+                 "by %.15g, which is more than the specified snap "
+                 "radius of %.15g", point.x(), point.y(), point.z(),
+                 dist_moved.ToAngle().radians(),
+                 site_snap_radius_ca_.ToAngle().radians());
+  }
+  return site;
+}
+
+// For each edge, find all sites within min_edge_site_query_radius_ca_ and
+// store them in edge_sites_.  Also, to implement idempotency this method also
+// checks whether the input vertices and edges may already satisfy the output
+// criteria.  If any problems are found then snapping_needed_ is set to true.
+void S2Builder::CollectSiteEdges(const S2PointIndex<SiteId>& site_index) {
+  // Find all points whose distance is <= edge_site_query_radius_ca_.
+  S2ClosestPointQueryOptions options;
+  options.set_conservative_max_distance(edge_site_query_radius_ca_);
+  S2ClosestPointQuery<SiteId> site_query(&site_index, options);
+  vector<S2ClosestPointQuery<SiteId>::Result> results;
+  edge_sites_.resize(input_edges_.size());
+  for (InputEdgeId e = 0; e < input_edges_.size(); ++e) {
+    const InputEdge& edge = input_edges_[e];
+    const S2Point& v0 = input_vertices_[edge.first];
+    const S2Point& v1 = input_vertices_[edge.second];
+    if (s2builder_verbose) {
+      cpp_compat_cout << "S2Polyline: " << s2textformat::ToString(v0)
+                << ", " << s2textformat::ToString(v1) << "\n";
+    }
+    S2ClosestPointQueryEdgeTarget target(v0, v1);
+    site_query.FindClosestPoints(&target, &results);
+    auto* sites = &edge_sites_[e];
+    sites->reserve(results.size());
+    for (const auto& result : results) {
+      sites->push_back(result.data());
+      if (!snapping_needed_ &&
+          result.distance() < min_edge_site_separation_ca_limit_ &&
+          result.point() != v0 && result.point() != v1 &&
+          s2pred::CompareEdgeDistance(result.point(), v0, v1,
+                                      min_edge_site_separation_ca_) < 0) {
+        snapping_needed_ = true;
+      }
+    }
+    SortSitesByDistance(v0, sites);
+  }
+}
+
+void S2Builder::SortSitesByDistance(const S2Point& x,
+                                    compact_array<SiteId>* sites) const {
+  // Sort sites in increasing order of distance to X.
+  std::sort(sites->begin(), sites->end(),
+            [&x, this](SiteId i, SiteId j) {
+      return s2pred::CompareDistances(x, sites_[i], sites_[j]) < 0;
+    });
+}
+
+// There are two situatons where we need to add extra Voronoi sites in order
+// to ensure that the snapped edges meet the output requirements:
+//
+//  (1) If a snapped edge deviates from its input edge by more than
+//      max_edge_deviation(), we add a new site on the input edge near the
+//      middle of the snapped edge.  This causes the snapped edge to split
+//      into two pieces, so that it follows the input edge more closely.
+//
+//  (2) If a snapped edge is closer than min_edge_vertex_separation() to any
+//      nearby site (the "site to avoid"), then we add a new site (the
+//      "separation site") on the input edge near the site to avoid.  This
+//      causes the snapped edge to follow the input edge more closely and is
+//      guaranteed to increase the separation to the required distance.
+//
+// We check these conditions by snapping all the input edges to a chain of
+// Voronoi sites and then testing each edge in the chain.  If a site needs to
+// be added, we mark all nearby edges for re-snapping.
+void S2Builder::AddExtraSites(const MutableS2ShapeIndex& input_edge_index) {
+  // When options_.split_crossing_edges() is true, this function may be called
+  // even when site_snap_radius_ca_ == 0 (because edge_snap_radius_ca_ > 0).
+  // However neither of the conditions above apply in that case.
+  if (site_snap_radius_ca_ == S1ChordAngle::Zero()) return;
+
+  vector<SiteId> chain;  // Temporary
+  vector<InputEdgeId> snap_queue;
+  for (InputEdgeId max_e = 0; max_e < input_edges_.size(); ++max_e) {
+    snap_queue.push_back(max_e);
+    while (!snap_queue.empty()) {
+      InputEdgeId e = snap_queue.back();
+      snap_queue.pop_back();
+      SnapEdge(e, &chain);
+      // We could save the snapped chain here in a snapped_chains_ vector, to
+      // avoid resnapping it in AddSnappedEdges() below, however currently
+      // SnapEdge only accounts for less than 5% of the runtime.
+      MaybeAddExtraSites(e, max_e, chain, input_edge_index, &snap_queue);
+    }
+  }
+}
+
+void S2Builder::MaybeAddExtraSites(InputEdgeId edge_id,
+                                   InputEdgeId max_edge_id,
+                                   const vector<SiteId>& chain,
+                                   const MutableS2ShapeIndex& input_edge_index,
+                                   vector<InputEdgeId>* snap_queue) {
+  // The snapped chain is always a *subsequence* of the nearby sites
+  // (edge_sites_), so we walk through the two arrays in parallel looking for
+  // sites that weren't snapped.  We also keep track of the current snapped
+  // edge, since it is the only edge that can be too close.
+  int i = 0;
+  for (SiteId id : edge_sites_[edge_id]) {
+    if (id == chain[i]) {
+      if (++i == chain.size()) break;
+      // Check whether this snapped edge deviates too far from its original
+      // position.  If so, we split the edge by adding an extra site.
+      const S2Point& v0 = sites_[chain[i - 1]];
+      const S2Point& v1 = sites_[chain[i]];
+      if (S1ChordAngle(v0, v1) < min_edge_length_to_split_ca_) continue;
+
+      const InputEdge& edge = input_edges_[edge_id];
+      const S2Point& a0 = input_vertices_[edge.first];
+      const S2Point& a1 = input_vertices_[edge.second];
+      if (!S2::IsEdgeBNearEdgeA(a0, a1, v0, v1, max_edge_deviation_)) {
+        // Add a new site on the input edge, positioned so that it splits the
+        // snapped edge into two approximately equal pieces.  Then we find all
+        // the edges near the new site (including this one) and add them to
+        // the snap queue.
+        //
+        // Note that with large snap radii, it is possible that the snapped
+        // edge wraps around the sphere the "wrong way".  To handle this we
+        // find the preferred split location by projecting both endpoints onto
+        // the input edge and taking their midpoint.
+        S2Point mid = (S2::Project(v0, a0, a1) +
+                       S2::Project(v1, a0, a1)).Normalize();
+        S2Point new_site = GetSeparationSite(mid, v0, v1, edge_id);
+        AddExtraSite(new_site, max_edge_id, input_edge_index, snap_queue);
+        return;
+      }
+    } else if (i > 0 && id >= num_forced_sites_) {
+      // Check whether this "site to avoid" is closer to the snapped edge than
+      // min_edge_vertex_separation().  Note that this is the only edge of the
+      // chain that can be too close because its vertices must span the point
+      // where "site_to_avoid" projects onto the input edge XY (this claim
+      // relies on the fact that all sites are separated by at least the snap
+      // radius).  We don't try to avoid sites added using ForceVertex()
+      // because we don't guarantee any minimum separation from such sites.
+      const S2Point& site_to_avoid = sites_[id];
+      const S2Point& v0 = sites_[chain[i - 1]];
+      const S2Point& v1 = sites_[chain[i]];
+      if (s2pred::CompareEdgeDistance(
+              site_to_avoid, v0, v1, min_edge_site_separation_ca_) < 0) {
+        // A snapped edge can only approach a site too closely when there are
+        // no sites near the input edge near that point.  We fix that by
+        // adding a new site along the input edge (a "separation site"), then
+        // we find all the edges near the new site (including this one) and
+        // add them to the snap queue.
+        S2Point new_site = GetSeparationSite(site_to_avoid, v0, v1, edge_id);
+        S2_DCHECK_NE(site_to_avoid, new_site);
+        AddExtraSite(new_site, max_edge_id, input_edge_index, snap_queue);
+        return;
+      }
+    }
+  }
+}
+
+// Adds a new site, then updates "edge_sites"_ for all edges near the new site
+// and adds them to "snap_queue" for resnapping (unless their edge id exceeds
+// "max_edge_id", since those edges have not been snapped the first time yet).
+void S2Builder::AddExtraSite(const S2Point& new_site,
+                             InputEdgeId max_edge_id,
+                             const MutableS2ShapeIndex& input_edge_index,
+                             vector<InputEdgeId>* snap_queue) {
+  SiteId new_site_id = sites_.size();
+  sites_.push_back(new_site);
+  // Find all edges whose distance is <= edge_site_query_radius_ca_.
+  S2ClosestEdgeQuery::Options options;
+  options.set_conservative_max_distance(edge_site_query_radius_ca_);
+  options.set_include_interiors(false);
+  S2ClosestEdgeQuery query(&input_edge_index, options);
+  S2ClosestEdgeQuery::PointTarget target(new_site);
+  for (const auto& result : query.FindClosestEdges(&target)) {
+    InputEdgeId e = result.edge_id();
+    auto* site_ids = &edge_sites_[e];
+    site_ids->push_back(new_site_id);
+    SortSitesByDistance(input_vertices_[input_edges_[e].first], site_ids);
+    if (e <= max_edge_id) snap_queue->push_back(e);
+  }
+}
+
+S2Point S2Builder::GetSeparationSite(const S2Point& site_to_avoid,
+                                     const S2Point& v0, const S2Point& v1,
+                                     InputEdgeId input_edge_id) const {
+  // Define the "coverage disc" of a site S to be the disc centered at S with
+  // radius "snap_radius".  Similarly, define the "coverage interval" of S for
+  // an edge XY to be the intersection of XY with the coverage disc of S.  The
+  // SnapFunction implementations guarantee that the only way that a snapped
+  // edge can be closer than min_edge_vertex_separation() to a non-snapped
+  // site (i.e., site_to_avoid) if is there is a gap in the coverage of XY
+  // near this site.  We can fix this problem simply by adding a new site to
+  // fill this gap, located as closely as possible to the site to avoid.
+  //
+  // To calculate the coverage gap, we look at the two snapped sites on
+  // either side of site_to_avoid, and find the endpoints of their coverage
+  // intervals.  The we place a new site in the gap, located as closely as
+  // possible to the site to avoid.  Note that the new site may move when it
+  // is snapped by the snap_function, but it is guaranteed not to move by
+  // more than snap_radius and therefore its coverage interval will still
+  // intersect the gap.
+  const InputEdge& edge = input_edges_[input_edge_id];
+  const S2Point& x = input_vertices_[edge.first];
+  const S2Point& y = input_vertices_[edge.second];
+  Vector3_d xy_dir = y - x;
+  S2Point n = S2::RobustCrossProd(x, y);
+  S2Point new_site = S2::Project(site_to_avoid, x, y, n);
+  S2Point gap_min = GetCoverageEndpoint(v0, x, y, n);
+  S2Point gap_max = GetCoverageEndpoint(v1, y, x, -n);
+  if ((new_site - gap_min).DotProd(xy_dir) < 0) {
+    new_site = gap_min;
+  } else if ((gap_max - new_site).DotProd(xy_dir) < 0) {
+    new_site = gap_max;
+  }
+  new_site = SnapSite(new_site);
+  S2_DCHECK_NE(v0, new_site);
+  S2_DCHECK_NE(v1, new_site);
+  return new_site;
+}
+
+// Given a site P and an edge XY with normal N, intersect XY with the disc of
+// radius snap_radius() around P, and return the intersection point that is
+// further along the edge XY toward Y.
+S2Point S2Builder::GetCoverageEndpoint(const S2Point& p, const S2Point& x,
+                                       const S2Point& y, const S2Point& n)
+    const {
+  // Consider the plane perpendicular to P that cuts off a spherical cap of
+  // radius snap_radius().  This plane intersects the plane through the edge
+  // XY (perpendicular to N) along a line, and that line intersects the unit
+  // sphere at two points Q and R, and we want to return the point R that is
+  // further along the edge XY toward Y.
+  //
+  // Let M be the midpoint of QR.  This is the point along QR that is closest
+  // to P.  We can now express R as the sum of two perpendicular vectors OM
+  // and MR in the plane XY.  Vector MR is in the direction N x P, while
+  // vector OM is in the direction (N x P) x N, where N = X x Y.
+  //
+  // The length of OM can be found using the Pythagorean theorem on triangle
+  // OPM, and the length of MR can be found using the Pythagorean theorem on
+  // triangle OMR.
+  //
+  // In the calculations below, we save some work by scaling all the vectors
+  // by n.CrossProd(p).Norm2(), and normalizing at the end.
+  double n2 = n.Norm2();
+  double nDp = n.DotProd(p);
+  S2Point nXp = n.CrossProd(p);
+  S2Point nXpXn = n2 * p - nDp * n;
+  Vector3_d om = sqrt(1 - edge_snap_radius_sin2_) * nXpXn;
+  double mr2 = edge_snap_radius_sin2_ * n2 - nDp * nDp;
+
+  // MR is constructed so that it points toward Y (rather than X).
+  Vector3_d mr = sqrt(max(0.0, mr2)) * nXp;
+  return (om + mr).Normalize();
+}
+
+void S2Builder::SnapEdge(InputEdgeId e, vector<SiteId>* chain) const {
+  chain->clear();
+  const InputEdge& edge = input_edges_[e];
+  if (!snapping_needed_) {
+    chain->push_back(edge.first);
+    chain->push_back(edge.second);
+    return;
+  }
+
+  const S2Point& x = input_vertices_[edge.first];
+  const S2Point& y = input_vertices_[edge.second];
+
+  // Optimization: if there is only one nearby site, return.
+  // Optimization: if there are exactly two nearby sites, and one is close
+  // enough to each vertex, then return.
+
+  // Now iterate through the sites.  We keep track of the sequence of sites
+  // that are visited.
+  const auto& candidates = edge_sites_[e];
+  for (SiteId site_id : candidates) {
+    const S2Point& c = sites_[site_id];
+    // Skip any sites that are too far away.  (There will be some of these,
+    // because we also keep track of "sites to avoid".)  Note that some sites
+    // may be close enough to the line containing the edge, but not to the
+    // edge itself, so we can just use the dot product with the edge normal.
+    if (s2pred::CompareEdgeDistance(c, x, y, edge_snap_radius_ca_) > 0) {
+      continue;
+    }
+    // Check whether the new site C excludes the previous site B.  If so,
+    // repeat with the previous site, and so on.
+    bool add_site_c = true;
+    for (; !chain->empty(); chain->pop_back()) {
+      S2Point b = sites_[chain->back()];
+
+      // First, check whether B and C are so far apart that their clipped
+      // Voronoi regions can't intersect.
+      S1ChordAngle bc(b, c);
+      if (bc >= max_adjacent_site_separation_ca_) break;
+
+      // Otherwise, we want to check whether site C prevents the Voronoi
+      // region of B from intersecting XY, or vice versa.  This can be
+      // determined by computing the "coverage interval" (the segment of XY
+      // intersected by the coverage disc of radius snap_radius) for each
+      // site.  If the coverage interval of one site contains the coverage
+      // interval of the other, then the contained site can be excluded.
+      s2pred::Excluded result = s2pred::GetVoronoiSiteExclusion(
+          b, c, x, y, edge_snap_radius_ca_);
+      if (result == s2pred::Excluded::FIRST) continue;  // Site B excluded by C
+      if (result == s2pred::Excluded::SECOND) {
+        add_site_c = false;  // Site C is excluded by B.
+        break;
+      }
+      S2_DCHECK_EQ(s2pred::Excluded::NEITHER, result);
+
+      // Otherwise check whether the previous site A is close enough to B and
+      // C that it might further clip the Voronoi region of B.
+      if (chain->size() < 2) break;
+      S2Point a = sites_[chain->end()[-2]];
+      S1ChordAngle ac(a, c);
+      if (ac >= max_adjacent_site_separation_ca_) break;
+
+      // If triangles ABC and XYB have the same orientation, the circumcenter
+      // Z of ABC is guaranteed to be on the same side of XY as B.
+      int xyb = s2pred::Sign(x, y, b);
+      if (s2pred::Sign(a, b, c) == xyb) {
+        break;  // The circumcenter is on the same side as B but further away.
+      }
+      // Other possible optimizations:
+      //  - if AB > max_adjacent_site_separation_ca_ then keep B.
+      //  - if d(B, XY) < 0.5 * min(AB, BC) then keep B.
+
+      // If the circumcenter of ABC is on the same side of XY as B, then B is
+      // excluded by A and C combined.  Otherwise B is needed and we can exit.
+      if (s2pred::EdgeCircumcenterSign(x, y, a, b, c) != xyb) break;
+    }
+    if (add_site_c) {
+      chain->push_back(site_id);
+    }
+  }
+  S2_DCHECK(!chain->empty());
+  if (google::DEBUG_MODE) {
+    for (SiteId site_id : candidates) {
+      if (s2pred::CompareDistances(y, sites_[chain->back()],
+                                   sites_[site_id]) > 0) {
+        S2_LOG(ERROR) << "Snapping invariant broken!";
+      }
+    }
+  }
+  if (s2builder_verbose) {
+    cpp_compat_cout << "(" << edge.first << "," << edge.second << "): ";
+    for (SiteId id : *chain) cpp_compat_cout << id << " ";
+    cpp_compat_cout << std::endl;
+  }
+}
+
+void S2Builder::BuildLayers() {
+  // Each output edge has an "input edge id set id" (an int32) representing
+  // the set of input edge ids that were snapped to this edge.  The actual
+  // InputEdgeIds can be retrieved using "input_edge_id_set_lexicon".
+  vector<vector<Edge>> layer_edges;
+  vector<vector<InputEdgeIdSetId>> layer_input_edge_ids;
+  IdSetLexicon input_edge_id_set_lexicon;
+  BuildLayerEdges(&layer_edges, &layer_input_edge_ids,
+                  &input_edge_id_set_lexicon);
+
+  // At this point we have no further need for the input geometry or nearby
+  // site data, so we clear those fields to save space.
+  vector<S2Point>().swap(input_vertices_);
+  vector<InputEdge>().swap(input_edges_);
+  vector<compact_array<SiteId>>().swap(edge_sites_);
+
+  // If there are a large number of layers, then we build a minimal subset of
+  // vertices for each layer.  This ensures that layer types that iterate over
+  // vertices will run in time proportional to the size of that layer rather
+  // than the size of all layers combined.
+  vector<vector<S2Point>> layer_vertices;
+  static const int kMinLayersForVertexFiltering = 10;
+  if (layers_.size() >= kMinLayersForVertexFiltering) {
+    // Disable vertex filtering if it is disallowed by any layer.  (This could
+    // be optimized, but in current applications either all layers allow
+    // filtering or none of them do.)
+    bool allow_vertex_filtering = false;
+    for (const auto& options : layer_options_) {
+      allow_vertex_filtering &= options.allow_vertex_filtering();
+    }
+    if (allow_vertex_filtering) {
+      vector<Graph::VertexId> filter_tmp;  // Temporary used by FilterVertices.
+      layer_vertices.resize(layers_.size());
+      for (int i = 0; i < layers_.size(); ++i) {
+        layer_vertices[i] = Graph::FilterVertices(sites_, &layer_edges[i],
+                                                  &filter_tmp);
+      }
+      vector<S2Point>().swap(sites_);  // Release memory
+    }
+  }
+  for (int i = 0; i < layers_.size(); ++i) {
+    const vector<S2Point>& vertices = (layer_vertices.empty() ?
+                                       sites_ : layer_vertices[i]);
+    Graph graph(layer_options_[i], &vertices, &layer_edges[i],
+                &layer_input_edge_ids[i], &input_edge_id_set_lexicon,
+                &label_set_ids_, &label_set_lexicon_,
+                layer_is_full_polygon_predicates_[i]);
+    layers_[i]->Build(graph, error_);
+    // Don't free the layer data until all layers have been built, in order to
+    // support building multiple layers at once (e.g. ClosedSetNormalizer).
+  }
+}
+
+static void DumpEdges(const vector<S2Builder::Graph::Edge>& edges,
+                      const vector<S2Point>& vertices) {
+  for (const auto& e : edges) {
+    vector<S2Point> v;
+    v.push_back(vertices[e.first]);
+    v.push_back(vertices[e.second]);
+    cpp_compat_cout << "S2Polyline: " << s2textformat::ToString(v)
+              << "(" << e.first << "," << e.second << ")" << std::endl;
+  }
+}
+
+// Snaps and possibly simplifies the edges for each layer, populating the
+// given output arguments.  The resulting edges can be used to construct an
+// S2Builder::Graph directly (no further processing is necessary).
+//
+// This method is not "const" because Graph::ProcessEdges can modify
+// layer_options_ in some cases (changing undirected edges to directed ones).
+void S2Builder::BuildLayerEdges(
+    vector<vector<Edge>>* layer_edges,
+    vector<vector<InputEdgeIdSetId>>* layer_input_edge_ids,
+    IdSetLexicon* input_edge_id_set_lexicon) {
+  // Edge chains are simplified only when a non-zero snap radius is specified.
+  // If so, we build a map from each site to the set of input vertices that
+  // snapped to that site.
+  vector<compact_array<InputVertexId>> site_vertices;
+  bool simplify = snapping_needed_ && options_.simplify_edge_chains();
+  if (simplify) site_vertices.resize(sites_.size());
+
+  layer_edges->resize(layers_.size());
+  layer_input_edge_ids->resize(layers_.size());
+  for (int i = 0; i < layers_.size(); ++i) {
+    AddSnappedEdges(layer_begins_[i], layer_begins_[i+1], layer_options_[i],
+                    &(*layer_edges)[i], &(*layer_input_edge_ids)[i],
+                    input_edge_id_set_lexicon, &site_vertices);
+  }
+  if (simplify) {
+    SimplifyEdgeChains(site_vertices, layer_edges, layer_input_edge_ids,
+                       input_edge_id_set_lexicon);
+  }
+  // We simplify edge chains before processing the per-layer GraphOptions
+  // because simplification can create duplicate edges and/or sibling edge
+  // pairs which may need to be removed.
+  for (int i = 0; i < layers_.size(); ++i) {
+    // The errors generated by ProcessEdges are really warnings, so we simply
+    // record them and continue.
+    Graph::ProcessEdges(&layer_options_[i], &(*layer_edges)[i],
+                        &(*layer_input_edge_ids)[i],
+                        input_edge_id_set_lexicon, error_);
+  }
+}
+
+// Snaps all the input edges for a given layer, populating the given output
+// arguments.  If (*site_vertices) is non-empty then it is updated so that
+// (*site_vertices)[site] contains a list of all input vertices that were
+// snapped to that site.
+void S2Builder::AddSnappedEdges(
+    InputEdgeId begin, InputEdgeId end, const GraphOptions& options,
+    vector<Edge>* edges, vector<InputEdgeIdSetId>* input_edge_ids,
+    IdSetLexicon* input_edge_id_set_lexicon,
+    vector<compact_array<InputVertexId>>* site_vertices) const {
+  bool discard_degenerate_edges = (options.degenerate_edges() ==
+                                   GraphOptions::DegenerateEdges::DISCARD);
+  vector<SiteId> chain;
+  for (InputEdgeId e = begin; e < end; ++e) {
+    InputEdgeIdSetId id = input_edge_id_set_lexicon->AddSingleton(e);
+    SnapEdge(e, &chain);
+    MaybeAddInputVertex(input_edges_[e].first, chain[0], site_vertices);
+    if (chain.size() == 1) {
+      if (discard_degenerate_edges) continue;
+      AddSnappedEdge(chain[0], chain[0], id, options.edge_type(),
+                     edges, input_edge_ids);
+    } else {
+      MaybeAddInputVertex(input_edges_[e].second, chain.back(), site_vertices);
+      for (int i = 1; i < chain.size(); ++i) {
+        AddSnappedEdge(chain[i-1], chain[i], id, options.edge_type(),
+                       edges, input_edge_ids);
+      }
+    }
+  }
+  if (s2builder_verbose) DumpEdges(*edges, sites_);
+}
+
+// If "site_vertices" is non-empty, ensures that (*site_vertices)[id] contains
+// "v".  Duplicate entries are allowed.
+inline void S2Builder::MaybeAddInputVertex(
+    InputVertexId v, SiteId id,
+    vector<compact_array<InputVertexId>>* site_vertices) const {
+  if (site_vertices->empty()) return;
+
+  // Optimization: check if we just added this vertex.  This is worthwhile
+  // because the input edges usually form a continuous chain, i.e. the
+  // destination of one edge is the same as the source of the next edge.
+  auto& vertices = (*site_vertices)[id];
+  if (vertices.empty() || vertices.back() != v) {
+    vertices.push_back(v);
+  }
+}
+
+// Adds the given edge to "edges" and "input_edge_ids".  If undirected edges
+// are being used, also adds an edge in the opposite direction.
+inline void S2Builder::AddSnappedEdge(
+    SiteId src, SiteId dst, InputEdgeIdSetId id, EdgeType edge_type,
+    vector<Edge>* edges, vector<InputEdgeIdSetId>* input_edge_ids) const {
+  edges->push_back(Edge(src, dst));
+  input_edge_ids->push_back(id);
+  if (edge_type == EdgeType::UNDIRECTED) {
+    edges->push_back(Edge(dst, src));
+    // Automatically created edges do not have input edge ids or labels.  This
+    // can be used to distinguish the original direction of the undirected edge.
+    input_edge_ids->push_back(IdSetLexicon::EmptySetId());
+  }
+}
+
+// A class that encapsulates the state needed for simplifying edge chains.
+class S2Builder::EdgeChainSimplifier {
+ public:
+  // The graph "g" contains all edges from all layers.  "edge_layers"
+  // indicates the original layer for each edge.  "site_vertices" is a map
+  // from SiteId to the set of InputVertexIds that were snapped to that site.
+  // "layer_edges" and "layer_input_edge_ids" are output arguments where the
+  // simplified edge chains will be placed.  The input and output edges are
+  // not sorted.
+  EdgeChainSimplifier(
+      const S2Builder& builder, const Graph& g,
+      const vector<int>& edge_layers,
+      const vector<compact_array<InputVertexId>>& site_vertices,
+      vector<vector<Edge>>* layer_edges,
+      vector<vector<InputEdgeIdSetId>>* layer_input_edge_ids,
+      IdSetLexicon* input_edge_id_set_lexicon);
+
+  void Run();
+
+ private:
+  using VertexId = Graph::VertexId;
+
+  class InteriorVertexMatcher;
+  void OutputEdge(EdgeId e);
+  int graph_edge_layer(EdgeId e) const;
+  int input_edge_layer(InputEdgeId id) const;
+  bool IsInterior(VertexId v);
+  void SimplifyChain(VertexId v0, VertexId v1);
+  Graph::VertexId FollowChain(VertexId v0, VertexId v1) const;
+  void OutputAllEdges(VertexId v0, VertexId v1);
+  bool TargetInputVertices(VertexId v, S2PolylineSimplifier* simplifier) const;
+  bool AvoidSites(VertexId v0, VertexId v1, VertexId v2,
+                  S2PolylineSimplifier* simplifier) const;
+  void MergeChain(const vector<VertexId>& vertices);
+  void AssignDegenerateEdges(
+      const vector<InputEdgeId>& degenerate_ids,
+      vector<vector<InputEdgeId>>* merged_input_ids) const;
+
+  const S2Builder& builder_;
+  const Graph& g_;
+  Graph::VertexInMap in_;
+  Graph::VertexOutMap out_;
+  vector<int> edge_layers_;
+  const vector<compact_array<InputVertexId>>& site_vertices_;
+  vector<vector<Edge>>* layer_edges_;
+  vector<vector<InputEdgeIdSetId>>* layer_input_edge_ids_;
+  IdSetLexicon* input_edge_id_set_lexicon_;
+
+  // Convenience member copied from builder_.
+  const std::vector<InputEdgeId>& layer_begins_;
+
+  // is_interior_[v] indicates that VertexId "v" is eligible to be an interior
+  // vertex of a simplified edge chain.  You can think of it as vertex whose
+  // indegree and outdegree are both 1 (although the actual definition is a
+  // bit more complicated because of duplicate edges and layers).
+  vector<bool> is_interior_;
+
+  // used_[e] indicates that EdgeId "e" has already been processed.
+  vector<bool> used_;
+
+  // Temporary vectors, declared here to avoid repeated allocation.
+  vector<VertexId> tmp_vertices_;
+  vector<EdgeId> tmp_edges_;
+
+  // The output edges after simplification.
+  vector<Edge> new_edges_;
+  vector<InputEdgeIdSetId> new_input_edge_ids_;
+  vector<int> new_edge_layers_;
+};
+
+// Simplifies edge chains, updating its input/output arguments as necessary.
+void S2Builder::SimplifyEdgeChains(
+    const vector<compact_array<InputVertexId>>& site_vertices,
+    vector<vector<Edge>>* layer_edges,
+    vector<vector<InputEdgeIdSetId>>* layer_input_edge_ids,
+    IdSetLexicon* input_edge_id_set_lexicon) const {
+  if (layers_.empty()) return;
+
+  // Merge the edges from all layers (in order to build a single graph).
+  vector<Edge> merged_edges;
+  vector<InputEdgeIdSetId> merged_input_edge_ids;
+  vector<int> merged_edge_layers;
+  MergeLayerEdges(*layer_edges, *layer_input_edge_ids,
+                  &merged_edges, &merged_input_edge_ids, &merged_edge_layers);
+
+  // The following fields will be reconstructed by EdgeChainSimplifier.
+  for (auto& edges : *layer_edges) edges.clear();
+  for (auto& input_edge_ids : *layer_input_edge_ids) input_edge_ids.clear();
+
+  // The graph options are irrelevant for edge chain simplification, but we
+  // try to set them appropriately anyway.
+  S2Builder::GraphOptions graph_options(EdgeType::DIRECTED,
+                                        GraphOptions::DegenerateEdges::KEEP,
+                                        GraphOptions::DuplicateEdges::KEEP,
+                                        GraphOptions::SiblingPairs::KEEP);
+  Graph graph(graph_options, &sites_, &merged_edges, &merged_input_edge_ids,
+              input_edge_id_set_lexicon, nullptr, nullptr,
+              IsFullPolygonPredicate());
+  EdgeChainSimplifier simplifier(
+      *this, graph, merged_edge_layers, site_vertices,
+      layer_edges, layer_input_edge_ids, input_edge_id_set_lexicon);
+  simplifier.Run();
+}
+
+// Merges the edges from all layers and sorts them in lexicographic order so
+// that we can construct a single graph.  The sort is stable, which means that
+// any duplicate edges within each layer will still be sorted by InputEdgeId.
+void S2Builder::MergeLayerEdges(
+    const vector<vector<Edge>>& layer_edges,
+    const vector<vector<InputEdgeIdSetId>>& layer_input_edge_ids,
+    vector<Edge>* edges, vector<InputEdgeIdSetId>* input_edge_ids,
+    vector<int>* edge_layers) const {
+  vector<LayerEdgeId> order;
+  for (int i = 0; i < layer_edges.size(); ++i) {
+    for (int e = 0; e < layer_edges[i].size(); ++e) {
+      order.push_back(LayerEdgeId(i, e));
+    }
+  }
+  std::sort(order.begin(), order.end(),
+    [&layer_edges](const LayerEdgeId& ai, const LayerEdgeId& bi) {
+         return StableLessThan(layer_edges[ai.first][ai.second],
+                               layer_edges[bi.first][bi.second], ai, bi);
+            });
+  edges->reserve(order.size());
+  input_edge_ids->reserve(order.size());
+  edge_layers->reserve(order.size());
+  for (const LayerEdgeId& id : order) {
+    edges->push_back(layer_edges[id.first][id.second]);
+    input_edge_ids->push_back(layer_input_edge_ids[id.first][id.second]);
+    edge_layers->push_back(id.first);
+  }
+}
+
+// A comparison function that allows stable sorting with std::sort (which is
+// fast but not stable).  It breaks ties between equal edges by comparing
+// their LayerEdgeIds.
+inline bool S2Builder::StableLessThan(
+    const Edge& a, const Edge& b,
+    const LayerEdgeId& ai, const LayerEdgeId& bi) {
+  // The compiler doesn't optimize this as well as it should:
+  //   return make_pair(a, ai) < make_pair(b, bi);
+  if (a.first < b.first) return true;
+  if (b.first < a.first) return false;
+  if (a.second < b.second) return true;
+  if (b.second < a.second) return false;
+  return ai < bi;  // Stable sort.
+}
+
+S2Builder::EdgeChainSimplifier::EdgeChainSimplifier(
+    const S2Builder& builder, const Graph& g, const vector<int>& edge_layers,
+    const vector<compact_array<InputVertexId>>& site_vertices,
+    vector<vector<Edge>>* layer_edges,
+    vector<vector<InputEdgeIdSetId>>* layer_input_edge_ids,
+    IdSetLexicon* input_edge_id_set_lexicon)
+    : builder_(builder), g_(g), in_(g), out_(g), edge_layers_(edge_layers),
+      site_vertices_(site_vertices), layer_edges_(layer_edges),
+      layer_input_edge_ids_(layer_input_edge_ids),
+      input_edge_id_set_lexicon_(input_edge_id_set_lexicon),
+      layer_begins_(builder_.layer_begins_),
+      is_interior_(g.num_vertices()), used_(g.num_edges()) {
+  new_edges_.reserve(g.num_edges());
+  new_input_edge_ids_.reserve(g.num_edges());
+  new_edge_layers_.reserve(g.num_edges());
+}
+
+void S2Builder::EdgeChainSimplifier::Run() {
+  // Determine which vertices can be interior vertices of an edge chain.
+  for (VertexId v = 0; v < g_.num_vertices(); ++v) {
+    is_interior_[v] = IsInterior(v);
+  }
+  // Attempt to simplify all edge chains that start from a non-interior
+  // vertex.  (This takes care of all chains except loops.)
+  for (EdgeId e = 0; e < g_.num_edges(); ++e) {
+    if (used_[e]) continue;
+    Edge edge = g_.edge(e);
+    if (is_interior_[edge.first]) continue;
+    if (!is_interior_[edge.second]) {
+      OutputEdge(e);  // An edge between two non-interior vertices.
+    } else {
+      SimplifyChain(edge.first, edge.second);
+    }
+  }
+  // If there are any edges left, they form one or more disjoint loops where
+  // all vertices are interior vertices.
+  //
+  // TODO(ericv): It would be better to start from the edge with the smallest
+  // min_input_edge_id(), since that would make the output more predictable
+  // for testing purposes.  It also means that we won't create an edge that
+  // spans the start and end of a polyline if the polyline is snapped into a
+  // loop.  (Unfortunately there are pathological examples that prevent us
+  // from guaranteeing this in general, e.g. there could be two polylines in
+  // different layers that snap to the same loop but start at different
+  // positions.  In general we only consider input edge ids to be a hint
+  // towards the preferred output ordering.)
+  for (EdgeId e = 0; e < g_.num_edges(); ++e) {
+    if (used_[e]) continue;
+    Edge edge = g_.edge(e);
+    if (edge.first == edge.second) {
+      // Note that it is safe to output degenerate edges as we go along,
+      // because this vertex has at least one non-degenerate outgoing edge and
+      // therefore we will (or just did) start an edge chain here.
+      OutputEdge(e);
+    } else {
+      SimplifyChain(edge.first, edge.second);
+    }
+  }
+
+  // Finally, copy the output edges into the appropriate layers.  They don't
+  // need to be sorted because the input edges were also unsorted.
+  for (int e = 0; e < new_edges_.size(); ++e) {
+    int layer = new_edge_layers_[e];
+    (*layer_edges_)[layer].push_back(new_edges_[e]);
+    (*layer_input_edge_ids_)[layer].push_back(new_input_edge_ids_[e]);
+  }
+}
+
+// Copies the given edge to the output and marks it as used.
+inline void S2Builder::EdgeChainSimplifier::OutputEdge(EdgeId e) {
+  new_edges_.push_back(g_.edge(e));
+  new_input_edge_ids_.push_back(g_.input_edge_id_set_id(e));
+  new_edge_layers_.push_back(edge_layers_[e]);
+  used_[e] = true;
+}
+
+// Returns the layer that a given graph edge belongs to.
+inline int S2Builder::EdgeChainSimplifier::graph_edge_layer(EdgeId e) const {
+  return edge_layers_[e];
+}
+
+// Returns the layer than a given input edge belongs to.
+int S2Builder::EdgeChainSimplifier::input_edge_layer(InputEdgeId id) const {
+  // NOTE(ericv): If this method shows up in profiling, the result could be
+  // stored with each edge (i.e., edge_layers_ and new_edge_layers_).
+  S2_DCHECK_GE(id, 0);
+  return (std::upper_bound(layer_begins_.begin(), layer_begins_.end(), id) -
+          (layer_begins_.begin() + 1));
+}
+
+// A helper class for determining whether a vertex can be an interior vertex
+// of a simplified edge chain.  Such a vertex must be adjacent to exactly two
+// vertices (across all layers combined), and in each layer the number of
+// incoming edges from one vertex must equal the number of outgoing edges to
+// the other vertex (in both directions).  Furthermore the vertex cannot have
+// any degenerate edges in a given layer unless it has at least one
+// non-degenerate edge in that layer as well.  (Note that usually there will
+// not be any degenerate edges at all, since most layer types discard them.)
+//
+// The last condition is necessary to prevent the following: suppose that one
+// layer has a chain ABC and another layer has a degenerate edge BB (with no
+// other edges incident to B).  Then we can't simplify ABC to AC because there
+// would be no suitable replacement for the edge BB (since the input edge that
+// mapped to BB can't be replaced by any of the edges AA, AC, or CC without
+// moving further than snap_radius).
+class S2Builder::EdgeChainSimplifier::InteriorVertexMatcher {
+ public:
+  // Checks whether "v0" can be an interior vertex of an edge chain.
+  explicit InteriorVertexMatcher(VertexId v0)
+      : v0_(v0), v1_(-1), v2_(-1), n0_(0), n1_(0), n2_(0), excess_out_(0),
+        too_many_endpoints_(false) {
+  }
+
+  // Starts analyzing the edges of a new layer.
+  void StartLayer() {
+    excess_out_ = n0_ = n1_ = n2_ = 0;
+  }
+
+  // This method should be called for each edge incident to "v0" in a given
+  // layer.  (For degenerate edges, it should be called twice.)
+  void Tally(VertexId v, bool outgoing) {
+    excess_out_ += outgoing ? 1 : -1;  // outdegree - indegree
+    if (v == v0_) {
+      ++n0_;  // Counts both endpoints of each degenerate edge.
+    } else {
+      // We keep track of the total number of edges (incoming or outgoing)
+      // connecting v0 to up to two adjacent vertices.
+      if (v1_ < 0) v1_ = v;
+      if (v1_ == v) {
+        ++n1_;
+      } else {
+        if (v2_ < 0) v2_ = v;
+        if (v2_ == v) {
+          ++n2_;
+        } else {
+          too_many_endpoints_ = true;
+        }
+      }
+    }
+  }
+
+  // This method should be called after processing the edges for each layer.
+  // It returns true if "v0" is an interior vertex based on the edges so far.
+  bool Matches() const {
+    // We check that there are the same number of incoming and outgoing edges
+    // in each direction by verifying that (1) indegree(v0) == outdegree(v0)
+    // and (2) the total number of edges (incoming and outgoing) to "v1" and
+    // "v2" are equal.  We also check the condition on degenerate edges that
+    // is documented above.
+    return (!too_many_endpoints_ && excess_out_ == 0 && n1_ == n2_ &&
+            (n0_ == 0 || n1_ > 0));
+  }
+
+ private:
+  VertexId v0_, v1_, v2_;
+  int n0_, n1_, n2_;
+  int excess_out_;           // outdegree(v0) - indegree(v0)
+  bool too_many_endpoints_;  // Have we seen more than two adjacent vertices?
+};
+
+// Returns true if VertexId "v" can be an interior vertex of a simplified edge
+// chain.  (See the InteriorVertexMatcher class for what this implies.)
+bool S2Builder::EdgeChainSimplifier::IsInterior(VertexId v) {
+  // Check a few simple prerequisites.
+  if (out_.degree(v) == 0) return false;
+  if (out_.degree(v) != in_.degree(v)) return false;
+  if (v < builder_.num_forced_sites_) return false;  // Keep forced vertices.
+
+  // Sort the edges so that they are grouped by layer.
+  vector<EdgeId>& edges = tmp_edges_;  // Avoid allocating each time.
+  edges.clear();
+  for (EdgeId e : out_.edge_ids(v)) edges.push_back(e);
+  for (EdgeId e : in_.edge_ids(v)) edges.push_back(e);
+  std::sort(edges.begin(), edges.end(), [this](EdgeId x, EdgeId y) {
+      return graph_edge_layer(x) < graph_edge_layer(y);
+    });
+  // Now feed the edges in each layer to the InteriorVertexMatcher.
+  InteriorVertexMatcher matcher(v);
+  for (auto e = edges.begin(); e != edges.end(); ) {
+    int layer = graph_edge_layer(*e);
+    matcher.StartLayer();
+    for (; e != edges.end() && graph_edge_layer(*e) == layer; ++e) {
+      Edge edge = g_.edge(*e);
+      if (edge.first == v) matcher.Tally(edge.second, true /*outgoing*/);
+      if (edge.second == v) matcher.Tally(edge.first, false /*outgoing*/);
+    }
+    if (!matcher.Matches()) return false;
+  }
+  return true;
+}
+
+// Follows the edge chain starting with (v0, v1) until either we find a
+// non-interior vertex or we return to the original vertex v0.  At each vertex
+// we simplify a subchain of edges that is as long as possible.
+void S2Builder::EdgeChainSimplifier::SimplifyChain(VertexId v0, VertexId v1) {
+  // Avoid allocating "chain" each time by reusing it.
+  vector<VertexId>& chain = tmp_vertices_;
+  S2PolylineSimplifier simplifier;
+  VertexId vstart = v0;
+  bool done = false;
+  do {
+    // Simplify a subchain of edges starting (v0, v1).
+    simplifier.Init(g_.vertex(v0));
+    AvoidSites(v0, v0, v1, &simplifier);
+    chain.push_back(v0);
+    do {
+      chain.push_back(v1);
+      done = !is_interior_[v1] || v1 == vstart;
+      if (done) break;
+
+      // Attempt to extend the chain to the next vertex.
+      VertexId vprev = v0;
+      v0 = v1;
+      v1 = FollowChain(vprev, v0);
+    } while (TargetInputVertices(v0, &simplifier) &&
+             AvoidSites(chain[0], v0, v1, &simplifier) &&
+             simplifier.Extend(g_.vertex(v1)));
+
+    if (chain.size() == 2) {
+      OutputAllEdges(chain[0], chain[1]);  // Could not simplify.
+    } else {
+      MergeChain(chain);
+    }
+    // Note that any degenerate edges that were not merged into a chain are
+    // output by EdgeChainSimplifier::Run().
+    chain.clear();
+  } while (!done);
+}
+
+// Given an edge (v0, v1) where v1 is an interior vertex, returns the (unique)
+// next vertex in the edge chain.
+S2Builder::Graph::VertexId S2Builder::EdgeChainSimplifier::FollowChain(
+    VertexId v0, VertexId v1) const {
+  S2_DCHECK(is_interior_[v1]);
+  for (EdgeId e : out_.edge_ids(v1)) {
+    VertexId v = g_.edge(e).second;
+    if (v != v0 && v != v1) return v;
+  }
+  S2_LOG(FATAL) << "Could not find next edge in edge chain";
+}
+
+// Copies all input edges between v0 and v1 (in both directions) to the output.
+void S2Builder::EdgeChainSimplifier::OutputAllEdges(VertexId v0, VertexId v1) {
+  for (EdgeId e : out_.edge_ids(v0, v1)) OutputEdge(e);
+  for (EdgeId e : out_.edge_ids(v1, v0)) OutputEdge(e);
+}
+
+// Ensures that the simplified edge passes within "edge_snap_radius" of all
+// the *input* vertices that snapped to the given vertex "v".
+bool S2Builder::EdgeChainSimplifier::TargetInputVertices(
+    VertexId v, S2PolylineSimplifier* simplifier) const {
+  for (InputVertexId i : site_vertices_[v]) {
+    if (!simplifier->TargetDisc(builder_.input_vertices_[i],
+                                builder_.edge_snap_radius_ca_)) {
+      return false;
+    }
+  }
+  return true;
+}
+
+// Given the starting vertex v0 and last edge (v1, v2) of an edge chain,
+// restricts the allowable range of angles in order to ensure that all sites
+// near the edge (v1, v2) are avoided by at least min_edge_vertex_separation.
+bool S2Builder::EdgeChainSimplifier::AvoidSites(
+    VertexId v0, VertexId v1, VertexId v2,
+    S2PolylineSimplifier* simplifier) const {
+  const S2Point& p0 = g_.vertex(v0);
+  const S2Point& p1 = g_.vertex(v1);
+  const S2Point& p2 = g_.vertex(v2);
+  S1ChordAngle r1(p0, p1);
+  S1ChordAngle r2(p0, p2);
+
+  // The distance from the start of the edge chain must increase monotonically
+  // for each vertex, since we don't want to simplify chains that backtrack on
+  // themselves (we want a parametric approximation, not a geometric one).
+  if (r2 < r1) return false;
+
+  // We also limit the maximum edge length in order to guarantee that the
+  // simplified edge stays with max_edge_deviation() of all the input edges
+  // that snap to it.
+  if (r2 >= builder_.min_edge_length_to_split_ca_) return false;
+
+  // Otherwise it is sufficient to consider the nearby sites (edge_sites_) for
+  // a single input edge that snapped to (v1, v2) or (v2, v1).  This is
+  // because each edge has a list of all sites within (max_edge_deviation +
+  // min_edge_vertex_separation), and since the output edge is within
+  // max_edge_deviation of all input edges, this list includes all sites
+  // within min_edge_vertex_separation of the output edge.
+  //
+  // Usually there is only one edge to choose from, but it's not much more
+  // effort to choose the edge with the shortest list of edge_sites_.
+  InputEdgeId best = -1;
+  const auto& edge_sites = builder_.edge_sites_;
+  for (EdgeId e : out_.edge_ids(v1, v2)) {
+    for (InputEdgeId id : g_.input_edge_ids(e)) {
+      if (best < 0 || edge_sites[id].size() < edge_sites[best].size())
+        best = id;
+    }
+  }
+  for (EdgeId e : out_.edge_ids(v2, v1)) {
+    for (InputEdgeId id : g_.input_edge_ids(e)) {
+      if (best < 0 || edge_sites[id].size() < edge_sites[best].size())
+        best = id;
+    }
+  }
+  S2_DCHECK_GE(best, 0);  // Because there is at least one outgoing edge.
+
+  for (VertexId v : edge_sites[best]) {
+    // This test is optional since these sites are excluded below anyway.
+    if (v == v0 || v == v1 || v == v2) continue;
+
+    // We are only interested in sites whose distance from "p0" is in the
+    // range (r1, r2).  Sites closer than "r1" have already been processed,
+    // and sites further than "r2" aren't relevant yet.
+    const S2Point& p = g_.vertex(v);
+    S1ChordAngle r(p0, p);
+    if (r <= r1 || r >= r2) continue;
+
+    // We need to figure out whether this site is to the left or right of the
+    // edge chain.  For the first edge this is easy.  Otherwise, since we are
+    // only considering sites in the radius range (r1, r2), we can do this by
+    // checking whether the site is to the left of the wedge (p0, p1, p2).
+    bool disc_on_left = (v1 == v0) ? (s2pred::Sign(p1, p2, p) > 0)
+                                   : s2pred::OrderedCCW(p0, p2, p, p1);
+    if (!simplifier->AvoidDisc(p, builder_.min_edge_site_separation_ca_,
+                               disc_on_left)) {
+      return false;
+    }
+  }
+  return true;
+}
+
+// Given the vertices in a simplified edge chain, adds the corresponding
+// simplified edge(s) to the output.  Note that (1) the edge chain may exist
+// in multiple layers, (2) the edge chain may exist in both directions, (3)
+// there may be more than one copy of an edge chain (in either direction)
+// within a single layer.
+void S2Builder::EdgeChainSimplifier::MergeChain(
+    const vector<VertexId>& vertices) {
+  // Suppose that all interior vertices have M outgoing edges and N incoming
+  // edges.  Our goal is to group the edges into M outgoing chains and N
+  // incoming chains, and then replace each chain by a single edge.
+  vector<vector<InputEdgeId>> merged_input_ids;
+  vector<InputEdgeId> degenerate_ids;
+  int num_out;  // Edge count in the outgoing direction.
+  for (int i = 1; i < vertices.size(); ++i) {
+    VertexId v0 = vertices[i-1];
+    VertexId v1 = vertices[i];
+    auto out_edges = out_.edge_ids(v0, v1);
+    auto in_edges = out_.edge_ids(v1, v0);
+    if (i == 1) {
+      // Allocate space to store the input edge ids associated with each edge.
+      num_out = out_edges.size();
+      merged_input_ids.resize(num_out + in_edges.size());
+      for (vector<InputEdgeId>& ids : merged_input_ids) {
+        ids.reserve(vertices.size() - 1);
+      }
+    } else {
+      // For each interior vertex, we build a list of input edge ids
+      // associated with degenerate edges.  Each input edge ids will be
+      // assigned to one of the output edges later.  (Normally there are no
+      // degenerate edges at all since most layer types don't want them.)
+      S2_DCHECK(is_interior_[v0]);
+      for (EdgeId e : out_.edge_ids(v0, v0)) {
+        for (InputEdgeId id : g_.input_edge_ids(e)) {
+          degenerate_ids.push_back(id);
+        }
+        used_[e] = true;
+      }
+    }
+    // Because the edges were created in layer order, and all sorts used are
+    // stable, the edges are still in layer order.  Therefore we can simply
+    // merge together all the edges in the same relative position.
+    int j = 0;
+    for (EdgeId e : out_edges) {
+      for (InputEdgeId id : g_.input_edge_ids(e)) {
+        merged_input_ids[j].push_back(id);
+      }
+      used_[e] = true;
+      ++j;
+    }
+    for (EdgeId e : in_edges) {
+      for (InputEdgeId id : g_.input_edge_ids(e)) {
+        merged_input_ids[j].push_back(id);
+      }
+      used_[e] = true;
+      ++j;
+    }
+    S2_DCHECK_EQ(merged_input_ids.size(), j);
+  }
+  if (!degenerate_ids.empty()) {
+    std::sort(degenerate_ids.begin(), degenerate_ids.end());
+    AssignDegenerateEdges(degenerate_ids, &merged_input_ids);
+  }
+  // Output the merged edges.
+  VertexId v0 = vertices[0], v1 = vertices[1], vb = vertices.back();
+  for (EdgeId e : out_.edge_ids(v0, v1)) {
+    new_edges_.push_back(Edge(v0, vb));
+    new_edge_layers_.push_back(graph_edge_layer(e));
+  }
+  for (EdgeId e : out_.edge_ids(v1, v0)) {
+    new_edges_.push_back(Edge(vb, v0));
+    new_edge_layers_.push_back(graph_edge_layer(e));
+  }
+  for (const auto& ids : merged_input_ids) {
+    new_input_edge_ids_.push_back(input_edge_id_set_lexicon_->Add(ids));
+  }
+}
+
+// Given a list of the input edge ids associated with degenerate edges in the
+// interior of an edge chain, assigns each input edge id to one of the output
+// edges.
+void S2Builder::EdgeChainSimplifier::AssignDegenerateEdges(
+    const vector<InputEdgeId>& degenerate_ids,
+    vector<vector<InputEdgeId>>* merged_ids) const {
+  // Each degenerate edge is assigned to an output edge in the appropriate
+  // layer.  If there is more than one candidate, we use heuristics so that if
+  // the input consists of a chain of edges provided in consecutive order
+  // (some of which became degenerate), then all those input edges are
+  // assigned to the same output edge.  For example, suppose that one output
+  // edge is labeled with input edges 3,4,7,8, while another output edge is
+  // labeled with input edges 50,51,54,57.  Then if we encounter degenerate
+  // edges labeled with input edges 5 and 6, we would prefer to assign them to
+  // the first edge (yielding the continuous range 3,4,5,6,7,8).
+  //
+  // The heuristic below is only smart enough to handle the case where the
+  // candidate output edges have non-overlapping ranges of input edges.
+  // (Otherwise there is probably not a good heuristic for assigning the
+  // degenerate edges in any case.)
+
+  // Duplicate edge ids don't affect the heuristic below, so we don't bother
+  // removing them.  (They will be removed by IdSetLexicon::Add.)
+  for (auto& ids : *merged_ids) std::sort(ids.begin(), ids.end());
+
+  // Sort the output edges by their minimum input edge id.  This is sufficient
+  // for the purpose of determining which layer they belong to.  With
+  // EdgeType::UNDIRECTED, some edges might not have any input edge ids (i.e.,
+  // if they consist entirely of siblings of input edges).  We simply remove
+  // such edges from the lists of candidates.
+  vector<unsigned> order;
+  order.reserve(merged_ids->size());
+  for (int i = 0; i < merged_ids->size(); ++i) {
+    if (!(*merged_ids)[i].empty()) order.push_back(i);
+  }
+  std::sort(order.begin(), order.end(), [&merged_ids](int i, int j) {
+      return (*merged_ids)[i][0] < (*merged_ids)[j][0];
+    });
+
+  // Now determine where each degenerate edge should be assigned.
+  for (InputEdgeId degenerate_id : degenerate_ids) {
+    int layer = input_edge_layer(degenerate_id);
+
+    // Find the first output edge whose range of input edge ids starts after
+    // "degenerate_id".  If the previous edge belongs to the correct layer,
+    // then we assign the degenerate edge to it.
+    auto it = std::upper_bound(order.begin(), order.end(), degenerate_id,
+                               [&merged_ids](InputEdgeId x, unsigned y) {
+                                 return x < (*merged_ids)[y][0];
+                               });
+    if (it != order.begin()) {
+      if ((*merged_ids)[it[-1]][0] >= layer_begins_[layer]) --it;
+    }
+    S2_DCHECK_EQ(layer, input_edge_layer((*merged_ids)[it[0]][0]));
+    (*merged_ids)[it[0]].push_back(degenerate_id);
+  }
+}
diff --git a/src/s2/s2builder.h b/src/s2/s2builder.h
new file mode 100644 (file)
index 0000000..32bf0e0
--- /dev/null
@@ -0,0 +1,1057 @@
+// Copyright 2016 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// Author: ericv@google.com (Eric Veach)
+//
+// This class is a replacement for S2PolygonBuilder.  Once all clients have
+// been updated to use this class, S2PolygonBuilder will be removed.
+
+#ifndef S2_S2BUILDER_H_
+#define S2_S2BUILDER_H_
+
+#include <memory>
+#include <utility>
+#include <vector>
+#include "s2/base/integral_types.h"
+#include "absl/base/macros.h"
+#include "s2/_fp_contract_off.h"
+#include "s2/id_set_lexicon.h"
+#include "s2/mutable_s2shape_index.h"
+#include "s2/s1angle.h"
+#include "s2/s1chord_angle.h"
+#include "s2/s2cell_id.h"
+#include "s2/s2error.h"
+#include "s2/s2point_index.h"
+#include "s2/s2shape_index.h"
+#include "s2/util/gtl/compact_array.h"
+
+class S2Loop;
+class S2Polygon;
+class S2Polyline;
+
+// S2Builder is a tool for assembling polygonal geometry from edges.  Here are
+// some of the things it is designed for:
+//
+// 1. Building polygons, polylines, and polygon meshes from unsorted
+//    collections of edges.
+//
+// 2. Snapping geometry to discrete representations (such as S2CellId centers
+//    or E7 lat/lng coordinates) while preserving the input topology and with
+//    guaranteed error bounds.
+//
+// 3. Simplifying geometry (e.g. for indexing, display, or storage).
+//
+// 4. Importing geometry from other formats, including repairing geometry
+//    that has errors.
+//
+// 5. As a tool for implementing more complex operations such as polygon
+//    intersections and unions.
+//
+// The implementation is based on the framework of "snap rounding".  Unlike
+// most snap rounding implementations, S2Builder defines edges as geodesics on
+// the sphere (straight lines) and uses the topology of the sphere (i.e.,
+// there are no "seams" at the poles or 180th meridian).  The algorithm is
+// designed to be 100% robust for arbitrary input geometry.  It offers the
+// following properties:
+//
+//   - Guaranteed bounds on how far input vertices and edges can move during
+//     the snapping process (i.e., at most the given "snap_radius").
+//
+//   - Guaranteed minimum separation between edges and vertices other than
+//     their endpoints (similar to the goals of Iterated Snap Rounding).  In
+//     other words, edges that do not intersect in the output are guaranteed
+//     to have a minimum separation between them.
+//
+//   - Idempotency (similar to the goals of Stable Snap Rounding), i.e. if the
+//     input already meets the output criteria then it will not be modified.
+//
+//   - Preservation of the input topology (up to the creation of
+//     degeneracies).  This means that there exists a continuous deformation
+//     from the input to the output such that no vertex crosses an edge.  In
+//     other words, self-intersections won't be created, loops won't change
+//     orientation, etc.
+//
+//   - The ability to snap to arbitrary discrete point sets (such as S2CellId
+//     centers, E7 lat/lng points on the sphere, or simply a subset of the
+//     input vertices), rather than being limited to an integer grid.
+//
+// Here are some of its other features:
+//
+//  - It can handle both directed and undirected edges.  Undirected edges can
+//    be useful for importing data from other formats, e.g. where loops have
+//    unspecified orientations.
+//
+//  - It can eliminate self-intersections by finding all edge pairs that cross
+//    and adding a new vertex at each intersection point.
+//
+//  - It can simplify polygons to within a specified tolerance.  For example,
+//    if two vertices are close enough they will be merged, and if an edge
+//    passes nearby a vertex then it will be rerouted through that vertex.
+//    Optionally, it can also detect nearly straight chains of short edges and
+//    replace them with a single long edge, while maintaining the same
+//    accuracy, separation, and topology guarantees ("simplify_edge_chains").
+//
+//  - It supports many different output types through the concept of "layers"
+//    (polylines, polygons, polygon meshes, etc).  You can build multiple
+//    layers at once in order to ensure that snapping does not create
+//    intersections between different objects (for example, you can simplify a
+//    set of contour lines without the risk of having them cross each other).
+//
+//  - It supports edge labels, which allow you to attach arbitrary information
+//    to edges and have it preserved during the snapping process.  (This can
+//    also be achieved using layers, at a coarser level of granularity.)
+//
+// Caveats:
+//
+//  - Because S2Builder only works with edges, it cannot distinguish between
+//    the empty and full polygons.  If your application can generate both the
+//    empty and full polygons, you must implement logic outside of this class.
+//
+// Example showing how to snap a polygon to E7 coordinates:
+//
+//  using s2builderutil::IntLatLngSnapFunction;
+//  S2Builder builder(S2Builder::Options(IntLatLngSnapFunction(7)));
+//  S2Polygon output;
+//  builder.StartLayer(absl::make_unique<s2builderutil::S2PolygonLayer>(&output));
+//  builder.AddPolygon(input);
+//  S2Error error;
+//  if (!builder.Build(&error)) {
+//    S2_LOG(ERROR) << error;
+//    ...
+//  }
+class S2Builder {
+ public:
+  // Indicates whether the input edges are undirected.  Typically this is
+  // specified for each output layer (e.g., s2builderutil::S2PolygonLayer).
+  //
+  // Directed edges are preferred, since otherwise the output is ambiguous.
+  // For example, output polygons may be the *inverse* of the intended result
+  // (e.g., a polygon intended to represent the world's oceans may instead
+  // represent the world's land masses).  Directed edges are also somewhat
+  // more efficient.
+  //
+  // However even with undirected edges, most S2Builder layer types try to
+  // preserve the input edge direction whenever possible.  Generally, edges
+  // are reversed only when it would yield a simpler output.  For example,
+  // S2PolygonLayer assumes that polygons created from undirected edges should
+  // cover at most half of the sphere.  Similarly, S2PolylineVectorLayer
+  // assembles edges into as few polylines as possible, even if this means
+  // reversing some of the "undirected" input edges.
+  //
+  // For shapes with interiors, directed edges should be oriented so that the
+  // interior is to the left of all edges.  This means that for a polygon with
+  // holes, the outer loops ("shells") should be directed counter-clockwise
+  // while the inner loops ("holes") should be directed clockwise.  Note that
+  // S2Builder::AddPolygon() follows this convention automatically.
+  enum class EdgeType { DIRECTED, UNDIRECTED };
+
+  // A SnapFunction restricts the locations of the output vertices.  For
+  // example, there are predefined snap functions that require vertices to be
+  // located at S2CellId centers or at E5/E6/E7 coordinates.  The SnapFunction
+  // can also specify a minimum spacing between vertices (the "snap radius").
+  //
+  // A SnapFunction defines the following methods:
+  //
+  // 1. The SnapPoint() method, which snaps a point P to a nearby point (the
+  //    "candidate snap site").  Any point may be returned, including P
+  //    itself (this is the "identity snap function").
+  //
+  // 2. "snap_radius", the maximum distance that vertices can move when
+  //    snapped.  The snap_radius must be at least as large as the maximum
+  //    distance between P and SnapPoint(P) for any point P.
+  //
+  // 3. "max_edge_deviation", the maximum distance that edges can move when
+  //    snapped.  It is slightly larger than "snap_radius" because when a
+  //    geodesic edge is snapped, the center of the edge moves further than
+  //    its endpoints.  This value is computed automatically by S2Builder.
+  //
+  // 4. "min_vertex_separation", the guaranteed minimum distance between
+  //    vertices in the output.  This is generally a fraction of
+  //    "snap_radius" where the fraction depends on the snap function.
+  //
+  // 5. A "min_edge_vertex_separation", the guaranteed minimum distance
+  //    between edges and non-incident vertices in the output.  This is
+  //    generally a fraction of "snap_radius" where the fraction depends on
+  //    the snap function.
+  //
+  // It is important to note that SnapPoint() does not define the actual
+  // mapping from input vertices to output vertices, since the points it
+  // returns (the candidate snap sites) are further filtered to ensure that
+  // they are separated by at least the snap radius.  For example, if you
+  // specify E7 coordinates (2cm resolution) and a snap radius of 10m, then a
+  // subset of points returned by SnapPoint will be chosen (the "snap sites"),
+  // and each input vertex will be mapped to the closest site.  Therefore you
+  // cannot assume that P is necessarily snapped to SnapPoint(P).
+  //
+  // S2Builder makes the following guarantees:
+  //
+  // 1. Every vertex is at a location returned by SnapPoint().
+  //
+  // 2. Vertices are within "snap_radius" of the corresponding input vertex.
+  //
+  // 3. Edges are within "max_edge_deviation" of the corresponding input edge
+  //    (a distance slightly larger than "snap_radius").
+  //
+  // 4. Vertices are separated by at least "min_vertex_separation"
+  //    (a fraction of "snap_radius" that depends on the snap function).
+  //
+  // 5. Edges and non-incident vertices are separated by at least
+  //    "min_edge_vertex_separation" (a fraction of "snap_radius").
+  //
+  // 6. Vertex and edge locations do not change unless one of the conditions
+  //    above is not already met (idempotency / stability).
+  //
+  // 7. The topology of the input geometry is preserved (up to the creation
+  //    of degeneracies).  This means that there exists a continuous
+  //    deformation from the input to the output such that no vertex
+  //    crosses an edge.
+  class SnapFunction {
+   public:
+    virtual ~SnapFunction() {}
+
+    // The maximum distance that vertices can move when snapped.
+    //
+    // If the snap radius is zero, then vertices are snapped together only if
+    // they are identical.  Edges will not be snapped to any vertices other
+    // than their endpoints, even if there are vertices whose distance to the
+    // edge is zero, unless split_crossing_edges() is true.
+    //
+    // REQUIRES: snap_radius() <= kMaxSnapRadius
+    virtual S1Angle snap_radius() const = 0;
+
+    // The maximum supported snap radius (equivalent to about 7800km).
+    static S1Angle kMaxSnapRadius();
+
+    // The maximum distance that the center of an edge can move when snapped.
+    // This is slightly larger than "snap_radius" because when a geodesic edge
+    // is snapped, the center of the edge moves further than its endpoints.
+    S1Angle max_edge_deviation() const;
+
+    // The guaranteed minimum distance between vertices in the output.
+    // This is generally some fraction of "snap_radius".
+    virtual S1Angle min_vertex_separation() const = 0;
+
+    // The guaranteed minimum spacing between edges and non-incident vertices
+    // in the output.  This is generally some fraction of "snap_radius".
+    virtual S1Angle min_edge_vertex_separation() const = 0;
+
+    // Returns a candidate snap site for the given point.  The final vertex
+    // locations are a subset of the snap sites returned by this function
+    // (spaced at least "min_vertex_separation" apart).
+    //
+    // The only requirement is that SnapPoint(x) must return a point whose
+    // distance from "x" is no greater than "snap_radius".
+    virtual S2Point SnapPoint(const S2Point& point) const = 0;
+
+    // Returns a deep copy of this SnapFunction.
+    virtual std::unique_ptr<SnapFunction> Clone() const = 0;
+  };
+
+  class Options {
+   public:
+    Options();
+
+    // Convenience constructor that calls set_snap_function().
+    explicit Options(const SnapFunction& snap_function);
+
+    // Sets the desired snap function.  The snap function is copied
+    // internally, so you can safely pass a temporary object.
+    //
+    // Note that if your input data includes vertices that were created using
+    // S2::GetIntersection(), then you should use a "snap_radius" of
+    // at least S2::kIntersectionSnapRadius, e.g. by calling
+    //
+    //  options.set_snap_function(s2builderutil::IdentitySnapFunction(
+    //      S2::kIntersectionSnapRadius));
+    //
+    // DEFAULT: s2builderutil::IdentitySnapFunction(S1Angle::Zero())
+    // [This does no snapping and preserves all input vertices exactly.]
+    const SnapFunction& snap_function() const;
+    void set_snap_function(const SnapFunction& snap_function);
+
+    // If true, then detect all pairs of crossing edges and eliminate them by
+    // adding a new vertex at their intersection point.
+    //
+    // When this option is true, the effective snap_radius() for edges is
+    // increased by S2::kIntersectionError to take into account the
+    // additional error when computing intersection points.  In other words,
+    // edges may move by up to snap_radius() + S2::kIntersectionError.
+    //
+    // Undirected edges should always be used when the output is a polygon,
+    // since splitting a directed loop at a self-intersection converts it into
+    // two loops that don't define a consistent interior according to the
+    // "interior is on the left" rule.  (On the other hand, it is fine to use
+    // directed edges when defining a polygon *mesh* because in that case the
+    // input consists of sibling edge pairs.)
+    //
+    // Self-intersections can also arise when importing data from a 2D
+    // projection.  You can minimize this problem by subdividing the input
+    // edges so that the S2 edges (which are geodesics) stay close to the
+    // original projected edges (which are curves on the sphere).  This can
+    // be done using s2builderutil::EdgeSplitter(), for example.
+    //
+    // DEFAULT: false
+    bool split_crossing_edges() const;
+    void set_split_crossing_edges(bool split_crossing_edges);
+
+    // If true, then simplify the output geometry by replacing nearly straight
+    // chains of short edges with a single long edge.
+    //
+    // The combined effect of snapping and simplifying will not change the
+    // input by more than the guaranteed tolerances (see the list documented
+    // with the SnapFunction class).  For example, simplified edges are
+    // guaranteed to pass within snap_radius() of the *original* positions of
+    // all vertices that were removed from that edge.  This is a much tighter
+    // guarantee than can be achieved by snapping and simplifying separately.
+    //
+    // However, note that this option does not guarantee idempotency.  In
+    // other words, simplifying geometry that has already been simplified once
+    // may simplify it further.  (This is unavoidable, since tolerances are
+    // measured with respect to the original geometry, which is no longer
+    // available when the geometry is simplified a second time.)
+    //
+    // When the output consists of multiple layers, simplification is
+    // guaranteed to be consistent: for example, edge chains are simplified in
+    // the same way across layers, and simplification preserves topological
+    // relationships between layers (e.g., no crossing edges will be created).
+    // Note that edge chains in different layers do not need to be identical
+    // (or even have the same number of vertices, etc) in order to be
+    // simplified together.  All that is required is that they are close
+    // enough together so that the same simplified edge can meet all of their
+    // individual snapping guarantees.
+    //
+    // Note that edge chains are approximated as parametric curves rather than
+    // point sets.  This means that if an edge chain backtracks on itself (for
+    // example, ABCDEFEDCDEFGH) then such backtracking will be preserved to
+    // within snap_radius() (for example, if the preceding point were all in a
+    // straight line then the edge chain would be simplified to ACFCFH, noting
+    // that C and F have degree > 2 and therefore can't be simplified away).
+    //
+    // Simplified edges are assigned all labels associated with the edges of
+    // the simplified chain.
+    //
+    // For this option to have any effect, a SnapFunction with a non-zero
+    // snap_radius() must be specified.  Also note that vertices specified
+    // using ForceVertex are never simplified away.
+    //
+    // DEFAULT: false
+    bool simplify_edge_chains() const;
+    void set_simplify_edge_chains(bool simplify_edge_chains);
+
+    // If true, then snapping occurs only when the input geometry does not
+    // already meet the S2Builder output guarantees (see the SnapFunction
+    // class description for details).  This means that if all input vertices
+    // are at snapped locations, all vertex pairs are separated by at least
+    // min_vertex_separation(), and all edge-vertex pairs are separated by at
+    // least min_edge_vertex_separation(), then no snapping is done.
+    //
+    // If false, then all vertex pairs and edge-vertex pairs closer than
+    // "snap_radius" will be considered for snapping.  This can be useful, for
+    // example, if you know that your geometry contains errors and you want to
+    // make sure that features closer together than "snap_radius" are merged.
+    //
+    // This option is automatically turned off by simplify_edge_chains(),
+    // since simplifying edge chains is never guaranteed to be idempotent.
+    //
+    // DEFAULT: true
+    bool idempotent() const;
+    void set_idempotent(bool idempotent);
+
+    // Options may be assigned and copied.
+    Options(const Options& options);
+    Options& operator=(const Options& options);
+
+   private:
+    std::unique_ptr<SnapFunction> snap_function_;
+    bool split_crossing_edges_ = false;
+    bool simplify_edge_chains_ = false;
+    bool idempotent_ = true;
+  };
+
+  // The following classes are only needed by Layer implementations.
+  class GraphOptions;
+  class Graph;
+
+  // For output layers that represent polygons, there is an ambiguity inherent
+  // in spherical geometry that does not exist in planar geometry.  Namely, if
+  // a polygon has no edges, does it represent the empty polygon (containing
+  // no points) or the full polygon (containing all points)?  This ambiguity
+  // also occurs for polygons that consist only of degeneracies, e.g. a
+  // degenerate loop with only two edges could be either a degenerate shell in
+  // the empty polygon or a degenerate hole in the full polygon.
+  //
+  // To resolve this ambiguity, an IsFullPolygonPredicate may be specified for
+  // each output layer (see AddIsFullPolygonPredicate below).  If the output
+  // after snapping consists only of degenerate edges and/or sibling pairs
+  // (including the case where there are no edges at all), then the layer
+  // implementation calls the given predicate to determine whether the polygon
+  // is empty or full except for those degeneracies.  The predicate is given
+  // an S2Builder::Graph containing the output edges, but note that in general
+  // the predicate must also have knowledge of the input geometry in order to
+  // determine the correct result.
+  //
+  // This predicate is only needed by layers that are assembled into polygons.
+  // It is not used by other layer types.
+  using IsFullPolygonPredicate =
+      std::function<bool (const Graph& g, S2Error* error)>;
+
+  // Default constructor; requires Init() to be called.
+  S2Builder();
+
+  // Convenience constructor that calls Init().  Note that to use the default
+  // options, C++ syntax requires an extra layer of parentheses:
+  //
+  //   S2Builder builder{S2Builder::Options()};
+  explicit S2Builder(const Options& options);
+
+  // Initializes an S2Builder with the given options.
+  void Init(const Options& options);
+  const Options& options() const { return options_; }
+
+  // Starts a new output layer.  This method must be called before adding any
+  // edges to the S2Builder.  You may call this method multiple times to build
+  // multiple geometric objects that are snapped to the same set of sites.
+  //
+  // For example, if you have a set of contour lines, then you could put each
+  // contour line in a separate layer.  This keeps the contour lines separate
+  // from each other, while also ensuring that no crossing edges are created
+  // when they are snapped and/or simplified.  (This is not true if the
+  // contour lines are snapped or simplified independently.)
+  //
+  // Similarly, if you have a set of polygons that share common boundaries
+  // (e.g., countries), you can snap and/or simplify them at the same time by
+  // putting them in different layers, while ensuring that their boundaries
+  // remain consistent (i.e., no crossing edges or T-vertices are introduced).
+  //
+  // Ownership of the layer is transferred to the S2Builder.  Example usage:
+  //
+  // S2Polyline line1, line2;
+  // builder.StartLayer(make_unique<s2builderutil::S2PolylineLayer>(&line1)));
+  // ... Add edges using builder.AddEdge(), etc ...
+  // builder.StartLayer(make_unique<s2builderutil::S2PolylineLayer>(&line2)));
+  // ... Add edges using builder.AddEdge(), etc ...
+  // S2Error error;
+  // S2_CHECK(builder.Build(&error)) << error;  // Builds "line1" & "line2"
+  class Layer;
+  void StartLayer(std::unique_ptr<Layer> layer);
+
+  // Adds a degenerate edge (representing a point) to the current layer.
+  void AddPoint(const S2Point& v);
+
+  // Adds the given edge to the current layer.
+  void AddEdge(const S2Point& v0, const S2Point& v1);
+
+  // Adds the edges in the given polyline.  (Note that if the polyline
+  // consists of 0 or 1 vertices, this method does nothing.)
+  void AddPolyline(const S2Polyline& polyline);
+
+  // Adds the edges in the given loop.  If the sign() of the loop is negative
+  // (i.e. this loop represents a hole within a polygon), the edge directions
+  // are automatically reversed to ensure that the polygon interior is always
+  // to the left of every edge.
+  void AddLoop(const S2Loop& loop);
+
+  // Adds the loops in the given polygon.  Loops representing holes have their
+  // edge directions automatically reversed as described for AddLoop().  Note
+  // that this method does not distinguish between the empty and full polygons,
+  // i.e. adding a full polygon has the same effect as adding an empty one.
+  void AddPolygon(const S2Polygon& polygon);
+
+  // Adds the edges of the given shape to the current layer.
+  void AddShape(const S2Shape& shape);
+
+  // For layers that are assembled into polygons, this method specifies a
+  // predicate that is called when the output consists entirely of degenerate
+  // edges and/or sibling pairs.  The predicate is given an S2Builder::Graph
+  // containing the output edges (if any) and is responsible for deciding
+  // whether this graph represents the empty polygon (possibly with degenerate
+  // shells) or the full polygon (possibly with degenerate holes).  Note that
+  // this cannot be determined from the output edges alone; it also requires
+  // knowledge of the input geometry.  (Also see IsFullPolygonPredicate above.)
+  //
+  // This method should be called at most once per layer; additional calls
+  // simply overwrite the previous value for the current layer.
+  //
+  // The default predicate simply returns false (i.e., degenerate polygons are
+  // assumed to be empty).  Arguably it would better to return an error in
+  // this case, but the fact is that relatively few clients need to be able to
+  // construct full polygons, and it is unreasonable to expect all such
+  // clients to supply an appropriate predicate.
+  //
+  // The reason for having a predicate rather than a boolean value is that the
+  // predicate is responsible for determining whether the output polygon is
+  // empty or full.  In general the input geometry is not degenerate, but
+  // rather collapses into a degenerate configuration due to snapping and/or
+  // simplification.
+  //
+  // TODO(ericv): Provide standard predicates to handle common cases,
+  // e.g. valid input geometry that becomes degenerate due to snapping.
+  void AddIsFullPolygonPredicate(IsFullPolygonPredicate predicate);
+
+  // A predicate that returns an error indicating that no polygon predicate
+  // has been specified.
+  static bool IsFullPolygonUnspecified(const S2Builder::Graph& g,
+                                       S2Error* error);
+
+  // Returns a predicate that returns a constant value (true or false);
+  static IsFullPolygonPredicate IsFullPolygon(bool is_full);
+
+  // Forces a vertex to be located at the given position.  This can be used to
+  // prevent certain input vertices from moving.  However if you are trying to
+  // preserve part of the input boundary, be aware that this option does not
+  // prevent edges from being split by new vertices.
+  //
+  // Forced vertices are never snapped; if this is desired then you need to
+  // call options().snap_function().SnapPoint() explicitly.  Forced vertices
+  // are also never simplified away (if simplify_edge_chains() is used).
+  //
+  // Caveat: Since this method can place vertices arbitrarily close together,
+  // S2Builder makes no minimum separation guaranteees with forced vertices.
+  void ForceVertex(const S2Point& vertex);
+
+  // Every edge can have a set of non-negative integer labels attached to it.
+  // When used with an appropriate layer type, you can then retrieve the
+  // labels associated with each output edge.  This can be useful when merging
+  // or combining data from several sources.  (Note that in many cases it is
+  // easier to use separate output layers rather than labels.)
+  //
+  // Labels are 32-bit non-negative integers.  To support other label types,
+  // you can use ValueLexicon to store the set of unique labels seen so far:
+  //
+  //   ValueLexicon<MyLabel> my_label_lexicon;
+  //   builder.set_label(my_label_lexicon.Add(label));
+  //
+  // The current set of labels is represented as a stack.  This makes it easy
+  // to add and remove labels hierarchically (e.g., polygon 5, loop 2).  Use
+  // set_label() and clear_labels() if you need at most one label per edge.
+  //
+  using Label = int32;
+
+  // Clear the stack of labels.
+  void clear_labels();
+
+  // Add a label to the stack.
+  // REQUIRES: label >= 0.
+  void push_label(Label label);
+
+  // Remove a label from the stack.
+  void pop_label();
+
+  // Convenience function that clears the stack and adds a single label.
+  // REQUIRES: label >= 0.
+  void set_label(Label label);
+
+  // Performs the requested edge splitting, snapping, simplification, etc, and
+  // then assembles the resulting edges into the requested output layers.
+  //
+  // Returns true if all edges were assembled; otherwise sets "error"
+  // appropriately.  Depending on the error, some or all output layers may
+  // have been created.  Automatically resets the S2Builder state so that it
+  // can be reused.
+  //
+  // REQUIRES: error != nullptr.
+  bool Build(S2Error* error);
+
+  // Clears all input data and resets the builder state.  Any options
+  // specified are preserved.
+  void Reset();
+
+ private:
+  //////////////////////  Input Types  /////////////////////////
+  // All types associated with the S2Builder inputs are prefixed with "Input".
+
+  // Identifies an input vertex.
+  using InputVertexId = int32;
+
+  // Defines an input edge.
+  using InputEdge = std::pair<InputVertexId, InputVertexId>;
+
+  // Identifies an input edge.
+  using InputEdgeId = int32;
+
+  // Identifies the set of input edge ids that were snapped to a given edge.
+  using InputEdgeIdSetId = int32;
+
+  // Sort key for prioritizing input vertices.  (Note that keys are *not*
+  // compared using std::less; see SortInputVertices for details.)
+  using InputVertexKey = std::pair<S2CellId, InputVertexId>;
+
+  //////////////////////  Output Types  /////////////////////////
+  // These types define the output vertices and edges.
+
+  // Identifies a snapped vertex ("snap site").  If there is only one layer,
+  // than SiteId is the same as Graph::VertexId, but if there are many layers
+  // then each Graph may contain only a subset of the sites.  Also see
+  // GraphOptions::allow_vertex_filtering().
+  using SiteId = int32;
+
+  // Defines an output edge.
+  using Edge = std::pair<SiteId, SiteId>;
+
+  // Identifies an output edge.
+  using EdgeId = int32;
+
+  // Identifies an output edge in a particular layer.
+  using LayerEdgeId = std::pair<int, EdgeId>;
+
+  class EdgeChainSimplifier;
+
+  InputVertexId AddVertex(const S2Point& v);
+  void ChooseSites();
+  void CopyInputEdges();
+  std::vector<InputVertexKey> SortInputVertices();
+  void AddEdgeCrossings(const MutableS2ShapeIndex& input_edge_index);
+  void AddForcedSites(S2PointIndex<SiteId>* site_index);
+  bool is_forced(SiteId v) const;
+  void ChooseInitialSites(S2PointIndex<SiteId>* site_index);
+  S2Point SnapSite(const S2Point& point) const;
+  void CollectSiteEdges(const S2PointIndex<SiteId>& site_index);
+  void SortSitesByDistance(const S2Point& x,
+                           gtl::compact_array<SiteId>* sites) const;
+  void AddExtraSites(const MutableS2ShapeIndex& input_edge_index);
+  void MaybeAddExtraSites(InputEdgeId edge_id,
+                          InputEdgeId max_edge_id,
+                          const std::vector<SiteId>& chain,
+                          const MutableS2ShapeIndex& input_edge_index,
+                          std::vector<InputEdgeId>* snap_queue);
+  void AddExtraSite(const S2Point& new_site,
+                    InputEdgeId max_edge_id,
+                    const MutableS2ShapeIndex& input_edge_index,
+                    std::vector<InputEdgeId>* snap_queue);
+  S2Point GetSeparationSite(const S2Point& site_to_avoid,
+                            const S2Point& v0, const S2Point& v1,
+                            InputEdgeId input_edge_id) const;
+  S2Point GetCoverageEndpoint(const S2Point& p, const S2Point& x,
+                              const S2Point& y, const S2Point& n) const;
+  void SnapEdge(InputEdgeId e, std::vector<SiteId>* chain) const;
+
+  void BuildLayers();
+  void BuildLayerEdges(
+      std::vector<std::vector<Edge>>* layer_edges,
+      std::vector<std::vector<InputEdgeIdSetId>>* layer_input_edge_ids,
+      IdSetLexicon* input_edge_id_set_lexicon);
+  void AddSnappedEdges(
+      InputEdgeId begin, InputEdgeId end, const GraphOptions& options,
+      std::vector<Edge>* edges, std::vector<InputEdgeIdSetId>* input_edge_ids,
+      IdSetLexicon* input_edge_id_set_lexicon,
+      std::vector<gtl::compact_array<InputVertexId>>* site_vertices) const;
+  void MaybeAddInputVertex(
+      InputVertexId v, SiteId id,
+      std::vector<gtl::compact_array<InputVertexId>>* site_vertices) const;
+  void AddSnappedEdge(SiteId src, SiteId dst, InputEdgeIdSetId id,
+                      EdgeType edge_type, std::vector<Edge>* edges,
+                      std::vector<InputEdgeIdSetId>* input_edge_ids) const;
+  void SimplifyEdgeChains(
+      const std::vector<gtl::compact_array<InputVertexId>>& site_vertices,
+      std::vector<std::vector<Edge>>* layer_edges,
+      std::vector<std::vector<InputEdgeIdSetId>>* layer_input_edge_ids,
+      IdSetLexicon* input_edge_id_set_lexicon) const;
+  void MergeLayerEdges(
+      const std::vector<std::vector<Edge>>& layer_edges,
+      const std::vector<std::vector<InputEdgeIdSetId>>& layer_input_edge_ids,
+      std::vector<Edge>* edges,
+      std::vector<InputEdgeIdSetId>* input_edge_ids,
+      std::vector<int>* edge_layers) const;
+  static bool StableLessThan(const Edge& a, const Edge& b,
+                             const LayerEdgeId& ai, const LayerEdgeId& bi);
+
+  //////////// Parameters /////////////
+
+  // S2Builder options.
+  Options options_;
+
+  // The maximum distance (inclusive) that a vertex can move when snapped,
+  // equal to S1ChordAngle(options_.snap_function().snap_radius()).
+  S1ChordAngle site_snap_radius_ca_;
+
+  // The maximum distance (inclusive) that an edge can move when snapping to a
+  // snap site.  It can be slightly larger than the site snap radius when
+  // edges are being split at crossings.
+  S1ChordAngle edge_snap_radius_ca_;
+
+  S1Angle max_edge_deviation_;
+  S1ChordAngle edge_site_query_radius_ca_;
+  S1ChordAngle min_edge_length_to_split_ca_;
+
+  S1Angle min_site_separation_;
+  S1ChordAngle min_site_separation_ca_;
+  S1ChordAngle min_edge_site_separation_ca_;
+  S1ChordAngle min_edge_site_separation_ca_limit_;
+
+  S1ChordAngle max_adjacent_site_separation_ca_;
+
+  // The squared sine of the edge snap radius.  This is equivalent to the snap
+  // radius (squared) for distances measured through the interior of the
+  // sphere to the plane containing an edge.  This value is used only when
+  // interpolating new points along edges (see GetSeparationSite).
+  double edge_snap_radius_sin2_;
+
+  // A copy of the argument to Build().
+  S2Error* error_;
+
+  // True if snapping was requested.  This is true if either snap_radius() is
+  // positive, or split_crossing_edges() is true (which implicitly requests
+  // snapping to ensure that both crossing edges are snapped to the
+  // intersection point).
+  bool snapping_requested_;
+
+  // Initially false, and set to true when it is discovered that at least one
+  // input vertex or edge does not meet the output guarantees (e.g., that
+  // vertices are separated by at least snap_function.min_vertex_separation).
+  bool snapping_needed_;
+
+  //////////// Input Data /////////////
+
+  // A flag indicating whether label_set_ has been modified since the last
+  // time label_set_id_ was computed.
+  bool label_set_modified_;
+
+  std::vector<S2Point> input_vertices_;
+  std::vector<InputEdge> input_edges_;
+
+  std::vector<std::unique_ptr<Layer>> layers_;
+  std::vector<GraphOptions> layer_options_;
+  std::vector<InputEdgeId> layer_begins_;
+  std::vector<IsFullPolygonPredicate> layer_is_full_polygon_predicates_;
+
+  // Each input edge has "label set id" (an int32) representing the set of
+  // labels attached to that edge.  This vector is populated only if at least
+  // one label is used.
+  using LabelSetId = int32;
+  std::vector<LabelSetId> label_set_ids_;
+  IdSetLexicon label_set_lexicon_;
+
+  // The current set of labels (represented as a stack).
+  std::vector<Label> label_set_;
+
+  // The LabelSetId corresponding to the current label set, computed on demand
+  // (by adding it to label_set_lexicon()).
+  LabelSetId label_set_id_;
+
+  ////////////// Data for Snapping and Simplifying //////////////
+
+  // The number of sites specified using ForceVertex().  These sites are
+  // always at the beginning of the sites_ vector.
+  SiteId num_forced_sites_;
+
+  // The set of snapped vertex locations ("sites").
+  std::vector<S2Point> sites_;
+
+  // A map from each input edge to the set of sites "nearby" that edge,
+  // defined as the set of sites that are candidates for snapping and/or
+  // avoidance.  Note that compact_array will inline up to two sites, which
+  // usually takes care of the vast majority of edges.  Sites are kept sorted
+  // by increasing distance from the origin of the input edge.
+  //
+  // Once snapping is finished, this field is discarded unless edge chain
+  // simplification was requested, in which case instead the sites are
+  // filtered by removing the ones that each edge was snapped to, leaving only
+  // the "sites to avoid" (needed for simplification).
+  std::vector<gtl::compact_array<SiteId>> edge_sites_;
+
+  S2Builder(const S2Builder&) = delete;
+  S2Builder& operator=(const S2Builder&) = delete;
+};
+
+// This class is only needed by S2Builder::Layer implementations.  A layer is
+// responsible for assembling an S2Builder::Graph of snapped edges into the
+// desired output format (e.g., an S2Polygon).  The GraphOptions class allows
+// each Layer type to specify requirements on its input graph: for example, if
+// DegenerateEdges::DISCARD is specified, then S2Builder will ensure that all
+// degenerate edges are removed before passing the graph to the S2Layer::Build
+// method.
+class S2Builder::GraphOptions {
+ public:
+  using EdgeType = S2Builder::EdgeType;
+  enum class DegenerateEdges;
+  enum class DuplicateEdges;
+  enum class SiblingPairs;
+
+  // All S2Builder::Layer subtypes should specify GraphOptions explicitly
+  // using this constructor, rather than relying on default values.
+  GraphOptions(EdgeType edge_type, DegenerateEdges degenerate_edges,
+               DuplicateEdges duplicate_edges, SiblingPairs sibling_pairs)
+      : edge_type_(edge_type), degenerate_edges_(degenerate_edges),
+        duplicate_edges_(duplicate_edges), sibling_pairs_(sibling_pairs),
+        allow_vertex_filtering_(true) {
+  }
+
+  // The default options specify that all edges should be kept, since this
+  // produces the least surprising output and makes it easier to diagnose the
+  // problem when an option is left unspecified.
+  GraphOptions() : edge_type_(EdgeType::DIRECTED),
+                   degenerate_edges_(DegenerateEdges::KEEP),
+                   duplicate_edges_(DuplicateEdges::KEEP),
+                   sibling_pairs_(SiblingPairs::KEEP),
+                   allow_vertex_filtering_(true) {
+  }
+
+  // Specifies whether the S2Builder input edges should be treated as
+  // undirected.  If true, then all input edges are duplicated into pairs
+  // consisting of an edge and a sibling (reverse) edge.  The layer
+  // implementation is responsible for ensuring that exactly one edge from
+  // each pair is used in the output, i.e. *only half* of the graph edges will
+  // be used.  (Note that some values of the sibling_pairs() option
+  // automatically take care of this issue by removing half of the edges and
+  // changing edge_type() to DIRECTED.)
+  //
+  // DEFAULT: EdgeType::DIRECTED
+  EdgeType edge_type() const;
+  void set_edge_type(EdgeType edge_type);
+
+  // Controls how degenerate edges (i.e., an edge from a vertex to itself) are
+  // handled.  Such edges may be present in the input, or they may be created
+  // when both endpoints of an edge are snapped to the same output vertex.
+  // The options available are:
+  //
+  // DISCARD: Discards all degenerate edges.  This is useful for layers that
+  //          do not support degeneracies, such as S2PolygonLayer.
+  //
+  // DISCARD_EXCESS: Discards all degenerate edges that are connected to
+  //                 non-degenerate edges.  (Any remaining duplicate edges can
+  //                 be merged using DuplicateEdges::MERGE.)  This is useful
+  //                 for simplifying polygons while ensuring that loops that
+  //                 collapse to a single point do not disappear.
+  //
+  // KEEP: Keeps all degenerate edges.  Be aware that this may create many
+  //       redundant edges when simplifying geometry (e.g., a polyline of the
+  //       form AABBBBBCCCCCCDDDD).  DegenerateEdges::KEEP is mainly useful
+  //       for algorithms that require an output edge for every input edge.
+  //
+  // DEFAULT: DegenerateEdges::KEEP
+  enum class DegenerateEdges { DISCARD, DISCARD_EXCESS, KEEP };
+  DegenerateEdges degenerate_edges() const;
+  void set_degenerate_edges(DegenerateEdges degenerate_edges);
+
+  // Controls how duplicate edges (i.e., edges that are present multiple
+  // times) are handled.  Such edges may be present in the input, or they can
+  // be created when vertices are snapped together.  When several edges are
+  // merged, the result is a single edge labelled with all of the original
+  // input edge ids.
+  //
+  // DEFAULT: DuplicateEdges::KEEP
+  enum class DuplicateEdges { MERGE, KEEP };
+  DuplicateEdges duplicate_edges() const;
+  void set_duplicate_edges(DuplicateEdges duplicate_edges);
+
+  // Controls how sibling edge pairs (i.e., pairs consisting of an edge and
+  // its reverse edge) are handled.  Layer types that define an interior
+  // (e.g., polygons) normally discard such edge pairs since they do not
+  // affect the result (i.e., they define a "loop" with no interior).  The
+  // various options include:
+  //
+  // DISCARD: Discards all sibling edge pairs.
+  //
+  // DISCARD_EXCESS: Like DISCARD, except that a single sibling pair is kept
+  //                 if the result would otherwise be empty.  This is useful
+  //                 for polygons with degeneracies (S2LaxPolygonShape), and
+  //                 for simplifying polylines while ensuring that they are
+  //                 not split into multiple disconnected pieces.
+  //
+  // KEEP: Keeps sibling pairs.  This can be used to create polylines that
+  //       double back on themselves, or degenerate loops (with a layer type
+  //       such as S2LaxPolygonShape).
+  //
+  // REQUIRE: Requires that all edges have a sibling (and returns an error
+  //          otherwise).  This is useful with layer types that create a
+  //          collection of adjacent polygons (a polygon mesh).
+  //
+  // CREATE: Ensures that all edges have a sibling edge by creating them if
+  //         necessary.  This is useful with polygon meshes where the input
+  //         polygons do not cover the entire sphere.  Such edges always
+  //         have an empty set of labels.
+  //
+  // If edge_type() is EdgeType::UNDIRECTED, a sibling edge pair is considered
+  // to consist of four edges (two duplicate edges and their siblings), since
+  // only two of these four edges will be used in the final output.
+  //
+  // Furthermore, since the options REQUIRE and CREATE guarantee that all
+  // edges will have siblings, S2Builder implements these options for
+  // undirected edges by discarding half of the edges in each direction and
+  // changing the edge_type() to EdgeType::DIRECTED.  For example, two
+  // undirected input edges between vertices A and B would first be converted
+  // into two directed edges in each direction, and then one edge of each pair
+  // would be discarded leaving only one edge in each direction.
+  //
+  // Degenerate edges are considered not to have siblings.  If such edges are
+  // present, they are passed through unchanged by SiblingPairs::DISCARD.  For
+  // SiblingPairs::REQUIRE or SiblingPairs::CREATE with undirected edges, the
+  // number of copies of each degenerate edge is reduced by a factor of two.
+  //
+  // Any of the options that discard edges (DISCARD, DISCARD_EXCESS, and
+  // REQUIRE/CREATE in the case of undirected edges) have the side effect that
+  // when duplicate edges are present, all of the corresponding edge labels
+  // are merged together and assigned to the remaining edges.  (This avoids
+  // the problem of having to decide which edges are discarded.)  Note that
+  // this merging takes place even when all copies of an edge are kept, and
+  // that even labels attached to duplicate degenerate edges are merged.  For
+  // example, consider the graph {AB1, AB2, BA3, CD4, CD5} (where XYn denotes
+  // an edge from X to Y with label "n").  With SiblingPairs::DISCARD, we need
+  // to discard one of the copies of AB.  But which one?  Rather than choosing
+  // arbitrarily, instead we merge the labels of all duplicate edges (even
+  // ones where no sibling pairs were discarded), yielding {AB12, CD45, CD45}
+  // (assuming that duplicate edges are being kept).
+  //
+  // DEFAULT: SiblingPairs::KEEP
+  enum class SiblingPairs { DISCARD, DISCARD_EXCESS, KEEP, REQUIRE, CREATE };
+  SiblingPairs sibling_pairs() const;
+  void set_sibling_pairs(SiblingPairs sibling_pairs);
+
+  // This is a specialized option that is only needed by clients want to work
+  // with the graphs for multiple layers at the same time (e.g., in order to
+  // check whether the same edge is present in two different graphs).  [Note
+  // that if you need to do this, usually it is easier just to build a single
+  // graph with suitable edge labels.]
+  //
+  // When there are a large number of layers, then by default S2Builder builds
+  // a minimal subgraph for each layer containing only the vertices needed by
+  // the edges in that layer.  This ensures that layer types that iterate over
+  // the vertices run in time proportional to the size of that layer rather
+  // than the size of all layers combined.  (For example, if there are a
+  // million layers with one edge each, then each layer would be passed a
+  // graph with 2 vertices rather than 2 million vertices.)
+  //
+  // If this option is set to false, this optimization is disabled.  Instead
+  // the graph passed to this layer will contain the full set of vertices.
+  // (This is not recommended when the number of layers could be large.)
+  //
+  // DEFAULT: true
+  bool allow_vertex_filtering() const;
+  void set_allow_vertex_filtering(bool allow_vertex_filtering);
+
+ private:
+  EdgeType edge_type_;
+  DegenerateEdges degenerate_edges_;
+  DuplicateEdges duplicate_edges_;
+  SiblingPairs sibling_pairs_;
+  bool allow_vertex_filtering_;
+};
+
+bool operator==(const S2Builder::GraphOptions& x,
+                const S2Builder::GraphOptions& y);
+
+
+//////////////////   Implementation details follow   ////////////////////
+
+
+// The maximum snap radius is just large enough to support snapping to
+// S2CellId level 0.  It is equivalent to 7800km on the Earth's surface.
+inline S1Angle S2Builder::SnapFunction::kMaxSnapRadius() {
+  // This value can't be larger than 85.7 degrees without changing the code
+  // related to min_edge_length_to_split_ca_, and increasing it to 90 degrees
+  // or more would most likely require significant changes to the algorithm.
+  return S1Angle::Degrees(70);
+}
+
+inline const S2Builder::SnapFunction& S2Builder::Options::snap_function()
+    const {
+  return *snap_function_;
+}
+
+inline void S2Builder::Options::set_snap_function(
+    const SnapFunction& snap_function) {
+  snap_function_ = snap_function.Clone();
+}
+
+inline bool S2Builder::Options::split_crossing_edges() const {
+  return split_crossing_edges_;
+}
+
+inline void S2Builder::Options::set_split_crossing_edges(
+    bool split_crossing_edges) {
+  split_crossing_edges_ = split_crossing_edges;
+}
+
+inline bool S2Builder::Options::simplify_edge_chains() const {
+  return simplify_edge_chains_;
+}
+
+inline void S2Builder::Options::set_simplify_edge_chains(
+    bool simplify_edge_chains) {
+  simplify_edge_chains_ = simplify_edge_chains;
+
+  // Simplification requires a non-zero snap radius, and while it might be
+  // possible to do some simplifying without snapping, it is much simpler to
+  // always snap (even if the input geometry already meets the other output
+  // requirements).  We need to compute edge_sites_ in order to avoid
+  // approaching non-incident vertices too closely, for example.
+  set_idempotent(false);
+}
+
+inline bool S2Builder::Options::idempotent() const {
+  return idempotent_;
+}
+
+inline void S2Builder::Options::set_idempotent(bool idempotent) {
+  idempotent_ = idempotent;
+}
+
+inline S2Builder::GraphOptions::EdgeType
+S2Builder::GraphOptions::edge_type() const {
+  return edge_type_;
+}
+
+inline void S2Builder::GraphOptions::set_edge_type(EdgeType edge_type) {
+  edge_type_ = edge_type;
+}
+
+inline S2Builder::GraphOptions::DegenerateEdges
+S2Builder::GraphOptions::degenerate_edges() const {
+  return degenerate_edges_;
+}
+
+inline void S2Builder::GraphOptions::set_degenerate_edges(
+    DegenerateEdges degenerate_edges) {
+  degenerate_edges_ = degenerate_edges;
+}
+
+inline S2Builder::GraphOptions::DuplicateEdges
+S2Builder::GraphOptions::duplicate_edges() const {
+  return duplicate_edges_;
+}
+
+inline void S2Builder::GraphOptions::set_duplicate_edges(
+    DuplicateEdges duplicate_edges) {
+  duplicate_edges_ = duplicate_edges;
+}
+
+inline S2Builder::GraphOptions::SiblingPairs
+S2Builder::GraphOptions::sibling_pairs() const {
+  return sibling_pairs_;
+}
+
+inline void S2Builder::GraphOptions::set_sibling_pairs(
+    SiblingPairs sibling_pairs) {
+  sibling_pairs_ = sibling_pairs;
+}
+
+inline bool S2Builder::GraphOptions::allow_vertex_filtering() const {
+  return allow_vertex_filtering_;
+}
+
+inline void S2Builder::GraphOptions::set_allow_vertex_filtering(
+    bool allow_vertex_filtering) {
+  allow_vertex_filtering_ = allow_vertex_filtering;
+}
+
+inline bool S2Builder::is_forced(SiteId v) const {
+  return v < num_forced_sites_;
+}
+
+inline void S2Builder::AddPoint(const S2Point& v) {
+  AddEdge(v, v);
+}
+
+#endif  // S2_S2BUILDER_H_
diff --git a/src/s2/s2builder_graph.cc b/src/s2/s2builder_graph.cc
new file mode 100644 (file)
index 0000000..3d51353
--- /dev/null
@@ -0,0 +1,1084 @@
+// Copyright 2016 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// Author: ericv@google.com (Eric Veach)
+
+#include "s2/s2builder_graph.h"
+
+#include <algorithm>
+#include <limits>
+#include <memory>
+#include <numeric>
+#include <vector>
+#include "s2/base/logging.h"
+#include "absl/container/btree_map.h"
+#include "s2/id_set_lexicon.h"
+#include "s2/s2builder.h"
+#include "s2/s2error.h"
+#include "s2/s2predicates.h"
+
+using std::make_pair;
+using std::max;
+using std::min;
+using std::pair;
+using std::vector;
+
+using Graph = S2Builder::Graph;
+using GraphOptions = S2Builder::GraphOptions;
+using DegenerateEdges = GraphOptions::DegenerateEdges;
+using DuplicateEdges = GraphOptions::DuplicateEdges;
+using SiblingPairs = GraphOptions::SiblingPairs;
+
+Graph::Graph(const GraphOptions& options,
+             const vector<S2Point>* vertices,
+             const vector<Edge>* edges,
+             const vector<InputEdgeIdSetId>* input_edge_id_set_ids,
+             const IdSetLexicon* input_edge_id_set_lexicon,
+             const vector<LabelSetId>* label_set_ids,
+             const IdSetLexicon* label_set_lexicon,
+             IsFullPolygonPredicate is_full_polygon_predicate)
+    : options_(options), num_vertices_(vertices->size()), vertices_(vertices),
+      edges_(edges), input_edge_id_set_ids_(input_edge_id_set_ids),
+      input_edge_id_set_lexicon_(input_edge_id_set_lexicon),
+      label_set_ids_(label_set_ids),
+      label_set_lexicon_(label_set_lexicon),
+      is_full_polygon_predicate_(std::move(is_full_polygon_predicate)) {
+  S2_DCHECK(std::is_sorted(edges->begin(), edges->end()));
+  S2_DCHECK_EQ(edges->size(), input_edge_id_set_ids->size());
+}
+
+vector<Graph::EdgeId> Graph::GetInEdgeIds() const {
+  vector<EdgeId> in_edge_ids(num_edges());
+  std::iota(in_edge_ids.begin(), in_edge_ids.end(), 0);
+  std::sort(in_edge_ids.begin(), in_edge_ids.end(),
+            [this](EdgeId ai, EdgeId bi) {
+      return StableLessThan(reverse(edge(ai)), reverse(edge(bi)), ai, bi);
+    });
+  return in_edge_ids;
+}
+
+vector<Graph::EdgeId> Graph::GetSiblingMap() const {
+  vector<EdgeId> in_edge_ids = GetInEdgeIds();
+  MakeSiblingMap(&in_edge_ids);
+  return in_edge_ids;
+}
+
+void Graph::MakeSiblingMap(vector<Graph::EdgeId>* in_edge_ids) const {
+  S2_DCHECK(options_.sibling_pairs() == SiblingPairs::REQUIRE ||
+         options_.sibling_pairs() == SiblingPairs::CREATE ||
+         options_.edge_type() == EdgeType::UNDIRECTED);
+  for (EdgeId e = 0; e < num_edges(); ++e) {
+    S2_DCHECK(edge(e) == reverse(edge((*in_edge_ids)[e])));
+  }
+  if (options_.edge_type() == EdgeType::DIRECTED) return;
+  if (options_.degenerate_edges() == DegenerateEdges::DISCARD) return;
+
+  for (EdgeId e = 0; e < num_edges(); ++e) {
+    VertexId v = edge(e).first;
+    if (edge(e).second == v) {
+      S2_DCHECK_LT(e + 1, num_edges());
+      S2_DCHECK_EQ(edge(e + 1).first, v);
+      S2_DCHECK_EQ(edge(e + 1).second, v);
+      S2_DCHECK_EQ((*in_edge_ids)[e], e);
+      S2_DCHECK_EQ((*in_edge_ids)[e + 1], e + 1);
+      (*in_edge_ids)[e] = e + 1;
+      (*in_edge_ids)[e + 1] = e;
+      ++e;
+    }
+  }
+}
+
+void Graph::VertexOutMap::Init(const Graph& g) {
+  edges_ = &g.edges();
+  edge_begins_.reserve(g.num_vertices() + 1);
+  EdgeId e = 0;
+  for (VertexId v = 0; v <= g.num_vertices(); ++v) {
+    while (e < g.num_edges() && g.edge(e).first < v) ++e;
+    edge_begins_.push_back(e);
+  }
+}
+
+void Graph::VertexInMap::Init(const Graph& g) {
+  in_edge_ids_ = g.GetInEdgeIds();
+  in_edge_begins_.reserve(g.num_vertices() + 1);
+  EdgeId e = 0;
+  for (VertexId v = 0; v <= g.num_vertices(); ++v) {
+    while (e < g.num_edges() && g.edge(in_edge_ids_[e]).second < v) ++e;
+    in_edge_begins_.push_back(e);
+  }
+}
+
+void Graph::LabelFetcher::Init(const Graph& g, S2Builder::EdgeType edge_type) {
+  g_ = &g;
+  edge_type_ = edge_type;
+  if (edge_type == EdgeType::UNDIRECTED) sibling_map_ = g.GetSiblingMap();
+}
+
+void Graph::LabelFetcher::Fetch(EdgeId e, vector<S2Builder::Label>* labels) {
+  labels->clear();
+  for (InputEdgeId input_edge_id : g_->input_edge_ids(e)) {
+    for (Label label : g_->labels(input_edge_id)) {
+      labels->push_back(label);
+    }
+  }
+  if (edge_type_ == EdgeType::UNDIRECTED) {
+    for (InputEdgeId input_edge_id : g_->input_edge_ids(sibling_map_[e])) {
+      for (Label label : g_->labels(input_edge_id)) {
+        labels->push_back(label);
+      }
+    }
+  }
+  if (labels->size() > 1) {
+    std::sort(labels->begin(), labels->end());
+    labels->erase(std::unique(labels->begin(), labels->end()), labels->end());
+  }
+}
+
+S2Builder::InputEdgeId Graph::min_input_edge_id(EdgeId e) const {
+  IdSetLexicon::IdSet id_set = input_edge_ids(e);
+  return (id_set.size() == 0) ? kNoInputEdgeId : *id_set.begin();
+}
+
+vector<S2Builder::InputEdgeId> Graph::GetMinInputEdgeIds() const {
+  vector<InputEdgeId> min_input_ids(num_edges());
+  for (EdgeId e = 0; e < num_edges(); ++e) {
+    min_input_ids[e] = min_input_edge_id(e);
+  }
+  return min_input_ids;
+}
+
+vector<Graph::EdgeId> Graph::GetInputEdgeOrder(
+    const vector<InputEdgeId>& input_ids) const {
+  vector<EdgeId> order(input_ids.size());
+  std::iota(order.begin(), order.end(), 0);
+  std::sort(order.begin(), order.end(), [&input_ids](EdgeId a, EdgeId b) {
+      // Comparison function ensures sort is stable.
+      return make_pair(input_ids[a], a) < make_pair(input_ids[b], b);
+    });
+  return order;
+}
+
+// A struct for sorting the incoming and outgoing edges around a vertex "v0".
+struct VertexEdge {
+  VertexEdge(bool _incoming, Graph::EdgeId _index,
+             Graph::VertexId _endpoint, int32 _rank)
+      : incoming(_incoming), index(_index),
+        endpoint(_endpoint), rank(_rank) {
+  }
+  bool incoming;             // Is this an incoming edge to "v0"?
+  Graph::EdgeId index;       // Index of this edge in "edges_" or "in_edge_ids"
+  Graph::VertexId endpoint;  // The other (not "v0") endpoint of this edge
+  int32 rank;                // Secondary key for edges with the same endpoint
+};
+
+// Given a set of duplicate outgoing edges (v0, v1) and a set of duplicate
+// incoming edges (v1, v0), this method assigns each edge an integer "rank" so
+// that the edges are sorted in a consistent order with respect to their
+// orderings around "v0" and "v1".  Usually there is just one edge, in which
+// case this is easy.  Sometimes there is one edge in each direction, in which
+// case the outgoing edge is always ordered before the incoming edge.
+//
+// In general, we allow any number of duplicate edges in each direction, in
+// which case outgoing edges are interleaved with incoming edges so as to
+// create as many degenerate (two-edge) loops as possible.  In order to get a
+// consistent ordering around "v0" and "v1", we move forwards through the list
+// of outgoing edges and backwards through the list of incoming edges.  If
+// there are more incoming edges, they go at the beginning of the ordering,
+// while if there are more outgoing edges then they go at the end.
+//
+// For example, suppose there are 2 edges "a,b" from "v0" to "v1", and 4 edges
+// "w,x,y,z" from "v1" to "v0".  Using lower/upper case letters to represent
+// incoming/outgoing edges, the clockwise ordering around v0 would be zyAxBw,
+// and the clockwise ordering around v1 would be WbXaYZ.  (Try making a
+// diagram with each edge as a separate arc.)
+static void AddVertexEdges(Graph::EdgeId out_begin, Graph::EdgeId out_end,
+                           Graph::EdgeId in_begin, Graph::EdgeId in_end,
+                           Graph::VertexId v1, vector<VertexEdge>* v0_edges) {
+  int rank = 0;
+  // Any extra incoming edges go at the beginning of the ordering.
+  while (in_end - in_begin > out_end - out_begin) {
+    v0_edges->push_back(VertexEdge(true, --in_end, v1, rank++));
+  }
+  // Next we interleave as many outgoing and incoming edges as possible.
+  while (in_end > in_begin) {
+    v0_edges->push_back(VertexEdge(false, out_begin++, v1, rank++));
+    v0_edges->push_back(VertexEdge(true, --in_end, v1, rank++));
+  }
+  // Any extra outgoing edges to at the end of the ordering.
+  while (out_end > out_begin) {
+    v0_edges->push_back(VertexEdge(false, out_begin++, v1, rank++));
+  }
+}
+
+bool Graph::GetLeftTurnMap(const vector<EdgeId>& in_edge_ids,
+                           vector<EdgeId>* left_turn_map,
+                           S2Error* error) const {
+  left_turn_map->assign(num_edges(), -1);
+  if (num_edges() == 0) return true;
+
+  // Declare vectors outside the loop to avoid reallocating them each time.
+  vector<VertexEdge> v0_edges;
+  vector<EdgeId> e_in, e_out;
+
+  // Walk through the two sorted arrays of edges (outgoing and incoming) and
+  // gather all the edges incident to each vertex.  Then we sort those edges
+  // and add an entry to the left turn map from each incoming edge to the
+  // immediately following outgoing edge in clockwise order.
+  int out = 0, in = 0;
+  const Edge* out_edge = &edge(out);
+  const Edge* in_edge = &edge(in_edge_ids[in]);
+  Edge sentinel(num_vertices(), num_vertices());
+  Edge min_edge = min(*out_edge, reverse(*in_edge));
+  while (min_edge != sentinel) {
+    // Gather all incoming and outgoing edges around vertex "v0".
+    VertexId v0 = min_edge.first;
+    for (; min_edge.first == v0; min_edge = min(*out_edge, reverse(*in_edge))) {
+      VertexId v1 = min_edge.second;
+      // Count the number of copies of "min_edge" in each direction.
+      int out_begin = out, in_begin = in;
+      while (*out_edge == min_edge) {
+        out_edge = (++out == num_edges()) ? &sentinel : &edge(out);
+      }
+      while (reverse(*in_edge) == min_edge) {
+        in_edge = (++in == num_edges()) ? &sentinel : &edge(in_edge_ids[in]);
+      }
+      if (v0 != v1) {
+        AddVertexEdges(out_begin, out, in_begin, in, v1, &v0_edges);
+      } else {
+        // Each degenerate edge becomes its own loop.
+        for (; in_begin < in; ++in_begin) {
+          (*left_turn_map)[in_begin] = in_begin;
+        }
+      }
+    }
+    if (v0_edges.empty()) continue;
+
+    // Sort the edges in clockwise order around "v0".
+    VertexId min_endpoint = v0_edges.front().endpoint;
+    std::sort(v0_edges.begin() + 1, v0_edges.end(),
+              [v0, min_endpoint, this](const VertexEdge& a,
+                                       const VertexEdge& b) {
+        if (a.endpoint == b.endpoint) return a.rank < b.rank;
+        if (a.endpoint == min_endpoint) return true;
+        if (b.endpoint == min_endpoint) return false;
+        return !s2pred::OrderedCCW(vertex(a.endpoint), vertex(b.endpoint),
+                                   vertex(min_endpoint), vertex(v0));
+      });
+    // Match incoming with outgoing edges.  We do this by keeping a stack of
+    // unmatched incoming edges.  We also keep a stack of outgoing edges with
+    // no previous incoming edge, and match these at the end by wrapping
+    // around circularly to the start of the edge ordering.
+    for (const VertexEdge& e : v0_edges) {
+      if (e.incoming) {
+        e_in.push_back(in_edge_ids[e.index]);
+      } else if (!e_in.empty()) {
+        (*left_turn_map)[e_in.back()] = e.index;
+        e_in.pop_back();
+      } else {
+        e_out.push_back(e.index);  // Matched below.
+      }
+    }
+    // Pair up additional edges using the fact that the ordering is circular.
+    std::reverse(e_out.begin(), e_out.end());
+    for (; !e_out.empty() && !e_in.empty(); e_out.pop_back(), e_in.pop_back()) {
+      (*left_turn_map)[e_in.back()] = e_out.back();
+    }
+    // We only need to process unmatched incoming edges, since we are only
+    // responsible for creating left turn map entries for those edges.
+    if (!e_in.empty() && error->ok()) {
+      error->Init(S2Error::BUILDER_EDGES_DO_NOT_FORM_LOOPS,
+                  "Given edges do not form loops (indegree != outdegree)");
+    }
+    e_in.clear();
+    e_out.clear();
+    v0_edges.clear();
+  }
+  return error->ok();
+}
+
+void Graph::CanonicalizeLoopOrder(const vector<InputEdgeId>& min_input_ids,
+                                  vector<EdgeId>* loop) {
+  if (loop->empty()) return;
+  // Find the position of the element with the highest input edge id.  If
+  // there are multiple such elements together (i.e., the edge was split
+  // into several pieces by snapping it to several vertices), then we choose
+  // the last such position in cyclic order (this attempts to preserve the
+  // original loop order even when new vertices are added).  For example, if
+  // the input edge id sequence is (7, 7, 4, 5, 6, 7) then we would rotate
+  // it to obtain (4, 5, 6, 7, 7, 7).
+
+  // The reason that we put the highest-numbered edge last, rather than the
+  // lowest-numbered edge first, is that S2Loop::Invert() reverses the loop
+  // edge order *except* for the last edge.  For example, the loop ABCD (with
+  // edges AB, BC, CD, DA) becomes DCBA (with edges DC, CB, BA, AD).  Note
+  // that the last edge is the same except for its direction (DA vs. AD).
+  // This has the advantage that if an undirected loop is assembled with the
+  // wrong orientation and later inverted (e.g. by S2Polygon::InitOriented),
+  // we still end up preserving the original cyclic vertex order.
+  int pos = 0;
+  bool saw_gap = false;
+  for (int i = 1; i < loop->size(); ++i) {
+    int cmp = min_input_ids[(*loop)[i]] - min_input_ids[(*loop)[pos]];
+    if (cmp < 0) {
+      saw_gap = true;
+    } else if (cmp > 0 || !saw_gap) {
+      pos = i;
+      saw_gap = false;
+    }
+  }
+  if (++pos == loop->size()) pos = 0;  // Convert loop end to loop start.
+  std::rotate(loop->begin(), loop->begin() + pos, loop->end());
+}
+
+void Graph::CanonicalizeVectorOrder(const vector<InputEdgeId>& min_input_ids,
+                                    vector<vector<EdgeId>>* chains) {
+  std::sort(chains->begin(), chains->end(),
+    [&min_input_ids](const vector<EdgeId>& a, const vector<EdgeId>& b) {
+      return min_input_ids[a[0]] < min_input_ids[b[0]];
+    });
+}
+
+bool Graph::GetDirectedLoops(LoopType loop_type, vector<EdgeLoop>* loops,
+                             S2Error* error) const {
+  S2_DCHECK(options_.degenerate_edges() == DegenerateEdges::DISCARD ||
+         options_.degenerate_edges() == DegenerateEdges::DISCARD_EXCESS);
+  S2_DCHECK(options_.edge_type() == EdgeType::DIRECTED);
+
+  vector<EdgeId> left_turn_map;
+  if (!GetLeftTurnMap(GetInEdgeIds(), &left_turn_map, error)) return false;
+  vector<InputEdgeId> min_input_ids = GetMinInputEdgeIds();
+
+  // If we are breaking loops at repeated vertices, we maintain a map from
+  // VertexId to its position in "path".
+  vector<int> path_index;
+  if (loop_type == LoopType::SIMPLE) path_index.assign(num_vertices(), -1);
+
+  // Visit edges in arbitrary order, and try to build a loop from each edge.
+  vector<EdgeId> path;
+  for (EdgeId start = 0; start < num_edges(); ++start) {
+    if (left_turn_map[start] < 0) continue;
+
+    // Build a loop by making left turns at each vertex until we return to
+    // "start".  We use "left_turn_map" to keep track of which edges have
+    // already been visited by setting its entries to -1 as we go along.  If
+    // we are building vertex cycles, then whenever we encounter a vertex that
+    // is already part of the path, we "peel off" a loop by removing those
+    // edges from the path so far.
+    for (EdgeId e = start, next; left_turn_map[e] >= 0; e = next) {
+      path.push_back(e);
+      next = left_turn_map[e];
+      left_turn_map[e] = -1;
+      if (loop_type == LoopType::SIMPLE) {
+        path_index[edge(e).first] = path.size() - 1;
+        int loop_start = path_index[edge(e).second];
+        if (loop_start < 0) continue;
+        // Peel off a loop from the path.
+        vector<EdgeId> loop(path.begin() + loop_start, path.end());
+        path.erase(path.begin() + loop_start, path.end());
+        for (EdgeId e2 : loop) path_index[edge(e2).first] = -1;
+        CanonicalizeLoopOrder(min_input_ids, &loop);
+        loops->push_back(std::move(loop));
+      }
+    }
+    if (loop_type == LoopType::SIMPLE) {
+      S2_DCHECK(path.empty());  // Invariant.
+    } else {
+      CanonicalizeLoopOrder(min_input_ids, &path);
+      loops->push_back(std::move(path));
+      path.clear();
+    }
+  }
+  CanonicalizeVectorOrder(min_input_ids, loops);
+  return true;
+}
+
+bool Graph::GetDirectedComponents(
+    DegenerateBoundaries degenerate_boundaries,
+    vector<DirectedComponent>* components, S2Error* error) const {
+  S2_DCHECK(options_.degenerate_edges() == DegenerateEdges::DISCARD ||
+         (options_.degenerate_edges() == DegenerateEdges::DISCARD_EXCESS &&
+          degenerate_boundaries == DegenerateBoundaries::KEEP));
+  S2_DCHECK(options_.sibling_pairs() == SiblingPairs::REQUIRE ||
+         options_.sibling_pairs() == SiblingPairs::CREATE);
+  S2_DCHECK(options_.edge_type() == EdgeType::DIRECTED);  // Implied by above.
+
+  vector<EdgeId> sibling_map = GetInEdgeIds();
+  vector<EdgeId> left_turn_map;
+  if (!GetLeftTurnMap(sibling_map, &left_turn_map, error)) return false;
+  MakeSiblingMap(&sibling_map);
+  vector<InputEdgeId> min_input_ids = GetMinInputEdgeIds();
+  vector<EdgeId> frontier;  // Unexplored sibling edges.
+
+  // A map from EdgeId to the position of that edge in "path".  Only needed if
+  // degenerate boundaries are being discarded.
+  vector<int> path_index;
+  if (degenerate_boundaries == DegenerateBoundaries::DISCARD) {
+    path_index.assign(num_edges(), -1);
+  }
+  for (EdgeId min_start = 0; min_start < num_edges(); ++min_start) {
+    if (left_turn_map[min_start] < 0) continue;  // Already used.
+
+    // Build a connected component by keeping a stack of unexplored siblings
+    // of the edges used so far.
+    DirectedComponent component;
+    frontier.push_back(min_start);
+    while (!frontier.empty()) {
+      EdgeId start = frontier.back();
+      frontier.pop_back();
+      if (left_turn_map[start] < 0) continue;  // Already used.
+
+      // Build a path by making left turns at each vertex until we return to
+      // "start".  Whenever we encounter an edge that is a sibling of an edge
+      // that is already on the path, we "peel off" a loop consisting of any
+      // edges that were between these two edges.
+      vector<EdgeId> path;
+      for (EdgeId e = start, next; left_turn_map[e] >= 0; e = next) {
+        path.push_back(e);
+        next = left_turn_map[e];
+        left_turn_map[e] = -1;
+        // If the sibling hasn't been visited yet, add it to the frontier.
+        EdgeId sibling = sibling_map[e];
+        if (left_turn_map[sibling] >= 0) {
+          frontier.push_back(sibling);
+        }
+        if (degenerate_boundaries == DegenerateBoundaries::DISCARD) {
+          path_index[e] = path.size() - 1;
+          int sibling_index = path_index[sibling];
+          if (sibling_index < 0) continue;
+
+          // Common special case: the edge and its sibling are adjacent, in
+          // which case we can simply remove them from the path and continue.
+          if (sibling_index == path.size() - 2) {
+            path.resize(sibling_index);
+            // We don't need to update "path_index" for these two edges
+            // because both edges of the sibling pair have now been used.
+            continue;
+          }
+          // Peel off a loop from the path.
+          vector<EdgeId> loop(path.begin() + sibling_index + 1, path.end() - 1);
+          path.erase(path.begin() + sibling_index, path.end());
+          // Mark the edges that are no longer part of the path.
+          for (EdgeId e2 : loop) path_index[e2] = -1;
+          CanonicalizeLoopOrder(min_input_ids, &loop);
+          component.push_back(std::move(loop));
+        }
+      }
+      // Mark the edges that are no longer part of the path.
+      if (degenerate_boundaries == DegenerateBoundaries::DISCARD) {
+        for (EdgeId e2 : path) path_index[e2] = -1;
+      }
+      CanonicalizeLoopOrder(min_input_ids, &path);
+      component.push_back(std::move(path));
+    }
+    CanonicalizeVectorOrder(min_input_ids, &component);
+    components->push_back(std::move(component));
+  }
+  // Sort the components to correspond to the input edge ordering.
+  std::sort(components->begin(), components->end(),
+            [&min_input_ids](const DirectedComponent& a,
+                             const DirectedComponent& b) {
+      return min_input_ids[a[0][0]] < min_input_ids[b[0][0]];
+    });
+  return true;
+}
+
+// Encodes the index of one of the two complements of each component
+// (a.k.a. the "slot", either 0 or 1) as a negative EdgeId.
+inline static Graph::EdgeId MarkEdgeUsed(int slot) { return -1 - slot; }
+
+bool Graph::GetUndirectedComponents(LoopType loop_type,
+                                    vector<UndirectedComponent>* components,
+                                    S2Error* error) const {
+  S2_DCHECK(options_.degenerate_edges() == DegenerateEdges::DISCARD ||
+         options_.degenerate_edges() == DegenerateEdges::DISCARD_EXCESS);
+  S2_DCHECK(options_.edge_type() == EdgeType::UNDIRECTED);
+
+  vector<EdgeId> sibling_map = GetInEdgeIds();
+  vector<EdgeId> left_turn_map;
+  if (!GetLeftTurnMap(sibling_map, &left_turn_map, error)) return false;
+  MakeSiblingMap(&sibling_map);
+  vector<InputEdgeId> min_input_ids = GetMinInputEdgeIds();
+
+  // A stack of unexplored sibling edges.  Each sibling edge has a "slot"
+  // (0 or 1) that indicates which of the two complements it belongs to.
+  vector<pair<EdgeId, int>> frontier;
+
+  // If we are breaking loops at repeated vertices, we maintain a map from
+  // VertexId to its position in "path".
+  vector<int> path_index;
+  if (loop_type == LoopType::SIMPLE) path_index.assign(num_vertices(), -1);
+
+  for (EdgeId min_start = 0; min_start < num_edges(); ++min_start) {
+    if (left_turn_map[min_start] < 0) continue;  // Already used.
+
+    // Build a connected component by keeping a stack of unexplored siblings
+    // of the edges used so far.
+    UndirectedComponent component;
+    frontier.push_back(make_pair(min_start, 0));
+    while (!frontier.empty()) {
+      EdgeId start = frontier.back().first;
+      int slot = frontier.back().second;
+      frontier.pop_back();
+      if (left_turn_map[start] < 0) continue;  // Already used.
+
+      // Build a path by making left turns at each vertex until we return to
+      // "start".  We use "left_turn_map" to keep track of which edges have
+      // already been visited, and which complement they were assigned to, by
+      // setting its entries to negative values as we go along.
+      vector<EdgeId> path;
+      for (EdgeId e = start, next; left_turn_map[e] >= 0; e = next) {
+        path.push_back(e);
+        next = left_turn_map[e];
+        left_turn_map[e] = MarkEdgeUsed(slot);
+        // If the sibling hasn't been visited yet, add it to the frontier.
+        EdgeId sibling = sibling_map[e];
+        if (left_turn_map[sibling] >= 0) {
+          frontier.push_back(make_pair(sibling, 1 - slot));
+        } else if (left_turn_map[sibling] != MarkEdgeUsed(1 - slot)) {
+          // Two siblings edges can only belong the same complement if the
+          // given undirected edges do not form loops.
+          error->Init(S2Error::BUILDER_EDGES_DO_NOT_FORM_LOOPS,
+                      "Given undirected edges do not form loops");
+          return false;
+        }
+        if (loop_type == LoopType::SIMPLE) {
+          // Whenever we encounter a vertex that is already part of the path,
+          // we "peel off" a loop by removing those edges from the path.
+          path_index[edge(e).first] = path.size() - 1;
+          int loop_start = path_index[edge(e).second];
+          if (loop_start < 0) continue;
+          vector<EdgeId> loop(path.begin() + loop_start, path.end());
+          path.erase(path.begin() + loop_start, path.end());
+          // Mark the vertices that are no longer part of the path.
+          for (EdgeId e2 : loop) path_index[edge(e2).first] = -1;
+          CanonicalizeLoopOrder(min_input_ids, &loop);
+          component[slot].push_back(std::move(loop));
+        }
+      }
+      if (loop_type == LoopType::SIMPLE) {
+        S2_DCHECK(path.empty());  // Invariant.
+      } else {
+        CanonicalizeLoopOrder(min_input_ids, &path);
+        component[slot].push_back(std::move(path));
+      }
+    }
+    CanonicalizeVectorOrder(min_input_ids, &component[0]);
+    CanonicalizeVectorOrder(min_input_ids, &component[1]);
+    // To save some work in S2PolygonLayer, we swap the two loop sets of the
+    // component so that the loop set whose first loop most closely follows
+    // the input edge ordering is first.  (If the input was a valid S2Polygon,
+    // then this component will contain normalized loops.)
+    if (min_input_ids[component[0][0][0]] > min_input_ids[component[1][0][0]]) {
+      component[0].swap(component[1]);
+    }
+    components->push_back(std::move(component));
+  }
+  // Sort the components to correspond to the input edge ordering.
+  std::sort(components->begin(), components->end(),
+       [&min_input_ids](const UndirectedComponent& a,
+                        const UndirectedComponent& b) {
+      return min_input_ids[a[0][0][0]] < min_input_ids[b[0][0][0]];
+    });
+  return true;
+}
+
+class Graph::PolylineBuilder {
+ public:
+  explicit PolylineBuilder(const Graph& g);
+  vector<EdgePolyline> BuildPaths();
+  vector<EdgePolyline> BuildWalks();
+
+ private:
+  bool is_interior(VertexId v);
+  int excess_degree(VertexId v);
+  EdgePolyline BuildPath(EdgeId e);
+  EdgePolyline BuildWalk(VertexId v);
+  void MaximizeWalk(EdgePolyline* polyline);
+
+  const Graph& g_;
+  Graph::VertexInMap in_;
+  Graph::VertexOutMap out_;
+  vector<EdgeId> sibling_map_;
+  vector<InputEdgeId> min_input_ids_;
+  bool directed_;
+  int edges_left_;
+  vector<bool> used_;
+  // A map of (outdegree(v) - indegree(v)) considering used edges only.
+  absl::btree_map<VertexId, int> excess_used_;
+};
+
+vector<Graph::EdgePolyline> Graph::GetPolylines(
+    PolylineType polyline_type) const {
+  S2_DCHECK(options_.sibling_pairs() == SiblingPairs::DISCARD ||
+         options_.sibling_pairs() == SiblingPairs::DISCARD_EXCESS ||
+         options_.sibling_pairs() == SiblingPairs::KEEP);
+  PolylineBuilder builder(*this);
+  if (polyline_type == PolylineType::PATH) {
+    return builder.BuildPaths();
+  } else {
+    return builder.BuildWalks();
+  }
+}
+
+Graph::PolylineBuilder::PolylineBuilder(const Graph& g)
+    : g_(g), in_(g), out_(g),
+      min_input_ids_(g.GetMinInputEdgeIds()),
+      directed_(g_.options().edge_type() == EdgeType::DIRECTED),
+      edges_left_(g.num_edges() / (directed_ ? 1 : 2)),
+      used_(g.num_edges(), false) {
+  if (!directed_) {
+    sibling_map_ = in_.in_edge_ids();
+    g.MakeSiblingMap(&sibling_map_);
+  }
+}
+
+inline bool Graph::PolylineBuilder::is_interior(VertexId v) {
+  if (directed_) {
+    return in_.degree(v) == 1 && out_.degree(v) == 1;
+  } else {
+    return out_.degree(v) == 2;
+  }
+}
+
+inline int Graph::PolylineBuilder::excess_degree(VertexId v) {
+  return directed_ ? out_.degree(v) - in_.degree(v) : out_.degree(v) % 2;
+}
+
+vector<Graph::EdgePolyline> Graph::PolylineBuilder::BuildPaths() {
+  // First build polylines starting at all the vertices that cannot be in the
+  // polyline interior (i.e., indegree != 1 or outdegree != 1 for directed
+  // edges, or degree != 2 for undirected edges).  We consider the possible
+  // starting edges in input edge id order so that we preserve the input path
+  // direction even when undirected edges are used.  (Undirected edges are
+  // represented by sibling pairs where only the edge in the input direction
+  // is labeled with an input edge id.)
+  vector<EdgePolyline> polylines;
+  vector<EdgeId> edges = g_.GetInputEdgeOrder(min_input_ids_);
+  for (EdgeId e : edges) {
+    if (!used_[e] && !is_interior(g_.edge(e).first)) {
+      polylines.push_back(BuildPath(e));
+    }
+  }
+  // If there are any edges left, they form non-intersecting loops.  We build
+  // each loop and then canonicalize its edge order.  We consider candidate
+  // starting edges in input edge id order in order to preserve the input
+  // direction of undirected loops.  Even so, we still need to canonicalize
+  // the edge order to ensure that when an input edge is split into an edge
+  // chain, the loop does not start in the middle of such a chain.
+  for (EdgeId e : edges) {
+    if (edges_left_ == 0) break;
+    if (used_[e]) continue;
+    EdgePolyline polyline = BuildPath(e);
+    CanonicalizeLoopOrder(min_input_ids_, &polyline);
+    polylines.push_back(std::move(polyline));
+  }
+  S2_DCHECK_EQ(0, edges_left_);
+
+  // Sort the polylines to correspond to the input order (if possible).
+  CanonicalizeVectorOrder(min_input_ids_, &polylines);
+  return polylines;
+}
+
+Graph::EdgePolyline Graph::PolylineBuilder::BuildPath(EdgeId e) {
+  // We simply follow edges until either we reach a vertex where there is a
+  // choice about which way to go (where is_interior(v) is false), or we
+  // return to the starting vertex (if the polyline is actually a loop).
+  EdgePolyline polyline;
+  VertexId start = g_.edge(e).first;
+  for (;;) {
+    polyline.push_back(e);
+    S2_DCHECK(!used_[e]);
+    used_[e] = true;
+    if (!directed_) used_[sibling_map_[e]] = true;
+    --edges_left_;
+    VertexId v = g_.edge(e).second;
+    if (!is_interior(v) || v == start) break;
+    if (directed_) {
+      S2_DCHECK_EQ(1, out_.degree(v));
+      e = *out_.edge_ids(v).begin();
+    } else {
+      S2_DCHECK_EQ(2, out_.degree(v));
+      for (EdgeId e2 : out_.edge_ids(v)) if (!used_[e2]) e = e2;
+    }
+  }
+  return polyline;
+}
+
+vector<Graph::EdgePolyline> Graph::PolylineBuilder::BuildWalks() {
+  // Note that some of this code is worst-case quadratic in the maximum vertex
+  // degree.  This could be fixed with a few extra arrays, but it should not
+  // be a problem in practice.
+
+  // First, build polylines from all vertices where outdegree > indegree (or
+  // for undirected edges, vertices whose degree is odd).  We consider the
+  // possible starting edges in input edge id order, for idempotency in the
+  // case where multiple input polylines share vertices or edges.
+  vector<EdgePolyline> polylines;
+  vector<EdgeId> edges = g_.GetInputEdgeOrder(min_input_ids_);
+  for (EdgeId e : edges) {
+    if (used_[e]) continue;
+    VertexId v = g_.edge(e).first;
+    int excess = excess_degree(v);
+    if (excess <= 0) continue;
+    excess -= excess_used_[v];
+    if (directed_ ? (excess <= 0) : (excess % 2 == 0)) continue;
+    ++excess_used_[v];
+    polylines.push_back(BuildWalk(v));
+    --excess_used_[g_.edge(polylines.back().back()).second];
+  }
+  // Now all vertices have outdegree == indegree (or even degree if undirected
+  // edges are being used).  Therefore all remaining edges can be assembled
+  // into loops.  We first try to expand the existing polylines if possible by
+  // adding loops to them.
+  if (edges_left_ > 0) {
+    for (EdgePolyline& polyline : polylines) {
+      MaximizeWalk(&polyline);
+    }
+  }
+  // Finally, if there are still unused edges then we build loops.  If the
+  // input is a polyline that forms a loop, then for idempotency we need to
+  // start from the edge with minimum input edge id.  If the minimal input
+  // edge was split into several edges, then we start from the first edge of
+  // the chain.
+  for (int i = 0; i < edges.size() && edges_left_ > 0; ++i) {
+    EdgeId e = edges[i];
+    if (used_[e]) continue;
+
+    // Determine whether the origin of this edge is the start of an edge
+    // chain.  To do this, we test whether (outdegree - indegree == 1) for the
+    // origin, considering only unused edges with the same minimum input edge
+    // id.  (Undirected edges have input edge ids in one direction only.)
+    VertexId v = g_.edge(e).first;
+    InputEdgeId id = min_input_ids_[e];
+    int excess = 0;
+    for (int j = i; j < edges.size() && min_input_ids_[edges[j]] == id; ++j) {
+      EdgeId e2 = edges[j];
+      if (used_[e2]) continue;
+      if (g_.edge(e2).first == v) ++excess;
+      if (g_.edge(e2).second == v) --excess;
+    }
+    // It is also acceptable to start a polyline from any degenerate edge.
+    if (excess == 1 || g_.edge(e).second == v) {
+      EdgePolyline polyline = BuildWalk(v);
+      MaximizeWalk(&polyline);
+      polylines.push_back(std::move(polyline));
+    }
+  }
+  S2_DCHECK_EQ(0, edges_left_);
+
+  // Sort the polylines to correspond to the input order (if possible).
+  CanonicalizeVectorOrder(min_input_ids_, &polylines);
+  return polylines;
+}
+
+Graph::EdgePolyline Graph::PolylineBuilder::BuildWalk(VertexId v) {
+  EdgePolyline polyline;
+  for (;;) {
+    // Follow the edge with the smallest input edge id.
+    EdgeId best_edge = -1;
+    InputEdgeId best_out_id = std::numeric_limits<InputEdgeId>::max();
+    for (EdgeId e : out_.edge_ids(v)) {
+      if (used_[e] || min_input_ids_[e] >= best_out_id) continue;
+      best_out_id = min_input_ids_[e];
+      best_edge = e;
+    }
+    if (best_edge < 0) return polyline;
+    // For idempotency when there are multiple input polylines, we stop the
+    // walk early if "best_edge" might be a continuation of a different
+    // incoming edge.
+    int excess = excess_degree(v) - excess_used_[v];
+    if (directed_ ? (excess < 0) : (excess % 2) == 1) {
+      for (EdgeId e : in_.edge_ids(v)) {
+        if (!used_[e] && min_input_ids_[e] <= best_out_id) {
+          return polyline;
+        }
+      }
+    }
+    polyline.push_back(best_edge);
+    used_[best_edge] = true;
+    if (!directed_) used_[sibling_map_[best_edge]] = true;
+    --edges_left_;
+    v = g_.edge(best_edge).second;
+  }
+}
+
+void Graph::PolylineBuilder::MaximizeWalk(EdgePolyline* polyline) {
+  // Examine all vertices of the polyline and check whether there are any
+  // unused outgoing edges.  If so, then build a loop starting at that vertex
+  // and insert it into the polyline.  (The walk is guaranteed to be a loop
+  // because this method is only called when all vertices have equal numbers
+  // of unused incoming and outgoing edges.)
+  for (int i = 0; i <= polyline->size(); ++i) {
+    VertexId v = (i == 0 ? g_.edge((*polyline)[i]).first
+                  : g_.edge((*polyline)[i - 1]).second);
+    for (EdgeId e : out_.edge_ids(v)) {
+      if (!used_[e]) {
+        EdgePolyline loop = BuildWalk(v);
+        S2_DCHECK_EQ(v, g_.edge(loop.back()).second);
+        polyline->insert(polyline->begin() + i, loop.begin(), loop.end());
+        S2_DCHECK(used_[e]);  // All outgoing edges from "v" are now used.
+        break;
+      }
+    }
+  }
+}
+
+class Graph::EdgeProcessor {
+ public:
+  EdgeProcessor(const GraphOptions& options,
+                vector<Edge>* edges,
+                vector<InputEdgeIdSetId>* input_ids,
+                IdSetLexicon* id_set_lexicon);
+  void Run(S2Error* error);
+
+ private:
+  void AddEdge(const Edge& edge, InputEdgeIdSetId input_edge_id_set_id);
+  void AddEdges(int num_edges, const Edge& edge,
+                InputEdgeIdSetId input_edge_id_set_id);
+  void CopyEdges(int out_begin, int out_end);
+  InputEdgeIdSetId MergeInputIds(int out_begin, int out_end);
+
+  GraphOptions options_;
+  vector<Edge>& edges_;
+  vector<InputEdgeIdSetId>& input_ids_;
+  IdSetLexicon* id_set_lexicon_;
+  vector<EdgeId> out_edges_;
+  vector<EdgeId> in_edges_;
+
+  vector<Edge> new_edges_;
+  vector<InputEdgeIdSetId> new_input_ids_;
+
+  vector<InputEdgeId> tmp_ids_;
+};
+
+void Graph::ProcessEdges(
+    GraphOptions* options, std::vector<Edge>* edges,
+    std::vector<InputEdgeIdSetId>* input_ids, IdSetLexicon* id_set_lexicon,
+    S2Error* error) {
+  EdgeProcessor processor(*options, edges, input_ids, id_set_lexicon);
+  processor.Run(error);
+  // Certain values of sibling_pairs() discard half of the edges and change
+  // the edge_type() to DIRECTED (see the description of GraphOptions).
+  if (options->sibling_pairs() == SiblingPairs::REQUIRE ||
+      options->sibling_pairs() == SiblingPairs::CREATE) {
+    options->set_edge_type(EdgeType::DIRECTED);
+  }
+}
+
+Graph::EdgeProcessor::EdgeProcessor(const GraphOptions& options,
+                                    vector<Edge>* edges,
+                                    vector<InputEdgeIdSetId>* input_ids,
+                                    IdSetLexicon* id_set_lexicon)
+    : options_(options), edges_(*edges),
+      input_ids_(*input_ids), id_set_lexicon_(id_set_lexicon),
+      out_edges_(edges_.size()), in_edges_(edges_.size()) {
+  // Sort the outgoing and incoming edges in lexigraphic order.  We use a
+  // stable sort to ensure that each undirected edge becomes a sibling pair,
+  // even if there are multiple identical input edges.
+  std::iota(out_edges_.begin(), out_edges_.end(), 0);
+  std::sort(out_edges_.begin(), out_edges_.end(), [this](EdgeId a, EdgeId b) {
+      return StableLessThan(edges_[a], edges_[b], a, b);
+    });
+  std::iota(in_edges_.begin(), in_edges_.end(), 0);
+  std::sort(in_edges_.begin(), in_edges_.end(), [this](EdgeId a, EdgeId b) {
+      return StableLessThan(reverse(edges_[a]), reverse(edges_[b]), a, b);
+    });
+  new_edges_.reserve(edges_.size());
+  new_input_ids_.reserve(edges_.size());
+}
+
+inline void Graph::EdgeProcessor::AddEdge(
+    const Edge& edge, InputEdgeIdSetId input_edge_id_set_id) {
+  new_edges_.push_back(edge);
+  new_input_ids_.push_back(input_edge_id_set_id);
+}
+
+void Graph::EdgeProcessor::AddEdges(int num_edges, const Edge& edge,
+                                    InputEdgeIdSetId input_edge_id_set_id) {
+  for (int i = 0; i < num_edges; ++i) {
+    AddEdge(edge, input_edge_id_set_id);
+  }
+}
+
+void Graph::EdgeProcessor::CopyEdges(int out_begin, int out_end) {
+  for (int i = out_begin; i < out_end; ++i) {
+    AddEdge(edges_[out_edges_[i]], input_ids_[out_edges_[i]]);
+  }
+}
+
+S2Builder::InputEdgeIdSetId Graph::EdgeProcessor::MergeInputIds(
+    int out_begin, int out_end) {
+  if (out_end - out_begin == 1) {
+    return input_ids_[out_edges_[out_begin]];
+  }
+  tmp_ids_.clear();
+  for (int i = out_begin; i < out_end; ++i) {
+    for (auto id : id_set_lexicon_->id_set(input_ids_[out_edges_[i]])) {
+      tmp_ids_.push_back(id);
+    }
+  }
+  return id_set_lexicon_->Add(tmp_ids_);
+}
+
+void Graph::EdgeProcessor::Run(S2Error* error) {
+  int num_edges = edges_.size();
+  if (num_edges == 0) return;
+
+  // Walk through the two sorted arrays performing a merge join.  For each
+  // edge, gather all the duplicate copies of the edge in both directions
+  // (outgoing and incoming).  Then decide what to do based on "options_" and
+  // how many copies of the edge there are in each direction.
+  int out = 0, in = 0;
+  const Edge* out_edge = &edges_[out_edges_[out]];
+  const Edge* in_edge = &edges_[in_edges_[in]];
+  Edge sentinel(std::numeric_limits<VertexId>::max(),
+                std::numeric_limits<VertexId>::max());
+  for (;;) {
+    Edge edge = min(*out_edge, reverse(*in_edge));
+    if (edge == sentinel) break;
+
+    int out_begin = out, in_begin = in;
+    while (*out_edge == edge) {
+      out_edge = (++out == num_edges) ? &sentinel : &edges_[out_edges_[out]];
+    }
+    while (reverse(*in_edge) == edge) {
+      in_edge = (++in == num_edges) ? &sentinel : &edges_[in_edges_[in]];
+    }
+    int n_out = out - out_begin;
+    int n_in = in - in_begin;
+    if (edge.first == edge.second) {
+      S2_DCHECK_EQ(n_out, n_in);
+      if (options_.degenerate_edges() == DegenerateEdges::DISCARD) {
+        continue;
+      }
+      if (options_.degenerate_edges() == DegenerateEdges::DISCARD_EXCESS &&
+          ((out_begin > 0 &&
+            edges_[out_edges_[out_begin - 1]].first == edge.first) ||
+           (out < num_edges && edges_[out_edges_[out]].first == edge.first) ||
+           (in_begin > 0 &&
+            edges_[in_edges_[in_begin - 1]].second == edge.first) ||
+           (in < num_edges && edges_[in_edges_[in]].second == edge.first))) {
+        continue;  // There were non-degenerate incident edges, so discard.
+      }
+      if (options_.edge_type() == EdgeType::UNDIRECTED &&
+          (options_.sibling_pairs() == SiblingPairs::REQUIRE ||
+           options_.sibling_pairs() == SiblingPairs::CREATE)) {
+        // When we have undirected edges and are guaranteed to have siblings,
+        // we cut the number of edges in half (see s2builder.h).
+        S2_DCHECK_EQ(0, n_out & 1);  // Number of edges is always even.
+        AddEdges(options_.duplicate_edges() == DuplicateEdges::MERGE ?
+                 1 : (n_out / 2), edge, MergeInputIds(out_begin, out));
+      } else if (options_.duplicate_edges() == DuplicateEdges::MERGE) {
+        AddEdges(options_.edge_type() == EdgeType::UNDIRECTED ? 2 : 1,
+                 edge, MergeInputIds(out_begin, out));
+      } else if (options_.sibling_pairs() == SiblingPairs::DISCARD ||
+                 options_.sibling_pairs() == SiblingPairs::DISCARD_EXCESS) {
+        // Any SiblingPair option that discards edges causes the labels of all
+        // duplicate edges to be merged together (see s2builder.h).
+        AddEdges(n_out, edge, MergeInputIds(out_begin, out));
+      } else {
+        CopyEdges(out_begin, out);
+      }
+    } else if (options_.sibling_pairs() == SiblingPairs::KEEP) {
+      if (n_out > 1 && options_.duplicate_edges() == DuplicateEdges::MERGE) {
+        AddEdge(edge, MergeInputIds(out_begin, out));
+      } else {
+        CopyEdges(out_begin, out);
+      }
+    } else if (options_.sibling_pairs() == SiblingPairs::DISCARD) {
+      if (options_.edge_type() == EdgeType::DIRECTED) {
+        // If n_out == n_in: balanced sibling pairs
+        // If n_out < n_in:  unbalanced siblings, in the form AB, BA, BA
+        // If n_out > n_in:  unbalanced siblings, in the form AB, AB, BA
+        if (n_out <= n_in) continue;
+        // Any option that discards edges causes the labels of all duplicate
+        // edges to be merged together (see s2builder.h).
+        AddEdges(options_.duplicate_edges() == DuplicateEdges::MERGE ?
+                 1 : (n_out - n_in), edge, MergeInputIds(out_begin, out));
+      } else {
+        if ((n_out & 1) == 0) continue;
+        AddEdge(edge, MergeInputIds(out_begin, out));
+      }
+    } else if (options_.sibling_pairs() == SiblingPairs::DISCARD_EXCESS) {
+      if (options_.edge_type() == EdgeType::DIRECTED) {
+        // See comments above.  The only difference is that if there are
+        // balanced sibling pairs, we want to keep one such pair.
+        if (n_out < n_in) continue;
+        AddEdges(options_.duplicate_edges() == DuplicateEdges::MERGE ?
+                 1 : max(1, n_out - n_in), edge, MergeInputIds(out_begin, out));
+      } else {
+        AddEdges((n_out & 1) ? 1 : 2, edge, MergeInputIds(out_begin, out));
+      }
+    } else {
+      S2_DCHECK(options_.sibling_pairs() == SiblingPairs::REQUIRE ||
+             options_.sibling_pairs() == SiblingPairs::CREATE);
+      if (error->ok() && options_.sibling_pairs() == SiblingPairs::REQUIRE &&
+          (options_.edge_type() == EdgeType::DIRECTED ? (n_out != n_in)
+                                                      : ((n_out & 1) != 0))) {
+        error->Init(S2Error::BUILDER_MISSING_EXPECTED_SIBLING_EDGES,
+                    "Expected all input edges to have siblings, "
+                    "but some were missing");
+      }
+      if (options_.duplicate_edges() == DuplicateEdges::MERGE) {
+        AddEdge(edge, MergeInputIds(out_begin, out));
+      } else if (options_.edge_type() == EdgeType::UNDIRECTED) {
+        // Convert graph to use directed edges instead (see documentation of
+        // REQUIRE/CREATE for undirected edges).
+        AddEdges((n_out + 1) / 2, edge, MergeInputIds(out_begin, out));
+      } else {
+        CopyEdges(out_begin, out);
+        if (n_in > n_out) {
+          // Automatically created edges have no input edge ids or labels.
+          AddEdges(n_in - n_out, edge, IdSetLexicon::EmptySetId());
+        }
+      }
+    }
+  }
+  edges_.swap(new_edges_);
+  edges_.shrink_to_fit();
+  input_ids_.swap(new_input_ids_);
+  input_ids_.shrink_to_fit();
+}
+
+vector<S2Point> Graph::FilterVertices(const vector<S2Point>& vertices,
+                                      std::vector<Edge>* edges,
+                                      vector<VertexId>* tmp) {
+  // Gather the vertices that are actually used.
+  vector<VertexId> used;
+  used.reserve(2 * edges->size());
+  for (const Edge& e : *edges) {
+    used.push_back(e.first);
+    used.push_back(e.second);
+  }
+  // Sort the vertices and find the distinct ones.
+  std::sort(used.begin(), used.end());
+  used.erase(std::unique(used.begin(), used.end()), used.end());
+
+  // Build the list of new vertices, and generate a map from old vertex id to
+  // new vertex id.
+  vector<VertexId>& vmap = *tmp;
+  vmap.resize(vertices.size());
+  vector<S2Point> new_vertices(used.size());
+  for (int i = 0; i < used.size(); ++i) {
+    new_vertices[i] = vertices[used[i]];
+    vmap[used[i]] = i;
+  }
+  // Update the edges.
+  for (Edge& e : *edges) {
+    e.first = vmap[e.first];
+    e.second = vmap[e.second];
+  }
+  return new_vertices;
+}
diff --git a/src/s2/s2builder_graph.h b/src/s2/s2builder_graph.h
new file mode 100644 (file)
index 0000000..b1ba3e4
--- /dev/null
@@ -0,0 +1,799 @@
+// Copyright 2016 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// Author: ericv@google.com (Eric Veach)
+
+#ifndef S2_S2BUILDER_GRAPH_H_
+#define S2_S2BUILDER_GRAPH_H_
+
+#include <array>
+#include <cstddef>
+#include <iterator>
+#include <utility>
+#include <vector>
+#include "s2/base/integral_types.h"
+#include "s2/id_set_lexicon.h"
+#include "s2/s2builder.h"
+#include "s2/s2error.h"
+
+// An S2Builder::Graph represents a collection of snapped edges that is passed
+// to a Layer for assembly.  (Example layers include polygons, polylines, and
+// polygon meshes.)  The Graph object does not own any of its underlying data;
+// it is simply a view of data that is stored elsewhere.  You will only
+// need this interface if you want to implement a new Layer subtype.
+//
+// The graph consists of vertices and directed edges.  Vertices are numbered
+// sequentially starting from zero.  An edge is represented as a pair of
+// vertex ids.  The edges are sorted in lexicographic order, therefore all of
+// the outgoing edges from a particular vertex form a contiguous range.
+//
+// S2Builder::Graph is movable and copyable.  Note that although this class
+// does not own the underlying vertex and edge data, S2Builder guarantees that
+// all Graph objects passed to S2Builder::Layer::Build() methods will remain
+// valid until all layers have been built.
+//
+// TODO(ericv): Consider pulling out the methods that are helper functions for
+// Layer implementations (such as GetDirectedLoops) into s2builderutil_graph.h.
+class S2Builder::Graph {
+ public:
+  // Identifies a vertex in the graph.  Vertices are numbered sequentially
+  // starting from zero.
+  using VertexId = int32;
+
+  // Defines an edge as an (origin, destination) vertex pair.
+  using Edge = std::pair<VertexId, VertexId>;
+
+  // Identifies an edge in the graph.  Edges are numbered sequentially
+  // starting from zero.
+  using EdgeId = int32;
+
+  // Identifies an S2Builder *input* edge (before snapping).
+  using InputEdgeId = S2Builder::InputEdgeId;
+
+  // Identifies a set of S2Builder input edges.
+  using InputEdgeIdSetId = S2Builder::InputEdgeIdSetId;
+
+  // Identifies a set of edge labels.
+  using LabelSetId = S2Builder::LabelSetId;
+
+  // Determines whether a degenerate polygon is empty or full.
+  using IsFullPolygonPredicate = S2Builder::IsFullPolygonPredicate;
+
+  // The default constructor exists only for the benefit of STL containers.
+  // The graph must be initialized (using the assignment operator) before it
+  // is used.
+  Graph();
+
+  // Note that most of the parameters are passed by const reference and must
+  // exist for the duration of the Graph object.  Notes on parameters:
+  // "options":
+  //    - the GraphOptions used to build the Graph.  In some cases these
+  //      can be different than the options provided by the Layer.
+  // "vertices":
+  //   - a vector of S2Points indexed by VertexId.
+  // "edges":
+  //   - a vector of VertexId pairs (sorted in lexicographic order)
+  //     indexed by EdgeId.
+  // "input_edge_id_set_ids":
+  //   - a vector indexed by EdgeId that allows access to the set of
+  //     InputEdgeIds that were mapped to the given edge, by looking up the
+  //     returned value (an InputEdgeIdSetId) in "input_edge_id_set_lexicon".
+  // "input_edge_id_set_lexicon":
+  //   - a class that maps an InputEdgeIdSetId to a set of InputEdgeIds.
+  // "label_set_ids":
+  //   - a vector indexed by InputEdgeId that allows access to the set of
+  //     labels that were attached to the given input edge, by looking up the
+  //     returned value (a LabelSetId) in the "label_set_lexicon".
+  // "label_set_lexicon":
+  //   - a class that maps a LabelSetId to a set of S2Builder::Labels.
+  // "is_full_polygon_predicate":
+  //   - a predicate called to determine whether a graph consisting only of
+  //     polygon degeneracies represents the empty polygon or the full polygon
+  //     (see s2builder.h for details).
+  Graph(const GraphOptions& options,
+        const std::vector<S2Point>* vertices,
+        const std::vector<Edge>* edges,
+        const std::vector<InputEdgeIdSetId>* input_edge_id_set_ids,
+        const IdSetLexicon* input_edge_id_set_lexicon,
+        const std::vector<LabelSetId>* label_set_ids,
+        const IdSetLexicon* label_set_lexicon,
+        IsFullPolygonPredicate is_full_polygon_predicate);
+
+  const GraphOptions& options() const;
+
+  // Returns the number of vertices in the graph.
+  VertexId num_vertices() const;
+
+  // Returns the vertex at the given index.
+  const S2Point& vertex(VertexId v) const;
+
+  // Returns the entire set of vertices.
+  const std::vector<S2Point>& vertices() const;
+
+  // Returns the total number of edges in the graph.
+  EdgeId num_edges() const;
+
+  // Returns the endpoints of the given edge (as vertex indices).
+  const Edge& edge(EdgeId e) const;
+
+  // Returns the entire set of edges.
+  const std::vector<Edge>& edges() const;
+
+  // Given an edge (src, dst), returns the reverse edge (dst, src).
+  static Edge reverse(const Edge& e);
+
+  // Returns a vector of edge ids sorted in lexicographic order by
+  // (destination, origin).  All of the incoming edges to each vertex form a
+  // contiguous subrange of this ordering.
+  std::vector<EdgeId> GetInEdgeIds() const;
+
+  // Given a graph such that every directed edge has a sibling, returns a map
+  // from EdgeId to the sibling EdgeId.  This method is identical to
+  // GetInEdgeIds() except that (1) it requires edges to have siblings, and
+  // (2) undirected degenerate edges are grouped together in pairs such that
+  // one edge is the sibling of the other.  Handles duplicate edges correctly
+  // and is also consistent with GetLeftTurnMap().
+  //
+  // REQUIRES: An option is chosen that guarantees sibling pairs:
+  //     (options.sibling_pairs() == { REQUIRE, CREATE } ||
+  //      options.edge_type() == UNDIRECTED)
+  std::vector<EdgeId> GetSiblingMap() const;
+
+  // Like GetSiblingMap(), but constructs the map starting from the vector of
+  // incoming edge ids returned by GetInEdgeIds().  (This operation is a no-op
+  // except unless undirected degenerate edges are present, in which case such
+  // edges are grouped together in pairs to satisfy the requirement that every
+  // edge must have a sibling edge.)
+  void MakeSiblingMap(std::vector<EdgeId>* in_edge_ids) const;
+
+  class VertexOutMap;  // Forward declaration
+  class VertexInMap;   // Forward declaration
+
+  // A helper class for VertexOutMap that represents the outgoing edges
+  // from a given vertex.
+  class VertexOutEdges {
+   public:
+    const Edge* begin() const { return begin_; }
+    const Edge* end() const { return end_; }
+    size_t size() const { return end_ - begin_; }
+
+   private:
+    friend class VertexOutMap;
+    VertexOutEdges(const Edge* begin, const Edge* end);
+    const Edge* begin_;
+    const Edge* end_;
+  };
+
+  // A helper class for VertexOutMap that represents the outgoing edge *ids*
+  // from a given vertex.
+  class VertexOutEdgeIds
+      : public std::iterator<std::forward_iterator_tag, EdgeId> {
+   public:
+    // An iterator over a range of edge ids (like boost::counting_iterator).
+    class Iterator {
+     public:
+      explicit Iterator(EdgeId id) : id_(id) {}
+      const EdgeId& operator*() const { return id_; }
+      Iterator& operator++() { ++id_; return *this; }
+      Iterator operator++(int) { return Iterator(id_++); }
+      size_t operator-(const Iterator& x) const { return id_ - x.id_; }
+      bool operator==(const Iterator& x) const { return id_ == x.id_; }
+      bool operator!=(const Iterator& x) const { return id_ != x.id_; }
+
+     private:
+      EdgeId id_;
+    };
+    Iterator begin() const { return Iterator(begin_); }
+    Iterator end() const { return Iterator(end_); }
+    size_t size() const { return end_ - begin_; }
+
+   private:
+    friend class VertexOutMap;
+    VertexOutEdgeIds(EdgeId begin, EdgeId end);
+    EdgeId begin_, end_;
+  };
+
+  // A class that maps vertices to their outgoing edge ids.  Example usage:
+  //   VertexOutMap out(g);
+  //   for (Graph::EdgeId e : out.edge_ids(v)) { ... }
+  //   for (const Graph::Edge& edge : out.edges(v)) { ... }
+  class VertexOutMap {
+   public:
+    VertexOutMap() = default;
+    explicit VertexOutMap(const Graph& g) { Init(g); }
+    void Init(const Graph& g);
+
+    int degree(VertexId v) const;
+    VertexOutEdges edges(VertexId v) const;
+    VertexOutEdgeIds edge_ids(VertexId v) const;
+
+    // Return the edges (or edge ids) between a specific pair of vertices.
+    VertexOutEdges edges(VertexId v0, VertexId v1) const;
+    VertexOutEdgeIds edge_ids(VertexId v0, VertexId v1) const;
+
+   private:
+    const std::vector<Edge>* edges_;
+    std::vector<EdgeId> edge_begins_;
+    VertexOutMap(const VertexOutMap&) = delete;
+    void operator=(const VertexOutMap&) = delete;
+  };
+
+  // A helper class for VertexInMap that represents the incoming edge *ids*
+  // to a given vertex.
+  class VertexInEdgeIds {
+   public:
+    const EdgeId* begin() const { return begin_; }
+    const EdgeId* end() const { return end_; }
+    size_t size() const { return end_ - begin_; }
+
+   private:
+    friend class VertexInMap;
+    VertexInEdgeIds(const EdgeId* begin, const EdgeId* end);
+    const EdgeId* begin_;
+    const EdgeId* end_;
+  };
+
+  // A class that maps vertices to their incoming edge ids.  Example usage:
+  //   VertexInMap in(g);
+  //   for (Graph::EdgeId e : in.edge_ids(v)) { ... }
+  class VertexInMap {
+   public:
+    VertexInMap() = default;
+    explicit VertexInMap(const Graph& g) { Init(g); }
+    void Init(const Graph& g);
+
+    int degree(VertexId v) const;
+    VertexInEdgeIds edge_ids(VertexId v) const;
+
+    // Returns a sorted vector of all incoming edges (see GetInEdgeIds).
+    const std::vector<EdgeId>& in_edge_ids() const { return in_edge_ids_; }
+
+   private:
+    std::vector<EdgeId> in_edge_ids_;
+    std::vector<EdgeId> in_edge_begins_;
+    VertexInMap(const VertexInMap&) = delete;
+    void operator=(const VertexInMap&) = delete;
+  };
+
+  // Defines a value larger than any valid InputEdgeId.
+  static const InputEdgeId kMaxInputEdgeId =
+      std::numeric_limits<InputEdgeId>::max();
+
+  // The following value of InputEdgeId means that an edge does not
+  // corresponds to any input edge.
+  static const InputEdgeId kNoInputEdgeId = kMaxInputEdgeId - 1;
+
+  // Returns the set of input edge ids that were snapped to the given
+  // edge.  ("Input edge ids" are assigned to input edges sequentially in
+  // the order they are added to the builder.)  For example, if input
+  // edges 2 and 17 were snapped to edge 12, then input_edge_ids(12)
+  // returns a set containing the numbers 2 and 17.  Example usage:
+  //
+  //   for (InputEdgeId input_edge_id : g.input_edge_ids(e)) { ... }
+  //
+  // Please note the following:
+  //
+  //  - When edge chains are simplified, the simplified edge is assigned all
+  //    the input edge ids associated with edges of the chain.
+  //
+  //  - Edges can also have multiple input edge ids due to edge merging
+  //    (if DuplicateEdges::MERGE is specified).
+  //
+  //  - Siblings edges automatically created by EdgeType::UNDIRECTED or
+  //    SiblingPairs::CREATE have an empty set of input edge ids.  (However
+  //    you can use a LabelFetcher to retrieve the set of labels associated
+  //    with both edges of a given sibling pair.)
+  IdSetLexicon::IdSet input_edge_ids(EdgeId e) const;
+
+  // Low-level method that returns an integer representing the entire set of
+  // input edge ids that were snapped to the given edge.  The elements of the
+  // IdSet can be accessed using input_edge_id_set_lexicon().
+  InputEdgeIdSetId input_edge_id_set_id(EdgeId e) const;
+
+  // Low-level method that returns a vector where each element represents the
+  // set of input edge ids that were snapped to a particular output edge.
+  const std::vector<InputEdgeIdSetId>& input_edge_id_set_ids() const;
+
+  // Returns a mapping from an InputEdgeIdSetId to a set of input edge ids.
+  const IdSetLexicon& input_edge_id_set_lexicon() const;
+
+  // Returns the minimum input edge id that was snapped to this edge, or -1 if
+  // no input edges were snapped (see SiblingPairs::CREATE).  This is
+  // useful for layers that wish to preserve the input edge ordering as much
+  // as possible (e.g., to ensure idempotency).
+  InputEdgeId min_input_edge_id(EdgeId e) const;
+
+  // Returns a vector containing the minimum input edge id for every edge.
+  // If an edge has no input ids, kNoInputEdgeId is used.
+  std::vector<InputEdgeId> GetMinInputEdgeIds() const;
+
+  // Returns a vector of EdgeIds sorted by minimum input edge id.  This is an
+  // approximation of the input edge ordering.
+  std::vector<EdgeId> GetInputEdgeOrder(
+      const std::vector<InputEdgeId>& min_input_edge_ids) const;
+
+  // Convenience class to return the set of labels associated with a given
+  // graph edge.  Note that due to snapping, one graph edge may correspond to
+  // several different input edges and will have all of their labels.
+  // This class is the preferred way to retrieve edge labels.
+  //
+  // The reason this is a class rather than a graph method is because for
+  // undirected edges, we need to fetch the labels associated with both
+  // siblings.  This is because only the original edge of the sibling pair has
+  // labels; the automatically generated sibling edge does not.
+  class LabelFetcher {
+   public:
+    LabelFetcher() = default;
+    LabelFetcher(const Graph& g, EdgeType edge_type) { Init(g, edge_type); }
+
+    // Prepares to fetch labels associated with the given edge type.  For
+    // EdgeType::UNDIRECTED, labels associated with both edges of the sibling
+    // pair will be returned.  "edge_type" is a parameter (rather than using
+    // g.options().edge_type()) so that clients can explicitly control whether
+    // labels from one or both siblings are returned.
+    void Init(const Graph& g, EdgeType edge_type);
+
+    // Returns the set of labels associated with edge "e" (and also the labels
+    // associated with the sibling of "e" if edge_type() is UNDIRECTED).
+    // Labels are sorted and duplicate labels are automatically removed.
+    //
+    // This method uses an output parameter rather than returning by value in
+    // order to avoid allocating a new vector on every call to this method.
+    void Fetch(EdgeId e, std::vector<S2Builder::Label>* labels);
+
+   private:
+    const Graph* g_;
+    EdgeType edge_type_;
+    std::vector<EdgeId> sibling_map_;
+  };
+
+  // Returns the set of labels associated with a given input edge.  Example:
+  //   for (Label label : g.labels(input_edge_id)) { ... }
+  IdSetLexicon::IdSet labels(InputEdgeId e) const;
+
+  // Low-level method that returns an integer representing the set of
+  // labels associated with a given input edge.  The elements of
+  // the IdSet can be accessed using label_set_lexicon().
+  LabelSetId label_set_id(InputEdgeId e) const;
+
+  // Low-level method that returns a vector where each element represents the
+  // set of labels associated with a particular output edge.
+  const std::vector<LabelSetId>& label_set_ids() const;
+
+  // Returns a mapping from a LabelSetId to a set of labels.
+  const IdSetLexicon& label_set_lexicon() const;
+
+  // Convenience method that calls is_full_polygon_predicate() to determine
+  // whether a graph that consists only of polygon degeneracies represents the
+  // empty polygon or the full polygon (see s2builder.h for details).
+  bool IsFullPolygon(S2Error* error) const;
+
+  // Returns a method that determines whether a graph that consists only of
+  // polygon degeneracies represents the empty polygon or the full polygon
+  // (see s2builder.h for details).
+  const IsFullPolygonPredicate& is_full_polygon_predicate() const;
+
+  // Returns a map "m" that maps each edge e=(v0,v1) to the following outgoing
+  // edge around "v1" in clockwise order.  (This corresponds to making a "left
+  // turn" at the vertex.)  By starting at a given edge and making only left
+  // turns, you can construct a loop whose interior does not contain any edges
+  // in the same connected component.
+  //
+  // If the incoming and outgoing edges around a vertex do not alternate
+  // perfectly (e.g., there are two incoming edges in a row), then adjacent
+  // (incoming, outgoing) pairs are repeatedly matched and removed.  This is
+  // similar to finding matching parentheses in a string such as "(()())()".
+  //
+  // For sibling edge pairs, the incoming edge is assumed to immediately
+  // follow the outgoing edge in clockwise order.  Thus a left turn is made
+  // from an edge to its sibling only if there are no other outgoing edges.
+  // With respect to the parentheses analogy, a sibling pair is ")(".
+  // Similarly, if there are multiple copies of a sibling edge pair then the
+  // duplicate incoming and outgoing edges are sorted in alternating order
+  // (e.g., ")()(").
+  //
+  // Degenerate edges (edges from a vertex to itself) are treated as loops
+  // consisting of a single edge.  This avoids the problem of deciding the
+  // connectivity and ordering of such edges when they share a vertex with
+  // other edges (possibly including other degenerate edges).
+  //
+  // If it is not possible to make a left turn from every input edge, this
+  // method returns false and sets "error" appropriately.  In this situation
+  // the left turn map is still valid except that any incoming edge where it
+  // is not possible to make a left turn will have its entry set to -1.
+  //
+  // "in_edge_ids" should be equal to GetInEdgeIds() or GetSiblingMap().
+  bool GetLeftTurnMap(const std::vector<EdgeId>& in_edge_ids,
+                      std::vector<EdgeId>* left_turn_map,
+                      S2Error* error) const;
+
+  // Rotates the edges of "loop" if necessary so that the edge(s) with the
+  // largest input edge ids are last.  This ensures that when an output loop
+  // is equivalent to an input loop, their cyclic edge orders are the same.
+  // "min_input_ids" is the output of GetMinInputEdgeIds().
+  static void CanonicalizeLoopOrder(
+      const std::vector<InputEdgeId>& min_input_ids,
+      std::vector<EdgeId>* loop);
+
+  // Sorts the given edge chains (i.e., loops or polylines) by the minimum
+  // input edge id of each chains's first edge.  This ensures that when the
+  // output consists of multiple loops or polylines, they are sorted in the
+  // same order as they were provided in the input.
+  static void CanonicalizeVectorOrder(
+      const std::vector<InputEdgeId>& min_input_ids,
+      std::vector<std::vector<EdgeId>>* chains);
+
+  // A loop consisting of a sequence of edges.
+  using EdgeLoop = std::vector<EdgeId>;
+
+  // Indicates whether loops should be simple cycles (no repeated vertices) or
+  // circuits (which allow repeated vertices but not repeated edges).  In
+  // terms of how the loops are built, this corresponds to closing off a loop
+  // at the first repeated vertex vs. the first repeated edge.
+  enum class LoopType { SIMPLE, CIRCUIT };
+
+  // Builds loops from a set of directed edges, turning left at each vertex
+  // until either a repeated vertex (for LoopType::SIMPLE) or a repeated edge
+  // (for LoopType::CIRCUIT) is found.  (Use LoopType::SIMPLE if you intend to
+  // construct an S2Loop.)
+  //
+  // Each loop is represented as a sequence of edges.  The edge ordering and
+  // loop ordering are automatically canonicalized in order to preserve the
+  // input ordering as much as possible.  Loops are non-crossing provided that
+  // the graph contains no crossing edges.  If some edges cannot be turned
+  // into loops, returns false and sets "error" appropriately.
+  //
+  // If any degenerate edges are present, then each such edge is treated as a
+  // separate loop.  This is mainly useful in conjunction with
+  // options.degenerate_edges() == DISCARD_EXCESS, in order to build polygons
+  // that preserve degenerate geometry.
+  //
+  // REQUIRES: options.degenerate_edges() == {DISCARD, DISCARD_EXCESS}
+  // REQUIRES: options.edge_type() == DIRECTED
+  bool GetDirectedLoops(LoopType loop_type, std::vector<EdgeLoop>* loops,
+                        S2Error* error) const;
+
+  // Builds loops from a set of directed edges, turning left at each vertex
+  // until a repeated edge is found (i.e., LoopType::CIRCUIT).  The loops are
+  // further grouped into connected components, where each component consists
+  // of one or more loops connected by shared vertices.
+  //
+  // This method is used to build polygon meshes from directed or undirected
+  // input edges.  To convert the output of this method into a mesh, the
+  // client must determine how the loops in different components are related
+  // to each other: for example, several loops from different components may
+  // bound the same region on the sphere, in which case all of those loops are
+  // combined into a single polygon.  (See s2shapeutil::BuildPolygonBoundaries
+  // and s2builderutil::LaxPolygonVectorLayer for details.)
+  //
+  // Note that loops may include both edges of a sibling pair.  When several
+  // such edges are connected in a chain or a spanning tree, they form a
+  // zero-area "filament".  The entire loop may be a filament (i.e., a
+  // degenerate loop with an empty interior), or the loop may have have
+  // non-empty interior with several filaments that extend inside it, or the
+  // loop may consist of several "holes" connected by filaments.  These
+  // filaments do not change the interior of any loop, so if you are only
+  // interested in point containment then they can safely be removed by
+  // setting the "degenerate_boundaries" parameter to DISCARD.  (They can't be
+  // removed by setting (options.sibling_pairs() == DISCARD) because the two
+  // siblings might belong to different polygons of the mesh.)  Note that you
+  // can prevent multiple copies of sibling pairs by specifying
+  // options.duplicate_edges() == MERGE.
+  //
+  // Each loop is represented as a sequence of edges.  The edge ordering and
+  // loop ordering are automatically canonicalized in order to preserve the
+  // input ordering as much as possible.  Loops are non-crossing provided that
+  // the graph contains no crossing edges.  If some edges cannot be turned
+  // into loops, returns false and sets "error" appropriately.
+  //
+  // REQUIRES: options.degenerate_edges() == { DISCARD, DISCARD_EXCESS }
+  //           (but requires DISCARD if degenerate_boundaries == DISCARD)
+  // REQUIRES: options.sibling_pairs() == { REQUIRE, CREATE }
+  //           [i.e., every edge must have a sibling edge]
+  enum class DegenerateBoundaries { DISCARD, KEEP };
+  using DirectedComponent = std::vector<EdgeLoop>;
+  bool GetDirectedComponents(
+      DegenerateBoundaries degenerate_boundaries,
+      std::vector<DirectedComponent>* components, S2Error* error) const;
+
+  // Builds loops from a set of undirected edges, turning left at each vertex
+  // until either a repeated vertex (for LoopType::SIMPLE) or a repeated edge
+  // (for LoopType::CIRCUIT) is found.  The loops are further grouped into
+  // "components" such that all the loops in a component are connected by
+  // shared vertices.  Finally, the loops in each component are divided into
+  // two "complements" such that every edge in one complement is the sibling
+  // of an edge in the other complement.  This corresponds to the fact that
+  // given any set of non-crossing undirected loops, there are exactly two
+  // possible interpretations of the region that those loops represent (where
+  // one possibility is the complement of the other).  This method does not
+  // attempt to resolve this ambiguity, but instead returns both possibilities
+  // for each connected component and lets the client choose among them.
+  //
+  // This method is used to build single polygons.  (Use GetDirectedComponents
+  // to build polygon meshes, even when the input edges are undirected.)  To
+  // convert the output of this method into a polygon, the client must choose
+  // one complement from each component such that the entire set of loops is
+  // oriented consistently (i.e., they define a region such that the interior
+  // of the region is always on the left).  The non-chosen complements form
+  // another set of loops that are also oriented consistently but represent
+  // the complementary region on the sphere.  Finally, the client needs to
+  // choose one of these two sets of loops based on heuristics (e.g., the area
+  // of each region), since both sets of loops are equally valid
+  // interpretations of the input.
+  //
+  // Each loop is represented as a sequence of edges.  The edge ordering and
+  // loop ordering are automatically canonicalized in order to preserve the
+  // input ordering as much as possible.  Loops are non-crossing provided that
+  // the graph contains no crossing edges.  If some edges cannot be turned
+  // into loops, returns false and sets "error" appropriately.
+  //
+  // REQUIRES: options.degenerate_edges() == { DISCARD, DISCARD_EXCESS }
+  // REQUIRES: options.edge_type() == UNDIRECTED
+  // REQUIRES: options.siblings_pairs() == { DISCARD, DISCARD_EXCESS, KEEP }
+  //           [since REQUIRE, CREATE convert the edge_type() to DIRECTED]
+  using UndirectedComponent = std::array<std::vector<EdgeLoop>, 2>;
+  bool GetUndirectedComponents(LoopType loop_type,
+                               std::vector<UndirectedComponent>* components,
+                               S2Error* error) const;
+
+  // Indicates whether polylines should be "paths" (which don't allow
+  // duplicate vertices, except possibly the first and last vertex) or
+  // "walks" (which allow duplicate vertices and edges).
+  enum class PolylineType { PATH, WALK };
+
+  // Builds polylines from a set of edges.  If "polyline_type" is PATH, then
+  // only vertices of indegree and outdegree 1 (or degree 2 in the case of
+  // undirected edges) will appear in the interior of polylines.  This
+  // essentially generates one polyline for each edge chain in the graph.  If
+  // "polyline_type" is WALK, then polylines may pass through the same vertex
+  // or even the same edge multiple times (if duplicate edges are present),
+  // and each polyline will be as long as possible.  This option is useful for
+  // reconstructing a polyline that has been snapped to a lower resolution,
+  // since snapping can cause edges to become identical.
+  //
+  // This method attempts to preserve the input edge ordering in order to
+  // implement idempotency, even when there are repeated edges or loops.  This
+  // is true whether directed or undirected edges are used.  Degenerate edges
+  // are also handled appropriately.
+  //
+  // REQUIRES: options.sibling_pairs() == { DISCARD, DISCARD_EXCESS, KEEP }
+  using EdgePolyline = std::vector<EdgeId>;
+  std::vector<EdgePolyline> GetPolylines(PolylineType polyline_type) const;
+
+  ////////////////////////////////////////////////////////////////////////
+  //////////////// Helper Functions for Creating Graphs //////////////////
+
+  // Given an unsorted collection of edges, transform them according to the
+  // given set of GraphOptions.  This includes actions such as discarding
+  // degenerate edges; merging duplicate edges; and canonicalizing sibling
+  // edge pairs in several possible ways (e.g. discarding or creating them).
+  // The output is suitable for passing to the Graph constructor.
+  //
+  // If options.edge_type() == EdgeType::UNDIRECTED, then all input edges
+  // should already have been transformed into a pair of directed edges.
+  //
+  // "input_ids" is a vector of the same length as "edges" that indicates
+  // which input edges were snapped to each edge.  This vector is also updated
+  // appropriately as edges are discarded, merged, etc.
+  //
+  // Note that "options" may be modified by this method: in particular, the
+  // edge_type() can be changed if sibling_pairs() is CREATE or REQUIRE (see
+  // the description of S2Builder::GraphOptions).
+  static void ProcessEdges(
+      GraphOptions* options, std::vector<Edge>* edges,
+      std::vector<InputEdgeIdSetId>* input_ids, IdSetLexicon* id_set_lexicon,
+      S2Error* error);
+
+  // Given a set of vertices and edges, removes all vertices that do not have
+  // any edges and returned the new, minimal set of vertices.  Also updates
+  // each edge in "edges" to correspond to the new vertex numbering.  (Note
+  // that this method does *not* merge duplicate vertices, it simply removes
+  // vertices of degree zero.)
+  //
+  // The new vertex ordering is a subsequence of the original ordering,
+  // therefore if the edges were lexicographically sorted before calling this
+  // method then they will still be sorted after calling this method.
+  //
+  // The extra argument "tmp" points to temporary storage used by this method.
+  // All calls to this method from a single thread can reuse the same
+  // temporary storage.  It should initially point to an empty vector.  This
+  // can make a big difference to efficiency when this method is called many
+  // times (e.g. to extract the vertices for different layers), since the
+  // incremental running time for each layer becomes O(edges.size()) rather
+  // than O(vertices.size() + edges.size()).
+  static std::vector<S2Point> FilterVertices(
+      const std::vector<S2Point>& vertices, std::vector<Edge>* edges,
+      std::vector<VertexId>* tmp);
+
+  // A comparison function that allows stable sorting with std::sort (which is
+  // fast but not stable).  It breaks ties between equal edges by comparing
+  // their edge ids.
+  static bool StableLessThan(const Edge& a, const Edge& b,
+                             EdgeId ai, EdgeId bi);
+
+ private:
+  class EdgeProcessor;
+  class PolylineBuilder;
+
+  GraphOptions options_;
+  VertexId num_vertices_;  // Cached to avoid division by 24.
+
+  const std::vector<S2Point>* vertices_;
+  const std::vector<Edge>* edges_;
+  const std::vector<InputEdgeIdSetId>* input_edge_id_set_ids_;
+  const IdSetLexicon* input_edge_id_set_lexicon_;
+  const std::vector<LabelSetId>* label_set_ids_;
+  const IdSetLexicon* label_set_lexicon_;
+  IsFullPolygonPredicate is_full_polygon_predicate_;
+};
+
+
+//////////////////   Implementation details follow   ////////////////////
+
+
+inline S2Builder::Graph::Graph()
+    : options_(), num_vertices_(-1), vertices_(nullptr), edges_(nullptr),
+      input_edge_id_set_ids_(nullptr), input_edge_id_set_lexicon_(nullptr),
+      label_set_ids_(nullptr), label_set_lexicon_(nullptr) {
+}
+
+inline const S2Builder::GraphOptions& S2Builder::Graph::options() const {
+  return options_;
+}
+
+inline S2Builder::Graph::VertexId S2Builder::Graph::num_vertices() const {
+  return num_vertices_;  // vertices_.size() requires division by 24.
+}
+
+inline const S2Point& S2Builder::Graph::vertex(VertexId v) const {
+  return vertices()[v];
+}
+
+inline const std::vector<S2Point>& S2Builder::Graph::vertices() const {
+  return *vertices_;
+}
+
+inline S2Builder::Graph::EdgeId S2Builder::Graph::num_edges() const {
+  return static_cast<S2Builder::Graph::EdgeId>(edges().size());
+}
+
+inline const S2Builder::Graph::Edge& S2Builder::Graph::edge(EdgeId e) const {
+  return edges()[e];
+}
+
+inline const std::vector<S2Builder::Graph::Edge>&
+S2Builder::Graph::edges() const {
+  return *edges_;
+}
+
+inline S2Builder::Graph::Edge S2Builder::Graph::reverse(const Edge& e) {
+  return Edge(e.second, e.first);
+}
+
+inline S2Builder::Graph::VertexOutEdges::VertexOutEdges(const Edge* begin,
+                                                        const Edge* end)
+    : begin_(begin), end_(end) {
+}
+
+inline S2Builder::Graph::VertexOutEdges
+S2Builder::Graph::VertexOutMap::edges(VertexId v) const {
+  return VertexOutEdges(edges_->data() + edge_begins_[v],
+                        edges_->data() + edge_begins_[v + 1]);
+}
+
+inline S2Builder::Graph::VertexOutEdges
+S2Builder::Graph::VertexOutMap::edges(VertexId v0, VertexId v1) const {
+  auto range = std::equal_range(edges_->data() + edge_begins_[v0],
+                                edges_->data() + edge_begins_[v0 + 1],
+                                Edge(v0, v1));
+  return VertexOutEdges(range.first, range.second);
+}
+
+inline S2Builder::Graph::VertexOutEdgeIds::VertexOutEdgeIds(EdgeId begin,
+                                                            EdgeId end)
+    : begin_(begin), end_(end) {
+}
+
+inline S2Builder::Graph::VertexOutEdgeIds
+S2Builder::Graph::VertexOutMap::edge_ids(VertexId v) const {
+  return VertexOutEdgeIds(edge_begins_[v], edge_begins_[v + 1]);
+}
+
+inline S2Builder::Graph::VertexOutEdgeIds
+S2Builder::Graph::VertexOutMap::edge_ids(VertexId v0, VertexId v1) const {
+  auto range = std::equal_range(edges_->data() + edge_begins_[v0],
+                                edges_->data() + edge_begins_[v0 + 1],
+                                Edge(v0, v1));
+  return VertexOutEdgeIds(
+      static_cast<S2Builder::Graph::EdgeId>(range.first - edges_->data()),
+      static_cast<S2Builder::Graph::EdgeId>(range.second - edges_->data()));
+}
+
+inline int S2Builder::Graph::VertexOutMap::degree(VertexId v) const {
+  return static_cast<int>(edge_ids(v).size());
+}
+
+inline S2Builder::Graph::VertexInEdgeIds::VertexInEdgeIds(const EdgeId* begin,
+                                                          const EdgeId* end)
+    : begin_(begin), end_(end) {
+}
+
+inline S2Builder::Graph::VertexInEdgeIds
+S2Builder::Graph::VertexInMap::edge_ids(VertexId v) const {
+  return VertexInEdgeIds(in_edge_ids_.data() + in_edge_begins_[v],
+                         in_edge_ids_.data() + in_edge_begins_[v + 1]);
+}
+
+inline int S2Builder::Graph::VertexInMap::degree(VertexId v) const {
+  return static_cast<int>(edge_ids(v).size());
+}
+
+inline IdSetLexicon::IdSet S2Builder::Graph::input_edge_ids(EdgeId e) const {
+  return input_edge_id_set_lexicon().id_set(input_edge_id_set_ids()[e]);
+}
+
+inline const std::vector<S2Builder::InputEdgeIdSetId>&
+S2Builder::Graph::input_edge_id_set_ids() const {
+  return *input_edge_id_set_ids_;
+}
+
+inline S2Builder::InputEdgeIdSetId
+S2Builder::Graph::input_edge_id_set_id(EdgeId e) const {
+  return input_edge_id_set_ids()[e];
+}
+
+inline const IdSetLexicon& S2Builder::Graph::input_edge_id_set_lexicon() const {
+  return *input_edge_id_set_lexicon_;
+}
+
+inline IdSetLexicon::IdSet S2Builder::Graph::labels(LabelSetId id) const {
+  return label_set_lexicon().id_set(label_set_ids()[id]);
+}
+
+inline S2Builder::LabelSetId S2Builder::Graph::label_set_id(EdgeId e) const {
+  return label_set_ids()[e];
+}
+
+inline const std::vector<S2Builder::LabelSetId>&
+S2Builder::Graph::label_set_ids() const {
+  return *label_set_ids_;
+}
+
+inline const IdSetLexicon& S2Builder::Graph::label_set_lexicon() const {
+  return *label_set_lexicon_;
+}
+
+inline bool S2Builder::Graph::IsFullPolygon(S2Error* error) const {
+  return is_full_polygon_predicate_(*this, error);
+}
+
+inline const S2Builder::IsFullPolygonPredicate&
+S2Builder::Graph::is_full_polygon_predicate() const {
+  return is_full_polygon_predicate_;
+}
+
+inline bool S2Builder::Graph::StableLessThan(
+    const Edge& a, const Edge& b, EdgeId ai, EdgeId bi) {
+  // The following is simpler but the compiler (2016) doesn't optimize it as
+  // well as it should:
+  //   return make_pair(a, ai) < make_pair(b, bi);
+  if (a.first < b.first) return true;
+  if (b.first < a.first) return false;
+  if (a.second < b.second) return true;
+  if (b.second < a.second) return false;
+  return ai < bi;  // Stable sort.
+}
+
+#endif  // S2_S2BUILDER_GRAPH_H_
diff --git a/src/s2/s2builder_layer.h b/src/s2/s2builder_layer.h
new file mode 100644 (file)
index 0000000..051f07e
--- /dev/null
@@ -0,0 +1,50 @@
+// Copyright 2016 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// Author: ericv@google.com (Eric Veach)
+
+#ifndef S2_S2BUILDER_LAYER_H_
+#define S2_S2BUILDER_LAYER_H_
+
+#include "s2/s2builder_graph.h"
+
+// This class is not needed by ordinary S2Builder clients.  It is only
+// necessary if you wish to implement a new S2Builder::Layer subtype.
+class S2Builder::Layer {
+ public:
+  // Convenience declarations for layer subtypes.
+  using EdgeType = S2Builder::EdgeType;
+  using GraphOptions = S2Builder::GraphOptions;
+  using Graph = S2Builder::Graph;
+  using Label = S2Builder::Label;
+  using LabelSetId = S2Builder::LabelSetId;
+
+  virtual ~Layer() {}
+
+  // Defines options for building the edge graph that is passed to Build().
+  virtual GraphOptions graph_options() const = 0;
+
+  // Assembles a graph of snapped edges into the geometry type implemented by
+  // this layer.  If an error is encountered, sets "error" appropriately.
+  //
+  // Note that when there are multiple layers, the Graph objects passed to all
+  // layers are guaranteed to be valid until the last Build() method returns.
+  // This makes it easier to write algorithms that gather the output graphs
+  // from several layers and process them all at once (such as
+  // s2builderutil::ClosedSetNormalizer).
+  virtual void Build(const Graph& g, S2Error* error) = 0;
+};
+
+#endif  // S2_S2BUILDER_LAYER_H_
diff --git a/src/s2/s2builderutil_closed_set_normalizer.cc b/src/s2/s2builderutil_closed_set_normalizer.cc
new file mode 100644 (file)
index 0000000..8be85f7
--- /dev/null
@@ -0,0 +1,313 @@
+// Copyright 2017 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// Author: ericv@google.com (Eric Veach)
+
+#include "s2/s2builderutil_closed_set_normalizer.h"
+
+#include <memory>
+
+#include "absl/memory/memory.h"
+#include "s2/s2builder_layer.h"
+
+using absl::make_unique;
+using std::shared_ptr;
+using std::unique_ptr;
+using std::vector;
+
+using EdgeType = S2Builder::EdgeType;
+using Graph = S2Builder::Graph;
+using GraphOptions = S2Builder::GraphOptions;
+
+using DegenerateEdges = GraphOptions::DegenerateEdges;
+using SiblingPairs = GraphOptions::SiblingPairs;
+
+using Edge = Graph::Edge;
+using EdgeId = Graph::EdgeId;
+using VertexId = Graph::VertexId;
+
+namespace s2builderutil {
+
+ClosedSetNormalizer::ClosedSetNormalizer(
+    const Options& options, const vector<GraphOptions>& graph_options_out)
+    : options_(options),
+      graph_options_out_(graph_options_out),
+      graph_options_in_(graph_options_out_),
+      sentinel_(std::numeric_limits<VertexId>::max(),
+                std::numeric_limits<VertexId>::max()) {
+  S2_DCHECK_EQ(graph_options_out_.size(), 3);
+  S2_DCHECK(graph_options_out_[0].edge_type() == EdgeType::DIRECTED);
+  S2_DCHECK(graph_options_out_[2].edge_type() == EdgeType::DIRECTED);
+
+  // NOTE(ericv): Supporting these options would require some extra code in
+  // order to handle undirected edges, and they are not useful for building
+  // polylines anyway (they are intended for polygon meshes).
+  S2_DCHECK(graph_options_out_[1].sibling_pairs() != SiblingPairs::CREATE);
+  S2_DCHECK(graph_options_out_[1].sibling_pairs() != SiblingPairs::REQUIRE);
+
+  // Set the GraphOptions for the input graphs to ensure that (1) they share a
+  // common set of vertices, (2) degenerate edges are kept only if they are
+  // isolated, and (3) multiple copies of siblings pairs are discarded.  (Note
+  // that there may be multiple copies of isolated degenerate edges; clients
+  // can eliminate them if desired using DuplicateEdges::MERGE.)
+  for (int dim = 0; dim < 3; ++dim) {
+    graph_options_in_[dim].set_allow_vertex_filtering(false);
+  }
+  graph_options_in_[1].set_degenerate_edges(DegenerateEdges::DISCARD_EXCESS);
+  graph_options_in_[2].set_degenerate_edges(DegenerateEdges::DISCARD_EXCESS);
+  graph_options_in_[2].set_sibling_pairs(SiblingPairs::DISCARD_EXCESS);
+}
+
+const vector<Graph>& ClosedSetNormalizer::Run(
+    const vector<Graph>& g, S2Error* error) {
+  // Ensure that the input graphs were built with our requested options.
+  for (int dim = 0; dim < 3; ++dim) {
+    S2_DCHECK(g[dim].options() == graph_options_in_[dim]);
+  }
+  if (options_.suppress_lower_dimensions()) {
+    // Build the auxiliary data needed to suppress lower-dimensional edges.
+    in_edges2_ = g[2].GetInEdgeIds();
+    is_suppressed_.resize(g[0].vertices().size());
+    for (int dim = 1; dim <= 2; ++dim) {
+      for (int e = 0; e < g[dim].num_edges(); ++e) {
+        Edge edge = g[dim].edge(e);
+        if (edge.first != edge.second) {
+          is_suppressed_[edge.first] = true;
+          is_suppressed_[edge.second] = true;
+        }
+      }
+    }
+  }
+
+  // Compute the edges that belong in the output graphs.
+  NormalizeEdges(g, error);
+
+  // If any edges were added or removed, we need to run Graph::ProcessEdges to
+  // ensure that the edges satisfy the requested GraphOptions.  Note that
+  // since edges are never added to dimension 2, we can use the edge count to
+  // test whether any edges were removed.  If no edges were removed from
+  // dimension 2, then no edges were added to dimension 1, and so we can again
+  // use the edge count to test whether any edges were removed, etc.
+  bool modified[3];
+  bool any_modified = false;
+  for (int dim = 2; dim >= 0; --dim) {
+    if (new_edges_[dim].size() != g[dim].num_edges()) any_modified = true;
+    modified[dim] = any_modified;
+  }
+  if (!any_modified) {
+    for (int dim = 0; dim < 3; ++dim) {
+      // Copy the graphs to ensure that they have the GraphOptions that were
+      // originally requested.
+      new_graphs_.push_back(Graph(
+          graph_options_out_[dim], &g[dim].vertices(), &g[dim].edges(),
+          &g[dim].input_edge_id_set_ids(), &g[dim].input_edge_id_set_lexicon(),
+          &g[dim].label_set_ids(), &g[dim].label_set_lexicon(),
+          g[dim].is_full_polygon_predicate()));
+    }
+  } else {
+    // Make a copy of input_edge_id_set_lexicon() so that ProcessEdges can
+    // merge edges if necessary.
+    new_input_edge_id_set_lexicon_ = g[0].input_edge_id_set_lexicon();
+    for (int dim = 0; dim < 3; ++dim) {
+      if (modified[dim]) {
+        Graph::ProcessEdges(&graph_options_out_[dim], &new_edges_[dim],
+                            &new_input_edge_ids_[dim],
+                            &new_input_edge_id_set_lexicon_, error);
+      }
+      new_graphs_.push_back(Graph(
+          graph_options_out_[dim], &g[dim].vertices(), &new_edges_[dim],
+          &new_input_edge_ids_[dim], &new_input_edge_id_set_lexicon_,
+          &g[dim].label_set_ids(), &g[dim].label_set_lexicon(),
+          g[dim].is_full_polygon_predicate()));
+    }
+  }
+  return new_graphs_;
+}
+
+// Helper function that advances to the next edge in the given graph,
+// returning a sentinel value once all edges are exhausted.
+inline Edge ClosedSetNormalizer::Advance(const Graph& g, EdgeId* e) const {
+  return (++*e == g.num_edges()) ? sentinel_ : g.edge(*e);
+}
+
+// Helper function that advances to the next incoming edge in the given graph,
+// returning a sentinel value once all edges are exhausted.
+inline Edge ClosedSetNormalizer::AdvanceIncoming(
+    const Graph& g, const vector<EdgeId>& in_edges, int* i) const {
+  return ((++*i == in_edges.size()) ? sentinel_ :
+          Graph::reverse(g.edge(in_edges[*i])));
+  }
+
+void ClosedSetNormalizer::NormalizeEdges(const vector<Graph>& g,
+                                         S2Error* error) {
+  // Find the degenerate polygon edges and sibling pairs, and classify each
+  // edge as belonging to either a shell or a hole.
+  auto degeneracies = FindPolygonDegeneracies(g[2], error);
+  auto degeneracy = degeneracies.begin();
+
+  // Walk through the three edge vectors performing a merge join.  We also
+  // maintain positions in two other auxiliary vectors: the vector of sorted
+  // polygon degeneracies (degeneracies), and the vector of incoming polygon
+  // edges (if we are suppressing lower-dimensional duplicate edges).
+  EdgeId e0 = -1, e1 = -1, e2 = -1;  // Current position in g[dim].edges()
+  int in_e2 = -1;  // Current position in in_edges2_
+  Edge edge0 = Advance(g[0], &e0);
+  Edge edge1 = Advance(g[1], &e1);
+  Edge edge2 = Advance(g[2], &e2);
+  Edge in_edge2 = AdvanceIncoming(g[2], in_edges2_, &in_e2);
+  for (;;) {
+    if (edge2 <= edge1 && edge2 <= edge0) {
+      if (edge2 == sentinel_) break;
+      if (degeneracy == degeneracies.end() || degeneracy->edge_id != e2) {
+        // Normal polygon edge (not part of a degeneracy).
+        AddEdge(2, g[2], e2);
+        while (options_.suppress_lower_dimensions() && edge1 == edge2) {
+          edge1 = Advance(g[1], &e1);
+        }
+      } else if (!(degeneracy++)->is_hole) {
+        // Edge belongs to a degenerate shell.
+        if (edge2.first != edge2.second) {
+          AddEdge(1, g[2], e2);
+          // Since this edge was demoted, make sure that it does not suppress
+          // any coincident polyline edge(s).
+          while (edge1 == edge2) {
+            AddEdge(1, g[1], e1);
+            edge1 = Advance(g[1], &e1);
+          }
+        } else {
+          // The test below is necessary because a single-vertex polygon shell
+          // can be discarded by a polyline edge incident to that vertex.
+          if (!is_suppressed(edge2.first)) AddEdge(0, g[2], e2);
+        }
+      }
+      edge2 = Advance(g[2], &e2);
+    } else if (edge1 <= edge0) {
+      if (edge1.first != edge1.second) {
+        // Non-degenerate polyline edge.  (Note that in_edges2_ is empty
+        // whenever "suppress_lower_dimensions" is false.)
+        while (in_edge2 < edge1) {
+          in_edge2 = AdvanceIncoming(g[2], in_edges2_, &in_e2);
+        }
+        if (edge1 != in_edge2) AddEdge(1, g[1], e1);
+      } else {
+        // Degenerate polyline edge.
+        if (!is_suppressed(edge1.first)) AddEdge(0, g[1], e1);
+        if (g[1].options().edge_type() == EdgeType::UNDIRECTED) ++e1;
+      }
+      edge1 = Advance(g[1], &e1);
+    } else {
+      // Input point.
+      if (!is_suppressed(edge0.first)) AddEdge(0, g[0], e0);
+      edge0 = Advance(g[0], &e0);
+    }
+  }
+}
+
+inline void ClosedSetNormalizer::AddEdge(int new_dim, const Graph& g,
+                                         EdgeId e) {
+  new_edges_[new_dim].push_back(g.edge(e));
+  new_input_edge_ids_[new_dim].push_back(g.input_edge_id_set_id(e));
+}
+
+inline bool ClosedSetNormalizer::is_suppressed(VertexId v) const {
+  return options_.suppress_lower_dimensions() && is_suppressed_[v];
+}
+
+// This method implements the NormalizeClosedSet function.  The Create()
+// method allocates a single object of this class whose ownership is shared
+// (using shared_ptr) among the three returned S2Builder::Layers.  Here is how
+// the process works:
+//
+//  - The returned layers are passed to a class (such as S2Builder or
+//    S2BooleanOperation) that calls their Build methods.  We call these the
+//    "input layers" because they provide the input to ClosedSetNormalizer.
+//
+//  - When Build() is called on the first two layers, pointers to the
+//    corresponding Graph arguments are saved.
+//
+//  - When Build() is called on the third layer, ClosedSetNormalizer is used
+//    to normalize the graphs, and then the Build() method of each of the
+//    three output layers is called.
+//
+// TODO(ericv): Consider generalizing this technique as a public class.
+class NormalizeClosedSetImpl {
+ public:
+  static LayerVector Create(LayerVector output_layers,
+                            const ClosedSetNormalizer::Options& options) {
+    using Impl = NormalizeClosedSetImpl;
+    shared_ptr<Impl> impl(new Impl(std::move(output_layers), options));
+    LayerVector result;
+    for (int dim = 0; dim < 3; ++dim) {
+      result.push_back(make_unique<DimensionLayer>(
+          dim, impl->normalizer_.graph_options()[dim], impl));
+    }
+    return result;
+  }
+
+ private:
+  NormalizeClosedSetImpl(LayerVector output_layers,
+                         const ClosedSetNormalizer::Options& options)
+      : output_layers_(std::move(output_layers)),
+        normalizer_(options, vector<GraphOptions>{
+            output_layers_[0]->graph_options(),
+            output_layers_[1]->graph_options(),
+            output_layers_[2]->graph_options()}),
+        graphs_(3), graphs_left_(3) {
+    S2_DCHECK_EQ(3, output_layers_.size());
+  }
+
+  class DimensionLayer : public S2Builder::Layer {
+   public:
+    DimensionLayer(int dimension, const GraphOptions& graph_options,
+                   shared_ptr<NormalizeClosedSetImpl> impl)
+        : dimension_(dimension), graph_options_(graph_options),
+          impl_(std::move(impl)) {}
+
+    GraphOptions graph_options() const override { return graph_options_; }
+
+    void Build(const Graph& g, S2Error* error) override {
+      impl_->Build(dimension_, g, error);
+    }
+
+   private:
+    int dimension_;
+    GraphOptions graph_options_;
+    shared_ptr<NormalizeClosedSetImpl> impl_;
+  };
+
+  void Build(int dimension, const Graph& g, S2Error* error) {
+    // Errors are reported only on the last layer built.
+    graphs_[dimension] = g;
+    if (--graphs_left_ > 0) return;
+
+    vector<Graph> output = normalizer_.Run(graphs_, error);
+    for (int dim = 0; dim < 3; ++dim) {
+      output_layers_[dim]->Build(output[dim], error);
+    }
+  }
+
+ private:
+  vector<unique_ptr<S2Builder::Layer>> output_layers_;
+  ClosedSetNormalizer normalizer_;
+  vector<Graph> graphs_;
+  int graphs_left_;
+};
+
+LayerVector NormalizeClosedSet(LayerVector output_layers,
+                               const ClosedSetNormalizer::Options& options) {
+  return NormalizeClosedSetImpl::Create(std::move(output_layers), options);
+}
+
+}  // namespace s2builderutil
diff --git a/src/s2/s2builderutil_closed_set_normalizer.h b/src/s2/s2builderutil_closed_set_normalizer.h
new file mode 100644 (file)
index 0000000..c7d9fc6
--- /dev/null
@@ -0,0 +1,221 @@
+// Copyright 2017 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// Author: ericv@google.com (Eric Veach)
+
+#ifndef S2_S2BUILDERUTIL_CLOSED_SET_NORMALIZER_H_
+#define S2_S2BUILDERUTIL_CLOSED_SET_NORMALIZER_H_
+
+#include <vector>
+#include "s2/id_set_lexicon.h"
+#include "s2/s2builder_graph.h"
+#include "s2/s2builderutil_find_polygon_degeneracies.h"
+
+namespace s2builderutil {
+
+// The purpose of this class is to allow S2Builder::Layer implementations to
+// remove polygon and polyline degeneracies by converting them to polylines or
+// points.  Note that most clients should not use ClosedSetNormalizer itself,
+// but should instead call NormalizeClosedSet defined below.
+//
+// A polyline degeneracy is a polyline consisting of a single degenerate edge.
+// A polygon degeneracy is either a single-vertex loop (a degenerate edge from
+// a vertex to itself) or a sibling edge pair (consisting of an edge and its
+// corresponding reverse edge).  Polygon degeneracies are further classified
+// as shells or holes depending on whether they are located in the exterior or
+// interior of the polygon respectively.  For example, a single-vertex loop
+// contained within a polygon shell would be classified as a hole.
+//
+// All objects are modeled as closed, i.e. polygons contain their boundaries
+// and polylines contain their endpoints.  Note that under this model,
+// degenerate polygon shells and holes need to be handled differently.
+// Degenerate shells are converted to polylines or points, whereas degenerate
+// holes do not affect the set of points contained by the polygon and are
+// simply discarded.
+//
+// Specifically, given three S2Builder::Graphs (corresponding to points,
+// polylines, and polygons), this class makes the following transformations:
+//
+//  - Polygon sibling edge pairs are either discarded (for holes) or converted
+//    to a pair of polyline edges (for shells).
+//  - Degenerate polygon edges are either discarded (for holes) or converted
+//    to points (for shells).
+//  - Degenerate polyline edges are converted to points.
+//
+// Optionally, this class further normalize the graphs by suppressing edges
+// that are duplicates of higher-dimensional edges.  In other words:
+//
+//  - Polyline edges that coincide with polygon edges are discarded.
+//  - Points that coincide with polyline or polygon vertices are discarded.
+//
+// (When edges are discarded, any labels attached to those edges are discarded
+// as well.)
+//
+// This class takes three graphs as input and yields three graphs as output.
+// However note that the output graphs are *not* independent objects; they may
+// point to data in the input graphs or data owned by the ClosedSetNormalizer
+// itself.  For this reason the input graphs and ClosedSetNormalizer must
+// persist until the output graphs are no longer needed.
+//
+// Finally, note that although this class may be necessary in some situations
+// (e.g., to implement the OGC Simple Features Access spec), in general the
+// recommended approach to degeneracies is simply to keep them (by using a
+// representation such as S2LaxPolygonShape or S2LaxPolylineShape).
+// Keeping degeneracies has many advantages, such as not needing to deal with
+// geometry of multiple dimensions, and being able to preserve polygon
+// boundaries accurately (including degenerate holes).
+class ClosedSetNormalizer {
+ public:
+  class Options {
+   public:
+    Options();
+
+    // If "suppress_lower_dimensions" is true, then the graphs are further
+    // normalized by discarding lower-dimensional edges that coincide with
+    // higher-dimensional edges.
+    //
+    // DEFAULT: true
+    bool suppress_lower_dimensions() const;
+    void set_suppress_lower_dimensions(bool suppress_lower_dimensions);
+
+   private:
+    bool suppress_lower_dimensions_;
+  };
+
+  // Constructs a ClosedSetNormalizer whose output will be three
+  // S2Builder::Graphs with the given "graph_options_out".
+  //
+  // REQUIRES: graph_options_out.size() == 3
+  // REQUIRES: graph_options_out[0].edge_type() == DIRECTED
+  // REQUIRES: graph_options_out[1].sibling_pairs() != {CREATE, REQUIRE}
+  // REQUIRES: graph_options_out[2].edge_type() == DIRECTED
+  ClosedSetNormalizer(
+      const Options& options,
+      const std::vector<S2Builder::GraphOptions>& graph_options_out);
+
+  // Returns the ClosedSetNormalizer options.
+  const Options& options() const { return options_; }
+
+  // Returns the GraphOptions that should be used to construct the input
+  // S2Builder::Graph of each dimension.
+  inline const std::vector<S2Builder::GraphOptions>& graph_options() const;
+
+  // Normalizes the input graphs and returns a new set of graphs where
+  // degeneracies have been discarded or converted to objects of lower
+  // dimension.  input[d] is the graph representing edges of dimension "d".
+  //
+  // Note that the input graphs, their contents, and the ClosedSetNormalizer
+  // itself must persist until the output of this class is no longer needed.
+  // (To emphasize this requirement, a const reference is returned.)
+  const std::vector<S2Builder::Graph>& Run(
+      const std::vector<S2Builder::Graph>& input, S2Error* error);
+
+ private:
+  S2Builder::Graph::Edge Advance(
+      const S2Builder::Graph& g, S2Builder::Graph::EdgeId* id) const;
+  S2Builder::Graph::Edge AdvanceIncoming(
+      const S2Builder::Graph& g,
+      const std::vector<S2Builder::Graph::EdgeId>& in_edges, int* i) const;
+  void NormalizeEdges(const std::vector<S2Builder::Graph>& g, S2Error* error);
+  void AddEdge(int new_dim, const S2Builder::Graph& g,
+               S2Builder::Graph::EdgeId e);
+  bool is_suppressed(S2Builder::Graph::VertexId v) const;
+
+  Options options_;
+
+  // Requested options for the output graphs.
+  std::vector<S2Builder::GraphOptions> graph_options_out_;
+
+  // Options to be used to construct the input graphs.
+  std::vector<S2Builder::GraphOptions> graph_options_in_;
+
+  // A sentinel value that compares larger than any valid edge.
+  const S2Builder::Graph::Edge sentinel_;
+
+  // is_suppressed_[i] is true if vertex[i] belongs to a non-degenerate edge,
+  // and therefore should be suppressed from the output graph for points.
+  std::vector<bool> is_suppressed_;
+
+  // A vector of incoming polygon edges sorted in lexicographic order.  This
+  // is used to suppress directed polyline edges that match a polygon edge in
+  // the reverse direction.
+  std::vector<S2Builder::Graph::EdgeId> in_edges2_;
+
+  // Output data.
+  std::vector<S2Builder::Graph> new_graphs_;
+  std::vector<S2Builder::Graph::Edge> new_edges_[3];
+  std::vector<S2Builder::Graph::InputEdgeIdSetId> new_input_edge_ids_[3];
+  IdSetLexicon new_input_edge_id_set_lexicon_;
+};
+
+// A LayerVector represents a set of layers that comprise a single object.
+// Such objects are typically assembled by gathering the S2Builder::Graphs
+// from all of the individual layers and processing them all at once.
+using LayerVector = std::vector<std::unique_ptr<S2Builder::Layer>>;
+
+// Given a set of three output layers (one each for dimensions 0, 1, and 2),
+// returns a new set of layers that preprocess the input graphs using a
+// ClosedSetNormalizer with the given options.  This can be used to ensure
+// that the graphs passed to "output_layers" do not contain any polyline or
+// polygon degeneracies.
+//
+// Example showing how to compute the union of two S2ShapeIndexes containing
+// points, polylines, and/or polygons, and save the result as a collection of
+// S2Points, S2Polylines, and S2Polygons in another S2ShapeIndex (where
+// degeneracies have been normalized to objects of lower dimension, and
+// maximal polylines are constructed from undirected edges):
+//
+// bool ComputeUnion(const S2ShapeIndex& a, const S2ShapeIndex& b,
+//                   MutableS2ShapeIndex* index, S2Error* error) {
+//   IndexedS2PolylineVectorLayer::Options polyline_options;
+//   polyline_options.set_edge_type(EdgeType::UNDIRECTED);
+//   polyline_options.set_polyline_type(Graph::PolylineType::WALK);
+//   polyline_options.set_duplicate_edges(DuplicateEdges::MERGE);
+//   LayerVector layers(3);
+//   layers[0] = absl::make_unique<IndexedS2PointVectorLayer>(index);
+//   layers[1] = absl::make_unique<IndexedS2PolylineVectorLayer>(
+//       index, polyline_options);
+//   layers[2] = absl::make_unique<IndexedS2PolygonLayer>(index);
+//   S2BooleanOperation op(S2BooleanOperation::OpType::UNION,
+//                         NormalizeClosedSet(std::move(layers)));
+//   return op.Build(a, b, error);
+// }
+LayerVector NormalizeClosedSet(LayerVector output_layers,
+                               const ClosedSetNormalizer::Options& options =
+                               ClosedSetNormalizer::Options());
+
+
+//////////////////   Implementation details follow   ////////////////////
+
+inline ClosedSetNormalizer::Options::Options()
+    : suppress_lower_dimensions_(true) {}
+
+inline bool ClosedSetNormalizer::Options::suppress_lower_dimensions() const {
+  return suppress_lower_dimensions_;
+}
+
+inline void ClosedSetNormalizer::Options::set_suppress_lower_dimensions(
+    bool suppress_lower_dimensions) {
+  suppress_lower_dimensions_ = suppress_lower_dimensions;
+}
+
+inline const std::vector<S2Builder::GraphOptions>&
+ClosedSetNormalizer::graph_options() const {
+  return graph_options_in_;
+}
+
+}  // namespace s2builderutil
+
+#endif  // S2_S2BUILDERUTIL_CLOSED_SET_NORMALIZER_H_
diff --git a/src/s2/s2builderutil_find_polygon_degeneracies.cc b/src/s2/s2builderutil_find_polygon_degeneracies.cc
new file mode 100644 (file)
index 0000000..28bc67c
--- /dev/null
@@ -0,0 +1,392 @@
+// Copyright 2017 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// Author: ericv@google.com (Eric Veach)
+
+#include "s2/s2builderutil_find_polygon_degeneracies.h"
+
+#include <cstdlib>
+#include <utility>
+#include <vector>
+
+#include "absl/memory/memory.h"
+#include "s2/mutable_s2shape_index.h"
+#include "s2/s2builder_graph.h"
+#include "s2/s2builderutil_graph_shape.h"
+#include "s2/s2contains_vertex_query.h"
+#include "s2/s2crossing_edge_query.h"
+#include "s2/s2edge_crosser.h"
+#include "s2/s2pointutil.h"
+#include "s2/s2predicates.h"
+
+using absl::make_unique;
+using std::make_pair;
+using std::pair;
+using std::vector;
+
+using EdgeType = S2Builder::EdgeType;
+using Graph = S2Builder::Graph;
+using GraphOptions = S2Builder::GraphOptions;
+
+using Edge = Graph::Edge;
+using EdgeId = Graph::EdgeId;
+using VertexId = Graph::VertexId;
+
+using DegenerateEdges = GraphOptions::DegenerateEdges;
+using SiblingPairs = GraphOptions::SiblingPairs;
+
+using ShapeEdgeId = s2shapeutil::ShapeEdgeId;
+
+namespace s2builderutil {
+
+namespace {
+
+// The algorithm builds a set of connected components containing all edges
+// that form degeneracies.  The shell/hole status of each degeneracy is
+// initially unknown, and is expressed relative to the root vertex: "is_hole"
+// means that the degeneracy is a hole if and only if the root vertex turns
+// out to be inside the polygon.
+struct Component {
+  // The root vertex from which this component was built.
+  VertexId root;
+
+  // +1 if "root" inside the polygon, -1 if outside, and 0 if unknown.
+  int root_sign = 0;
+
+  // The degeneracies found in this component.  "is_hole" is expressed
+  // relative to the root vertex: the degeneracy is a hole iff the root vertex
+  // turns out to be inside the polygon (i.e., root_sign > 0).
+  vector<PolygonDegeneracy> degeneracies;
+};
+
+// The actual implementation of FindPolygonDegeneracies.
+class DegeneracyFinder {
+ public:
+  explicit DegeneracyFinder(const S2Builder::Graph* g)
+      : g_(*g), in_(g_), out_(g_) {
+  }
+  vector<PolygonDegeneracy> Run(S2Error* error);
+
+ private:
+  // Methods are documented below.
+  int ComputeDegeneracies();
+  Component BuildComponent(VertexId root);
+  bool CrossingParity(VertexId v0, VertexId v1, bool include_same) const;
+  VertexId FindUnbalancedVertex() const;
+  int ContainsVertexSign(VertexId v0) const;
+  void ComputeUnknownSignsBruteForce(VertexId known_vertex,
+                                     int known_vertex_sign,
+                                     vector<Component>* components) const;
+  void ComputeUnknownSignsIndexed(VertexId known_vertex, int known_vertex_sign,
+                                  vector<Component>* components) const;
+  vector<PolygonDegeneracy> MergeDegeneracies(
+      const vector<Component>& components) const;
+
+  const Graph& g_;
+  Graph::VertexInMap in_;
+  Graph::VertexOutMap out_;
+  vector<bool> is_vertex_used_;        // Has vertex been visited?
+  vector<bool> is_edge_degeneracy_;    // Belongs to a degeneracy?
+  vector<bool> is_vertex_unbalanced_;  // Has unbalanced sibling pairs?
+};
+
+vector<PolygonDegeneracy> DegeneracyFinder::Run(S2Error* error) {
+  // Mark all degenerate edges and sibling pairs in the "is_edge_degeneracy_"
+  // vector, and mark any vertices with unbalanced edges in the
+  // "is_vertex_unbalanced_" vector.
+  int num_degeneracies = ComputeDegeneracies();
+  if (num_degeneracies == 0) return {};
+
+  // If all edges are degenerate, then use IsFullPolygon() to classify the
+  // degeneracies (they are necessarily all the same type).
+  if (num_degeneracies == g_.num_edges()) {
+    bool is_hole = g_.IsFullPolygon(error);
+    vector<PolygonDegeneracy> result(g_.num_edges());
+    for (int e = 0; e < g_.num_edges(); ++e) {
+      result[e] = PolygonDegeneracy(e, is_hole);
+    }
+    return result;
+  }
+
+  // Otherwise repeatedly build components starting from an unvisited
+  // degeneracy.  (This avoids building components that don't contain any
+  // degeneracies.)  Each component records the "is_hole" status of each
+  // degeneracy relative to the root vertex of that component.  If the
+  // component contains any non-degenerate portions, then we also determine
+  // whether the root vertex is contained by the component (root_sign).
+  // In addition we keep track of the number of components that were
+  // completely degenerate (to help us decide whether to build an index).
+  vector<Component> components;
+  VertexId known_vertex = -1;
+  int known_vertex_sign = 0;
+  int num_unknown_signs = 0;
+  is_vertex_used_.resize(g_.num_vertices());
+  for (int e = 0; e < g_.num_edges(); ++e) {
+    if (is_edge_degeneracy_[e]) {
+      VertexId root = g_.edge(e).first;
+      if (is_vertex_used_[root]) continue;
+      Component component = BuildComponent(root);
+      if (component.root_sign == 0) {
+        ++num_unknown_signs;
+      } else {
+        known_vertex = root;
+        known_vertex_sign = component.root_sign;
+      }
+      components.push_back(component);
+    }
+  }
+
+  // If some components have an unknown root_sign (i.e., it is unknown whether
+  // the root vertex is contained by the polygon or not), we determine the
+  // sign of those root vertices by counting crossings starting from a vertex
+  // whose sign is known.  Depending on how many components we need to do this
+  // for, it may be worthwhile to build an index first.
+  if (num_unknown_signs > 0) {
+    if (known_vertex_sign == 0) {
+      known_vertex = FindUnbalancedVertex();
+      known_vertex_sign = ContainsVertexSign(known_vertex);
+    }
+    const int kMaxUnindexedContainsCalls = 20;  // Tuned using benchmarks.
+    if (num_unknown_signs <= kMaxUnindexedContainsCalls) {
+      ComputeUnknownSignsBruteForce(known_vertex, known_vertex_sign,
+                                    &components);
+    } else {
+      ComputeUnknownSignsIndexed(known_vertex, known_vertex_sign,
+                                 &components);
+    }
+  }
+  // Finally we convert the "is_hole" status of each degeneracy from a
+  // relative value (compared to the component's root vertex) to an absolute
+  // one, and sort all the degeneracies by EdgeId.
+  return MergeDegeneracies(components);
+}
+
+int DegeneracyFinder::ComputeDegeneracies() {
+  is_edge_degeneracy_.resize(g_.num_edges());
+  is_vertex_unbalanced_.resize(g_.num_vertices());
+  int num_degeneracies = 0;
+  const vector<EdgeId>& in_edge_ids = in_.in_edge_ids();
+  int n = g_.num_edges();
+  for (int in = 0, out = 0; out < n; ++out) {
+    Edge out_edge = g_.edge(out);
+    if (out_edge.first == out_edge.second) {
+      is_edge_degeneracy_[out] = true;
+      ++num_degeneracies;
+    } else {
+      while (in < n && Graph::reverse(g_.edge(in_edge_ids[in])) < out_edge) {
+        ++in;
+      }
+      if (in < n && Graph::reverse(g_.edge(in_edge_ids[in])) == out_edge) {
+        is_edge_degeneracy_[out] = true;
+        ++num_degeneracies;
+      } else {
+        // This edge does not have a sibling, which mean that we can determine
+        // whether either vertex is contained by the polygon (using semi-open
+        // boundaries) by examining only the edges incident to that vertex.
+        // We only mark the first vertex since there is no advantage to
+        // finding more than one unbalanced vertex per connected component.
+        is_vertex_unbalanced_[out_edge.first] = true;
+      }
+    }
+  }
+  return num_degeneracies;
+}
+
+// Build a connected component starting at the given root vertex.  The
+// information returned includes: the root vertex, whether the containment
+// status of the root vertex could be determined using only the edges in this
+// component, and a vector of the edges that belong to degeneracies along with
+// the shell/hole status of each such edge relative to the root vertex.
+Component DegeneracyFinder::BuildComponent(VertexId root) {
+  Component result;
+  result.root = root;
+  // We keep track of the frontier of unexplored vertices, and whether each
+  // vertex is on the same side of the polygon boundary as the root vertex.
+  vector<pair<VertexId, bool>> frontier;
+  frontier.push_back(make_pair(root, true));
+  is_vertex_used_[root] = true;
+  while (!frontier.empty()) {
+    VertexId v0 = frontier.back().first;
+    bool v0_same_inside = frontier.back().second;  // Same as root vertex?
+    frontier.pop_back();
+    if (result.root_sign == 0 && is_vertex_unbalanced_[v0]) {
+      int v0_sign = ContainsVertexSign(v0);
+      S2_DCHECK_NE(v0_sign, 0);
+      result.root_sign = v0_same_inside ? v0_sign : -v0_sign;
+    }
+    for (EdgeId e : out_.edge_ids(v0)) {
+      VertexId v1 = g_.edge(e).second;
+      bool same_inside = v0_same_inside ^ CrossingParity(v0, v1, false);
+      if (is_edge_degeneracy_[e]) {
+        result.degeneracies.push_back(PolygonDegeneracy(e, same_inside));
+      }
+      if (is_vertex_used_[v1]) continue;
+      same_inside ^= CrossingParity(v1, v0, true);
+      frontier.push_back(make_pair(v1, same_inside));
+      is_vertex_used_[v1] = true;
+    }
+  }
+  return result;
+}
+
+// Counts the number of times that (v0, v1) crosses the edges incident to v0,
+// and returns the result modulo 2.  This is equivalent to calling
+// S2::VertexCrossing for the edges incident to v0, except that this
+// implementation is more efficient (since it doesn't need to determine which
+// two edge vertices are the same).
+//
+// If "include_same" is false, then the edge (v0, v1) and its sibling (v1, v0)
+// (if any) are excluded from the parity calculation.
+bool DegeneracyFinder::CrossingParity(VertexId v0, VertexId v1,
+                                      bool include_same) const {
+  int crossings = 0;
+  S2Point p0 = g_.vertex(v0);
+  S2Point p1 = g_.vertex(v1);
+  S2Point p0_ref = S2::Ortho(p0);
+  for (const Edge& edge : out_.edges(v0)) {
+    if (edge.second == v1) {
+      if (include_same) ++crossings;
+    } else if (s2pred::OrderedCCW(p0_ref, g_.vertex(edge.second), p1, p0)) {
+      ++crossings;
+    }
+  }
+  for (EdgeId e : in_.edge_ids(v0)) {
+    Edge edge = g_.edge(e);
+    if (edge.first == v1) {
+      if (include_same) ++crossings;
+    } else if (s2pred::OrderedCCW(p0_ref, g_.vertex(edge.first), p1, p0)) {
+      ++crossings;
+    }
+  }
+  return crossings & 1;
+}
+
+VertexId DegeneracyFinder::FindUnbalancedVertex() const {
+  for (VertexId v = 0; v < g_.num_vertices(); ++v) {
+    if (is_vertex_unbalanced_[v]) return v;
+  }
+  S2_LOG(DFATAL) << "Could not find previously marked unbalanced vertex";
+  return -1;
+}
+
+int DegeneracyFinder::ContainsVertexSign(VertexId v0) const {
+  S2ContainsVertexQuery query(g_.vertex(v0));
+  for (const Edge& edge : out_.edges(v0)) {
+    query.AddEdge(g_.vertex(edge.second), 1);
+  }
+  for (EdgeId e : in_.edge_ids(v0)) {
+    query.AddEdge(g_.vertex(g_.edge(e).first), -1);
+  }
+  return query.ContainsSign();
+}
+
+// Determines any unknown signs of component root vertices by counting
+// crossings starting from a vertex whose sign is known.  This version simply
+// tests all edges for crossings.
+void DegeneracyFinder::ComputeUnknownSignsBruteForce(
+    VertexId known_vertex, int known_vertex_sign,
+    vector<Component>* components) const {
+  S2EdgeCrosser crosser;
+  for (Component& component : *components) {
+    if (component.root_sign != 0) continue;
+    bool inside = known_vertex_sign > 0;
+    crosser.Init(&g_.vertex(known_vertex), &g_.vertex(component.root));
+    for (EdgeId e = 0; e < g_.num_edges(); ++e) {
+      if (is_edge_degeneracy_[e]) continue;
+      const Edge& edge = g_.edge(e);
+      inside ^= crosser.EdgeOrVertexCrossing(&g_.vertex(edge.first),
+                                             &g_.vertex(edge.second));
+    }
+    component.root_sign = inside ? 1 : -1;
+  }
+}
+
+// Like ComputeUnknownSignsBruteForce, except that this method uses an index
+// to find the set of edges that cross a given edge.
+void DegeneracyFinder::ComputeUnknownSignsIndexed(
+    VertexId known_vertex, int known_vertex_sign,
+    vector<Component>* components) const {
+  MutableS2ShapeIndex index;
+  index.Add(make_unique<GraphShape>(&g_));
+  S2CrossingEdgeQuery query(&index);
+  vector<ShapeEdgeId> crossing_edges;
+  S2EdgeCrosser crosser;
+  for (Component& component : *components) {
+    if (component.root_sign != 0) continue;
+    bool inside = known_vertex_sign > 0;
+    crosser.Init(&g_.vertex(known_vertex), &g_.vertex(component.root));
+    query.GetCandidates(g_.vertex(known_vertex), g_.vertex(component.root),
+                       *index.shape(0), &crossing_edges);
+    for (ShapeEdgeId id : crossing_edges) {
+      int e = id.edge_id;
+      if (is_edge_degeneracy_[e]) continue;
+      inside ^= crosser.EdgeOrVertexCrossing(&g_.vertex(g_.edge(e).first),
+                                             &g_.vertex(g_.edge(e).second));
+    }
+    component.root_sign = inside ? 1 : -1;
+  }
+}
+
+// Merges the degeneracies from all components together, and computes the
+// final "is_hole" status of each edge (since up to this point, the "is_hole"
+// value has been expressed relative to the root vertex of each component).
+vector<PolygonDegeneracy> DegeneracyFinder::MergeDegeneracies(
+    const vector<Component>& components) const {
+  vector<PolygonDegeneracy> result;
+  for (const Component& component : components) {
+    S2_DCHECK_NE(component.root_sign, 0);
+    bool invert = component.root_sign < 0;
+    for (const auto& d : component.degeneracies) {
+      result.push_back(PolygonDegeneracy(d.edge_id, d.is_hole ^ invert));
+    }
+  }
+  std::sort(result.begin(), result.end());
+  return result;
+}
+
+void CheckGraphOptions(const Graph& g) {
+  S2_DCHECK(g.options().edge_type() == EdgeType::DIRECTED);
+  S2_DCHECK(g.options().degenerate_edges() == DegenerateEdges::DISCARD ||
+         g.options().degenerate_edges() == DegenerateEdges::DISCARD_EXCESS);
+  S2_DCHECK(g.options().sibling_pairs() == SiblingPairs::DISCARD ||
+         g.options().sibling_pairs() == SiblingPairs::DISCARD_EXCESS);
+}
+
+}  // namespace
+
+vector<PolygonDegeneracy> FindPolygonDegeneracies(const Graph& g,
+                                                  S2Error* error) {
+  CheckGraphOptions(g);
+  if (g.options().degenerate_edges() == DegenerateEdges::DISCARD &&
+      g.options().sibling_pairs() == SiblingPairs::DISCARD) {
+    return {};  // All degeneracies have already been discarded.
+  }
+  return DegeneracyFinder(&g).Run(error);
+}
+
+bool IsFullyDegenerate(const S2Builder::Graph& g) {
+  CheckGraphOptions(g);
+  const vector<Edge>& edges = g.edges();
+  for (int e = 0; e < g.num_edges(); ++e) {
+    Edge edge = edges[e];
+    if (edge.first == edge.second) continue;
+    if (!std::binary_search(edges.begin(), edges.end(), Graph::reverse(edge))) {
+      return false;
+    }
+  }
+  return true;
+}
+
+}  // namespace s2builderutil
diff --git a/src/s2/s2builderutil_find_polygon_degeneracies.h b/src/s2/s2builderutil_find_polygon_degeneracies.h
new file mode 100644 (file)
index 0000000..49157ac
--- /dev/null
@@ -0,0 +1,86 @@
+// Copyright 2017 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// Author: ericv@google.com (Eric Veach)
+
+#ifndef S2_S2BUILDERUTIL_FIND_POLYGON_DEGENERACIES_H_
+#define S2_S2BUILDERUTIL_FIND_POLYGON_DEGENERACIES_H_
+
+#include <vector>
+
+#include "s2/base/integral_types.h"
+#include "s2/s2builder_graph.h"
+#include "s2/s2error.h"
+
+namespace s2builderutil {
+
+// A polygon degeneracy is either a degenerate edge (an edge from a vertex to
+// itself) or a sibling edge pair (consisting of an edge and its corresponding
+// reverse edge).  "is_hole" indicates whether the degeneracy corresponds to a
+// polygon hole (as opposed to a polygon shell).
+//
+// Degeneracies are not allowed to coincide with any non-degenerate portions
+// of the polygon's boundary (since that would make it impossible to classify
+// the degeneracy as a shell or hole).  Specifically, degenerate edges must
+// coincide only with other degenerate edges, and sibling pairs must coincide
+// only with other sibling pairs.  (Below we require a slightly stronger
+// condition, namely that sibling pairs cannot coincide with any other edges.)
+struct PolygonDegeneracy {
+  uint32 edge_id : 31;
+  uint32 is_hole : 1;
+
+  PolygonDegeneracy() : edge_id(0), is_hole(false) {}
+  PolygonDegeneracy(S2Builder::Graph::EdgeId _edge_id, bool _is_hole)
+      : edge_id(_edge_id), is_hole(_is_hole) {
+  }
+  bool operator==(PolygonDegeneracy y) const {
+    return edge_id == y.edge_id && is_hole == y.is_hole;
+  }
+  bool operator<(PolygonDegeneracy y) const {
+    return edge_id < y.edge_id || (edge_id == y.edge_id && is_hole < y.is_hole);
+  }
+};
+
+// Given a graph representing a polygon, finds all degenerate edges and
+// sibling pairs and classifies them as being either shells or holes.  The
+// result vector is sorted by edge id.
+//
+// REQUIRES: g.options().edge_type() == DIRECTED
+// REQUIRES: g.options().sibling_pairs() == DISCARD_EXCESS (or DISCARD)
+// REQUIRES: g.options().degenerate_edges() == DISCARD_EXCESS (or DISCARD)
+//
+// Usually callers will want to specify SiblingPairs::DISCARD_EXCESS and
+// DegenerateEdges::DISCARD_EXCESS in order to remove all redundant
+// degeneracies.  DISCARD is also allowed in case you want to keep only one
+// type of degeneracy (i.e., degenerate edges or sibling pairs).
+//
+// If the graph edges cannot be assembled into loops, the result is undefined.
+// (An error may or may not be returned.)
+std::vector<PolygonDegeneracy> FindPolygonDegeneracies(
+    const S2Builder::Graph& g, S2Error* error);
+
+// Given a graph representing a polygon, returns true the graph consists
+// entirely of degenerate edges and/or sibling pairs.  Such a graph represents
+// either the empty polygon together with a collection of degenerate shells,
+// or the full polygon together with a collection of degenerate holes.
+//
+// REQUIRES: g.options().edge_type() == DIRECTED
+// REQUIRES: g.options().sibling_pairs() == DISCARD_EXCESS (or DISCARD)
+// REQUIRES: g.options().degenerate_edges() == DISCARD_EXCESS (or DISCARD)
+bool IsFullyDegenerate(const S2Builder::Graph& g);
+
+}  // namespace s2builderutil
+
+#endif  // S2_S2BUILDERUTIL_FIND_POLYGON_DEGENERACIES_H_
diff --git a/src/s2/s2builderutil_graph_shape.h b/src/s2/s2builderutil_graph_shape.h
new file mode 100644 (file)
index 0000000..9edbc2b
--- /dev/null
@@ -0,0 +1,57 @@
+// Copyright 2017 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// Author: ericv@google.com (Eric Veach)
+
+#ifndef S2_S2BUILDERUTIL_GRAPH_SHAPE_H_
+#define S2_S2BUILDERUTIL_GRAPH_SHAPE_H_
+
+#include <vector>
+
+#include "s2/s2builder_graph.h"
+
+namespace s2builderutil {
+
+// An S2Shape representing the edges in an S2Builder::Graph.
+class GraphShape final : public S2Shape {
+ public:
+  using Graph = S2Builder::Graph;
+  explicit GraphShape(const Graph* g) : g_(*g) {}
+  int num_edges() const override { return g_.num_edges(); }
+  Edge edge(int e) const override {
+    Graph::Edge g_edge = g_.edge(e);
+    return Edge(g_.vertex(g_edge.first), g_.vertex(g_edge.second));
+  }
+  int dimension() const override { return 1; }
+  ReferencePoint GetReferencePoint() const override {
+    return ReferencePoint::Contained(false);
+  }
+  int num_chains() const override { return g_.num_edges(); }
+  Chain chain(int i) const override { return Chain(i, 1); }
+  Edge chain_edge(int i, int j) const override {
+    S2_DCHECK_EQ(j, 0);
+    return edge(i);
+  }
+  ChainPosition chain_position(int e) const override {
+    return ChainPosition(e, 0);
+  }
+
+ private:
+  const Graph& g_;
+};
+
+}  // namespace s2builderutil
+
+#endif  // S2_S2BUILDERUTIL_GRAPH_SHAPE_H_
diff --git a/src/s2/s2builderutil_lax_polygon_layer.cc b/src/s2/s2builderutil_lax_polygon_layer.cc
new file mode 100644 (file)
index 0000000..9b92240
--- /dev/null
@@ -0,0 +1,212 @@
+// Copyright 2018 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// Author: ericv@google.com (Eric Veach)
+
+#include "s2/s2builderutil_lax_polygon_layer.h"
+
+#include <algorithm>
+#include <memory>
+#include "absl/memory/memory.h"
+#include "s2/s2builderutil_find_polygon_degeneracies.h"
+#include "s2/s2debug.h"
+
+using std::vector;
+
+using EdgeType = S2Builder::EdgeType;
+using Graph = S2Builder::Graph;
+using GraphOptions = S2Builder::GraphOptions;
+using Label = S2Builder::Label;
+
+using DegenerateEdges = GraphOptions::DegenerateEdges;
+using DuplicateEdges = GraphOptions::DuplicateEdges;
+using SiblingPairs = GraphOptions::SiblingPairs;
+
+using Edge = Graph::Edge;
+using EdgeId = Graph::EdgeId;
+using InputEdgeIdSetId = Graph::InputEdgeIdSetId;
+using LoopType = Graph::LoopType;
+
+namespace s2builderutil {
+
+using DegenerateBoundaries = LaxPolygonLayer::Options::DegenerateBoundaries;
+
+LaxPolygonLayer::LaxPolygonLayer(S2LaxPolygonShape* polygon,
+                                 const Options& options) {
+  Init(polygon, nullptr, nullptr, options);
+}
+
+LaxPolygonLayer::LaxPolygonLayer(
+    S2LaxPolygonShape* polygon, LabelSetIds* label_set_ids,
+    IdSetLexicon* label_set_lexicon, const Options& options) {
+  Init(polygon, label_set_ids, label_set_lexicon, options);
+}
+
+void LaxPolygonLayer::Init(
+    S2LaxPolygonShape* polygon, LabelSetIds* label_set_ids,
+    IdSetLexicon* label_set_lexicon, const Options& options) {
+  S2_DCHECK_EQ(label_set_ids == nullptr, label_set_lexicon == nullptr);
+  polygon_ = polygon;
+  label_set_ids_ = label_set_ids;
+  label_set_lexicon_ = label_set_lexicon;
+  options_ = options;
+}
+
+GraphOptions LaxPolygonLayer::graph_options() const {
+  if (options_.degenerate_boundaries() == DegenerateBoundaries::DISCARD) {
+    // There should not be any duplicate edges, but if there are then we keep
+    // them since this yields more comprehensible error messages.
+    return GraphOptions(options_.edge_type(), DegenerateEdges::DISCARD,
+                        DuplicateEdges::KEEP, SiblingPairs::DISCARD);
+  } else {
+    // Keep at most one copy of each sibling pair and each isolated vertex.
+    // We need DuplicateEdges::MERGE because DegenerateEdges::DISCARD_EXCESS
+    // can still keep multiple copies (it only discards degenerate edges that
+    // are connected to non-degenerate edges).
+    return GraphOptions(options_.edge_type(), DegenerateEdges::DISCARD_EXCESS,
+                        DuplicateEdges::MERGE, SiblingPairs::DISCARD_EXCESS);
+  }
+}
+
+void LaxPolygonLayer::AppendPolygonLoops(
+    const Graph& g, const vector<Graph::EdgeLoop>& edge_loops,
+    vector<vector<S2Point>>* loops) const {
+  for (const auto& edge_loop : edge_loops) {
+    vector<S2Point> vertices;
+    vertices.reserve(edge_loop.size());
+    for (auto edge_id : edge_loop) {
+      vertices.push_back(g.vertex(g.edge(edge_id).first));
+    }
+    loops->push_back(std::move(vertices));
+  }
+}
+
+void LaxPolygonLayer::AppendEdgeLabels(
+    const Graph& g,
+    const vector<Graph::EdgeLoop>& edge_loops) {
+  if (!label_set_ids_) return;
+
+  vector<Label> labels;  // Temporary storage for labels.
+  Graph::LabelFetcher fetcher(g, options_.edge_type());
+  for (const auto& edge_loop : edge_loops) {
+    vector<LabelSetId> loop_label_set_ids;
+    loop_label_set_ids.reserve(edge_loop.size());
+    for (auto edge_id : edge_loop) {
+      fetcher.Fetch(edge_id, &labels);
+      loop_label_set_ids.push_back(label_set_lexicon_->Add(labels));
+    }
+    label_set_ids_->push_back(std::move(loop_label_set_ids));
+  }
+}
+
+// Returns all edges of "g" except for those identified by "edges_to_discard".
+static void DiscardEdges(const Graph& g, const vector<EdgeId>& edges_to_discard,
+                         vector<Edge>* new_edges,
+                         vector<InputEdgeIdSetId>* new_input_edge_id_set_ids) {
+  S2_DCHECK(std::is_sorted(edges_to_discard.begin(), edges_to_discard.end()));
+  new_edges->clear();
+  new_input_edge_id_set_ids->clear();
+  new_edges->reserve(g.num_edges());
+  new_input_edge_id_set_ids->reserve(g.num_edges());
+  auto it = edges_to_discard.begin();
+  for (int e = 0; e < g.num_edges(); ++e) {
+    if (it != edges_to_discard.end() && e == *it) {
+      ++it;
+    } else {
+      new_edges->push_back(g.edge(e));
+      new_input_edge_id_set_ids->push_back(g.input_edge_id_set_id(e));
+    }
+  }
+  S2_DCHECK(it == edges_to_discard.end());
+}
+
+static void MaybeAddFullLoop(
+    const Graph& g, vector<vector<S2Point>>* loops, S2Error* error) {
+  if (g.IsFullPolygon(error)) {
+    loops->push_back({});  // Full loop.
+  }
+}
+void LaxPolygonLayer::BuildDirected(Graph g, S2Error* error) {
+  // Some cases are implemented by constructing a new graph with certain
+  // degenerate edges removed (overwriting "g").  "new_edges" is where the
+  // edges for the new graph are stored.
+  vector<Edge> new_edges;
+  vector<InputEdgeIdSetId> new_input_edge_id_set_ids;
+  vector<vector<S2Point>> loops;
+  auto degenerate_boundaries = options_.degenerate_boundaries();
+  if (degenerate_boundaries == DegenerateBoundaries::DISCARD) {
+    // This is the easiest case, since there are no degeneracies.
+    if (g.num_edges() == 0) MaybeAddFullLoop(g, &loops, error);
+  } else if (degenerate_boundaries == DegenerateBoundaries::KEEP) {
+    // S2LaxPolygonShape doesn't need to distinguish degenerate shells from
+    // holes except when the entire graph is degenerate, in which case we need
+    // to decide whether it represents an empty polygons possibly with
+    // degenerate shells, or a full polygon possibly with degenerate holes.
+    if (s2builderutil::IsFullyDegenerate(g)) {
+      MaybeAddFullLoop(g, &loops, error);
+    }
+  } else {
+    // For DISCARD_SHELLS and DISCARD_HOLES we first determine whether any
+    // degenerate loops of the given type exist, and if so we construct a new
+    // graph with those edges removed (overwriting "g").
+    bool discard_holes =
+        (degenerate_boundaries == DegenerateBoundaries::DISCARD_HOLES);
+    auto degeneracies = s2builderutil::FindPolygonDegeneracies(g, error);
+    if (!error->ok()) return;
+    if (degeneracies.size() == g.num_edges()) {
+      if (degeneracies.empty()) {
+        MaybeAddFullLoop(g, &loops, error);
+      } else if (degeneracies[0].is_hole) {
+        loops.push_back({});  // Full loop.
+      }
+    }
+    vector<EdgeId> edges_to_discard;
+    for (auto degeneracy : degeneracies) {
+      if (degeneracy.is_hole == discard_holes) {
+        edges_to_discard.push_back(degeneracy.edge_id);
+      }
+    }
+    if (!edges_to_discard.empty()) {
+      // Construct a new graph that discards the unwanted edges.
+      std::sort(edges_to_discard.begin(), edges_to_discard.end());
+      DiscardEdges(g, edges_to_discard, &new_edges, &new_input_edge_id_set_ids);
+      g = Graph(g.options(), &g.vertices(),
+                &new_edges, &new_input_edge_id_set_ids,
+                &g.input_edge_id_set_lexicon(), &g.label_set_ids(),
+                &g.label_set_lexicon(), g.is_full_polygon_predicate());
+    }
+  }
+  vector<Graph::EdgeLoop> edge_loops;
+  if (!g.GetDirectedLoops(LoopType::CIRCUIT, &edge_loops, error)) {
+    return;
+  }
+  AppendPolygonLoops(g, edge_loops, &loops);
+  AppendEdgeLabels(g, edge_loops);
+  vector<Graph::EdgeLoop>().swap(edge_loops);  // Release memory
+  vector<Edge>().swap(new_edges);
+  vector<InputEdgeIdSetId>().swap(new_input_edge_id_set_ids);
+  polygon_->Init(loops);
+}
+
+void LaxPolygonLayer::Build(const Graph& g, S2Error* error) {
+  if (label_set_ids_) label_set_ids_->clear();
+  if (g.options().edge_type() == EdgeType::DIRECTED) {
+    BuildDirected(g, error);
+  } else {
+    error->Init(S2Error::UNIMPLEMENTED, "Undirected edges not supported yet");
+  }
+}
+
+}  // namespace s2builderutil
diff --git a/src/s2/s2builderutil_lax_polygon_layer.h b/src/s2/s2builderutil_lax_polygon_layer.h
new file mode 100644 (file)
index 0000000..8a1e63e
--- /dev/null
@@ -0,0 +1,218 @@
+// Copyright 2018 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// Author: ericv@google.com (Eric Veach)
+//
+// Note that there are two supported output types for polygons: S2Polygon and
+// S2LaxPolygonShape.  Use S2Polygon if you need the full range of operations
+// that S2Polygon implements.  Use S2LaxPolygonShape if you want to represent
+// polygons with zero-area degenerate regions, or if you need a type that has
+// low memory overhead and fast initialization.  However, be aware that to
+// convert from S2LaxPolygonShape to S2Polygon you will need to use S2Builder
+// again.
+//
+// Similarly, there are two supported output formats for polygon meshes:
+// S2PolygonMesh and S2LaxPolygonShapeVector.  Use S2PolygonMesh if you need
+// to be able to determine which polygons are adjacent to each edge or vertex;
+// otherwise use S2LaxPolygonShapeVector, which uses less memory and is faster
+// to construct.
+
+#ifndef S2_S2BUILDERUTIL_LAX_POLYGON_LAYER_H_
+#define S2_S2BUILDERUTIL_LAX_POLYGON_LAYER_H_
+
+#include <memory>
+#include <vector>
+#include "s2/base/logging.h"
+#include "absl/memory/memory.h"
+#include "s2/id_set_lexicon.h"
+#include "s2/mutable_s2shape_index.h"
+#include "s2/s2builder.h"
+#include "s2/s2builder_graph.h"
+#include "s2/s2builder_layer.h"
+#include "s2/s2error.h"
+#include "s2/s2lax_polygon_shape.h"
+
+namespace s2builderutil {
+
+// A layer type that assembles edges (directed or undirected) into an
+// S2LaxPolygonShape.  Returns an error if the edges cannot be assembled into
+// loops.
+//
+// If the input edges are directed, they must be oriented such that the
+// polygon interior is to the left of all edges.  Directed edges are always
+// preferred (see S2Builder::EdgeType).
+//
+// LaxPolygonLayer is implemented such that if the input to S2Builder is a
+// polygon and is not modified, then the output has the same cyclic ordering
+// of loop vertices and the same loop ordering as the input polygon.
+//
+// If the given edge graph is degenerate (i.e., it consists entirely of
+// degenerate edges and sibling pairs), then the IsFullPolygonPredicate
+// associated with the edge graph is called to determine whether the output
+// polygon should be empty (possibly with degenerate shells) or full (possibly
+// with degenerate holes).  This predicate can be specified as part of the
+// S2Builder input geometry.
+class LaxPolygonLayer : public S2Builder::Layer {
+ public:
+  class Options {
+   public:
+    // Constructor that uses the default options (listed below).
+    Options();
+
+    // Constructor that specifies the edge type.
+    explicit Options(S2Builder::EdgeType edge_type);
+
+    // Indicates whether the input edges provided to S2Builder are directed or
+    // undirected.  Directed edges should be used whenever possible (see
+    // S2Builder::EdgeType for details).
+    //
+    // If the input edges are directed, they should be oriented so that the
+    // polygon interior is to the left of all edges.  This means that for a
+    // polygon with holes, the outer loops ("shells") should be directed
+    // counter-clockwise while the inner loops ("holes") should be directed
+    // clockwise.  Note that S2Builder::AddPolygon() does this automatically.
+    //
+    // DEFAULT: S2Builder::EdgeType::DIRECTED
+    S2Builder::EdgeType edge_type() const;
+    void set_edge_type(S2Builder::EdgeType edge_type);
+
+    // Specifies whether degenerate boundaries should be discarded or kept.
+    // (A degenerate boundary consists of either a sibling edge pair or an
+    // edge from a vertex to itself.)  Optionally, degenerate boundaries may
+    // be kept only if they represent shells, or only if they represent holes.
+    //
+    // This option is useful for normalizing polygons with various boundary
+    // conditions.  For example, DISCARD_HOLES can be used to normalize closed
+    // polygons (those that include their boundary), since degenerate holes do
+    // not affect the set of points contained by such polygons.  Similarly,
+    // DISCARD_SHELLS can be used to normalize polygons with open boundaries.
+    // DISCARD is used to normalize polygons with semi-open boundaries (since
+    // degenerate loops do not affect point containment in that case), and
+    // finally KEEP is useful for working with any type of polygon where
+    // degeneracies are assumed to contain an infinitesmal interior.  (This
+    // last model is the most useful for working with simplified geometry,
+    // since it maintains the closest fidelity to the original geometry.)
+    //
+    // DEFAULT: DegenerateBoundaries::KEEP
+    enum class DegenerateBoundaries {
+      DISCARD, DISCARD_HOLES, DISCARD_SHELLS, KEEP
+    };
+    DegenerateBoundaries degenerate_boundaries() const;
+    void set_degenerate_boundaries(DegenerateBoundaries degenerate_boundaries);
+
+   private:
+    S2Builder::EdgeType edge_type_;
+    DegenerateBoundaries degenerate_boundaries_;
+  };
+
+  // Specifies that a polygon should be constructed using the given options.
+  explicit LaxPolygonLayer(S2LaxPolygonShape* polygon,
+                           const Options& options = Options());
+
+  // Specifies that a polygon should be constructed using the given options,
+  // and that any labels attached to the input edges should be returned in
+  // "label_set_ids" and "label_set_lexicion".
+  //
+  // The labels associated with the edge "polygon.chain_edge(i, j)"
+  // can be retrieved as follows:
+  //
+  //   for (int32 label : label_set_lexicon.id_set(label_set_ids[i][j])) {...}
+  using LabelSetIds = std::vector<std::vector<LabelSetId>>;
+  LaxPolygonLayer(S2LaxPolygonShape* polygon, LabelSetIds* label_set_ids,
+                  IdSetLexicon* label_set_lexicon,
+                  const Options& options = Options());
+
+  // Layer interface:
+  GraphOptions graph_options() const override;
+  void Build(const Graph& g, S2Error* error) override;
+
+ private:
+  void Init(S2LaxPolygonShape* polygon, LabelSetIds* label_set_ids,
+            IdSetLexicon* label_set_lexicon, const Options& options);
+  void AppendPolygonLoops(const Graph& g,
+                          const std::vector<Graph::EdgeLoop>& edge_loops,
+                          std::vector<std::vector<S2Point>>* loops) const;
+  void AppendEdgeLabels(const Graph& g,
+                        const std::vector<Graph::EdgeLoop>& edge_loops);
+  void BuildDirected(Graph g, S2Error* error);
+
+  S2LaxPolygonShape* polygon_;
+  LabelSetIds* label_set_ids_;
+  IdSetLexicon* label_set_lexicon_;
+  Options options_;
+};
+
+// Like LaxPolygonLayer, but adds the polygon to a MutableS2ShapeIndex (if the
+// polygon is non-empty).
+class IndexedLaxPolygonLayer : public S2Builder::Layer {
+ public:
+  using Options = LaxPolygonLayer::Options;
+  explicit IndexedLaxPolygonLayer(MutableS2ShapeIndex* index,
+                                 const Options& options = Options())
+      : index_(index), polygon_(new S2LaxPolygonShape),
+        layer_(polygon_.get(), options) {}
+
+  GraphOptions graph_options() const override {
+    return layer_.graph_options();
+  }
+
+  void Build(const Graph& g, S2Error* error) override {
+    layer_.Build(g, error);
+    if (error->ok() && !polygon_->is_empty()) {
+      index_->Add(std::move(polygon_));
+    }
+  }
+
+ private:
+  MutableS2ShapeIndex* index_;
+  std::unique_ptr<S2LaxPolygonShape> polygon_;
+  LaxPolygonLayer layer_;
+};
+
+
+//////////////////   Implementation details follow   ////////////////////
+
+
+inline LaxPolygonLayer::Options::Options()
+    : Options(S2Builder::EdgeType::DIRECTED) {
+}
+
+inline LaxPolygonLayer::Options::Options(S2Builder::EdgeType edge_type)
+    : edge_type_(edge_type),
+      degenerate_boundaries_(DegenerateBoundaries::KEEP) {
+}
+
+inline S2Builder::EdgeType LaxPolygonLayer::Options::edge_type() const {
+  return edge_type_;
+}
+
+inline void LaxPolygonLayer::Options::set_edge_type(
+    S2Builder::EdgeType edge_type) {
+  edge_type_ = edge_type;
+}
+
+inline LaxPolygonLayer::Options::DegenerateBoundaries
+LaxPolygonLayer::Options::degenerate_boundaries() const {
+  return degenerate_boundaries_;
+}
+
+inline void LaxPolygonLayer::Options::set_degenerate_boundaries(
+    DegenerateBoundaries degenerate_boundaries) {
+  degenerate_boundaries_ = degenerate_boundaries;
+}
+
+}  // namespace s2builderutil
+
+#endif  // S2_S2BUILDERUTIL_LAX_POLYGON_LAYER_H_
diff --git a/src/s2/s2builderutil_s2point_vector_layer.cc b/src/s2/s2builderutil_s2point_vector_layer.cc
new file mode 100644 (file)
index 0000000..013a912
--- /dev/null
@@ -0,0 +1,74 @@
+// Copyright 2016 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// Author: ericv@google.com (Eric Veach)
+
+#include "s2/s2builderutil_s2point_vector_layer.h"
+
+#include "s2/s2builder_graph.h"
+
+using std::vector;
+
+using EdgeType = S2Builder::EdgeType;
+using Graph = S2Builder::Graph;
+using GraphOptions = S2Builder::GraphOptions;
+using Label = S2Builder::Label;
+
+using DegenerateEdges = GraphOptions::DegenerateEdges;
+using DuplicateEdges = GraphOptions::DuplicateEdges;
+using SiblingPairs = GraphOptions::SiblingPairs;
+
+using EdgeId = Graph::EdgeId;
+
+namespace s2builderutil {
+
+S2PointVectorLayer::S2PointVectorLayer(vector<S2Point>* points,
+                                       const Options& options)
+    : S2PointVectorLayer(points, nullptr, nullptr, options) {}
+
+S2PointVectorLayer::S2PointVectorLayer(vector<S2Point>* points,
+                                       LabelSetIds* label_set_ids,
+                                       IdSetLexicon* label_set_lexicon,
+                                       const Options& options)
+    : points_(points),
+      label_set_ids_(label_set_ids),
+      label_set_lexicon_(label_set_lexicon),
+      options_(options) {}
+
+void S2PointVectorLayer::Build(const Graph& g, S2Error* error) {
+  Graph::LabelFetcher fetcher(g, EdgeType::DIRECTED);
+
+  vector<Label> labels;  // Temporary storage for labels.
+  for (EdgeId edge_id = 0; edge_id < g.edges().size(); edge_id++) {
+    auto& edge = g.edge(edge_id);
+    if (edge.first != edge.second) {
+      error->Init(S2Error::INVALID_ARGUMENT, "Found non-degenerate edges");
+      continue;
+    }
+    points_->push_back(g.vertex(edge.first));
+    if (label_set_ids_) {
+      fetcher.Fetch(edge_id, &labels);
+      int set_id = label_set_lexicon_->Add(labels);
+      label_set_ids_->push_back(set_id);
+    }
+  }
+}
+
+GraphOptions S2PointVectorLayer::graph_options() const {
+  return GraphOptions(EdgeType::DIRECTED, DegenerateEdges::KEEP,
+                      options_.duplicate_edges(), SiblingPairs::KEEP);
+}
+
+}  // namespace s2builderutil
diff --git a/src/s2/s2builderutil_s2point_vector_layer.h b/src/s2/s2builderutil_s2point_vector_layer.h
new file mode 100644 (file)
index 0000000..b7d210a
--- /dev/null
@@ -0,0 +1,122 @@
+// Copyright 2016 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// Author: ericv@google.com (Eric Veach)
+
+#ifndef S2_S2BUILDERUTIL_S2POINT_VECTOR_LAYER_H_
+#define S2_S2BUILDERUTIL_S2POINT_VECTOR_LAYER_H_
+
+#include <memory>
+#include <vector>
+#include "s2/base/logging.h"
+#include "absl/memory/memory.h"
+#include "s2/id_set_lexicon.h"
+#include "s2/mutable_s2shape_index.h"
+#include "s2/s2builder.h"
+#include "s2/s2builder_graph.h"
+#include "s2/s2builder_layer.h"
+#include "s2/s2error.h"
+#include "s2/s2point_vector_shape.h"
+
+namespace s2builderutil {
+
+// A layer type that collects degenerate edges as points.
+// This layer expects all edges to be degenerate. In case of finding
+// non-degenerate edges it sets S2Error but it still generates the
+// output with degenerate edges.
+class S2PointVectorLayer : public S2Builder::Layer {
+ public:
+  class Options {
+   public:
+    using DuplicateEdges = GraphOptions::DuplicateEdges;
+    Options();
+    explicit Options(DuplicateEdges duplicate_edges);
+
+    // DEFAULT: DuplicateEdges::MERGE
+    DuplicateEdges duplicate_edges() const;
+    void set_duplicate_edges(DuplicateEdges duplicate_edges);
+
+   private:
+    DuplicateEdges duplicate_edges_;
+  };
+
+  explicit S2PointVectorLayer(std::vector<S2Point>* points,
+                              const Options& options = Options());
+
+  using LabelSetIds = std::vector<LabelSetId>;
+  S2PointVectorLayer(std::vector<S2Point>* points, LabelSetIds* label_set_ids,
+                     IdSetLexicon* label_set_lexicon,
+                     const Options& options = Options());
+
+  // Layer interface:
+  GraphOptions graph_options() const override;
+  void Build(const Graph& g, S2Error* error) override;
+
+ private:
+  std::vector<S2Point>* points_;
+  LabelSetIds* label_set_ids_;
+  IdSetLexicon* label_set_lexicon_;
+  Options options_;
+};
+
+// Like S2PointVectorLayer, but adds the points to a MutableS2ShapeIndex (if
+// the point vector is non-empty).
+class IndexedS2PointVectorLayer : public S2Builder::Layer {
+ public:
+  using Options = S2PointVectorLayer::Options;
+  explicit IndexedS2PointVectorLayer(MutableS2ShapeIndex* index,
+                                     const Options& options = Options())
+      : index_(index), layer_(&points_, options) {}
+
+  GraphOptions graph_options() const override {
+    return layer_.graph_options();
+  }
+
+  void Build(const Graph& g, S2Error* error) override {
+    layer_.Build(g, error);
+    if (error->ok() && !points_.empty()) {
+      index_->Add(absl::make_unique<S2PointVectorShape>(std::move(points_)));
+    }
+  }
+
+ private:
+  MutableS2ShapeIndex* index_;
+  std::vector<S2Point> points_;
+  S2PointVectorLayer layer_;
+};
+
+
+//////////////////   Implementation details follow   ////////////////////
+
+
+inline S2PointVectorLayer::Options::Options()
+    : duplicate_edges_(DuplicateEdges::MERGE) {}
+
+inline S2PointVectorLayer::Options::Options(DuplicateEdges duplicate_edges)
+    : duplicate_edges_(duplicate_edges) {}
+
+inline S2Builder::GraphOptions::DuplicateEdges
+S2PointVectorLayer::Options::duplicate_edges() const {
+  return duplicate_edges_;
+}
+
+inline void S2PointVectorLayer::Options::set_duplicate_edges(
+    S2Builder::GraphOptions::DuplicateEdges duplicate_edges) {
+  duplicate_edges_ = duplicate_edges;
+}
+
+}  // namespace s2builderutil
+
+#endif  // S2_S2BUILDERUTIL_S2POINT_VECTOR_LAYER_H_
diff --git a/src/s2/s2builderutil_s2polygon_layer.cc b/src/s2/s2builderutil_s2polygon_layer.cc
new file mode 100644 (file)
index 0000000..b37a8bc
--- /dev/null
@@ -0,0 +1,191 @@
+// Copyright 2016 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// Author: ericv@google.com (Eric Veach)
+
+#include "s2/s2builderutil_s2polygon_layer.h"
+
+#include <algorithm>
+#include <memory>
+#include "absl/memory/memory.h"
+#include "s2/s2debug.h"
+
+using absl::make_unique;
+using std::make_pair;
+using std::pair;
+using std::unique_ptr;
+using std::vector;
+
+using EdgeType = S2Builder::EdgeType;
+using Graph = S2Builder::Graph;
+using GraphOptions = S2Builder::GraphOptions;
+using Label = S2Builder::Label;
+
+using DegenerateEdges = GraphOptions::DegenerateEdges;
+using DuplicateEdges = GraphOptions::DuplicateEdges;
+using SiblingPairs = GraphOptions::SiblingPairs;
+
+using LoopType = Graph::LoopType;
+
+namespace s2builderutil {
+
+S2PolygonLayer::S2PolygonLayer(S2Polygon* polygon, const Options& options) {
+  Init(polygon, nullptr, nullptr, options);
+}
+
+S2PolygonLayer::S2PolygonLayer(
+    S2Polygon* polygon, LabelSetIds* label_set_ids,
+    IdSetLexicon* label_set_lexicon, const Options& options) {
+  Init(polygon, label_set_ids, label_set_lexicon, options);
+}
+
+void S2PolygonLayer::Init(
+    S2Polygon* polygon, LabelSetIds* label_set_ids,
+    IdSetLexicon* label_set_lexicon, const Options& options) {
+  S2_DCHECK_EQ(label_set_ids == nullptr, label_set_lexicon == nullptr);
+  polygon_ = polygon;
+  label_set_ids_ = label_set_ids;
+  label_set_lexicon_ = label_set_lexicon;
+  options_ = options;
+
+  if (options_.validate()) {
+    polygon_->set_s2debug_override(S2Debug::DISABLE);
+  }
+}
+
+GraphOptions S2PolygonLayer::graph_options() const {
+  // Prevent degenerate edges and sibling edge pairs.  There should not be any
+  // duplicate edges if the input is valid, but if there are then we keep them
+  // since this tends to produce more comprehensible errors.
+  return GraphOptions(options_.edge_type(), DegenerateEdges::DISCARD,
+                      DuplicateEdges::KEEP, SiblingPairs::DISCARD);
+}
+
+void S2PolygonLayer::AppendS2Loops(const Graph& g,
+                                   const vector<Graph::EdgeLoop>& edge_loops,
+                                   vector<unique_ptr<S2Loop>>* loops) const {
+  vector<S2Point> vertices;
+  for (const auto& edge_loop : edge_loops) {
+    vertices.reserve(edge_loop.size());
+    for (auto edge_id : edge_loop) {
+      vertices.push_back(g.vertex(g.edge(edge_id).first));
+    }
+    loops->push_back(
+        make_unique<S2Loop>(vertices, polygon_->s2debug_override()));
+    vertices.clear();
+  }
+}
+
+void S2PolygonLayer::AppendEdgeLabels(
+    const Graph& g,
+    const vector<Graph::EdgeLoop>& edge_loops) {
+  if (!label_set_ids_) return;
+
+  vector<Label> labels;  // Temporary storage for labels.
+  Graph::LabelFetcher fetcher(g, options_.edge_type());
+  for (const auto& edge_loop : edge_loops) {
+    vector<LabelSetId> loop_label_set_ids;
+    loop_label_set_ids.reserve(edge_loop.size());
+    for (auto edge_id : edge_loop) {
+      fetcher.Fetch(edge_id, &labels);
+      loop_label_set_ids.push_back(label_set_lexicon_->Add(labels));
+    }
+    label_set_ids_->push_back(std::move(loop_label_set_ids));
+  }
+}
+
+void S2PolygonLayer::InitLoopMap(const vector<unique_ptr<S2Loop>>& loops,
+                                 LoopMap* loop_map) const {
+  if (!label_set_ids_) return;
+  for (const auto& loop : loops) {
+    (*loop_map)[&*loop] =
+        make_pair(&loop - &loops[0], loop->contains_origin());
+  }
+}
+
+void S2PolygonLayer::ReorderEdgeLabels(const LoopMap& loop_map) {
+  if (!label_set_ids_) return;
+  LabelSetIds new_ids(label_set_ids_->size());
+  for (int i = 0; i < polygon_->num_loops(); ++i) {
+    S2Loop* loop = polygon_->loop(i);
+    const pair<int, bool>& old = loop_map.find(loop)->second;
+    new_ids[i].swap((*label_set_ids_)[old.first]);
+    if (loop->contains_origin() != old.second) {
+      // S2Loop::Invert() reverses the order of the vertices, which leaves
+      // the last edge unchanged.  For example, the loop ABCD (with edges
+      // AB, BC, CD, DA) becomes the loop DCBA (with edges DC, CB, BA, AD).
+      std::reverse(new_ids[i].begin(), new_ids[i].end() - 1);
+    }
+  }
+  label_set_ids_->swap(new_ids);
+}
+
+void S2PolygonLayer::Build(const Graph& g, S2Error* error) {
+  if (label_set_ids_) label_set_ids_->clear();
+
+  // It's tricky to compute the edge labels for S2Polygons because the
+  // S2Polygon::Init methods can reorder and/or invert the loops.  We handle
+  // this by remembering the original vector index of each loop and whether or
+  // not the loop contained S2::Origin().  By comparing this with the final
+  // S2Polygon loops we can fix up the edge labels appropriately.
+  LoopMap loop_map;
+  if (g.num_edges() == 0) {
+    // The polygon is either full or empty.
+    if (g.IsFullPolygon(error)) {
+      polygon_->Init(make_unique<S2Loop>(S2Loop::kFull()));
+    } else {
+      polygon_->InitNested(vector<unique_ptr<S2Loop>>{});
+    }
+  } else if (g.options().edge_type() == EdgeType::DIRECTED) {
+    vector<Graph::EdgeLoop> edge_loops;
+    if (!g.GetDirectedLoops(LoopType::SIMPLE, &edge_loops, error)) {
+      return;
+    }
+    vector<unique_ptr<S2Loop>> loops;
+    AppendS2Loops(g, edge_loops, &loops);
+    AppendEdgeLabels(g, edge_loops);
+    vector<Graph::EdgeLoop>().swap(edge_loops);  // Release memory
+    InitLoopMap(loops, &loop_map);
+    polygon_->InitOriented(std::move(loops));
+  } else {
+    vector<Graph::UndirectedComponent> components;
+    if (!g.GetUndirectedComponents(LoopType::SIMPLE, &components, error)) {
+      return;
+    }
+    // It doesn't really matter which complement of each component we use,
+    // since below we normalize all the loops so that they enclose at most
+    // half of the sphere (to ensure that the loops can always be nested).
+    //
+    // The only reason to prefer one over the other is that when there are
+    // multiple loops that touch, only one of the two complements matches the
+    // structure of the input loops.  GetUndirectedComponents() tries to
+    // ensure that this is always complement 0 of each component.
+    vector<unique_ptr<S2Loop>> loops;
+    for (const auto& component : components) {
+      AppendS2Loops(g, component[0], &loops);
+      AppendEdgeLabels(g, component[0]);
+    }
+    vector<Graph::UndirectedComponent>().swap(components);  // Release memory
+    InitLoopMap(loops, &loop_map);
+    for (const auto& loop : loops) loop->Normalize();
+    polygon_->InitNested(std::move(loops));
+  }
+  ReorderEdgeLabels(loop_map);
+  if (options_.validate()) {
+    polygon_->FindValidationError(error);
+  }
+}
+
+}  // namespace s2builderutil
diff --git a/src/s2/s2builderutil_s2polygon_layer.h b/src/s2/s2builderutil_s2polygon_layer.h
new file mode 100644 (file)
index 0000000..6fd8c2e
--- /dev/null
@@ -0,0 +1,211 @@
+// Copyright 2016 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// Author: ericv@google.com (Eric Veach)
+//
+// Note that there are two supported output types for polygons: S2Polygon and
+// S2LaxPolygonShape.  Use S2Polygon if you need the full range of operations
+// that S2Polygon implements.  Use S2LaxPolygonShape if you want to represent
+// polygons with zero-area degenerate regions, or if you need a type that has
+// low memory overhead and fast initialization.  However, be aware that to
+// convert from a S2LaxPolygonShape to an S2Polygon you will need to use
+// S2Builder again.
+//
+// Similarly, there are two supported output formats for polygon meshes:
+// S2LaxPolygonShapeVector and S2PolygonMesh.  Use S2PolygonMesh if you need
+// to be able to determine which polygons are adjacent to each edge or vertex;
+// otherwise use S2LaxPolygonShapeVector, which uses less memory and is faster
+// to construct.
+
+#ifndef S2_S2BUILDERUTIL_S2POLYGON_LAYER_H_
+#define S2_S2BUILDERUTIL_S2POLYGON_LAYER_H_
+
+#include <memory>
+#include <utility>
+#include <vector>
+#include "s2/base/logging.h"
+#include "absl/container/btree_map.h"
+#include "absl/memory/memory.h"
+#include "s2/id_set_lexicon.h"
+#include "s2/mutable_s2shape_index.h"
+#include "s2/s2builder.h"
+#include "s2/s2builder_graph.h"
+#include "s2/s2builder_layer.h"
+#include "s2/s2error.h"
+#include "s2/s2loop.h"
+#include "s2/s2polygon.h"
+
+namespace s2builderutil {
+
+// A layer type that assembles edges (directed or undirected) into an
+// S2Polygon.  Returns an error if the edges cannot be assembled into loops.
+//
+// If the input edges are directed, they must be oriented such that the
+// polygon interior is to the left of all edges.  Directed edges are always
+// preferred (see S2Builder::EdgeType).
+//
+// Before the edges are assembled into loops, "sibling pairs" consisting of an
+// edge and its reverse edge are automatically removed.  Such edge pairs
+// represent zero-area degenerate regions, which S2Polygon does not allow.
+// (If you need to build polygons with degeneracies, use LaxPolygonLayer
+// instead.)
+//
+// S2PolygonLayer is implemented such that if the input to S2Builder is a
+// polygon and is not modified, then the output has the same cyclic ordering
+// of loop vertices and the same loop ordering as the input polygon.
+//
+// If the polygon has no edges, then the graph's IsFullPolygonPredicate is
+// called to determine whether the output polygon should be empty (containing
+// no points) or full (containing all points).  This predicate can be
+// specified as part of the S2Builder input geometry.
+class S2PolygonLayer : public S2Builder::Layer {
+ public:
+  class Options {
+   public:
+    // Constructor that uses the default options (listed below).
+    Options();
+
+    // Constructor that specifies the edge type.
+    explicit Options(S2Builder::EdgeType edge_type);
+
+    // Indicates whether the input edges provided to S2Builder are directed or
+    // undirected.  Directed edges should be used whenever possible (see
+    // S2Builder::EdgeType for details).
+    //
+    // If the input edges are directed, they should be oriented so that the
+    // polygon interior is to the left of all edges.  This means that for a
+    // polygon with holes, the outer loops ("shells") should be directed
+    // counter-clockwise while the inner loops ("holes") should be directed
+    // clockwise.  Note that S2Builder::AddPolygon() does this automatically.
+    //
+    // DEFAULT: S2Builder::EdgeType::DIRECTED
+    S2Builder::EdgeType edge_type() const;
+    void set_edge_type(S2Builder::EdgeType edge_type);
+
+    // If true, calls FindValidationError() on the output polygon.  If any
+    // error is found, it will be returned by S2Builder::Build().
+    //
+    // Note that this option calls set_s2debug_override(S2Debug::DISABLE) in
+    // order to turn off the default error checking in debug builds.
+    //
+    // DEFAULT: false
+    bool validate() const;
+    void set_validate(bool validate);
+
+   private:
+    S2Builder::EdgeType edge_type_;
+    bool validate_;
+  };
+
+  // Specifies that a polygon should be constructed using the given options.
+  explicit S2PolygonLayer(S2Polygon* polygon,
+                          const Options& options = Options());
+
+  // Specifies that a polygon should be constructed using the given options,
+  // and that any labels attached to the input edges should be returned in
+  // "label_set_ids" and "label_set_lexicion".
+  //
+  // The labels associated with the edge "polygon.loop(i).vertex({j, j+1})"
+  // can be retrieved as follows:
+  //
+  //   for (int32 label : label_set_lexicon.id_set(label_set_ids[i][j])) {...}
+  using LabelSetIds = std::vector<std::vector<LabelSetId>>;
+  S2PolygonLayer(S2Polygon* polygon, LabelSetIds* label_set_ids,
+                 IdSetLexicon* label_set_lexicon,
+                 const Options& options = Options());
+
+  // Layer interface:
+  GraphOptions graph_options() const override;
+  void Build(const Graph& g, S2Error* error) override;
+
+ private:
+  void Init(S2Polygon* polygon, LabelSetIds* label_set_ids,
+            IdSetLexicon* label_set_lexicon, const Options& options);
+  void AppendS2Loops(const Graph& g,
+                     const std::vector<Graph::EdgeLoop>& edge_loops,
+                     std::vector<std::unique_ptr<S2Loop>>* loops) const;
+  void AppendEdgeLabels(const Graph& g,
+                        const std::vector<Graph::EdgeLoop>& edge_loops);
+  using LoopMap = absl::btree_map<S2Loop*, std::pair<int, bool>>;
+  void InitLoopMap(const std::vector<std::unique_ptr<S2Loop>>& loops,
+                   LoopMap* loop_map) const;
+  void ReorderEdgeLabels(const LoopMap& loop_map);
+
+  S2Polygon* polygon_;
+  LabelSetIds* label_set_ids_;
+  IdSetLexicon* label_set_lexicon_;
+  Options options_;
+};
+
+// Like S2PolygonLayer, but adds the polygon to a MutableS2ShapeIndex (if the
+// polygon is non-empty).
+class IndexedS2PolygonLayer : public S2Builder::Layer {
+ public:
+  using Options = S2PolygonLayer::Options;
+  explicit IndexedS2PolygonLayer(MutableS2ShapeIndex* index,
+                                 const Options& options = Options())
+      : index_(index), polygon_(new S2Polygon),
+        layer_(polygon_.get(), options) {}
+
+  GraphOptions graph_options() const override {
+    return layer_.graph_options();
+  }
+
+  void Build(const Graph& g, S2Error* error) override {
+    layer_.Build(g, error);
+    if (error->ok() && !polygon_->is_empty()) {
+      index_->Add(
+          absl::make_unique<S2Polygon::OwningShape>(std::move(polygon_)));
+    }
+  }
+
+ private:
+  MutableS2ShapeIndex* index_;
+  std::unique_ptr<S2Polygon> polygon_;
+  S2PolygonLayer layer_;
+};
+
+
+//////////////////   Implementation details follow   ////////////////////
+
+
+inline S2PolygonLayer::Options::Options()
+    : edge_type_(S2Builder::EdgeType::DIRECTED), validate_(false) {
+}
+
+inline S2PolygonLayer::Options::Options(S2Builder::EdgeType edge_type)
+    : edge_type_(edge_type), validate_(false) {
+}
+
+inline S2Builder::EdgeType S2PolygonLayer::Options::edge_type() const {
+  return edge_type_;
+}
+
+inline void S2PolygonLayer::Options::set_edge_type(
+    S2Builder::EdgeType edge_type) {
+  edge_type_ = edge_type;
+}
+
+inline bool S2PolygonLayer::Options::validate() const {
+  return validate_;
+}
+
+inline void S2PolygonLayer::Options::set_validate(bool validate) {
+  validate_ = validate;
+}
+
+}  // namespace s2builderutil
+
+#endif  // S2_S2BUILDERUTIL_S2POLYGON_LAYER_H_
diff --git a/src/s2/s2builderutil_s2polyline_layer.cc b/src/s2/s2builderutil_s2polyline_layer.cc
new file mode 100644 (file)
index 0000000..d74a84f
--- /dev/null
@@ -0,0 +1,105 @@
+// Copyright 2016 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// Author: ericv@google.com (Eric Veach)
+
+#include "s2/s2builderutil_s2polyline_layer.h"
+
+#include "s2/s2debug.h"
+
+using std::vector;
+
+using EdgeType = S2Builder::EdgeType;
+using Graph = S2Builder::Graph;
+using GraphOptions = S2Builder::GraphOptions;
+using Label = S2Builder::Label;
+
+using DegenerateEdges = GraphOptions::DegenerateEdges;
+using DuplicateEdges = GraphOptions::DuplicateEdges;
+using SiblingPairs = GraphOptions::SiblingPairs;
+
+using EdgeId = Graph::EdgeId;
+using PolylineType = Graph::PolylineType;
+
+namespace s2builderutil {
+
+S2PolylineLayer::S2PolylineLayer(S2Polyline* polyline,
+                                 const S2PolylineLayer::Options& options) {
+  Init(polyline, nullptr, nullptr, options);
+}
+
+S2PolylineLayer::S2PolylineLayer(
+    S2Polyline* polyline, LabelSetIds* label_set_ids,
+    IdSetLexicon* label_set_lexicon, const Options& options) {
+  Init(polyline, label_set_ids, label_set_lexicon, options);
+}
+
+void S2PolylineLayer::Init(S2Polyline* polyline, LabelSetIds* label_set_ids,
+                           IdSetLexicon* label_set_lexicon,
+                           const Options& options) {
+  S2_DCHECK_EQ(label_set_ids == nullptr, label_set_lexicon == nullptr);
+  polyline_ = polyline;
+  label_set_ids_ = label_set_ids;
+  label_set_lexicon_ = label_set_lexicon;
+  options_ = options;
+
+  if (options_.validate()) {
+    polyline_->set_s2debug_override(S2Debug::DISABLE);
+  }
+}
+
+GraphOptions S2PolylineLayer::graph_options() const {
+  // Remove edges that collapse to a single vertex, but keep duplicate and
+  // sibling edges, since merging duplicates or discarding siblings can make
+  // it impossible to assemble the edges into a single polyline.
+  return GraphOptions(options_.edge_type(), DegenerateEdges::DISCARD,
+                      DuplicateEdges::KEEP, SiblingPairs::KEEP);
+}
+
+void S2PolylineLayer::Build(const Graph& g, S2Error* error) {
+  if (g.num_edges() == 0) {
+    polyline_->Init(vector<S2Point>{});
+    return;
+  }
+  vector<Graph::EdgePolyline> edge_polylines =
+      g.GetPolylines(PolylineType::WALK);
+  if (edge_polylines.size() != 1) {
+    error->Init(S2Error::BUILDER_EDGES_DO_NOT_FORM_POLYLINE,
+                "Input edges cannot be assembled into polyline");
+    return;
+  }
+  const Graph::EdgePolyline& edge_polyline = edge_polylines[0];
+  vector<S2Point> vertices;  // Temporary storage for vertices.
+  vertices.reserve(edge_polyline.size());
+  vertices.push_back(g.vertex(g.edge(edge_polyline[0]).first));
+  for (EdgeId e : edge_polyline) {
+    vertices.push_back(g.vertex(g.edge(e).second));
+  }
+  if (label_set_ids_) {
+    Graph::LabelFetcher fetcher(g, options_.edge_type());
+    vector<Label> labels;  // Temporary storage for labels.
+    label_set_ids_->reserve(edge_polyline.size());
+    for (EdgeId e : edge_polyline) {
+      fetcher.Fetch(e, &labels);
+      label_set_ids_->push_back(label_set_lexicon_->Add(labels));
+    }
+  }
+  polyline_->Init(vertices);
+  if (options_.validate()) {
+    polyline_->FindValidationError(error);
+  }
+}
+
+}  // namespace s2builderutil
diff --git a/src/s2/s2builderutil_s2polyline_layer.h b/src/s2/s2builderutil_s2polyline_layer.h
new file mode 100644 (file)
index 0000000..c38d280
--- /dev/null
@@ -0,0 +1,174 @@
+// Copyright 2016 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// Author: ericv@google.com (Eric Veach)
+
+#ifndef S2_S2BUILDERUTIL_S2POLYLINE_LAYER_H_
+#define S2_S2BUILDERUTIL_S2POLYLINE_LAYER_H_
+
+#include <memory>
+#include <vector>
+#include "s2/base/logging.h"
+#include "absl/memory/memory.h"
+#include "s2/id_set_lexicon.h"
+#include "s2/mutable_s2shape_index.h"
+#include "s2/s2builder.h"
+#include "s2/s2builder_graph.h"
+#include "s2/s2builder_layer.h"
+#include "s2/s2error.h"
+#include "s2/s2polyline.h"
+
+namespace s2builderutil {
+
+// A layer type that assembles edges (directed or undirected) into an
+// S2Polyline.  Returns an error if the edges cannot be assembled into a
+// single unbroken polyline.
+//
+// Duplicate edges are handled correctly (e.g., if a polyline backtracks on
+// itself, or loops around and retraces some of its previous edges.)  The
+// implementation attempts to preserve the order of directed input edges
+// whenever possible, so that if the input is a polyline and it is not
+// modified by S2Builder, then the output will be the same polyline (even if
+// the polyline backtracks on itself or forms a loop).  With undirected edges,
+// there are no such guarantees; for example, even if the input consists of a
+// single undirected edge, then either directed edge may be returned.
+//
+// S2PolylineLayer does not support options such as discarding sibling pairs
+// or merging duplicate edges because these options can split the polyline
+// into several pieces.  Use S2PolylineVectorLayer if you need these features.
+class S2PolylineLayer : public S2Builder::Layer {
+ public:
+  class Options {
+   public:
+    // Constructor that uses the default options (listed below).
+    Options();
+
+    // Constructor that specifies the edge type.
+    explicit Options(S2Builder::EdgeType edge_type);
+
+    // Indicates whether the input edges provided to S2Builder are directed or
+    // undirected.  Directed edges should be used whenever possible to avoid
+    // ambiguity.
+    //
+    // DEFAULT: S2Builder::EdgeType::DIRECTED
+    S2Builder::EdgeType edge_type() const;
+    void set_edge_type(S2Builder::EdgeType edge_type);
+
+    // If true, calls FindValidationError() on the output polyline.  If any
+    // error is found, it will be returned by S2Builder::Build().
+    //
+    // Note that this option calls set_s2debug_override(S2Debug::DISABLE) in
+    // order to turn off the default error checking in debug builds.
+    //
+    // DEFAULT: false
+    bool validate() const;
+    void set_validate(bool validate);
+
+   private:
+    S2Builder::EdgeType edge_type_;
+    bool validate_;
+  };
+
+  // Specifies that a polyline should be constructed using the given options.
+  explicit S2PolylineLayer(S2Polyline* polyline,
+                           const Options& options = Options());
+
+  // Specifies that a polyline should be constructed using the given options,
+  // and that any labels attached to the input edges should be returned in
+  // "label_set_ids" and "label_set_lexicion".
+  //
+  // The labels associated with the edge "polyline.vertex({j, j+1})" can be
+  // retrieved as follows:
+  //
+  //   for (int32 label : label_set_lexicon.id_set(label_set_ids[j])) {...}
+  using LabelSetIds = std::vector<LabelSetId>;
+  S2PolylineLayer(S2Polyline* polyline, LabelSetIds* label_set_ids,
+                 IdSetLexicon* label_set_lexicon,
+                 const Options& options = Options());
+
+  // Layer interface:
+  GraphOptions graph_options() const override;
+  void Build(const Graph& g, S2Error* error) override;
+
+ private:
+  void Init(S2Polyline* polyline, LabelSetIds* label_set_ids,
+            IdSetLexicon* label_set_lexicon, const Options& options);
+
+  S2Polyline* polyline_;
+  LabelSetIds* label_set_ids_;
+  IdSetLexicon* label_set_lexicon_;
+  Options options_;
+};
+
+// Like S2PolylineLayer, but adds the polyline to a MutableS2ShapeIndex (if the
+// polyline is non-empty).
+class IndexedS2PolylineLayer : public S2Builder::Layer {
+ public:
+  using Options = S2PolylineLayer::Options;
+  explicit IndexedS2PolylineLayer(MutableS2ShapeIndex* index,
+                                 const Options& options = Options())
+      : index_(index), polyline_(new S2Polyline),
+        layer_(polyline_.get(), options) {}
+
+  GraphOptions graph_options() const override {
+    return layer_.graph_options();
+  }
+
+  void Build(const Graph& g, S2Error* error) override {
+    layer_.Build(g, error);
+    if (error->ok() && polyline_->num_vertices() > 0) {
+      index_->Add(
+          absl::make_unique<S2Polyline::OwningShape>(std::move(polyline_)));
+    }
+  }
+
+ private:
+  MutableS2ShapeIndex* index_;
+  std::unique_ptr<S2Polyline> polyline_;
+  S2PolylineLayer layer_;
+};
+
+
+//////////////////   Implementation details follow   ////////////////////
+
+
+inline S2PolylineLayer::Options::Options()
+    : edge_type_(S2Builder::EdgeType::DIRECTED), validate_(false) {
+}
+
+inline S2PolylineLayer::Options::Options(S2Builder::EdgeType edge_type)
+    : edge_type_(edge_type), validate_(false) {
+}
+
+inline S2Builder::EdgeType S2PolylineLayer::Options::edge_type() const {
+  return edge_type_;
+}
+
+inline void S2PolylineLayer::Options::set_edge_type(
+    S2Builder::EdgeType edge_type) {
+  edge_type_ = edge_type;
+}
+
+inline bool S2PolylineLayer::Options::validate() const {
+  return validate_;
+}
+
+inline void S2PolylineLayer::Options::set_validate(bool validate) {
+  validate_ = validate;
+}
+
+}  // namespace s2builderutil
+
+#endif  // S2_S2BUILDERUTIL_S2POLYLINE_LAYER_H_
diff --git a/src/s2/s2builderutil_s2polyline_vector_layer.cc b/src/s2/s2builderutil_s2polyline_vector_layer.cc
new file mode 100644 (file)
index 0000000..adae46a
--- /dev/null
@@ -0,0 +1,98 @@
+// Copyright 2016 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// Author: ericv@google.com (Eric Veach)
+
+#include "s2/s2builderutil_s2polyline_vector_layer.h"
+
+#include <memory>
+
+using std::unique_ptr;
+using std::vector;
+
+using EdgeType = S2Builder::EdgeType;
+using Graph = S2Builder::Graph;
+using GraphOptions = S2Builder::GraphOptions;
+using Label = S2Builder::Label;
+
+using DegenerateEdges = GraphOptions::DegenerateEdges;
+using DuplicateEdges = GraphOptions::DuplicateEdges;
+using SiblingPairs = GraphOptions::SiblingPairs;
+
+using EdgeId = Graph::EdgeId;
+
+namespace s2builderutil {
+
+S2PolylineVectorLayer::S2PolylineVectorLayer(
+    vector<unique_ptr<S2Polyline>>* polylines,
+    const S2PolylineVectorLayer::Options& options) {
+  Init(polylines, nullptr, nullptr, options);
+}
+
+S2PolylineVectorLayer::S2PolylineVectorLayer(
+    vector<unique_ptr<S2Polyline>>* polylines, LabelSetIds* label_set_ids,
+    IdSetLexicon* label_set_lexicon, const Options& options) {
+  Init(polylines, label_set_ids, label_set_lexicon, options);
+}
+
+void S2PolylineVectorLayer::Init(vector<unique_ptr<S2Polyline>>* polylines,
+                                 LabelSetIds* label_set_ids,
+                                 IdSetLexicon* label_set_lexicon,
+                                 const Options& options) {
+  S2_DCHECK_EQ(label_set_ids == nullptr, label_set_lexicon == nullptr);
+  polylines_ = polylines;
+  label_set_ids_ = label_set_ids;
+  label_set_lexicon_ = label_set_lexicon;
+  options_ = options;
+}
+
+GraphOptions S2PolylineVectorLayer::graph_options() const {
+  return GraphOptions(options_.edge_type(), DegenerateEdges::DISCARD,
+                      options_.duplicate_edges(), options_.sibling_pairs());
+}
+
+void S2PolylineVectorLayer::Build(const Graph& g, S2Error* error) {
+  vector<Graph::EdgePolyline> edge_polylines = g.GetPolylines(
+      options_.polyline_type());
+  polylines_->reserve(edge_polylines.size());
+  if (label_set_ids_) label_set_ids_->reserve(edge_polylines.size());
+  vector<S2Point> vertices;  // Temporary storage for vertices.
+  vector<Label> labels;  // Temporary storage for labels.
+  for (const auto& edge_polyline : edge_polylines) {
+    vertices.push_back(g.vertex(g.edge(edge_polyline[0]).first));
+    for (EdgeId e : edge_polyline) {
+      vertices.push_back(g.vertex(g.edge(e).second));
+    }
+    S2Polyline* polyline = new S2Polyline(vertices,
+                                          options_.s2debug_override());
+    vertices.clear();
+    if (options_.validate()) {
+      polyline->FindValidationError(error);
+    }
+    polylines_->emplace_back(polyline);
+    if (label_set_ids_) {
+      Graph::LabelFetcher fetcher(g, options_.edge_type());
+      vector<LabelSetId> polyline_labels;
+      polyline_labels.reserve(edge_polyline.size());
+      for (EdgeId e : edge_polyline) {
+        fetcher.Fetch(e, &labels);
+        polyline_labels.push_back(label_set_lexicon_->Add(labels));
+      }
+      label_set_ids_->push_back(std::move(polyline_labels));
+    }
+  }
+}
+
+}  // namespace s2builderutil
diff --git a/src/s2/s2builderutil_s2polyline_vector_layer.h b/src/s2/s2builderutil_s2polyline_vector_layer.h
new file mode 100644 (file)
index 0000000..ea95106
--- /dev/null
@@ -0,0 +1,292 @@
+// Copyright 2016 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// Author: ericv@google.com (Eric Veach)
+
+#ifndef S2_S2BUILDERUTIL_S2POLYLINE_VECTOR_LAYER_H_
+#define S2_S2BUILDERUTIL_S2POLYLINE_VECTOR_LAYER_H_
+
+#include <memory>
+#include <vector>
+#include "s2/base/logging.h"
+#include "absl/memory/memory.h"
+#include "s2/id_set_lexicon.h"
+#include "s2/mutable_s2shape_index.h"
+#include "s2/s2builder.h"
+#include "s2/s2builder_graph.h"
+#include "s2/s2builder_layer.h"
+#include "s2/s2debug.h"
+#include "s2/s2error.h"
+#include "s2/s2polyline.h"
+
+namespace s2builderutil {
+
+// A layer type that assembles edges (directed or undirected) into multiple
+// S2Polylines.  Returns an error if S2Builder found any problem with the
+// input edges; this layer type does not generate any errors of its own.
+//
+// Duplicate edges are handled correctly (e.g., if a polyline backtracks on
+// itself, or loops around and retraces some of its previous edges.)  The
+// implementation attempts to preserve the order of the input edges whenever
+// possible, so that if the input is a polyline and it is not modified by
+// S2Builder, then the output will be the same polyline even if the polyline
+// forms a loop.  However, note that this is not guaranteed when undirected
+// edges are used: for example, if the input consists of a single undirected
+// edge, then either directed edge may be returned.
+class S2PolylineVectorLayer : public S2Builder::Layer {
+ public:
+  class Options {
+   public:
+    // Constructor that uses the default options (listed below).
+    Options();
+
+    // Constructor that specifies the edge type.
+    explicit Options(S2Builder::EdgeType edge_type);
+
+    // Indicates whether the input edges provided to S2Builder are directed or
+    // undirected.
+    //
+    // Directed edges should be used whenever possible to avoid ambiguity.
+    // The implementation attempts to preserve the structure of directed input
+    // edges whenever possible, so that if the input is a vector of disjoint
+    // polylines and none of them need to be modified then the output will be
+    // the same polylines in the same order.  With undirected edges, there are
+    // no such guarantees.
+    //
+    // DEFAULT: S2Builder::EdgeType::DIRECTED
+    S2Builder::EdgeType edge_type() const;
+    void set_edge_type(S2Builder::EdgeType edge_type);
+
+    // Indicates whether polylines should be "paths" (which don't allow
+    // duplicate vertices, except possibly the first and last vertex) or
+    // "walks" (which allow duplicate vertices and edges).
+    //
+    // If your input consists of polylines, and you want to split them into
+    // separate pieces whenever they self-intersect or cross each other, then
+    // use PolylineType::PATH (and probably use split_crossing_edges()).  If
+    // you don't mind if your polylines backtrack or contain loops, then use
+    // PolylineType::WALK.
+    //
+    // DEFAULT: PolylineType::PATH
+    using PolylineType = S2Builder::Graph::PolylineType;
+    PolylineType polyline_type() const;
+    void set_polyline_type(PolylineType polyline_type);
+
+    // Indicates whether duplicate edges in the input should be kept (KEEP) or
+    // merged together (MERGE).  Note you can use edge labels to determine
+    // which input edges were merged into a given output edge.
+    //
+    // DEFAULT: DuplicateEdges::KEEP
+    using DuplicateEdges = GraphOptions::DuplicateEdges;
+    DuplicateEdges duplicate_edges() const;
+    void set_duplicate_edges(DuplicateEdges duplicate_edges);
+
+    // Indicates whether sibling edge pairs (i.e., pairs consisting of an edge
+    // and its reverse edge) should be kept (KEEP) or discarded (DISCARD).
+    // For example, if a polyline backtracks on itself, the DISCARD option
+    // would cause this section of the polyline to be removed.  Note that this
+    // option may cause a single polyline to split into several pieces (e.g.,
+    // if a polyline has a "lollipop" shape).
+    //
+    // REQUIRES: sibling_pairs == { DISCARD, KEEP }
+    //           (the CREATE and REQUIRE options are not allowed)
+    //
+    // DEFAULT: SiblingPairs::KEEP
+    using SiblingPairs = GraphOptions::SiblingPairs;
+    SiblingPairs sibling_pairs() const;
+    void set_sibling_pairs(SiblingPairs sibling_pairs);
+
+    // If true, calls FindValidationError() on each output polyline.  If any
+    // error is found, it will be returned by S2Builder::Build().
+    //
+    // Note that this option calls set_s2debug_override(S2Debug::DISABLE) in
+    // order to turn off the default error checking in debug builds.
+    //
+    // DEFAULT: false
+    bool validate() const;
+    void set_validate(bool validate);
+
+    // This method can turn off the automatic validity checks triggered by the
+    // --s2debug flag (which is on by default in debug builds).  The main
+    // reason to do this is if your code already does its own error checking,
+    // or if you need to work with invalid geometry for some reason.
+    //
+    // In any case, polylines have very few restrictions so they are unlikely
+    // to have errors.  Errors include vertices that aren't unit length (which
+    // can only happen if they are present in the input data), or adjacent
+    // vertices that are at antipodal points on the sphere (unlikely with real
+    // data).  The other possible error is adjacent identical vertices, but
+    // this can't happen because S2Builder does not generate such polylines.
+    //
+    // DEFAULT: S2Debug::ALLOW
+    S2Debug s2debug_override() const;
+    void set_s2debug_override(S2Debug override);
+
+   private:
+    S2Builder::EdgeType edge_type_;
+    PolylineType polyline_type_;
+    DuplicateEdges duplicate_edges_;
+    SiblingPairs sibling_pairs_;
+    bool validate_;
+    S2Debug s2debug_override_;
+  };
+
+  // Specifies that a vector of polylines should be constructed using the
+  // given options.
+  explicit S2PolylineVectorLayer(
+      std::vector<std::unique_ptr<S2Polyline>>* polylines,
+      const Options& options = Options());
+
+  // Specifies that a vector of polylines should be constructed using the
+  // given options, and that any labels attached to the input edges should be
+  // returned in "label_set_ids" and "label_set_lexicion".
+  //
+  // The labels associated with the edge "polyline[i].vertex({j, j+1})" can be
+  // retrieved as follows:
+  //
+  //   for (int32 label : label_set_lexicon.id_set(label_set_ids[i][j])) {...}
+  using LabelSetIds = std::vector<std::vector<LabelSetId>>;
+  S2PolylineVectorLayer(std::vector<std::unique_ptr<S2Polyline>>* polylines,
+                        LabelSetIds* label_set_ids,
+                        IdSetLexicon* label_set_lexicon,
+                        const Options& options = Options());
+
+  // Layer interface:
+  GraphOptions graph_options() const override;
+  void Build(const Graph& g, S2Error* error) override;
+
+ private:
+  void Init(std::vector<std::unique_ptr<S2Polyline>>* polylines,
+            LabelSetIds* label_set_ids, IdSetLexicon* label_set_lexicon,
+            const Options& options);
+
+  std::vector<std::unique_ptr<S2Polyline>>* polylines_;
+  LabelSetIds* label_set_ids_;
+  IdSetLexicon* label_set_lexicon_;
+  Options options_;
+};
+
+// Like S2PolylineVectorLayer, but adds the polylines to a MutableS2ShapeIndex.
+class IndexedS2PolylineVectorLayer : public S2Builder::Layer {
+ public:
+  using Options = S2PolylineVectorLayer::Options;
+  explicit IndexedS2PolylineVectorLayer(MutableS2ShapeIndex* index,
+                                        const Options& options = Options())
+      : index_(index), layer_(&polylines_, options) {}
+
+  GraphOptions graph_options() const override {
+    return layer_.graph_options();
+  }
+
+  void Build(const Graph& g, S2Error* error) override {
+    layer_.Build(g, error);
+    if (error->ok()) {
+      for (auto& polyline : polylines_) {
+        index_->Add(
+            absl::make_unique<S2Polyline::OwningShape>(std::move(polyline)));
+      }
+    }
+  }
+
+ private:
+  MutableS2ShapeIndex* index_;
+  std::vector<std::unique_ptr<S2Polyline>> polylines_;
+  S2PolylineVectorLayer layer_;
+};
+
+
+//////////////////   Implementation details follow   ////////////////////
+
+
+inline S2PolylineVectorLayer::Options::Options()
+    : edge_type_(S2Builder::EdgeType::DIRECTED),
+      polyline_type_(PolylineType::PATH),
+      duplicate_edges_(DuplicateEdges::KEEP),
+      sibling_pairs_(SiblingPairs::KEEP),
+      validate_(false),
+      s2debug_override_(S2Debug::ALLOW) {
+}
+
+inline S2PolylineVectorLayer::Options::Options(S2Builder::EdgeType edge_type)
+    : edge_type_(edge_type),
+      polyline_type_(PolylineType::PATH),
+      duplicate_edges_(DuplicateEdges::KEEP),
+      sibling_pairs_(SiblingPairs::KEEP),
+      validate_(false),
+      s2debug_override_(S2Debug::ALLOW) {
+}
+
+inline S2Builder::EdgeType S2PolylineVectorLayer::Options::edge_type() const {
+  return edge_type_;
+}
+
+inline void S2PolylineVectorLayer::Options::set_edge_type(
+    S2Builder::EdgeType edge_type) {
+  edge_type_ = edge_type;
+}
+
+inline S2PolylineVectorLayer::Options::PolylineType
+S2PolylineVectorLayer::Options::polyline_type() const {
+  return polyline_type_;
+}
+
+inline void S2PolylineVectorLayer::Options::set_polyline_type(
+    PolylineType polyline_type) {
+  polyline_type_ = polyline_type;
+}
+
+inline S2PolylineVectorLayer::Options::DuplicateEdges
+S2PolylineVectorLayer::Options::duplicate_edges() const {
+  return duplicate_edges_;
+}
+
+inline void S2PolylineVectorLayer::Options::set_duplicate_edges(
+    DuplicateEdges duplicate_edges) {
+  duplicate_edges_ = duplicate_edges;
+}
+
+inline S2PolylineVectorLayer::Options::SiblingPairs
+S2PolylineVectorLayer::Options::sibling_pairs() const {
+  return sibling_pairs_;
+}
+
+inline void S2PolylineVectorLayer::Options::set_sibling_pairs(
+    SiblingPairs sibling_pairs) {
+  S2_DCHECK(sibling_pairs == SiblingPairs::KEEP ||
+         sibling_pairs == SiblingPairs::DISCARD);
+  sibling_pairs_ = sibling_pairs;
+}
+
+inline bool S2PolylineVectorLayer::Options::validate() const {
+  return validate_;
+}
+
+inline void S2PolylineVectorLayer::Options::set_validate(bool validate) {
+  validate_ = validate;
+  set_s2debug_override(S2Debug::DISABLE);
+}
+
+inline S2Debug S2PolylineVectorLayer::Options::s2debug_override() const {
+  return s2debug_override_;
+}
+
+inline void S2PolylineVectorLayer::Options::set_s2debug_override(
+    S2Debug s2debug_override) {
+  s2debug_override_ = s2debug_override;
+}
+
+}  // namespace s2builderutil
+
+#endif  // S2_S2BUILDERUTIL_S2POLYLINE_VECTOR_LAYER_H_
diff --git a/src/s2/s2builderutil_snap_functions.cc b/src/s2/s2builderutil_snap_functions.cc
new file mode 100644 (file)
index 0000000..55fe61d
--- /dev/null
@@ -0,0 +1,354 @@
+// Copyright 2016 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// Author: ericv@google.com (Eric Veach)
+
+#include "s2/s2builderutil_snap_functions.h"
+
+#include <algorithm>
+#include <cfloat>
+#include <cmath>
+#include <memory>
+#include "s2/base/integral_types.h"
+#include "s2/base/logging.h"
+#include "absl/memory/memory.h"
+#include "s2/s2cell_id.h"
+#include "s2/s2latlng.h"
+#include "s2/s2metrics.h"
+
+using absl::make_unique;
+using std::max;
+using std::min;
+using std::unique_ptr;
+
+namespace s2builderutil {
+
+const int IntLatLngSnapFunction::kMinExponent;
+const int IntLatLngSnapFunction::kMaxExponent;
+
+IdentitySnapFunction::IdentitySnapFunction()
+    : snap_radius_(S1Angle::Zero()) {
+}
+
+IdentitySnapFunction::IdentitySnapFunction(S1Angle snap_radius) {
+  set_snap_radius(snap_radius);
+}
+
+void IdentitySnapFunction::set_snap_radius(S1Angle snap_radius) {
+  S2_DCHECK_LE(snap_radius, kMaxSnapRadius());
+  snap_radius_ = snap_radius;
+}
+
+S1Angle IdentitySnapFunction::snap_radius() const {
+  return snap_radius_;
+}
+
+S1Angle IdentitySnapFunction::min_vertex_separation() const {
+  // Since SnapFunction does not move the input point, output vertices are
+  // separated by the full snap_radius().
+  return snap_radius_;
+}
+
+S1Angle IdentitySnapFunction::min_edge_vertex_separation() const {
+  // In the worst case configuration, the edge separation is half of the
+  // vertex separation.
+  return 0.5 * snap_radius_;
+}
+
+S2Point IdentitySnapFunction::SnapPoint(const S2Point& point) const {
+  return point;
+}
+
+unique_ptr<S2Builder::SnapFunction> IdentitySnapFunction::Clone() const {
+  return make_unique<IdentitySnapFunction>(*this);
+}
+
+
+S2CellIdSnapFunction::S2CellIdSnapFunction() {
+  set_level(S2CellId::kMaxLevel);
+}
+
+S2CellIdSnapFunction::S2CellIdSnapFunction(int level) {
+  set_level(level);
+}
+
+void S2CellIdSnapFunction::set_level(int level) {
+  S2_DCHECK_GE(level, 0);
+  S2_DCHECK_LE(level, S2CellId::kMaxLevel);
+  level_ = level;
+  set_snap_radius(MinSnapRadiusForLevel(level));
+}
+
+int S2CellIdSnapFunction::level() const {
+  return level_;
+}
+
+void S2CellIdSnapFunction::set_snap_radius(S1Angle snap_radius) {
+  S2_DCHECK_GE(snap_radius, MinSnapRadiusForLevel(level()));
+  S2_DCHECK_LE(snap_radius, kMaxSnapRadius());
+  snap_radius_ = snap_radius;
+}
+
+S1Angle S2CellIdSnapFunction::snap_radius() const {
+  return snap_radius_;
+}
+
+S1Angle S2CellIdSnapFunction::MinSnapRadiusForLevel(int level) {
+  // snap_radius() needs to be an upper bound on the true distance that a
+  // point can move when snapped, taking into account numerical errors.
+  //
+  // The maximum error when converting from an S2Point to an S2CellId is
+  // S2::kMaxDiag.deriv() * DBL_EPSILON.  The maximum error when converting an
+  // S2CellId center back to an S2Point is 1.5 * DBL_EPSILON.  These add up to
+  // just slightly less than 4 * DBL_EPSILON.
+  return S1Angle::Radians(0.5 * S2::kMaxDiag.GetValue(level) + 4 * DBL_EPSILON);
+}
+
+int S2CellIdSnapFunction::LevelForMaxSnapRadius(S1Angle snap_radius) {
+  // When choosing a level, we need to acount for the error bound of
+  // 4 * DBL_EPSILON that is added by MinSnapRadiusForLevel().
+  return S2::kMaxDiag.GetLevelForMaxValue(
+      2 * (snap_radius.radians() - 4 * DBL_EPSILON));
+}
+
+S1Angle S2CellIdSnapFunction::min_vertex_separation() const {
+  // We have three different bounds for the minimum vertex separation: one is
+  // a constant bound, one is proportional to snap_radius, and one is equal to
+  // snap_radius minus a constant.  These bounds give the best results for
+  // small, medium, and large snap radii respectively.  We return the maximum
+  // of the three bounds.
+  //
+  // 1. Constant bound: Vertices are always separated by at least
+  //    kMinEdge(level), the minimum edge length for the chosen snap level.
+  //
+  // 2. Proportional bound: It can be shown that in the plane, the worst-case
+  //    configuration has a vertex separation of 2 / sqrt(13) * snap_radius.
+  //    This is verified in the unit test, except that on the sphere the ratio
+  //    is slightly smaller at cell level 2 (0.54849 vs. 0.55470).  We reduce
+  //    that value a bit more below to be conservative.
+  //
+  // 3. Best asymptotic bound: This bound bound is derived by observing we
+  //    only select a new site when it is at least snap_radius() away from all
+  //    existing sites, and the site can move by at most 0.5 * kMaxDiag(level)
+  //    when snapped.
+  S1Angle min_edge = S1Angle::Radians(S2::kMinEdge.GetValue(level_));
+  S1Angle max_diag = S1Angle::Radians(S2::kMaxDiag.GetValue(level_));
+  return max(min_edge,
+             max(0.548 * snap_radius_,  // 2 / sqrt(13) in the plane
+                 snap_radius_ - 0.5 * max_diag));
+}
+
+S1Angle S2CellIdSnapFunction::min_edge_vertex_separation() const {
+  // Similar to min_vertex_separation(), in this case we have four bounds: a
+  // constant bound that holds only at the minimum snap radius, a constant
+  // bound that holds for any snap radius, a bound that is proportional to
+  // snap_radius, and a bound that is equal to snap_radius minus a constant.
+  //
+  // 1. Constant bounds:
+  //
+  //    (a) At the minimum snap radius for a given level, it can be shown that
+  //    vertices are separated from edges by at least 0.5 * kMinDiag(level) in
+  //    the plane.  The unit test verifies this, except that on the sphere the
+  //    worst case is slightly better: 0.5652980068 * kMinDiag(level).
+  //
+  //    (b) Otherwise, for arbitrary snap radii the worst-case configuration
+  //    in the plane has an edge-vertex separation of sqrt(3/19) *
+  //    kMinDiag(level), where sqrt(3/19) is about 0.3973597071.  The unit
+  //    test verifies that the bound is slighty better on the sphere:
+  //    0.3973595687 * kMinDiag(level).
+  //
+  // 2. Proportional bound: In the plane, the worst-case configuration has an
+  //    edge-vertex separation of 2 * sqrt(3/247) * snap_radius, which is
+  //    about 0.2204155075.  The unit test verifies this, except that on the
+  //    sphere the bound is slightly worse for certain large S2Cells: the
+  //    minimum ratio occurs at cell level 6, and is about 0.2196666953.
+  //
+  // 3. Best asymptotic bound: If snap_radius() is large compared to the
+  //    minimum snap radius, then the best bound is achieved by 3 sites on a
+  //    circular arc of radius "snap_radius", spaced "min_vertex_separation"
+  //    apart.  An input edge passing just to one side of the center of the
+  //    circle intersects the Voronoi regions of the two end sites but not the
+  //    Voronoi region of the center site, and gives an edge separation of
+  //    (min_vertex_separation ** 2) / (2 * snap_radius).  This bound
+  //    approaches 0.5 * snap_radius for large snap radii, i.e.  the minimum
+  //    edge-vertex separation approaches half of the minimum vertex
+  //    separation as the snap radius becomes large compared to the cell size.
+
+  S1Angle min_diag = S1Angle::Radians(S2::kMinDiag.GetValue(level_));
+  if (snap_radius() == MinSnapRadiusForLevel(level_)) {
+    // This bound only holds when the minimum snap radius is being used.
+    return 0.565 * min_diag;            // 0.500 in the plane
+  }
+  // Otherwise, these bounds hold for any snap_radius().
+  S1Angle vertex_sep = min_vertex_separation();
+  return max(0.397 * min_diag,          // sqrt(3 / 19) in the plane
+             max(0.219 * snap_radius_,  // 2 * sqrt(3 / 247) in the plane
+                 0.5 * (vertex_sep / snap_radius_) * vertex_sep));
+}
+
+S2Point S2CellIdSnapFunction::SnapPoint(const S2Point& point) const {
+  return S2CellId(point).parent(level_).ToPoint();
+}
+
+unique_ptr<S2Builder::SnapFunction> S2CellIdSnapFunction::Clone() const {
+  return make_unique<S2CellIdSnapFunction>(*this);
+}
+
+IntLatLngSnapFunction::IntLatLngSnapFunction()
+    : exponent_(-1), snap_radius_(), from_degrees_(0), to_degrees_(0) {
+}
+
+IntLatLngSnapFunction::IntLatLngSnapFunction(int exponent) {
+  set_exponent(exponent);
+}
+
+void IntLatLngSnapFunction::set_exponent(int exponent) {
+  S2_DCHECK_GE(exponent, kMinExponent);
+  S2_DCHECK_LE(exponent, kMaxExponent);
+  exponent_ = exponent;
+  set_snap_radius(MinSnapRadiusForExponent(exponent));
+
+  // Precompute the scale factors needed for snapping.  Note that these
+  // calculations need to exactly match the ones in s1angle.h to ensure
+  // that the same S2Points are generated.
+  double power = 1;
+  for (int i = 0; i < exponent; ++i) power *= 10;
+  from_degrees_ = power;
+  to_degrees_ = 1 / power;
+}
+
+int IntLatLngSnapFunction::exponent() const {
+  return exponent_;
+}
+
+void IntLatLngSnapFunction::set_snap_radius(S1Angle snap_radius) {
+  S2_DCHECK_GE(snap_radius, MinSnapRadiusForExponent(exponent()));
+  S2_DCHECK_LE(snap_radius, kMaxSnapRadius());
+  snap_radius_ = snap_radius;
+}
+
+S1Angle IntLatLngSnapFunction::snap_radius() const {
+  return snap_radius_;
+}
+
+S1Angle IntLatLngSnapFunction::MinSnapRadiusForExponent(int exponent) {
+  // snap_radius() needs to be an upper bound on the true distance that a
+  // point can move when snapped, taking into account numerical errors.
+  //
+  // The maximum errors in latitude and longitude can be bounded as
+  // follows (as absolute errors in terms of DBL_EPSILON):
+  //
+  //                                      Latitude      Longitude
+  // Convert to S2LatLng:                    1.000          1.000
+  // Convert to degrees:                     1.032          2.063
+  // Scale by 10**exp:                       0.786          1.571
+  // Round to integer: 0.5 * S1Angle::Degrees(to_degrees_)
+  // Scale by 10**(-exp):                    1.375          2.749
+  // Convert to radians:                     1.252          1.503
+  // ------------------------------------------------------------
+  // Total (except for rounding)             5.445          8.886
+  //
+  // The maximum error when converting the S2LatLng back to an S2Point is
+  //
+  //   sqrt(2) * (maximum error in latitude or longitude) + 1.5 * DBL_EPSILON
+  //
+  // which works out to (9 * sqrt(2) + 1.5) * DBL_EPSILON radians.  Finally
+  // we need to consider the effect of rounding to integer coordinates
+  // (much larger than the errors above), which can change the position by
+  // up to (sqrt(2) * 0.5 * to_degrees_) radians.
+  double power = 1;
+  for (int i = 0; i < exponent; ++i) power *= 10;
+  return (S1Angle::Degrees(M_SQRT1_2 / power) +
+          S1Angle::Radians((9 * M_SQRT2 + 1.5) * DBL_EPSILON));
+}
+
+int IntLatLngSnapFunction::ExponentForMaxSnapRadius(S1Angle snap_radius) {
+  // When choosing an exponent, we need to acount for the error bound of
+  // (9 * sqrt(2) + 1.5) * DBL_EPSILON added by MinSnapRadiusForExponent().
+  snap_radius -= S1Angle::Radians((9 * M_SQRT2 + 1.5) * DBL_EPSILON);
+  snap_radius = max(snap_radius, S1Angle::Radians(1e-30));
+  double exponent = log10(M_SQRT1_2 / snap_radius.degrees());
+
+  // There can be small errors in the calculation above, so to ensure that
+  // this function is the inverse of MinSnapRadiusForExponent() we subtract a
+  // small error tolerance.
+  return max(kMinExponent,
+             min(kMaxExponent,
+                 static_cast<int>(std::ceil(exponent - 2 * DBL_EPSILON))));
+}
+
+S1Angle IntLatLngSnapFunction::min_vertex_separation() const {
+  // We have two bounds for the minimum vertex separation: one is proportional
+  // to snap_radius, and one is equal to snap_radius minus a constant.  These
+  // bounds give the best results for small and large snap radii respectively.
+  // We return the maximum of the two bounds.
+  //
+  // 1. Proportional bound: It can be shown that in the plane, the worst-case
+  //    configuration has a vertex separation of (sqrt(2) / 3) * snap_radius.
+  //    This is verified in the unit test, except that on the sphere the ratio
+  //    is slightly smaller (0.471337 vs. 0.471404).  We reduce that value a
+  //    bit more below to be conservative.
+  //
+  // 2. Best asymptotic bound: This bound bound is derived by observing we
+  //    only select a new site when it is at least snap_radius() away from all
+  //    existing sites, and snapping a vertex can move it by up to
+  //    ((1 / sqrt(2)) * to_degrees_) degrees.
+  return max(0.471 * snap_radius_,        // sqrt(2) / 3 in the plane
+             snap_radius_ - S1Angle::Degrees(M_SQRT1_2 * to_degrees_));
+}
+
+S1Angle IntLatLngSnapFunction::min_edge_vertex_separation() const {
+  // Similar to min_vertex_separation(), in this case we have three bounds:
+  // one is a constant bound, one is proportional to snap_radius, and one is
+  // equal to snap_radius minus a constant.
+  //
+  // 1. Constant bound: In the plane, the worst-case configuration has an
+  //    edge-vertex separation of ((1 / sqrt(13)) * to_degrees_) degrees.
+  //    The unit test verifies this, except that on the sphere the ratio is
+  //    slightly lower when small exponents such as E1 are used
+  //    (0.2772589 vs 0.2773501).
+  //
+  // 2. Proportional bound: In the plane, the worst-case configuration has an
+  //    edge-vertex separation of (2 / 9) * snap_radius (0.222222222222).  The
+  //    unit test verifies this, except that on the sphere the bound can be
+  //    slightly worse with large exponents (e.g., E9) due to small numerical
+  //    errors (0.222222126756717).
+  //
+  // 3. Best asymptotic bound: If snap_radius() is large compared to the
+  //    minimum snap radius, then the best bound is achieved by 3 sites on a
+  //    circular arc of radius "snap_radius", spaced "min_vertex_separation"
+  //    apart (see S2CellIdSnapFunction::min_edge_vertex_separation).  This
+  //    bound approaches 0.5 * snap_radius as the snap radius becomes large
+  //    relative to the grid spacing.
+
+  S1Angle vertex_sep = min_vertex_separation();
+  return max(0.277 * S1Angle::Degrees(to_degrees_),  // 1/sqrt(13) in the plane
+             max(0.222 * snap_radius_,               // 2/9 in the plane
+                 0.5 * (vertex_sep / snap_radius_) * vertex_sep));
+}
+
+S2Point IntLatLngSnapFunction::SnapPoint(const S2Point& point) const {
+  S2_DCHECK_GE(exponent_, 0);  // Make sure the snap function was initialized.
+  S2LatLng input(point);
+  int64 lat = MathUtil::FastInt64Round(input.lat().degrees() * from_degrees_);
+  int64 lng = MathUtil::FastInt64Round(input.lng().degrees() * from_degrees_);
+  return S2LatLng::FromDegrees(lat * to_degrees_, lng * to_degrees_).ToPoint();
+}
+
+unique_ptr<S2Builder::SnapFunction> IntLatLngSnapFunction::Clone() const {
+  return make_unique<IntLatLngSnapFunction>(*this);
+}
+
+}  // namespace s2builderutil
diff --git a/src/s2/s2builderutil_snap_functions.h b/src/s2/s2builderutil_snap_functions.h
new file mode 100644 (file)
index 0000000..29a99a0
--- /dev/null
@@ -0,0 +1,239 @@
+// Copyright 2016 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// Author: ericv@google.com (Eric Veach)
+
+#ifndef S2_S2BUILDERUTIL_SNAP_FUNCTIONS_H_
+#define S2_S2BUILDERUTIL_SNAP_FUNCTIONS_H_
+
+#include <memory>
+#include "s2/s1angle.h"
+#include "s2/s2builder.h"
+#include "s2/s2cell_id.h"
+
+namespace s2builderutil {
+
+// A SnapFunction that snaps every vertex to itself.  It should be used when
+// vertices do not need to be snapped to a discrete set of locations (such as
+// E7 lat/lngs), or when maximum accuracy is desired.
+//
+// If the given "snap_radius" is zero, then all input vertices are preserved
+// exactly.  Otherwise, S2Builder merges nearby vertices to ensure that no
+// vertex pair is closer than "snap_radius".  Furthermore, vertices are
+// separated from non-incident edges by at least "min_edge_vertex_separation",
+// equal to (0.5 * snap_radius).  For example, if the snap_radius is 1km, then
+// vertices will be separated from non-incident edges by at least 500m.
+class IdentitySnapFunction : public S2Builder::SnapFunction {
+ public:
+  // The default constructor uses a snap_radius of zero (i.e., no snapping).
+  IdentitySnapFunction();
+
+  // Convenience constructor that calls set_snap_radius().
+  explicit IdentitySnapFunction(S1Angle snap_radius);
+
+  // REQUIRES: snap_radius <= SnapFunction::kMaxSnapRadius()
+  void set_snap_radius(S1Angle snap_radius);
+  S1Angle snap_radius() const override;
+
+  // For the identity snap function, all vertex pairs are separated by at
+  // least snap_radius().
+  S1Angle min_vertex_separation() const override;
+
+  // For the identity snap function, edges are separated from all non-incident
+  // vertices by at least 0.5 * snap_radius().
+  S1Angle min_edge_vertex_separation() const override;
+
+  S2Point SnapPoint(const S2Point& point) const override;
+
+  std::unique_ptr<SnapFunction> Clone() const override;
+
+ private:
+  // Copying and assignment are allowed.
+  S1Angle snap_radius_;
+};
+
+// A SnapFunction that snaps vertices to S2CellId centers.  This can be useful
+// if you want to encode your geometry compactly using S2Polygon::Encode(),
+// for example.  You can snap to the centers of cells at any level.
+//
+// Every snap level has a corresponding minimum snap radius, which is simply
+// the maximum distance that a vertex can move when snapped.  It is
+// approximately equal to half of the maximum diagonal length for cells at the
+// chosen level.  You can also set the snap radius to a larger value; for
+// example, you could snap to the centers of leaf cells (1cm resolution) but
+// set the snap_radius() to 10m.  This would result in significant extra
+// simplification, without moving vertices unnecessarily (i.e., vertices that
+// are at least 10m away from all other vertices will move by less than 1cm).
+class S2CellIdSnapFunction : public S2Builder::SnapFunction {
+ public:
+  // The default constructor snaps to S2CellId::kMaxLevel (i.e., the centers
+  // of leaf cells), and uses the minimum allowable snap radius at that level.
+  S2CellIdSnapFunction();
+
+  // Convenience constructor equivalent to calling set_level(level).
+  explicit S2CellIdSnapFunction(int level);
+
+  // Snaps vertices to S2Cell centers at the given level.  As a side effect,
+  // this method also resets "snap_radius" to the minimum value allowed at
+  // this level:
+  //
+  //   set_snap_radius(MinSnapRadiusForLevel(level))
+  //
+  // This means that if you want to use a larger snap radius than the minimum,
+  // you must call set_snap_radius() *after* calling set_level().
+  void set_level(int level);
+  int level() const;
+
+  // Defines the snap radius to be used (see s2builder.h).  The snap radius
+  // must be at least the minimum value for the current level(), but larger
+  // values can also be used (e.g., to simplify the geometry).
+  //
+  // REQUIRES: snap_radius >= MinSnapRadiusForLevel(level())
+  // REQUIRES: snap_radius <= SnapFunction::kMaxSnapRadius()
+  void set_snap_radius(S1Angle snap_radius);
+  S1Angle snap_radius() const override;
+
+  // Returns the minimum allowable snap radius for the given S2Cell level
+  // (approximately equal to half of the maximum cell diagonal length).
+  static S1Angle MinSnapRadiusForLevel(int level);
+
+  // Returns the minimum S2Cell level (i.e., largest S2Cells) such that
+  // vertices will not move by more than "snap_radius".  This can be useful
+  // when choosing an appropriate level to snap to.  The return value is
+  // always a valid level (out of range values are silently clamped).
+  //
+  // If you want to choose the snap level based on a distance, and then use
+  // the minimum possible snap radius for the chosen level, do this:
+  //
+  //   S2CellIdSnapFunction f(
+  //       S2CellIdSnapFunction::LevelForMaxSnapRadius(distance));
+  static int LevelForMaxSnapRadius(S1Angle snap_radius);
+
+  // For S2CellId snapping, the minimum separation between vertices depends on
+  // level() and snap_radius().  It can vary between 0.5 * snap_radius()
+  // and snap_radius().
+  S1Angle min_vertex_separation() const override;
+
+  // For S2CellId snapping, the minimum separation between edges and
+  // non-incident vertices depends on level() and snap_radius().  It can
+  // be as low as 0.219 * snap_radius(), but is typically 0.5 * snap_radius()
+  // or more.
+  S1Angle min_edge_vertex_separation() const override;
+
+  S2Point SnapPoint(const S2Point& point) const override;
+
+  std::unique_ptr<SnapFunction> Clone() const override;
+
+ private:
+  // Copying and assignment are allowed.
+  int level_;
+  S1Angle snap_radius_;
+};
+
+// A SnapFunction that snaps vertices to S2LatLng E5, E6, or E7 coordinates.
+// These coordinates are expressed in degrees multiplied by a power of 10 and
+// then rounded to the nearest integer.  For example, in E6 coordinates the
+// point (23.12345651, -45.65432149) would become (23123457, -45654321).
+//
+// The main argument of the SnapFunction is the exponent for the power of 10
+// that coordinates should be multipled by before rounding.  For example,
+// IntLatLngSnapFunction(7) is a function that snaps to E7 coordinates.  The
+// exponent can range from 0 to 10.
+//
+// Each exponent has a corresponding minimum snap radius, which is simply the
+// maximum distance that a vertex can move when snapped.  It is approximately
+// equal to 1/sqrt(2) times the nominal point spacing; for example, for
+// snapping to E7 the minimum snap radius is (1e-7 / sqrt(2)) degrees.
+// You can also set the snap radius to any value larger than this; this can
+// result in significant extra simplification (similar to using a larger
+// exponent) but does not move vertices unnecessarily.
+class IntLatLngSnapFunction : public S2Builder::SnapFunction {
+ public:
+  // The default constructor yields an invalid snap function.  You must set
+  // the exponent explicitly before using it.
+  IntLatLngSnapFunction();
+
+  // Convenience constructor equivalent to calling set_exponent(exponent).
+  explicit IntLatLngSnapFunction(int exponent);
+
+  // Snaps vertices to points whose (lat, lng) coordinates are integers after
+  // converting to degrees and multiplying by 10 raised to the given exponent.
+  // For example, (exponent == 7) yields E7 coordinates.  As a side effect,
+  // this method also resets "snap_radius" to the minimum value allowed for
+  // this exponent:
+  //
+  //   set_snap_radius(MinSnapRadiusForExponent(exponent))
+  //
+  // This means that if you want to use a larger snap radius than the minimum,
+  // you must call set_snap_radius() *after* calling set_exponent().
+  //
+  // REQUIRES: kMinExponent <= exponent <= kMaxExponent
+  void set_exponent(int exponent);
+  int exponent() const;
+
+  // The minum exponent supported for snapping.
+  static const int kMinExponent = 0;
+
+  // The maximum exponent supported for snapping.
+  static const int kMaxExponent = 10;
+
+  // Defines the snap radius to be used (see s2builder.h).  The snap radius
+  // must be at least the minimum value for the current exponent(), but larger
+  // values can also be used (e.g., to simplify the geometry).
+  //
+  // REQUIRES: snap_radius >= MinSnapRadiusForExponent(exponent())
+  // REQUIRES: snap_radius <= SnapFunction::kMaxSnapRadius()
+  void set_snap_radius(S1Angle snap_radius);
+  S1Angle snap_radius() const override;
+
+  // Returns the minimum allowable snap radius for the given exponent
+  // (approximately equal to (pow(10, -exponent) / sqrt(2)) degrees).
+  static S1Angle MinSnapRadiusForExponent(int exponent);
+
+  // Returns the minimum exponent such that vertices will not move by more
+  // than "snap_radius".  This can be useful when choosing an appropriate
+  // exponent for snapping.  The return value is always a valid exponent
+  // (out of range values are silently clamped).
+  //
+  // If you want to choose the exponent based on a distance, and then use
+  // the minimum possible snap radius for that exponent, do this:
+  //
+  //   IntLatLngSnapFunction f(
+  //       IntLatLngSnapFunction::ExponentForMaxSnapRadius(distance));
+  static int ExponentForMaxSnapRadius(S1Angle snap_radius);
+
+  // For IntLatLng snapping, the minimum separation between vertices depends on
+  // exponent() and snap_radius().  It can vary between snap_radius()
+  // and snap_radius().
+  S1Angle min_vertex_separation() const override;
+
+  // For IntLatLng snapping, the minimum separation between edges and
+  // non-incident vertices depends on level() and snap_radius().  It can
+  // be as low as 0.222 * snap_radius(), but is typically 0.39 * snap_radius()
+  // or more.
+  S1Angle min_edge_vertex_separation() const override;
+  S2Point SnapPoint(const S2Point& point) const override;
+  std::unique_ptr<SnapFunction> Clone() const override;
+
+ private:
+  // Copying and assignment are allowed.
+  int exponent_;
+  S1Angle snap_radius_;
+  double from_degrees_, to_degrees_;
+};
+
+}  // namespace s2builderutil
+
+#endif  // S2_S2BUILDERUTIL_SNAP_FUNCTIONS_H_
diff --git a/src/s2/s2builderutil_testing.cc b/src/s2/s2builderutil_testing.cc
new file mode 100644 (file)
index 0000000..2c28396
--- /dev/null
@@ -0,0 +1,37 @@
+// Copyright 2017 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// Author: ericv@google.com (Eric Veach)
+
+#include "s2/s2builderutil_testing.h"
+
+namespace s2builderutil {
+
+void GraphClone::Init(const S2Builder::Graph& g) {
+  options_ = g.options();
+  vertices_ = g.vertices();
+  edges_ = g.edges();
+  input_edge_id_set_ids_ = g.input_edge_id_set_ids();
+  input_edge_id_set_lexicon_ = g.input_edge_id_set_lexicon();
+  label_set_ids_ = g.label_set_ids();
+  label_set_lexicon_ = g.label_set_lexicon();
+  is_full_polygon_predicate_ = g.is_full_polygon_predicate();
+  g_ = S2Builder::Graph(
+      options_, &vertices_, &edges_, &input_edge_id_set_ids_,
+      &input_edge_id_set_lexicon_, &label_set_ids_, &label_set_lexicon_,
+      is_full_polygon_predicate_);
+}
+
+}  // namespace s2builderutil
diff --git a/src/s2/s2builderutil_testing.h b/src/s2/s2builderutil_testing.h
new file mode 100644 (file)
index 0000000..87e6d5f
--- /dev/null
@@ -0,0 +1,100 @@
+// Copyright 2017 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// Author: ericv@google.com (Eric Veach)
+
+#ifndef S2_S2BUILDERUTIL_TESTING_H_
+#define S2_S2BUILDERUTIL_TESTING_H_
+
+#include <vector>
+
+#include "absl/memory/memory.h"
+#include "s2/s2builder.h"
+#include "s2/s2builder_graph.h"
+#include "s2/s2builder_layer.h"
+
+namespace s2builderutil {
+
+// A class that copies an S2Builder::Graph and owns the underlying data
+// (unlike S2Builder::Graph, which is just a view).
+class GraphClone {
+ public:
+  GraphClone() {}  // Must call Init().
+  explicit GraphClone(const S2Builder::Graph& g) { Init(g); }
+  void Init(const S2Builder::Graph& g);
+  const S2Builder::Graph& graph() { return g_; }
+
+ private:
+  S2Builder::GraphOptions options_;
+  std::vector<S2Point> vertices_;
+  std::vector<S2Builder::Graph::Edge> edges_;
+  std::vector<S2Builder::Graph::InputEdgeIdSetId> input_edge_id_set_ids_;
+  IdSetLexicon input_edge_id_set_lexicon_;
+  std::vector<S2Builder::Graph::LabelSetId> label_set_ids_;
+  IdSetLexicon label_set_lexicon_;
+  S2Builder::IsFullPolygonPredicate is_full_polygon_predicate_;
+  S2Builder::Graph g_;
+};
+
+// A layer type that copies an S2Builder::Graph into a GraphClone object
+// (which owns the underlying data, unlike S2Builder::Graph itself).
+class GraphCloningLayer : public S2Builder::Layer {
+ public:
+  GraphCloningLayer(const S2Builder::GraphOptions& graph_options,
+                    GraphClone* gc)
+      : graph_options_(graph_options), gc_(gc) {}
+
+  S2Builder::GraphOptions graph_options() const override {
+    return graph_options_;
+  }
+
+  void Build(const S2Builder::Graph& g, S2Error* error) override {
+    gc_->Init(g);
+  }
+
+ private:
+  GraphOptions graph_options_;
+  GraphClone* gc_;
+};
+
+// A layer type that copies an S2Builder::Graph and appends it to a vector,
+// and appends the corresponding GraphClone object (which owns the Graph data)
+// to a separate vector.
+class GraphAppendingLayer : public S2Builder::Layer {
+ public:
+  GraphAppendingLayer(
+      const S2Builder::GraphOptions& graph_options,
+      std::vector<S2Builder::Graph>* graphs,
+      std::vector<std::unique_ptr<GraphClone>>* clones)
+      : graph_options_(graph_options), graphs_(graphs), clones_(clones) {}
+
+  S2Builder::GraphOptions graph_options() const override {
+    return graph_options_;
+  }
+
+  void Build(const S2Builder::Graph& g, S2Error* error) override {
+    clones_->push_back(absl::make_unique<GraphClone>(g));
+    graphs_->push_back(clones_->back()->graph());
+  }
+
+ private:
+  GraphOptions graph_options_;
+  std::vector<S2Builder::Graph>* graphs_;
+  std::vector<std::unique_ptr<GraphClone>>* clones_;
+};
+
+}  // namespace s2builderutil
+
+#endif  // S2_S2BUILDERUTIL_TESTING_H_
diff --git a/src/s2/s2cap.cc b/src/s2/s2cap.cc
new file mode 100644 (file)
index 0000000..5c19ad0
--- /dev/null
@@ -0,0 +1,347 @@
+// Copyright 2005 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// Author: ericv@google.com (Eric Veach)
+
+#include "s2/s2cap.h"
+
+#include <cfloat>
+#include <cmath>
+#include <iosfwd>
+#include <vector>
+
+#include "s2/base/integral_types.h"
+#include "s2/base/logging.h"
+#include "s2/r1interval.h"
+#include "s2/s1interval.h"
+#include "s2/s2cell.h"
+#include "s2/s2debug.h"
+#include "s2/s2edge_distances.h"
+#include "s2/s2latlng.h"
+#include "s2/s2latlng_rect.h"
+#include "s2/s2metrics.h"
+#include "s2/s2pointutil.h"
+#include "s2/util/math/vector.h"
+
+using std::fabs;
+using std::max;
+using std::vector;
+
+double S2Cap::GetArea() const {
+  return 2 * M_PI * max(0.0, height());
+}
+
+S2Point S2Cap::GetCentroid() const {
+  // From symmetry, the centroid of the cap must be somewhere on the line
+  // from the origin to the center of the cap on the surface of the sphere.
+  // When a sphere is divided into slices of constant thickness by a set of
+  // parallel planes, all slices have the same surface area. This implies
+  // that the radial component of the centroid is simply the midpoint of the
+  // range of radial distances spanned by the cap. That is easily computed
+  // from the cap height.
+  if (is_empty()) return S2Point();
+  double r = 1.0 - 0.5 * height();
+  return r * GetArea() * center_;
+}
+
+S2Cap S2Cap::Complement() const {
+  // The complement of a full cap is an empty cap, not a singleton.
+  // Also make sure that the complement of an empty cap is full.
+  if (is_full()) return Empty();
+  if (is_empty()) return Full();
+  return S2Cap(-center_, S1ChordAngle::FromLength2(4 - radius_.length2()));
+}
+
+bool S2Cap::Contains(const S2Cap& other) const {
+  if (is_full() || other.is_empty()) return true;
+  return radius_ >= S1ChordAngle(center_, other.center_) + other.radius_;
+}
+
+bool S2Cap::Intersects(const S2Cap& other) const {
+  if (is_empty() || other.is_empty()) return false;
+  return radius_ + other.radius_ >= S1ChordAngle(center_, other.center_);
+}
+
+bool S2Cap::InteriorIntersects(const S2Cap& other) const {
+  // Make sure this cap has an interior and the other cap is non-empty.
+  if (radius_.length2() <= 0 || other.is_empty()) return false;
+  return radius_ + other.radius_ > S1ChordAngle(center_, other.center_);
+}
+
+void S2Cap::AddPoint(const S2Point& p) {
+  // Compute the squared chord length, then convert it into a height.
+  S2_DCHECK(S2::IsUnitLength(p));
+  if (is_empty()) {
+    center_ = p;
+    radius_ = S1ChordAngle::Zero();
+  } else {
+    // After calling cap.AddPoint(p), cap.Contains(p) must be true.  However
+    // we don't need to do anything special to achieve this because Contains()
+    // does exactly the same distance calculation that we do here.
+    radius_ = max(radius_, S1ChordAngle(center_, p));
+  }
+}
+
+void S2Cap::AddCap(const S2Cap& other) {
+  if (is_empty()) {
+    *this = other;
+  } else if (!other.is_empty()) {
+    // We round up the distance to ensure that the cap is actually contained.
+    // TODO(ericv): Do some error analysis in order to guarantee this.
+    S1ChordAngle dist = S1ChordAngle(center_, other.center_) + other.radius_;
+    radius_ = max(radius_, dist.PlusError(DBL_EPSILON * dist.length2()));
+  }
+}
+
+S2Cap S2Cap::Expanded(S1Angle distance) const {
+  S2_DCHECK_GE(distance.radians(), 0);
+  if (is_empty()) return Empty();
+  return S2Cap(center_, radius_ + S1ChordAngle(distance));
+}
+
+S2Cap S2Cap::Union(const S2Cap& other) const {
+  if (radius_ < other.radius_) {
+    return other.Union(*this);
+  }
+  if (is_full() || other.is_empty()) {
+    return *this;
+  }
+  // This calculation would be more efficient using S1ChordAngles.
+  S1Angle this_radius = GetRadius();
+  S1Angle other_radius = other.GetRadius();
+  S1Angle distance(center(), other.center());
+  if (this_radius >= distance + other_radius) {
+    return *this;
+  } else {
+    S1Angle result_radius = 0.5 * (distance + this_radius + other_radius);
+    S2Point result_center = S2::InterpolateAtDistance(
+        0.5 * (distance - this_radius + other_radius),
+        center(),
+        other.center());
+    return S2Cap(result_center, result_radius);
+  }
+}
+
+S2Cap* S2Cap::Clone() const {
+  return new S2Cap(*this);
+}
+
+S2Cap S2Cap::GetCapBound() const {
+  return *this;
+}
+
+S2LatLngRect S2Cap::GetRectBound() const {
+  if (is_empty()) return S2LatLngRect::Empty();
+
+  // Convert the center to a (lat,lng) pair, and compute the cap angle.
+  S2LatLng center_ll(center_);
+  double cap_angle = GetRadius().radians();
+
+  bool all_longitudes = false;
+  double lat[2], lng[2];
+  lng[0] = -M_PI;
+  lng[1] = M_PI;
+
+  // Check whether cap includes the south pole.
+  lat[0] = center_ll.lat().radians() - cap_angle;
+  if (lat[0] <= -M_PI_2) {
+    lat[0] = -M_PI_2;
+    all_longitudes = true;
+  }
+  // Check whether cap includes the north pole.
+  lat[1] = center_ll.lat().radians() + cap_angle;
+  if (lat[1] >= M_PI_2) {
+    lat[1] = M_PI_2;
+    all_longitudes = true;
+  }
+  if (!all_longitudes) {
+    // Compute the range of longitudes covered by the cap.  We use the law
+    // of sines for spherical triangles.  Consider the triangle ABC where
+    // A is the north pole, B is the center of the cap, and C is the point
+    // of tangency between the cap boundary and a line of longitude.  Then
+    // C is a right angle, and letting a,b,c denote the sides opposite A,B,C,
+    // we have sin(a)/sin(A) = sin(c)/sin(C), or sin(A) = sin(a)/sin(c).
+    // Here "a" is the cap angle, and "c" is the colatitude (90 degrees
+    // minus the latitude).  This formula also works for negative latitudes.
+    //
+    // The formula for sin(a) follows from the relationship h = 1 - cos(a).
+
+    double sin_a = sin(radius_);
+    double sin_c = cos(center_ll.lat().radians());
+    if (sin_a <= sin_c) {
+      double angle_A = asin(sin_a / sin_c);
+      lng[0] = remainder(center_ll.lng().radians() - angle_A, 2 * M_PI);
+      lng[1] = remainder(center_ll.lng().radians() + angle_A, 2 * M_PI);
+    }
+  }
+  return S2LatLngRect(R1Interval(lat[0], lat[1]),
+                      S1Interval(lng[0], lng[1]));
+}
+
+// Computes a covering of the S2Cap.  In general the covering consists of at
+// most 4 cells except for very large caps, which may need up to 6 cells.
+// The output is not sorted.
+void S2Cap::GetCellUnionBound(vector<S2CellId>* cell_ids) const {
+  // TODO(ericv): The covering could be made quite a bit tighter by mapping
+  // the cap to a rectangle in (i,j)-space and finding a covering for that.
+  cell_ids->clear();
+
+  // Find the maximum level such that the cap contains at most one cell vertex
+  // and such that S2CellId::AppendVertexNeighbors() can be called.
+  int level = S2::kMinWidth.GetLevelForMinValue(GetRadius().radians()) - 1;
+
+  // If level < 0, then more than three face cells are required.
+  if (level < 0) {
+    cell_ids->reserve(6);
+    for (int face = 0; face < 6; ++face) {
+      cell_ids->push_back(S2CellId::FromFace(face));
+    }
+  } else {
+    // The covering consists of the 4 cells at the given level that share the
+    // cell vertex that is closest to the cap center.
+    cell_ids->reserve(4);
+    S2CellId(center_).AppendVertexNeighbors(level, cell_ids);
+  }
+}
+
+bool S2Cap::Intersects(const S2Cell& cell, const S2Point* vertices) const {
+  // Return true if this cap intersects any point of 'cell' excluding its
+  // vertices (which are assumed to already have been checked).
+
+  // If the cap is a hemisphere or larger, the cell and the complement of the
+  // cap are both convex.  Therefore since no vertex of the cell is contained,
+  // no other interior point of the cell is contained either.
+  if (radius_ >= S1ChordAngle::Right()) return false;
+
+  // We need to check for empty caps due to the center check just below.
+  if (is_empty()) return false;
+
+  // Optimization: return true if the cell contains the cap center.  (This
+  // allows half of the edge checks below to be skipped.)
+  if (cell.Contains(center_)) return true;
+
+  // At this point we know that the cell does not contain the cap center,
+  // and the cap does not contain any cell vertex.  The only way that they
+  // can intersect is if the cap intersects the interior of some edge.
+
+  double sin2_angle = sin2(radius_);
+  for (int k = 0; k < 4; ++k) {
+    S2Point edge = cell.GetEdgeRaw(k);
+    double dot = center_.DotProd(edge);
+    if (dot > 0) {
+      // The center is in the interior half-space defined by the edge.  We don't
+      // need to consider these edges, since if the cap intersects this edge
+      // then it also intersects the edge on the opposite side of the cell
+      // (because we know the center is not contained with the cell).
+      continue;
+    }
+    // The Norm2() factor is necessary because "edge" is not normalized.
+    if (dot * dot > sin2_angle * edge.Norm2()) {
+      return false;  // Entire cap is on the exterior side of this edge.
+    }
+    // Otherwise, the great circle containing this edge intersects
+    // the interior of the cap.  We just need to check whether the point
+    // of closest approach occurs between the two edge endpoints.
+    Vector3_d dir = edge.CrossProd(center_);
+    if (dir.DotProd(vertices[k]) < 0 && dir.DotProd(vertices[(k+1)&3]) > 0)
+      return true;
+  }
+  return false;
+}
+
+bool S2Cap::Contains(const S2Cell& cell) const {
+  // If the cap does not contain all cell vertices, return false.
+  // We check the vertices before taking the Complement() because we can't
+  // accurately represent the complement of a very small cap (a height
+  // of 2-epsilon is rounded off to 2).
+  S2Point vertices[4];
+  for (int k = 0; k < 4; ++k) {
+    vertices[k] = cell.GetVertex(k);
+    if (!Contains(vertices[k])) return false;
+  }
+  // Otherwise, return true if the complement of the cap does not intersect
+  // the cell.  (This test is slightly conservative, because technically we
+  // want Complement().InteriorIntersects() here.)
+  return !Complement().Intersects(cell, vertices);
+}
+
+bool S2Cap::MayIntersect(const S2Cell& cell) const {
+  // If the cap contains any cell vertex, return true.
+  S2Point vertices[4];
+  for (int k = 0; k < 4; ++k) {
+    vertices[k] = cell.GetVertex(k);
+    if (Contains(vertices[k])) return true;
+  }
+  return Intersects(cell, vertices);
+}
+
+bool S2Cap::Contains(const S2Point& p) const {
+  S2_DCHECK(S2::IsUnitLength(p));
+  return S1ChordAngle(center_, p) <= radius_;
+}
+
+bool S2Cap::InteriorContains(const S2Point& p) const {
+  S2_DCHECK(S2::IsUnitLength(p));
+  return is_full() || S1ChordAngle(center_, p) < radius_;
+}
+
+bool S2Cap::operator==(const S2Cap& other) const {
+  return (center_ == other.center_ && radius_ == other.radius_) ||
+         (is_empty() && other.is_empty()) ||
+         (is_full() && other.is_full());
+}
+
+bool S2Cap::ApproxEquals(const S2Cap& other, S1Angle max_error_angle) const {
+  const double max_error = max_error_angle.radians();
+  const double r2 = radius_.length2();
+  const double other_r2 = other.radius_.length2();
+  return (S2::ApproxEquals(center_, other.center_, max_error_angle) &&
+          fabs(r2 - other_r2) <= max_error) ||
+         (is_empty() && other_r2 <= max_error) ||
+         (other.is_empty() && r2 <= max_error) ||
+         (is_full() && other_r2 >= 2 - max_error) ||
+         (other.is_full() && r2 >= 2 - max_error);
+}
+
+std::ostream& operator<<(std::ostream& os, const S2Cap& cap) {
+  return os << "[Center=" << cap.center()
+            << ", Radius=" << cap.GetRadius() << "]";
+}
+
+void S2Cap::Encode(Encoder* encoder) const {
+  encoder->Ensure(4 * sizeof(double));
+
+  encoder->putdouble(center_.x());
+  encoder->putdouble(center_.y());
+  encoder->putdouble(center_.z());
+  encoder->putdouble(radius_.length2());
+
+  S2_DCHECK_GE(encoder->avail(), 0);
+}
+
+bool S2Cap::Decode(Decoder* decoder) {
+  if (decoder->avail() < 4 * sizeof(double)) return false;
+
+  double x = decoder->getdouble();
+  double y = decoder->getdouble();
+  double z = decoder->getdouble();
+  center_ = S2Point(x, y, z);
+  radius_ = S1ChordAngle::FromLength2(decoder->getdouble());
+
+  if (FLAGS_s2debug) {
+     S2_CHECK(is_valid()) << "Invalid S2Cap: " << *this;
+  }
+  return true;
+}
diff --git a/src/s2/s2cap.h b/src/s2/s2cap.h
new file mode 100644 (file)
index 0000000..4b15858
--- /dev/null
@@ -0,0 +1,286 @@
+// Copyright 2005 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// Author: ericv@google.com (Eric Veach)
+
+#ifndef S2_S2CAP_H_
+#define S2_S2CAP_H_
+
+#include <algorithm>
+#include <cmath>
+#include <iosfwd>
+#include <vector>
+
+#include "s2/base/logging.h"
+#include "s2/_fp_contract_off.h"
+#include "s2/s1angle.h"
+#include "s2/s1chord_angle.h"
+#include "s2/s2pointutil.h"
+#include "s2/s2region.h"
+
+class Decoder;
+class Encoder;
+class S2Cell;
+class S2LatLngRect;
+
+// S2Cap represents a disc-shaped region defined by a center and radius.
+// Technically this shape is called a "spherical cap" (rather than disc)
+// because it is not planar; the cap represents a portion of the sphere that
+// has been cut off by a plane.  The boundary of the cap is the circle defined
+// by the intersection of the sphere and the plane.  For containment purposes,
+// the cap is a closed set, i.e. it contains its boundary.
+//
+// For the most part, you can use a spherical cap wherever you would use a
+// disc in planar geometry.  The radius of the cap is measured along the
+// surface of the sphere (rather than the straight-line distance through the
+// interior).  Thus a cap of radius Pi/2 is a hemisphere, and a cap of radius
+// Pi covers the entire sphere.
+//
+// A cap can also be defined by its center point and height.  The height is
+// simply the distance from the center point to the cutoff plane.  There is
+// also support for empty and full caps, which contain no points and all
+// points respectively.
+//
+// This class is intended to be copied by value as desired.  It uses the
+// default copy constructor and assignment operator, however it is not a
+// "plain old datatype" (POD) because it has virtual functions.
+class S2Cap final : public S2Region {
+ public:
+  // The default constructor returns an empty S2Cap.
+  S2Cap() : center_(1, 0, 0), radius_(S1ChordAngle::Negative()) {}
+
+  // Constructs a cap with the given center and radius.  A negative radius
+  // yields an empty cap; a radius of 180 degrees or more yields a full cap
+  // (containing the entire sphere).  "center" should be unit length.
+  S2Cap(const S2Point& center, S1Angle radius);
+
+  // Constructs a cap where the angle is expressed as an S1ChordAngle.  This
+  // constructor is more efficient than the one above.
+  S2Cap(const S2Point& center, S1ChordAngle radius);
+
+  // Convenience function that creates a cap containing a single point.  This
+  // method is more efficient that the S2Cap(center, radius) constructor.
+  static S2Cap FromPoint(const S2Point& center);
+
+  // Returns a cap with the given center and height (see comments above).  A
+  // negative height yields an empty cap; a height of 2 or more yields a full
+  // cap.  "center" should be unit length.
+  static S2Cap FromCenterHeight(const S2Point& center, double height);
+
+  // Return a cap with the given center and surface area.  Note that the area
+  // can also be interpreted as the solid angle subtended by the cap (because
+  // the sphere has unit radius).  A negative area yields an empty cap; an
+  // area of 4*Pi or more yields a full cap.  "center" should be unit length.
+  static S2Cap FromCenterArea(const S2Point& center, double area);
+
+  // Return an empty cap, i.e. a cap that contains no points.
+  static S2Cap Empty();
+
+  // Return a full cap, i.e. a cap that contains all points.
+  static S2Cap Full();
+
+  ~S2Cap() override {}
+
+  // Accessor methods.
+  const S2Point& center() const { return center_; }
+  S1ChordAngle radius() const { return radius_; }
+
+  // Returns the height of the cap, i.e. the distance from the center point to
+  // the cutoff plane.
+  double height() const;
+
+  // Return the cap radius as an S1Angle.  (Note that the cap angle is stored
+  // internally as an S1ChordAngle, so this method requires a trigonometric
+  // operation and may yield a slightly different result than the value passed
+  // to the (S2Point, S1Angle) constructor.)
+  S1Angle GetRadius() const;
+
+  // Return the area of the cap.
+  double GetArea() const;
+
+  // Return the true centroid of the cap multiplied by its surface area (see
+  // s2centroids.h for details on centroids). The result lies on the ray from
+  // the origin through the cap's center, but it is not unit length. Note that
+  // if you just want the "surface centroid", i.e. the normalized result, then
+  // it is much simpler just to call center().
+  //
+  // The reason for multiplying the result by the cap area is to make it
+  // easier to compute the centroid of more complicated shapes.  The centroid
+  // of a union of disjoint regions can be computed simply by adding their
+  // GetCentroid() results. Caveat: for caps that contain a single point
+  // (i.e., zero radius), this method always returns the origin (0, 0, 0).
+  // This is because shapes with no area don't affect the centroid of a
+  // union whose total area is positive.
+  S2Point GetCentroid() const;
+
+  // We allow negative heights (to represent empty caps) but heights are
+  // normalized so that they do not exceed 2.
+  bool is_valid() const;
+
+  // Return true if the cap is empty, i.e. it contains no points.
+  bool is_empty() const;
+
+  // Return true if the cap is full, i.e. it contains all points.
+  bool is_full() const;
+
+  // Return the complement of the interior of the cap.  A cap and its
+  // complement have the same boundary but do not share any interior points.
+  // The complement operator is not a bijection because the complement of a
+  // singleton cap (containing a single point) is the same as the complement
+  // of an empty cap.
+  S2Cap Complement() const;
+
+  // Return true if and only if this cap contains the given other cap
+  // (in a set containment sense, e.g. every cap contains the empty cap).
+  bool Contains(const S2Cap& other) const;
+
+  // Return true if and only if this cap intersects the given other cap,
+  // i.e. whether they have any points in common.
+  bool Intersects(const S2Cap& other) const;
+
+  // Return true if and only if the interior of this cap intersects the
+  // given other cap.  (This relationship is not symmetric, since only
+  // the interior of this cap is used.)
+  bool InteriorIntersects(const S2Cap& other) const;
+
+  // Return true if and only if the given point is contained in the interior
+  // of the cap (i.e. the cap excluding its boundary).  "p" should be be a
+  // unit-length vector.
+  bool InteriorContains(const S2Point& p) const;
+
+  // Increase the cap height if necessary to include the given point.  If the
+  // cap is empty then the center is set to the given point, but otherwise the
+  // center is not changed.  "p" should be a unit-length vector.
+  void AddPoint(const S2Point& p);
+
+  // Increase the cap height if necessary to include "other".  If the current
+  // cap is empty it is set to the given other cap.
+  void AddCap(const S2Cap& other);
+
+  // Return a cap that contains all points within a given distance of this
+  // cap.  Note that any expansion of the empty cap is still empty.
+  S2Cap Expanded(S1Angle distance) const;
+
+  // Return the smallest cap which encloses this cap and "other".
+  S2Cap Union(const S2Cap& other) const;
+
+  ////////////////////////////////////////////////////////////////////////
+  // S2Region interface (see s2region.h for details):
+
+  S2Cap* Clone() const override;
+  S2Cap GetCapBound() const override;
+  S2LatLngRect GetRectBound() const override;
+  void GetCellUnionBound(std::vector<S2CellId> *cell_ids) const override;
+  bool Contains(const S2Cell& cell) const override;
+  bool MayIntersect(const S2Cell& cell) const override;
+
+  // The point "p" should be a unit-length vector.
+  bool Contains(const S2Point& p) const override;
+
+  // Appends a serialized representation of the S2Cap to "encoder".
+  //
+  // REQUIRES: "encoder" uses the default constructor, so that its buffer
+  //           can be enlarged as necessary by calling Ensure(int).
+  void Encode(Encoder* const encoder) const;
+
+  // Decodes an S2Cap encoded with Encode().  Returns true on success.
+  bool Decode(Decoder* const decoder);
+
+  ///////////////////////////////////////////////////////////////////////
+  // The following static methods are convenience functions for assertions
+  // and testing purposes only.
+
+  // Return true if two caps are identical.
+  bool operator==(const S2Cap& other) const;
+
+  // Return true if the cap center and height differ by at most "max_error"
+  // from the given cap "other".
+  bool ApproxEquals(const S2Cap& other,
+                    S1Angle max_error = S1Angle::Radians(1e-14)) const;
+
+ private:
+  // Here are some useful relationships between the cap height (h), the cap
+  // radius (r), the maximum chord length from the cap's center (d), and the
+  // radius of cap's base (a).
+  //
+  //     h = 1 - cos(r)
+  //       = 2 * sin^2(r/2)
+  //   d^2 = 2 * h
+  //       = a^2 + h^2
+
+  // Return true if the cap intersects "cell", given that the cap does contain
+  // any of the cell vertices (supplied in "vertices", an array of length 4).
+  bool Intersects(const S2Cell& cell, const S2Point* vertices) const;
+
+  S2Point center_;
+  S1ChordAngle radius_;
+};
+
+std::ostream& operator<<(std::ostream& os, const S2Cap& cap);
+
+
+//////////////////   Implementation details follow   ////////////////////
+
+
+inline S2Cap::S2Cap(const S2Point& center, S1Angle radius)
+    : center_(center), radius_(std::min(radius, S1Angle::Radians(M_PI))) {
+  // The "min" calculation above is necessary to handle S1Angle::Infinity().
+  S2_DCHECK(is_valid());
+}
+
+inline S2Cap::S2Cap(const S2Point& center, S1ChordAngle radius)
+    : center_(center), radius_(radius) {
+  S2_DCHECK(is_valid());
+}
+
+inline S2Cap S2Cap::FromPoint(const S2Point& center) {
+  return S2Cap(center, S1ChordAngle::Zero());
+}
+
+inline S2Cap S2Cap::FromCenterHeight(const S2Point& center, double height) {
+  return S2Cap(center, S1ChordAngle::FromLength2(2 * height));
+}
+
+inline S2Cap S2Cap::FromCenterArea(const S2Point& center, double area) {
+  return S2Cap(center, S1ChordAngle::FromLength2(area / M_PI));
+}
+
+inline S2Cap S2Cap::Empty() { return S2Cap(); }
+
+inline S2Cap S2Cap::Full() {
+  return S2Cap(S2Point(1, 0, 0), S1ChordAngle::Straight());
+}
+
+inline double S2Cap::height() const {
+  return 0.5 * radius_.length2();
+}
+
+inline S1Angle S2Cap::GetRadius() const {
+  return radius_.ToAngle();
+}
+
+inline bool S2Cap::is_valid() const {
+  return S2::IsUnitLength(center_) && radius_.length2() <= 4;
+}
+
+inline bool S2Cap::is_empty() const {
+  return radius_.is_negative();
+}
+
+inline bool S2Cap::is_full() const {
+  return radius_.length2() == 4;
+}
+
+#endif  // S2_S2CAP_H_
diff --git a/src/s2/s2cell.cc b/src/s2/s2cell.cc
new file mode 100644 (file)
index 0000000..26a1d58
--- /dev/null
@@ -0,0 +1,552 @@
+// Copyright 2005 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// Author: ericv@google.com (Eric Veach)
+
+#include "s2/s2cell.h"
+
+#include <algorithm>
+#include <cfloat>
+#include <cmath>
+#include <iomanip>
+
+#include "s2/base/logging.h"
+#include "s2/r1interval.h"
+#include "s2/r2.h"
+#include "s2/s1chord_angle.h"
+#include "s2/s1interval.h"
+#include "s2/s2cap.h"
+#include "s2/s2coords.h"
+#include "s2/s2edge_crosser.h"
+#include "s2/s2edge_distances.h"
+#include "s2/s2latlng.h"
+#include "s2/s2latlng_rect.h"
+#include "s2/s2measures.h"
+#include "s2/s2metrics.h"
+
+using S2::internal::kPosToIJ;
+using S2::internal::kPosToOrientation;
+using std::min;
+using std::max;
+
+// Since S2Cells are copied by value, the following assertion is a reminder
+// not to add fields unnecessarily.  An S2Cell currently consists of 43 data
+// bytes, one vtable pointer, plus alignment overhead.  This works out to 48
+// bytes on 32 bit architectures and 56 bytes on 64 bit architectures.
+//
+// The expression below rounds up (43 + sizeof(void*)) to the nearest
+// multiple of sizeof(void*).
+static_assert(sizeof(S2Cell) <= ((43+2*sizeof(void*)-1) & -sizeof(void*)),
+              "S2Cell is getting bloated");
+
+S2Cell::S2Cell(S2CellId id) {
+  id_ = id;
+  int ij[2], orientation;
+  face_ = id.ToFaceIJOrientation(&ij[0], &ij[1], &orientation);
+  orientation_ = orientation;  // Compress int to a byte.
+  level_ = id.level();
+  uv_ = S2CellId::IJLevelToBoundUV(ij, level_);
+}
+
+S2Point S2Cell::GetVertexRaw(int k) const {
+  return S2::FaceUVtoXYZ(face_, uv_.GetVertex(k));
+}
+
+S2Point S2Cell::GetEdgeRaw(int k) const {
+  switch (k & 3) {
+    case 0:  return S2::GetVNorm(face_, uv_[1][0]);   // Bottom
+    case 1:  return S2::GetUNorm(face_, uv_[0][1]);   // Right
+    case 2:  return -S2::GetVNorm(face_, uv_[1][1]);  // Top
+    default: return -S2::GetUNorm(face_, uv_[0][0]);  // Left
+  }
+}
+
+bool S2Cell::Subdivide(S2Cell children[4]) const {
+  // This function is equivalent to just iterating over the child cell ids
+  // and calling the S2Cell constructor, but it is about 2.5 times faster.
+
+  if (id_.is_leaf()) return false;
+
+  // Compute the cell midpoint in uv-space.
+  R2Point uv_mid = id_.GetCenterUV();
+
+  // Create four children with the appropriate bounds.
+  S2CellId id = id_.child_begin();
+  for (int pos = 0; pos < 4; ++pos, id = id.next()) {
+    S2Cell *child = &children[pos];
+    child->face_ = face_;
+    child->level_ = level_ + 1;
+    child->orientation_ = orientation_ ^ kPosToOrientation[pos];
+    child->id_ = id;
+    // We want to split the cell in half in "u" and "v".  To decide which
+    // side to set equal to the midpoint value, we look at cell's (i,j)
+    // position within its parent.  The index for "i" is in bit 1 of ij.
+    int ij = kPosToIJ[orientation_][pos];
+    int i = ij >> 1;
+    int j = ij & 1;
+    child->uv_[0][i] = uv_[0][i];
+    child->uv_[0][1-i] = uv_mid[0];
+    child->uv_[1][j] = uv_[1][j];
+    child->uv_[1][1-j] = uv_mid[1];
+  }
+  return true;
+}
+
+S2Point S2Cell::GetCenterRaw() const {
+  return id_.ToPointRaw();
+}
+
+double S2Cell::AverageArea(int level) {
+  return S2::kAvgArea.GetValue(level);
+}
+
+double S2Cell::ApproxArea() const {
+  // All cells at the first two levels have the same area.
+  if (level_ < 2) return AverageArea(level_);
+
+  // First, compute the approximate area of the cell when projected
+  // perpendicular to its normal.  The cross product of its diagonals gives
+  // the normal, and the length of the normal is twice the projected area.
+  double flat_area = 0.5 * (GetVertex(2) - GetVertex(0)).
+                     CrossProd(GetVertex(3) - GetVertex(1)).Norm();
+
+  // Now, compensate for the curvature of the cell surface by pretending
+  // that the cell is shaped like a spherical cap.  The ratio of the
+  // area of a spherical cap to the area of its projected disc turns out
+  // to be 2 / (1 + sqrt(1 - r*r)) where "r" is the radius of the disc.
+  // For example, when r=0 the ratio is 1, and when r=1 the ratio is 2.
+  // Here we set Pi*r*r == flat_area to find the equivalent disc.
+  return flat_area * 2 / (1 + sqrt(1 - min(M_1_PI * flat_area, 1.0)));
+}
+
+double S2Cell::ExactArea() const {
+  // There is a straightforward mathematical formula for the exact surface
+  // area (based on 4 calls to asin), but as the cell size gets small this
+  // formula has too much cancellation error.  So instead we compute the area
+  // as the sum of two triangles (which is very accurate at all cell levels).
+  S2Point v0 = GetVertex(0);
+  S2Point v1 = GetVertex(1);
+  S2Point v2 = GetVertex(2);
+  S2Point v3 = GetVertex(3);
+  return S2::Area(v0, v1, v2) + S2::Area(v0, v2, v3);
+}
+
+S2Cell* S2Cell::Clone() const {
+  return new S2Cell(*this);
+}
+
+S2Cap S2Cell::GetCapBound() const {
+  // Use the cell center in (u,v)-space as the cap axis.  This vector is
+  // very close to GetCenter() and faster to compute.  Neither one of these
+  // vectors yields the bounding cap with minimal surface area, but they
+  // are both pretty close.
+  //
+  // It's possible to show that the two vertices that are furthest from
+  // the (u,v)-origin never determine the maximum cap size (this is a
+  // possible future optimization).
+
+  S2Point center = S2::FaceUVtoXYZ(face_, uv_.GetCenter()).Normalize();
+  S2Cap cap = S2Cap::FromPoint(center);
+  for (int k = 0; k < 4; ++k) {
+    cap.AddPoint(GetVertex(k));
+  }
+  return cap;
+}
+
+inline double S2Cell::GetLatitude(int i, int j) const {
+  S2Point p = S2::FaceUVtoXYZ(face_, uv_[0][i], uv_[1][j]);
+  return S2LatLng::Latitude(p).radians();
+}
+
+inline double S2Cell::GetLongitude(int i, int j) const {
+  S2Point p = S2::FaceUVtoXYZ(face_, uv_[0][i], uv_[1][j]);
+  return S2LatLng::Longitude(p).radians();
+}
+
+S2LatLngRect S2Cell::GetRectBound() const {
+  if (level_ > 0) {
+    // Except for cells at level 0, the latitude and longitude extremes are
+    // attained at the vertices.  Furthermore, the latitude range is
+    // determined by one pair of diagonally opposite vertices and the
+    // longitude range is determined by the other pair.
+    //
+    // We first determine which corner (i,j) of the cell has the largest
+    // absolute latitude.  To maximize latitude, we want to find the point in
+    // the cell that has the largest absolute z-coordinate and the smallest
+    // absolute x- and y-coordinates.  To do this we look at each coordinate
+    // (u and v), and determine whether we want to minimize or maximize that
+    // coordinate based on the axis direction and the cell's (u,v) quadrant.
+    double u = uv_[0][0] + uv_[0][1];
+    double v = uv_[1][0] + uv_[1][1];
+    int i = S2::GetUAxis(face_)[2] == 0 ? (u < 0) : (u > 0);
+    int j = S2::GetVAxis(face_)[2] == 0 ? (v < 0) : (v > 0);
+    R1Interval lat = R1Interval::FromPointPair(GetLatitude(i, j),
+                                               GetLatitude(1-i, 1-j));
+    S1Interval lng = S1Interval::FromPointPair(GetLongitude(i, 1-j),
+                                               GetLongitude(1-i, j));
+
+    // We grow the bounds slightly to make sure that the bounding rectangle
+    // contains S2LatLng(P) for any point P inside the loop L defined by the
+    // four *normalized* vertices.  Note that normalization of a vector can
+    // change its direction by up to 0.5 * DBL_EPSILON radians, and it is not
+    // enough just to add Normalize() calls to the code above because the
+    // latitude/longitude ranges are not necessarily determined by diagonally
+    // opposite vertex pairs after normalization.
+    //
+    // We would like to bound the amount by which the latitude/longitude of a
+    // contained point P can exceed the bounds computed above.  In the case of
+    // longitude, the normalization error can change the direction of rounding
+    // leading to a maximum difference in longitude of 2 * DBL_EPSILON.  In
+    // the case of latitude, the normalization error can shift the latitude by
+    // up to 0.5 * DBL_EPSILON and the other sources of error can cause the
+    // two latitudes to differ by up to another 1.5 * DBL_EPSILON, which also
+    // leads to a maximum difference of 2 * DBL_EPSILON.
+    return S2LatLngRect(lat, lng).
+        Expanded(S2LatLng::FromRadians(2 * DBL_EPSILON, 2 * DBL_EPSILON)).
+        PolarClosure();
+  }
+
+  // The 4 cells around the equator extend to +/-45 degrees latitude at the
+  // midpoints of their top and bottom edges.  The two cells covering the
+  // poles extend down to +/-35.26 degrees at their vertices.  The maximum
+  // error in this calculation is 0.5 * DBL_EPSILON.
+  static const double kPoleMinLat = asin(sqrt(1./3)) - 0.5 * DBL_EPSILON;
+
+  // The face centers are the +X, +Y, +Z, -X, -Y, -Z axes in that order.
+  S2_DCHECK_EQ(((face_ < 3) ? 1 : -1), S2::GetNorm(face_)[face_ % 3]);
+
+  S2LatLngRect bound;
+  switch (face_) {
+    case 0:
+      bound = S2LatLngRect(R1Interval(-M_PI_4, M_PI_4),
+                           S1Interval(-M_PI_4, M_PI_4));
+      break;
+    case 1:
+      bound = S2LatLngRect(R1Interval(-M_PI_4, M_PI_4),
+                           S1Interval(M_PI_4, 3*M_PI_4));
+      break;
+    case 2:
+      bound = S2LatLngRect(R1Interval(kPoleMinLat, M_PI_2),
+                           S1Interval::Full());
+      break;
+    case 3:
+      bound = S2LatLngRect(R1Interval(-M_PI_4, M_PI_4),
+                           S1Interval(3*M_PI_4, -3*M_PI_4));
+      break;
+    case 4:
+      bound = S2LatLngRect(R1Interval(-M_PI_4, M_PI_4),
+                           S1Interval(-3*M_PI_4, -M_PI_4));
+      break;
+    default:
+      bound = S2LatLngRect(R1Interval(-M_PI_2, -kPoleMinLat),
+                           S1Interval::Full());
+      break;
+  }
+  // Finally, we expand the bound to account for the error when a point P is
+  // converted to an S2LatLng to test for containment.  (The bound should be
+  // large enough so that it contains the computed S2LatLng of any contained
+  // point, not just the infinite-precision version.)  We don't need to expand
+  // longitude because longitude is calculated via a single call to atan2(),
+  // which is guaranteed to be semi-monotonic.  (In fact the Gnu implementation
+  // is also correctly rounded, but we don't even need that here.)
+  return bound.Expanded(S2LatLng::FromRadians(DBL_EPSILON, 0));
+}
+
+bool S2Cell::MayIntersect(const S2Cell& cell) const {
+  return id_.intersects(cell.id_);
+}
+
+bool S2Cell::Contains(const S2Cell& cell) const {
+  return id_.contains(cell.id_);
+}
+
+bool S2Cell::Contains(const S2Point& p) const {
+  // We can't just call XYZtoFaceUV, because for points that lie on the
+  // boundary between two faces (i.e. u or v is +1/-1) we need to return
+  // true for both adjacent cells.
+  R2Point uv;
+  if (!S2::FaceXYZtoUV(face_, p, &uv)) return false;
+
+  // Expand the (u,v) bound to ensure that
+  //
+  //   S2Cell(S2CellId(p)).Contains(p)
+  //
+  // is always true.  To do this, we need to account for the error when
+  // converting from (u,v) coordinates to (s,t) coordinates.  At least in the
+  // case of S2_QUADRATIC_PROJECTION, the total error is at most DBL_EPSILON.
+  return uv_.Expanded(DBL_EPSILON).Contains(uv);
+}
+
+void S2Cell::Encode(Encoder* const encoder) const {
+  id_.Encode(encoder);
+}
+
+bool S2Cell::Decode(Decoder* const decoder) {
+  S2CellId id;
+  if (!id.Decode(decoder)) return false;
+  this->~S2Cell();
+  new (this) S2Cell(id);
+  return true;
+}
+
+// Return the squared chord distance from point P to corner vertex (i,j).
+inline S1ChordAngle S2Cell::VertexChordDist(
+    const S2Point& p, int i, int j) const {
+  S2Point vertex = S2Point(uv_[0][i], uv_[1][j], 1).Normalize();
+  return S1ChordAngle(p, vertex);
+}
+
+// Given a point P and either the lower or upper edge of the S2Cell (specified
+// by setting "v_end" to 0 or 1 respectively), return true if P is closer to
+// the interior of that edge than it is to either endpoint.
+bool S2Cell::UEdgeIsClosest(const S2Point& p, int v_end) const {
+  double u0 = uv_[0][0], u1 = uv_[0][1], v = uv_[1][v_end];
+  // These are the normals to the planes that are perpendicular to the edge
+  // and pass through one of its two endpoints.
+  S2Point dir0(v * v + 1, -u0 * v, -u0);
+  S2Point dir1(v * v + 1, -u1 * v, -u1);
+  return p.DotProd(dir0) > 0 && p.DotProd(dir1) < 0;
+}
+
+// Given a point P and either the left or right edge of the S2Cell (specified
+// by setting "u_end" to 0 or 1 respectively), return true if P is closer to
+// the interior of that edge than it is to either endpoint.
+bool S2Cell::VEdgeIsClosest(const S2Point& p, int u_end) const {
+  double v0 = uv_[1][0], v1 = uv_[1][1], u = uv_[0][u_end];
+  // See comments above.
+  S2Point dir0(-u * v0, u * u + 1, -v0);
+  S2Point dir1(-u * v1, u * u + 1, -v1);
+  return p.DotProd(dir0) > 0 && p.DotProd(dir1) < 0;
+}
+
+// Given the dot product of a point P with the normal of a u- or v-edge at the
+// given coordinate value, return the distance from P to that edge.
+inline static S1ChordAngle EdgeDistance(double dirIJ, double uv) {
+  // Let P by the target point and let R be the closest point on the given
+  // edge AB.  The desired distance PR can be expressed as PR^2 = PQ^2 + QR^2
+  // where Q is the point P projected onto the plane through the great circle
+  // through AB.  We can compute the distance PQ^2 perpendicular to the plane
+  // from "dirIJ" (the dot product of the target point P with the edge
+  // normal) and the squared length the edge normal (1 + uv**2).
+  double pq2 = (dirIJ * dirIJ) / (1 + uv * uv);
+
+  // We can compute the distance QR as (1 - OQ) where O is the sphere origin,
+  // and we can compute OQ^2 = 1 - PQ^2 using the Pythagorean theorem.
+  // (This calculation loses accuracy as angle POQ approaches Pi/2.)
+  double qr = 1 - sqrt(1 - pq2);
+  return S1ChordAngle::FromLength2(pq2 + qr * qr);
+}
+
+S1ChordAngle S2Cell::GetDistanceInternal(const S2Point& target_xyz,
+                                         bool to_interior) const {
+  // All calculations are done in the (u,v,w) coordinates of this cell's face.
+  S2Point target = S2::FaceXYZtoUVW(face_, target_xyz);
+
+  // Compute dot products with all four upward or rightward-facing edge
+  // normals.  "dirIJ" is the dot product for the edge corresponding to axis
+  // I, endpoint J.  For example, dir01 is the right edge of the S2Cell
+  // (corresponding to the upper endpoint of the u-axis).
+  double dir00 = target[0] - target[2] * uv_[0][0];
+  double dir01 = target[0] - target[2] * uv_[0][1];
+  double dir10 = target[1] - target[2] * uv_[1][0];
+  double dir11 = target[1] - target[2] * uv_[1][1];
+  bool inside = true;
+  if (dir00 < 0) {
+    inside = false;  // Target is to the left of the cell
+    if (VEdgeIsClosest(target, 0)) return EdgeDistance(-dir00, uv_[0][0]);
+  }
+  if (dir01 > 0) {
+    inside = false;  // Target is to the right of the cell
+    if (VEdgeIsClosest(target, 1)) return EdgeDistance(dir01, uv_[0][1]);
+  }
+  if (dir10 < 0) {
+    inside = false;  // Target is below the cell
+    if (UEdgeIsClosest(target, 0)) return EdgeDistance(-dir10, uv_[1][0]);
+  }
+  if (dir11 > 0) {
+    inside = false;  // Target is above the cell
+    if (UEdgeIsClosest(target, 1)) return EdgeDistance(dir11, uv_[1][1]);
+  }
+  if (inside) {
+    if (to_interior) return S1ChordAngle::Zero();
+    // Although you might think of S2Cells as rectangles, they are actually
+    // arbitrary quadrilaterals after they are projected onto the sphere.
+    // Therefore the simplest approach is just to find the minimum distance to
+    // any of the four edges.
+    return min(min(EdgeDistance(-dir00, uv_[0][0]),
+                   EdgeDistance(dir01, uv_[0][1])),
+               min(EdgeDistance(-dir10, uv_[1][0]),
+                   EdgeDistance(dir11, uv_[1][1])));
+  }
+  // Otherwise, the closest point is one of the four cell vertices.  Note that
+  // it is *not* trivial to narrow down the candidates based on the edge sign
+  // tests above, because (1) the edges don't meet at right angles and (2)
+  // there are points on the far side of the sphere that are both above *and*
+  // below the cell, etc.
+  return min(min(VertexChordDist(target, 0, 0),
+                 VertexChordDist(target, 1, 0)),
+             min(VertexChordDist(target, 0, 1),
+                 VertexChordDist(target, 1, 1)));
+}
+
+S1ChordAngle S2Cell::GetDistance(const S2Point& target) const {
+  return GetDistanceInternal(target, true /*to_interior*/);
+}
+
+S1ChordAngle S2Cell::GetBoundaryDistance(const S2Point& target) const {
+  return GetDistanceInternal(target, false /*to_interior*/);
+}
+
+S1ChordAngle S2Cell::GetMaxDistance(const S2Point& target) const {
+  // First check the 4 cell vertices.  If all are within the hemisphere
+  // centered around target, the max distance will be to one of these vertices.
+  S2Point target_uvw = S2::FaceXYZtoUVW(face_, target);
+  S1ChordAngle max_dist = max(max(VertexChordDist(target_uvw, 0, 0),
+                                         VertexChordDist(target_uvw, 1, 0)),
+                                     max(VertexChordDist(target_uvw, 0, 1),
+                                         VertexChordDist(target_uvw, 1, 1)));
+
+  if (max_dist <= S1ChordAngle::Right()) {
+    return max_dist;
+  }
+
+  // Otherwise, find the minimum distance d_min to the antipodal point and the
+  // maximum distance will be Pi - d_min.
+  return S1ChordAngle::Straight() - GetDistance(-target);
+}
+
+S1ChordAngle S2Cell::GetDistance(const S2Point& a, const S2Point& b) const {
+  // Possible optimizations:
+  //  - Currently the (cell vertex, edge endpoint) distances are computed
+  //    twice each, and the length of AB is computed 4 times.
+  //  - To fix this, refactor GetDistance(target) so that it skips calculating
+  //    the distance to each cell vertex.  Instead, compute the cell vertices
+  //    and distances in this function, and add a low-level UpdateMinDistance
+  //    that allows the XA, XB, and AB distances to be passed in.
+  //  - It might also be more efficient to do all calculations in UVW-space,
+  //    since this would involve transforming 2 points rather than 4.
+
+  // First, check the minimum distance to the edge endpoints A and B.
+  // (This also detects whether either endpoint is inside the cell.)
+  S1ChordAngle min_dist = min(GetDistance(a), GetDistance(b));
+  if (min_dist == S1ChordAngle::Zero()) return min_dist;
+
+  // Otherwise, check whether the edge crosses the cell boundary.
+  // Note that S2EdgeCrosser needs pointers to vertices.
+  S2Point v[4];
+  for (int i = 0; i < 4; ++i) {
+    v[i] = GetVertex(i);
+  }
+  S2EdgeCrosser crosser(&a, &b, &v[3]);
+  for (int i = 0; i < 4; ++i) {
+    if (crosser.CrossingSign(&v[i]) >= 0) {
+      return S1ChordAngle::Zero();
+    }
+  }
+  // Finally, check whether the minimum distance occurs between a cell vertex
+  // and the interior of the edge AB.  (Some of this work is redundant, since
+  // it also checks the distance to the endpoints A and B again.)
+  //
+  // Note that we don't need to check the distance from the interior of AB to
+  // the interior of a cell edge, because the only way that this distance can
+  // be minimal is if the two edges cross (already checked above).
+  for (int i = 0; i < 4; ++i) {
+    S2::UpdateMinDistance(v[i], a, b, &min_dist);
+  }
+  return min_dist;
+}
+
+S1ChordAngle S2Cell::GetMaxDistance(const S2Point& a, const S2Point& b) const {
+  // If the maximum distance from both endpoints to the cell is less than Pi/2
+  // then the maximum distance from the edge to the cell is the maximum of the
+  // two endpoint distances.
+  S1ChordAngle max_dist = max(GetMaxDistance(a), GetMaxDistance(b));
+  if (max_dist <= S1ChordAngle::Right()) {
+    return max_dist;
+  }
+
+  return S1ChordAngle::Straight() - GetDistance(-a, -b);
+}
+
+S1ChordAngle S2Cell::GetDistance(const S2Cell& target) const {
+  // If the cells intersect, the distance is zero.  We use the (u,v) ranges
+  // rather S2CellId::intersects() so that cells that share a partial edge or
+  // corner are considered to intersect.
+  if (face_ == target.face_ && uv_.Intersects(target.uv_)) {
+    return S1ChordAngle::Zero();
+  }
+
+  // Otherwise, the minimum distance always occurs between a vertex of one
+  // cell and an edge of the other cell (including the edge endpoints).  This
+  // represents a total of 32 possible (vertex, edge) pairs.
+  //
+  // TODO(ericv): This could be optimized to be at least 5x faster by pruning
+  // the set of possible closest vertex/edge pairs using the faces and (u,v)
+  // ranges of both cells.
+  S2Point va[4], vb[4];
+  for (int i = 0; i < 4; ++i) {
+    va[i] = GetVertex(i);
+    vb[i] = target.GetVertex(i);
+  }
+  S1ChordAngle min_dist = S1ChordAngle::Infinity();
+  for (int i = 0; i < 4; ++i) {
+    for (int j = 0; j < 4; ++j) {
+      S2::UpdateMinDistance(va[i], vb[j], vb[(j + 1) & 3], &min_dist);
+      S2::UpdateMinDistance(vb[i], va[j], va[(j + 1) & 3], &min_dist);
+    }
+  }
+  return min_dist;
+}
+
+inline static int OppositeFace(int face) {
+  return face >= 3 ? face - 3 : face + 3;
+}
+
+// The antipodal UV is the transpose of the original UV, interpreted within
+// the opposite face.
+inline static R2Rect OppositeUV(const R2Rect& uv) {
+  return R2Rect(uv[1], uv[0]);
+}
+
+S1ChordAngle S2Cell::GetMaxDistance(const S2Cell& target) const {
+  // Need to check the antipodal target for intersection with the cell. If it
+  // intersects, the distance is S1ChordAngle::Straight().
+  if (face_ == OppositeFace(target.face_) &&
+      uv_.Intersects(OppositeUV(target.uv_))) {
+    return S1ChordAngle::Straight();
+  }
+
+  // Otherwise, the maximum distance always occurs between a vertex of one
+  // cell and an edge of the other cell (including the edge endpoints).  This
+  // represents a total of 32 possible (vertex, edge) pairs.
+  //
+  // TODO(user): When the maximum distance is at most Pi/2, the maximum is
+  // always attained between a pair of vertices, and this could be made much
+  // faster by testing each vertex pair once rather than the current 4 times.
+  S2Point va[4], vb[4];
+  for (int i = 0; i < 4; ++i) {
+    va[i] = GetVertex(i);
+    vb[i] = target.GetVertex(i);
+  }
+  S1ChordAngle max_dist = S1ChordAngle::Negative();
+  for (int i = 0; i < 4; ++i) {
+    for (int j = 0; j < 4; ++j) {
+      S2::UpdateMaxDistance(va[i], vb[j], vb[(j + 1) & 3], &max_dist);
+      S2::UpdateMaxDistance(vb[i], va[j], va[(j + 1) & 3], &max_dist);
+    }
+  }
+  return max_dist;
+}
+
diff --git a/src/s2/s2cell.h b/src/s2/s2cell.h
new file mode 100644 (file)
index 0000000..ab4d105
--- /dev/null
@@ -0,0 +1,249 @@
+// Copyright 2005 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// Author: ericv@google.com (Eric Veach)
+
+#ifndef S2_S2CELL_H_
+#define S2_S2CELL_H_
+
+#include "s2/base/integral_types.h"
+#include "s2/base/logging.h"
+#include "s2/_fp_contract_off.h"
+#include "s2/r2rect.h"
+#include "s2/s1chord_angle.h"
+#include "s2/s2cell_id.h"
+#include "s2/s2region.h"
+#include "s2/util/math/vector.h"
+
+class Decoder;
+class Encoder;
+class S2Cap;
+class S2LatLng;
+class S2LatLngRect;
+
+// An S2Cell is an S2Region object that represents a cell.  Unlike S2CellIds,
+// it supports efficient containment and intersection tests.  However, it is
+// also a more expensive representation (currently 48 bytes rather than 8).
+
+// This class is intended to be copied by value as desired.  It uses
+// the default copy constructor and assignment operator, however it is
+// not a "plain old datatype" (POD) because it has virtual functions.
+class S2Cell final : public S2Region {
+ public:
+  // The default constructor is required in order to use freelists.
+  // Cells should otherwise always be constructed explicitly.
+  S2Cell() {}
+
+  // An S2Cell always corresponds to a particular S2CellId.  The other
+  // constructors are just convenience methods.
+  explicit S2Cell(S2CellId id);
+
+  // Convenience constructors.  The S2LatLng must be normalized.
+  explicit S2Cell(const S2Point& p) : S2Cell(S2CellId(p)) {}
+  explicit S2Cell(const S2LatLng& ll) : S2Cell(S2CellId(ll)) {}
+
+  // Returns the cell corresponding to the given S2 cube face.
+  static S2Cell FromFace(int face) {
+    return S2Cell(S2CellId::FromFace(face));
+  }
+
+  // Returns a cell given its face (range 0..5), Hilbert curve position within
+  // that face (an unsigned integer with S2CellId::kPosBits bits), and level
+  // (range 0..kMaxLevel).  The given position will be modified to correspond
+  // to the Hilbert curve position at the center of the returned cell.  This
+  // is a static function rather than a constructor in order to indicate what
+  // the arguments represent.
+  static S2Cell FromFacePosLevel(int face, uint64 pos, int level) {
+    return S2Cell(S2CellId::FromFacePosLevel(face, pos, level));
+  }
+
+  S2CellId id() const { return id_; }
+  int face() const { return face_; }
+  int level() const { return level_; }
+  int orientation() const { return orientation_; }
+  bool is_leaf() const { return level_ == S2CellId::kMaxLevel; }
+
+  // These are equivalent to the S2CellId methods, but have a more efficient
+  // implementation since the level has been precomputed.
+  int GetSizeIJ() const;
+  double GetSizeST() const;
+
+  // Returns the k-th vertex of the cell (k = 0,1,2,3).  Vertices are returned
+  // in CCW order (lower left, lower right, upper right, upper left in the UV
+  // plane).  The points returned by GetVertexRaw are not normalized.
+  // For convenience, the argument is reduced modulo 4 to the range [0..3].
+  S2Point GetVertex(int k) const { return GetVertexRaw(k).Normalize(); }
+  S2Point GetVertexRaw(int k) const;
+
+  // Returns the inward-facing normal of the great circle passing through the
+  // edge from vertex k to vertex k+1 (mod 4).  The normals returned by
+  // GetEdgeRaw are not necessarily unit length.  For convenience, the
+  // argument is reduced modulo 4 to the range [0..3].
+  S2Point GetEdge(int k) const { return GetEdgeRaw(k).Normalize(); }
+  S2Point GetEdgeRaw(int k) const;
+
+  // If this is not a leaf cell, sets children[0..3] to the four children of
+  // this cell (in traversal order) and return true.  Otherwise returns false.
+  // This method is equivalent to the following:
+  //
+  // for (pos=0, id=child_begin(); id != child_end(); id = id.next(), ++pos)
+  //   children[pos] = S2Cell(id);
+  //
+  // except that it is more than two times faster.
+  bool Subdivide(S2Cell children[4]) const;
+
+  // Returns the direction vector corresponding to the center in (s,t)-space of
+  // the given cell.  This is the point at which the cell is divided into four
+  // subcells; it is not necessarily the centroid of the cell in (u,v)-space
+  // or (x,y,z)-space.  The point returned by GetCenterRaw is not necessarily
+  // unit length.
+  S2Point GetCenter() const { return GetCenterRaw().Normalize(); }
+  S2Point GetCenterRaw() const;
+
+  // Returns the average area for cells at the given level.
+  static double AverageArea(int level);
+
+  // Returns the average area of cells at this level in steradians.  This is
+  // accurate to within a factor of 1.7 (for S2_QUADRATIC_PROJECTION) and is
+  // extremely cheap to compute.
+  double AverageArea() const { return AverageArea(level_); }
+
+  // Returns the approximate area of this cell in steradians.  This method is
+  // accurate to within 3% percent for all cell sizes and accurate to within
+  // 0.1% for cells at level 5 or higher (i.e. squares 350km to a side or
+  // smaller on the Earth's surface).  It is moderately cheap to compute.
+  double ApproxArea() const;
+
+  // Returns the area of this cell as accurately as possible.  This method is
+  // more expensive but it is accurate to 6 digits of precision even for leaf
+  // cells (whose area is approximately 1e-18).
+  double ExactArea() const;
+
+  // Returns the bounds of this cell in (u,v)-space.
+  R2Rect GetBoundUV() const { return uv_; }
+
+  // Returns the distance from the cell to the given point.  Returns zero if
+  // the point is inside the cell.
+  S1ChordAngle GetDistance(const S2Point& target) const;
+
+  // Return the distance from the cell boundary to the given point.
+  S1ChordAngle GetBoundaryDistance(const S2Point& target) const;
+
+  // Returns the maximum distance from the cell (including its interior) to the
+  // given point.
+  S1ChordAngle GetMaxDistance(const S2Point& target) const;
+
+  // Returns the minimum distance from the cell to the given edge AB.  Returns
+  // zero if the edge intersects the cell interior.
+  S1ChordAngle GetDistance(const S2Point& a, const S2Point& b) const;
+
+  // Returns the maximum distance from the cell (including its interior) to the
+  // given edge AB.
+  S1ChordAngle GetMaxDistance(const S2Point& a, const S2Point& b) const;
+
+  // Returns the distance from the cell to the given cell.  Returns zero if
+  // one cell contains the other.
+  S1ChordAngle GetDistance(const S2Cell& target) const;
+
+  // Returns the maximum distance from the cell (including its interior) to the
+  // given target cell.
+  S1ChordAngle GetMaxDistance(const S2Cell& target) const;
+
+  ////////////////////////////////////////////////////////////////////////
+  // S2Region interface (see s2region.h for details):
+
+  S2Cell* Clone() const override;
+  S2Cap GetCapBound() const override;
+  S2LatLngRect GetRectBound() const override;
+  bool Contains(const S2Cell& cell) const override;
+  bool MayIntersect(const S2Cell& cell) const override;
+
+  // Returns true if the cell contains the given point "p".  Note that unlike
+  // S2Loop/S2Polygon, S2Cells are considered to be closed sets.  This means
+  // that points along an S2Cell edge (or at a vertex) belong to the adjacent
+  // cell(s) as well.
+  //
+  // If instead you want every point to be contained by exactly one S2Cell,
+  // you will need to convert the S2Cells to S2Loops (which implement point
+  // containment this way).
+  //
+  // The point "p" does not need to be normalized.
+  bool Contains(const S2Point& p) const override;
+
+  // Appends a serialized representation of the S2Cell to "encoder".
+  //
+  // REQUIRES: "encoder" uses the default constructor, so that its buffer
+  //           can be enlarged as necessary by calling Ensure(int).
+  void Encode(Encoder* const encoder) const;
+
+  // Decodes an S2Cell encoded with Encode().  Returns true on success.
+  bool Decode(Decoder* const decoder);
+
+ private:
+  // Returns the latitude or longitude of the cell vertex given by (i,j),
+  // where "i" and "j" are either 0 or 1.
+  double GetLatitude(int i, int j) const;
+  double GetLongitude(int i, int j) const;
+
+  S1ChordAngle VertexChordDist(const S2Point& p, int i, int j) const;
+  bool UEdgeIsClosest(const S2Point& target, int v_end) const;
+  bool VEdgeIsClosest(const S2Point& target, int u_end) const;
+
+  // Returns the distance from the given point to the interior of the cell if
+  // "to_interior" is true, and to the boundary of the cell otherwise.
+  S1ChordAngle GetDistanceInternal(const S2Point& target_xyz,
+                                   bool to_interior) const;
+
+  // This structure occupies 44 bytes plus one pointer for the vtable.
+  int8 face_;
+  int8 level_;
+  int8 orientation_;
+  S2CellId id_;
+  R2Rect uv_;
+};
+
+inline bool operator==(const S2Cell& x, const S2Cell& y) {
+  return x.id() == y.id();
+}
+
+inline bool operator!=(const S2Cell& x, const S2Cell& y) {
+  return x.id() != y.id();
+}
+
+inline bool operator<(const S2Cell& x, const S2Cell& y) {
+  return x.id() < y.id();
+}
+
+inline bool operator>(const S2Cell& x, const S2Cell& y) {
+  return x.id() > y.id();
+}
+
+inline bool operator<=(const S2Cell& x, const S2Cell& y) {
+  return x.id() <= y.id();
+}
+
+inline bool operator>=(const S2Cell& x, const S2Cell& y) {
+  return x.id() >= y.id();
+}
+
+inline int S2Cell::GetSizeIJ() const {
+  return S2CellId::GetSizeIJ(level());
+}
+
+inline double S2Cell::GetSizeST() const {
+  return S2CellId::GetSizeST(level());
+}
+
+#endif  // S2_S2CELL_H_
diff --git a/src/s2/s2cell_id.cc b/src/s2/s2cell_id.cc
new file mode 100644 (file)
index 0000000..0864feb
--- /dev/null
@@ -0,0 +1,619 @@
+// Copyright 2005 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// Author: ericv@google.com (Eric Veach)
+
+#include "s2/s2cell_id.h"
+
+#include <algorithm>
+#include <cfloat>
+#include <cmath>
+#include <cstring>
+#include <iosfwd>
+#include <mutex>
+#include <vector>
+
+#include "s2/base/integral_types.h"
+#include "s2/base/logging.h"
+#include "s2/r1interval.h"
+#include "s2/s2coords.h"
+#include "s2/s2latlng.h"
+#include "absl/base/casts.h"
+#include "absl/strings/str_cat.h"
+
+using absl::StrCat;
+using S2::internal::kSwapMask;
+using S2::internal::kInvertMask;
+using S2::internal::kPosToIJ;
+using S2::internal::kPosToOrientation;
+using std::fabs;
+using std::max;
+using std::min;
+using std::vector;
+
+// The following lookup tables are used to convert efficiently between an
+// (i,j) cell index and the corresponding position along the Hilbert curve.
+// "lookup_pos" maps 4 bits of "i", 4 bits of "j", and 2 bits representing the
+// orientation of the current cell into 8 bits representing the order in which
+// that subcell is visited by the Hilbert curve, plus 2 bits indicating the
+// new orientation of the Hilbert curve within that subcell.  (Cell
+// orientations are represented as combination of kSwapMask and kInvertMask.)
+//
+// "lookup_ij" is an inverted table used for mapping in the opposite
+// direction.
+//
+// We also experimented with looking up 16 bits at a time (14 bits of position
+// plus 2 of orientation) but found that smaller lookup tables gave better
+// performance.  (2KB fits easily in the primary cache.)
+
+
+// Values for these constants are *declared* in the *.h file. Even though
+// the declaration specifies a value for the constant, that declaration
+// is not a *definition* of storage for the value. Because the values are
+// supplied in the declaration, we don't need the values here. Failing to
+// define storage causes link errors for any code that tries to take the
+// address of one of these values.
+const int S2CellId::kFaceBits;
+const int S2CellId::kNumFaces;
+const int S2CellId::kMaxLevel;
+const int S2CellId::kPosBits;
+const int S2CellId::kMaxSize;
+
+static const int kLookupBits = 4;
+static uint16 lookup_pos[1 << (2 * kLookupBits + 2)];
+static uint16 lookup_ij[1 << (2 * kLookupBits + 2)];
+
+static void InitLookupCell(int level, int i, int j, int orig_orientation,
+                           int pos, int orientation) {
+  if (level == kLookupBits) {
+    int ij = (i << kLookupBits) + j;
+    lookup_pos[(ij << 2) + orig_orientation] = (pos << 2) + orientation;
+    lookup_ij[(pos << 2) + orig_orientation] = (ij << 2) + orientation;
+  } else {
+    level++;
+    i <<= 1;
+    j <<= 1;
+    pos <<= 2;
+    const int* r = kPosToIJ[orientation];
+    InitLookupCell(level, i + (r[0] >> 1), j + (r[0] & 1), orig_orientation,
+                   pos, orientation ^ kPosToOrientation[0]);
+    InitLookupCell(level, i + (r[1] >> 1), j + (r[1] & 1), orig_orientation,
+                   pos + 1, orientation ^ kPosToOrientation[1]);
+    InitLookupCell(level, i + (r[2] >> 1), j + (r[2] & 1), orig_orientation,
+                   pos + 2, orientation ^ kPosToOrientation[2]);
+    InitLookupCell(level, i + (r[3] >> 1), j + (r[3] & 1), orig_orientation,
+                   pos + 3, orientation ^ kPosToOrientation[3]);
+  }
+}
+
+static std::once_flag flag;
+inline static void MaybeInit() {
+  std::call_once(flag, []{
+    InitLookupCell(0, 0, 0, 0, 0, 0);
+    InitLookupCell(0, 0, 0, kSwapMask, 0, kSwapMask);
+    InitLookupCell(0, 0, 0, kInvertMask, 0, kInvertMask);
+    InitLookupCell(0, 0, 0, kSwapMask|kInvertMask, 0, kSwapMask|kInvertMask);
+  });
+}
+
+S2CellId S2CellId::advance(int64 steps) const {
+  if (steps == 0) return *this;
+
+  // We clamp the number of steps if necessary to ensure that we do not
+  // advance past the End() or before the Begin() of this level.  Note that
+  // min_steps and max_steps always fit in a signed 64-bit integer.
+
+  int step_shift = 2 * (kMaxLevel - level()) + 1;
+  if (steps < 0) {
+    int64 min_steps = -static_cast<int64>(id_ >> step_shift);
+    if (steps < min_steps) steps = min_steps;
+  } else {
+    int64 max_steps = (kWrapOffset + lsb() - id_) >> step_shift;
+    if (steps > max_steps) steps = max_steps;
+  }
+  // If steps is negative, then shifting it left has undefined behavior.
+  // Cast to uint64 for a 2's complement answer.
+  return S2CellId(id_ + (static_cast<uint64>(steps) << step_shift));
+}
+
+int64 S2CellId::distance_from_begin() const {
+  const int step_shift = 2 * (kMaxLevel - level()) + 1;
+  return id_ >> step_shift;
+}
+
+S2CellId S2CellId::advance_wrap(int64 steps) const {
+  S2_DCHECK(is_valid());
+  if (steps == 0) return *this;
+
+  int step_shift = 2 * (kMaxLevel - level()) + 1;
+  if (steps < 0) {
+    int64 min_steps = -static_cast<int64>(id_ >> step_shift);
+    if (steps < min_steps) {
+      int64 step_wrap = kWrapOffset >> step_shift;
+      steps %= step_wrap;
+      if (steps < min_steps) steps += step_wrap;
+    }
+  } else {
+    // Unlike advance(), we don't want to return End(level).
+    int64 max_steps = (kWrapOffset - id_) >> step_shift;
+    if (steps > max_steps) {
+      int64 step_wrap = kWrapOffset >> step_shift;
+      steps %= step_wrap;
+      if (steps > max_steps) steps -= step_wrap;
+    }
+  }
+  return S2CellId(id_ + (static_cast<uint64>(steps) << step_shift));
+}
+
+S2CellId S2CellId::maximum_tile(const S2CellId limit) const {
+  S2CellId id = *this;
+  S2CellId start = id.range_min();
+  if (start >= limit.range_min()) return limit;
+
+  if (id.range_max() >= limit) {
+    // The cell is too large.  Shrink it.  Note that when generating coverings
+    // of S2CellId ranges, this loop usually executes only once.  Also because
+    // id.range_min() < limit.range_min(), we will always exit the loop by the
+    // time we reach a leaf cell.
+    do { id = id.child(0); } while (id.range_max() >= limit);
+    return id;
+  }
+  // The cell may be too small.  Grow it if necessary.  Note that generally
+  // this loop only iterates once.
+  while (!id.is_face()) {
+    S2CellId parent = id.parent();
+    if (parent.range_min() != start || parent.range_max() >= limit) break;
+    id = parent;
+  }
+  return id;
+}
+
+int S2CellId::GetCommonAncestorLevel(S2CellId other) const {
+  // Basically we find the first bit position at which the two S2CellIds
+  // differ and convert that to a level.  The max() below is necessary for the
+  // case where one S2CellId is a descendant of the other.
+  uint64 bits = max(id() ^ other.id(), max(lsb(), other.lsb()));
+  S2_DCHECK_NE(bits, 0);  // Because lsb() is non-zero.
+
+  // Compute the position of the most significant bit, and then map the bit
+  // position as follows:
+  // {0} -> 30, {1,2} -> 29, {3,4} -> 28, ... , {59,60} -> 0, {61,62,63} -> -1.
+  return max(60 - Bits::FindMSBSetNonZero64(bits), -1) >> 1;
+}
+
+// Print the num_digits low order hex digits.
+static std::string HexFormatString(uint64 val, size_t num_digits) {
+  std::string result(num_digits, ' ');
+  for (; num_digits--; val >>= 4)
+    result[num_digits] = "0123456789abcdef"[val & 0xF];
+  return result;
+}
+
+std::string S2CellId::ToToken() const {
+  // Simple implementation: print the id in hex without trailing zeros.
+  // Using hex has the advantage that the tokens are case-insensitive, all
+  // characters are alphanumeric, no characters require any special escaping
+  // in queries for most indexing systems, and it's easy to compare cell
+  // tokens against the feature ids of the corresponding features.
+  //
+  // Using base 64 would produce slightly shorter tokens, but for typical cell
+  // sizes used during indexing (up to level 15 or so) the average savings
+  // would be less than 2 bytes per cell which doesn't seem worth it.
+
+  // "0" with trailing 0s stripped is the empty string, which is not a
+  // reasonable token.  Encode as "X".
+  if (id_ == 0) return "X";
+  const size_t num_zero_digits = Bits::FindLSBSetNonZero64(id_) / 4;
+  return HexFormatString(id_ >> (4 * num_zero_digits), 16 - num_zero_digits);
+}
+
+S2CellId S2CellId::FromToken(const char* token, size_t length) {
+  if (length > 16) return S2CellId::None();
+  uint64 id = 0;
+  for (int i = 0, pos = 60; i < length; ++i, pos -= 4) {
+    uint64 d;
+    if ('0' <= token[i] && token[i] <= '9') {
+      d = token[i] - '0';
+    } else if ('a' <= token[i] && token[i] <= 'f') {
+      d = token[i] - 'a' + 10;
+    } else if ('A' <= token[i] && token[i] <= 'F') {
+      d = token[i] - 'A' + 10;
+    } else {
+      return S2CellId::None();
+    }
+    id |= d << pos;
+  }
+  return S2CellId(id);
+}
+
+S2CellId S2CellId::FromToken(const std::string& token) {
+  return FromToken(token.data(), token.size());
+}
+
+void S2CellId::Encode(Encoder* const encoder) const {
+  encoder->Ensure(sizeof(uint64));  // A single uint64.
+  encoder->put64(id_);
+}
+
+bool S2CellId::Decode(Decoder* const decoder) {
+  if (decoder->avail() < sizeof(uint64)) return false;
+  id_ = decoder->get64();
+  return true;
+}
+
+S2CellId S2CellId::FromFaceIJ(int face, int i, int j) {
+  // Initialization if not done yet
+  MaybeInit();
+
+  // Optimization notes:
+  //  - Non-overlapping bit fields can be combined with either "+" or "|".
+  //    Generally "+" seems to produce better code, but not always.
+
+  // Note that this value gets shifted one bit to the left at the end
+  // of the function.
+  uint64 n = absl::implicit_cast<uint64>(face) << (kPosBits - 1);
+
+  // Alternating faces have opposite Hilbert curve orientations; this
+  // is necessary in order for all faces to have a right-handed
+  // coordinate system.
+  uint64 bits = (face & kSwapMask);
+
+  // Each iteration maps 4 bits of "i" and "j" into 8 bits of the Hilbert
+  // curve position.  The lookup table transforms a 10-bit key of the form
+  // "iiiijjjjoo" to a 10-bit value of the form "ppppppppoo", where the
+  // letters [ijpo] denote bits of "i", "j", Hilbert curve position, and
+  // Hilbert curve orientation respectively.
+#define GET_BITS(k) do { \
+    const int mask = (1 << kLookupBits) - 1; \
+    bits += ((i >> (k * kLookupBits)) & mask) << (kLookupBits + 2); \
+    bits += ((j >> (k * kLookupBits)) & mask) << 2; \
+    bits = lookup_pos[bits]; \
+    n |= (bits >> 2) << (k * 2 * kLookupBits); \
+    bits &= (kSwapMask | kInvertMask); \
+  } while (0)
+
+  GET_BITS(7);
+  GET_BITS(6);
+  GET_BITS(5);
+  GET_BITS(4);
+  GET_BITS(3);
+  GET_BITS(2);
+  GET_BITS(1);
+  GET_BITS(0);
+#undef GET_BITS
+
+  return S2CellId(n * 2 + 1);
+}
+
+S2CellId::S2CellId(const S2Point& p) {
+  double u, v;
+  int face = S2::XYZtoFaceUV(p, &u, &v);
+  int i = S2::STtoIJ(S2::UVtoST(u));
+  int j = S2::STtoIJ(S2::UVtoST(v));
+  id_ = FromFaceIJ(face, i, j).id();
+}
+
+S2CellId::S2CellId(const S2LatLng& ll)
+  : S2CellId(ll.ToPoint()) {
+}
+
+int S2CellId::ToFaceIJOrientation(int* pi, int* pj, int* orientation) const {
+  // Initialization if not done yet
+  MaybeInit();
+
+  int i = 0, j = 0;
+  int face = this->face();
+  int bits = (face & kSwapMask);
+
+  // Each iteration maps 8 bits of the Hilbert curve position into
+  // 4 bits of "i" and "j".  The lookup table transforms a key of the
+  // form "ppppppppoo" to a value of the form "iiiijjjjoo", where the
+  // letters [ijpo] represents bits of "i", "j", the Hilbert curve
+  // position, and the Hilbert curve orientation respectively.
+  //
+  // On the first iteration we need to be careful to clear out the bits
+  // representing the cube face.
+#define GET_BITS(k) do { \
+    const int nbits = (k == 7) ? (kMaxLevel - 7 * kLookupBits) : kLookupBits; \
+    bits += (static_cast<int>(id_ >> (k * 2 * kLookupBits + 1)) \
+             & ((1 << (2 * nbits)) - 1)) << 2; \
+    bits = lookup_ij[bits]; \
+    i += (bits >> (kLookupBits + 2)) << (k * kLookupBits); \
+    j += ((bits >> 2) & ((1 << kLookupBits) - 1)) << (k * kLookupBits); \
+    bits &= (kSwapMask | kInvertMask); \
+  } while (0)
+
+  GET_BITS(7);
+  GET_BITS(6);
+  GET_BITS(5);
+  GET_BITS(4);
+  GET_BITS(3);
+  GET_BITS(2);
+  GET_BITS(1);
+  GET_BITS(0);
+#undef GET_BITS
+
+  *pi = i;
+  *pj = j;
+
+  if (orientation != nullptr) {
+    // The position of a non-leaf cell at level "n" consists of a prefix of
+    // 2*n bits that identifies the cell, followed by a suffix of
+    // 2*(kMaxLevel-n)+1 bits of the form 10*.  If n==kMaxLevel, the suffix is
+    // just "1" and has no effect.  Otherwise, it consists of "10", followed
+    // by (kMaxLevel-n-1) repetitions of "00", followed by "0".  The "10" has
+    // no effect, while each occurrence of "00" has the effect of reversing
+    // the kSwapMask bit.
+    S2_DCHECK_EQ(0, kPosToOrientation[2]);
+    S2_DCHECK_EQ(kSwapMask, kPosToOrientation[0]);
+    if (lsb() & 0x1111111111111110ULL) {
+      bits ^= kSwapMask;
+    }
+    *orientation = bits;
+  }
+  return face;
+}
+
+S2Point S2CellId::ToPointRaw() const {
+  int si, ti;
+  int face = GetCenterSiTi(&si, &ti);
+  return S2::FaceSiTitoXYZ(face, si, ti);
+}
+
+S2LatLng S2CellId::ToLatLng() const {
+  return S2LatLng(ToPointRaw());
+}
+
+R2Point S2CellId::GetCenterST() const {
+  int si, ti;
+  GetCenterSiTi(&si, &ti);
+  return R2Point(S2::SiTitoST(si), S2::SiTitoST(ti));
+}
+
+R2Point S2CellId::GetCenterUV() const {
+  int si, ti;
+  GetCenterSiTi(&si, &ti);
+  return R2Point(S2::STtoUV(S2::SiTitoST(si)),
+                 S2::STtoUV(S2::SiTitoST(ti)));
+}
+
+R2Rect S2CellId::IJLevelToBoundUV(int ij[2], int level) {
+  R2Rect bound;
+  int cell_size = GetSizeIJ(level);
+  for (int d = 0; d < 2; ++d) {
+    int ij_lo = ij[d] & -cell_size;
+    int ij_hi = ij_lo + cell_size;
+    bound[d][0] = S2::STtoUV(S2::IJtoSTMin(ij_lo));
+    bound[d][1] = S2::STtoUV(S2::IJtoSTMin(ij_hi));
+  }
+  return bound;
+}
+
+R2Rect S2CellId::GetBoundST() const {
+  double size = GetSizeST();
+  return R2Rect::FromCenterSize(GetCenterST(), R2Point(size, size));
+}
+
+R2Rect S2CellId::GetBoundUV() const {
+  int ij[2];
+  ToFaceIJOrientation(&ij[0], &ij[1], nullptr);
+  return IJLevelToBoundUV(ij, level());
+}
+
+// This is a helper function for ExpandedByDistanceUV().
+//
+// Given an edge of the form (u,v0)-(u,v1), let max_v = max(abs(v0), abs(v1)).
+// This method returns a new u-coordinate u' such that the distance from the
+// line u=u' to the given edge (u,v0)-(u,v1) is exactly the given distance
+// (which is specified as the sine of the angle corresponding to the distance).
+static double ExpandEndpoint(double u, double max_v, double sin_dist) {
+  // This is based on solving a spherical right triangle, similar to the
+  // calculation in S2Cap::GetRectBound.
+  double sin_u_shift = sin_dist * sqrt((1 + u * u + max_v * max_v) /
+                                       (1 + u * u));
+  double cos_u_shift = sqrt(1 - sin_u_shift * sin_u_shift);
+  // The following is an expansion of tan(atan(u) + asin(sin_u_shift)).
+  return (cos_u_shift * u + sin_u_shift) / (cos_u_shift - sin_u_shift * u);
+}
+
+/* static */
+R2Rect S2CellId::ExpandedByDistanceUV(const R2Rect& uv, S1Angle distance) {
+  // Expand each of the four sides of the rectangle just enough to include all
+  // points within the given distance of that side.  (The rectangle may be
+  // expanded by a different amount in (u,v)-space on each side.)
+  double u0 = uv[0][0], u1 = uv[0][1], v0 = uv[1][0], v1 = uv[1][1];
+  double max_u = std::max(fabs(u0), fabs(u1));
+  double max_v = std::max(fabs(v0), fabs(v1));
+  double sin_dist = sin(distance);
+  return R2Rect(R1Interval(ExpandEndpoint(u0, max_v, -sin_dist),
+                           ExpandEndpoint(u1, max_v, sin_dist)),
+                R1Interval(ExpandEndpoint(v0, max_u, -sin_dist),
+                           ExpandEndpoint(v1, max_u, sin_dist)));
+}
+
+S2CellId S2CellId::FromFaceIJWrap(int face, int i, int j) {
+  // Convert i and j to the coordinates of a leaf cell just beyond the
+  // boundary of this face.  This prevents 32-bit overflow in the case
+  // of finding the neighbors of a face cell.
+  i = max(-1, min(kMaxSize, i));
+  j = max(-1, min(kMaxSize, j));
+
+  // We want to wrap these coordinates onto the appropriate adjacent face.
+  // The easiest way to do this is to convert the (i,j) coordinates to (x,y,z)
+  // (which yields a point outside the normal face boundary), and then call
+  // S2::XYZtoFaceUV() to project back onto the correct face.
+  //
+  // The code below converts (i,j) to (si,ti), and then (si,ti) to (u,v) using
+  // the linear projection (u=2*s-1 and v=2*t-1).  (The code further below
+  // converts back using the inverse projection, s=0.5*(u+1) and t=0.5*(v+1).
+  // Any projection would work here, so we use the simplest.)  We also clamp
+  // the (u,v) coordinates so that the point is barely outside the
+  // [-1,1]x[-1,1] face rectangle, since otherwise the reprojection step
+  // (which divides by the new z coordinate) might change the other
+  // coordinates enough so that we end up in the wrong leaf cell.
+  static const double kScale = 1.0 / kMaxSize;
+  static const double kLimit = 1.0 + DBL_EPSILON;
+  // The arithmetic below is designed to avoid 32-bit integer overflows.
+  S2_DCHECK_EQ(0, kMaxSize % 2);
+  double u = max(-kLimit, min(kLimit, kScale * (2 * (i - kMaxSize / 2) + 1)));
+  double v = max(-kLimit, min(kLimit, kScale * (2 * (j - kMaxSize / 2) + 1)));
+
+  // Find the leaf cell coordinates on the adjacent face, and convert
+  // them to a cell id at the appropriate level.
+  face = S2::XYZtoFaceUV(S2::FaceUVtoXYZ(face, u, v), &u, &v);
+  return FromFaceIJ(face, S2::STtoIJ(0.5*(u+1)), S2::STtoIJ(0.5*(v+1)));
+}
+
+inline S2CellId S2CellId::FromFaceIJSame(int face, int i, int j,
+                                         bool same_face) {
+  if (same_face)
+    return S2CellId::FromFaceIJ(face, i, j);
+  else
+    return S2CellId::FromFaceIJWrap(face, i, j);
+}
+
+void S2CellId::GetEdgeNeighbors(S2CellId neighbors[4]) const {
+  int i, j;
+  int level = this->level();
+  int size = GetSizeIJ(level);
+  int face = ToFaceIJOrientation(&i, &j, nullptr);
+
+  // Edges 0, 1, 2, 3 are in the down, right, up, left directions.
+  neighbors[0] = FromFaceIJSame(face, i, j - size, j - size >= 0)
+                 .parent(level);
+  neighbors[1] = FromFaceIJSame(face, i + size, j, i + size < kMaxSize)
+                 .parent(level);
+  neighbors[2] = FromFaceIJSame(face, i, j + size, j + size < kMaxSize)
+                 .parent(level);
+  neighbors[3] = FromFaceIJSame(face, i - size, j, i - size >= 0)
+                 .parent(level);
+}
+
+void S2CellId::AppendVertexNeighbors(int level,
+                                     vector<S2CellId>* output) const {
+  // "level" must be strictly less than this cell's level so that we can
+  // determine which vertex this cell is closest to.
+  S2_DCHECK_LT(level, this->level());
+  int i, j;
+  int face = ToFaceIJOrientation(&i, &j, nullptr);
+
+  // Determine the i- and j-offsets to the closest neighboring cell in each
+  // direction.  This involves looking at the next bit of "i" and "j" to
+  // determine which quadrant of this->parent(level) this cell lies in.
+  int halfsize = GetSizeIJ(level + 1);
+  int size = halfsize << 1;
+  bool isame, jsame;
+  int ioffset, joffset;
+  if (i & halfsize) {
+    ioffset = size;
+    isame = (i + size) < kMaxSize;
+  } else {
+    ioffset = -size;
+    isame = (i - size) >= 0;
+  }
+  if (j & halfsize) {
+    joffset = size;
+    jsame = (j + size) < kMaxSize;
+  } else {
+    joffset = -size;
+    jsame = (j - size) >= 0;
+  }
+
+  output->push_back(parent(level));
+  output->push_back(FromFaceIJSame(face, i + ioffset, j, isame).parent(level));
+  output->push_back(FromFaceIJSame(face, i, j + joffset, jsame).parent(level));
+  // If i- and j- edge neighbors are *both* on a different face, then this
+  // vertex only has three neighbors (it is one of the 8 cube vertices).
+  if (isame || jsame) {
+    output->push_back(FromFaceIJSame(face, i + ioffset, j + joffset,
+                                     isame && jsame).parent(level));
+  }
+}
+
+void S2CellId::AppendAllNeighbors(int nbr_level,
+                                  vector<S2CellId>* output) const {
+  S2_DCHECK_GE(nbr_level, level());
+  int i, j;
+  int face = ToFaceIJOrientation(&i, &j, nullptr);
+
+  // Find the coordinates of the lower left-hand leaf cell.  We need to
+  // normalize (i,j) to a known position within the cell because nbr_level
+  // may be larger than this cell's level.
+  int size = GetSizeIJ();
+  i &= -size;
+  j &= -size;
+
+  int nbr_size = GetSizeIJ(nbr_level);
+  S2_DCHECK_LE(nbr_size, size);
+
+  // We compute the top-bottom, left-right, and diagonal neighbors in one
+  // pass.  The loop test is at the end of the loop to avoid 32-bit overflow.
+  for (int k = -nbr_size; ; k += nbr_size) {
+    bool same_face;
+    if (k < 0) {
+      same_face = (j + k >= 0);
+    } else if (k >= size) {
+      same_face = (j + k < kMaxSize);
+    } else {
+      same_face = true;
+      // Top and bottom neighbors.
+      output->push_back(FromFaceIJSame(face, i + k, j - nbr_size,
+                                       j - size >= 0).parent(nbr_level));
+      output->push_back(FromFaceIJSame(face, i + k, j + size,
+                                       j + size < kMaxSize).parent(nbr_level));
+    }
+    // Left, right, and diagonal neighbors.
+    output->push_back(FromFaceIJSame(face, i - nbr_size, j + k,
+                                     same_face && i - size >= 0)
+                      .parent(nbr_level));
+    output->push_back(FromFaceIJSame(face, i + size, j + k,
+                                     same_face && i + size < kMaxSize)
+                      .parent(nbr_level));
+    if (k >= size) break;
+  }
+}
+
+std::string S2CellId::ToString() const {
+  if (!is_valid()) {
+    return StrCat("Invalid: ", absl::Hex(id(), absl::kZeroPad16));
+  }
+  std::string out = StrCat(face(), "/");
+  for (int current_level = 1; current_level <= level(); ++current_level) {
+    // Avoid dependencies of SimpleItoA, and slowness of StrAppend &
+    // std::to_string.
+    out += "0123"[child_position(current_level)];
+  }
+  return out;
+}
+
+std::ostream& operator<<(std::ostream& os, S2CellId id) {
+  return os << id.ToString();
+}
+
+S2CellId S2CellId::FromDebugString(absl::string_view str) {
+  // This function is reasonably efficient, but is only intended for use in
+  // tests.
+  int level = static_cast<int>(str.size() - 2);
+  if (level < 0 || level > S2CellId::kMaxLevel) return S2CellId::None();
+  int face = str[0] - '0';
+  if (face < 0 || face > 5 || str[1] != '/') return S2CellId::None();
+  S2CellId id = S2CellId::FromFace(face);
+  for (int i = 2; i < str.size(); ++i) {
+    int child_pos = str[i] - '0';
+    if (child_pos < 0 || child_pos > 3) return S2CellId::None();
+    id = id.child(child_pos);
+  }
+  return id;
+}
diff --git a/src/s2/s2cell_id.h b/src/s2/s2cell_id.h
new file mode 100644 (file)
index 0000000..ee6eb43
--- /dev/null
@@ -0,0 +1,705 @@
+// Copyright 2005 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// Author: ericv@google.com (Eric Veach)
+
+#ifndef S2_S2CELL_ID_H_
+#define S2_S2CELL_ID_H_
+
+#include <cstddef>
+#include <functional>
+#include <iostream>
+#include <string>
+#include <vector>
+
+#include "s2/base/integral_types.h"
+#include "s2/base/logging.h"
+#include "s2/base/port.h"
+#include "s2/_fp_contract_off.h"
+#include "s2/r2.h"
+#include "s2/r2rect.h"
+#include "s2/s1angle.h"
+#include "s2/s2coords.h"
+#include "absl/strings/string_view.h"
+#include "s2/util/bits/bits.h"
+#include "s2/util/coding/coder.h"
+
+class S2LatLng;
+
+#ifndef SWIG
+#define IFNDEF_SWIG(x) x
+#else
+#define IFNDEF_SWIG(x)
+#endif
+
+// An S2CellId is a 64-bit unsigned integer that uniquely identifies a
+// cell in the S2 cell decomposition.  It has the following format:
+//
+//   id = [face][face_pos]
+//
+//   face:     a 3-bit number (range 0..5) encoding the cube face.
+//
+//   face_pos: a 61-bit number encoding the position of the center of this
+//             cell along the Hilbert curve over this face (see the Wiki
+//             pages for details).
+//
+// Sequentially increasing cell ids follow a continuous space-filling curve
+// over the entire sphere.  They have the following properties:
+//
+//  - The id of a cell at level k consists of a 3-bit face number followed
+//    by k bit pairs that recursively select one of the four children of
+//    each cell.  The next bit is always 1, and all other bits are 0.
+//    Therefore, the level of a cell is determined by the position of its
+//    lowest-numbered bit that is turned on (for a cell at level k, this
+//    position is 2 * (kMaxLevel - k).)
+//
+//  - The id of a parent cell is at the midpoint of the range of ids spanned
+//    by its children (or by its descendants at any level).
+//
+// Leaf cells are often used to represent points on the unit sphere, and
+// this class provides methods for converting directly between these two
+// representations.  For cells that represent 2D regions rather than
+// discrete point, it is better to use the S2Cell class.
+//
+// This class is intended to be copied by value as desired.  It uses
+// the default copy constructor and assignment operator.
+class S2CellId {
+ public:
+  // The extra position bit (61 rather than 60) let us encode each cell as its
+  // Hilbert curve position at the cell center (which is halfway along the
+  // portion of the Hilbert curve that fills that cell).
+  static const int kFaceBits = 3;
+  static const int kNumFaces = 6;
+  static const int kMaxLevel = S2::kMaxCellLevel;  // Valid levels: 0..kMaxLevel
+  static const int kPosBits = 2 * kMaxLevel + 1;
+  static const int kMaxSize = 1 << kMaxLevel;
+
+  explicit IFNDEF_SWIG(constexpr) S2CellId(uint64 id) : id_(id) {}
+
+  // Construct a leaf cell containing the given point "p".  Usually there is
+  // is exactly one such cell, but for points along the edge of a cell, any
+  // adjacent cell may be (deterministically) chosen.  This is because
+  // S2CellIds are considered to be closed sets.  The returned cell will
+  // always contain the given point, i.e.
+  //
+  //   S2Cell(S2CellId(p)).Contains(p)
+  //
+  // is always true.  The point "p" does not need to be normalized.
+  //
+  // If instead you want every point to be contained by exactly one S2Cell,
+  // you will need to convert the S2CellIds to S2Loops (which implement point
+  // containment this way).
+  explicit S2CellId(const S2Point& p);
+
+  // Construct a leaf cell containing the given normalized S2LatLng.
+  explicit S2CellId(const S2LatLng& ll);
+
+  // The default constructor returns an invalid cell id.
+  IFNDEF_SWIG(constexpr) S2CellId() : id_(0) {}
+  static constexpr S2CellId None() { return S2CellId(); }
+
+  // Returns an invalid cell id guaranteed to be larger than any
+  // valid cell id.  Useful for creating indexes.
+  static constexpr S2CellId Sentinel() { return S2CellId(~uint64{0}); }
+
+  // Return the cell corresponding to a given S2 cube face.
+  static S2CellId FromFace(int face);
+
+  // Return a cell given its face (range 0..5), Hilbert curve position within
+  // that face (an unsigned integer with S2CellId::kPosBits bits), and level
+  // (range 0..kMaxLevel).  The given position will be modified to correspond
+  // to the Hilbert curve position at the center of the returned cell.  This
+  // is a static function rather than a constructor in order to indicate what
+  // the arguments represent.
+  static S2CellId FromFacePosLevel(int face, uint64 pos, int level);
+
+  // Return the direction vector corresponding to the center of the given
+  // cell.  The vector returned by ToPointRaw is not necessarily unit length.
+  // This method returns the same result as S2Cell::GetCenter().
+  //
+  // The maximum directional error in ToPoint() (compared to the exact
+  // mathematical result) is 1.5 * DBL_EPSILON radians, and the maximum length
+  // error is 2 * DBL_EPSILON (the same as Normalize).
+  S2Point ToPoint() const { return ToPointRaw().Normalize(); }
+  S2Point ToPointRaw() const;
+
+  // Return the center of the cell in (s,t) coordinates (see s2coords.h).
+  R2Point GetCenterST() const;
+
+  // Return the edge length of this cell in (s,t)-space.
+  double GetSizeST() const;
+
+  // Return the edge length in (s,t)-space of cells at the given level.
+  static double GetSizeST(int level);
+
+  // Return the bounds of this cell in (s,t)-space.
+  R2Rect GetBoundST() const;
+
+  // Return the center of the cell in (u,v) coordinates (see s2coords.h).
+  // Note that the center of the cell is defined as the point at which it is
+  // recursively subdivided into four children; in general, it is not at the
+  // midpoint of the (u,v) rectangle covered by the cell.
+  R2Point GetCenterUV() const;
+
+  // Return the bounds of this cell in (u,v)-space.
+  R2Rect GetBoundUV() const;
+
+  // Expand a rectangle in (u,v)-space so that it contains all points within
+  // the given distance of the boundary, and return the smallest such
+  // rectangle.  If the distance is negative, then instead shrink this
+  // rectangle so that it excludes all points within the given absolute
+  // distance of the boundary.
+  //
+  // Distances are measured *on the sphere*, not in (u,v)-space.  For example,
+  // you can use this method to expand the (u,v)-bound of an S2CellId so that
+  // it contains all points within 5km of the original cell.  You can then
+  // test whether a point lies within the expanded bounds like this:
+  //
+  //   R2Point uv;
+  //   if (S2::FaceXYZtoUV(face, point, &uv) && bound.Contains(uv)) { ... }
+  //
+  // Limitations:
+  //
+  //  - Because the rectangle is drawn on one of the six cube-face planes
+  //    (i.e., {x,y,z} = +/-1), it can cover at most one hemisphere.  This
+  //    limits the maximum amount that a rectangle can be expanded.  For
+  //    example, S2CellId bounds can be expanded safely by at most 45 degrees
+  //    (about 5000 km on the Earth's surface).
+  //
+  //  - The implementation is not exact for negative distances.  The resulting
+  //    rectangle will exclude all points within the given distance of the
+  //    boundary but may be slightly smaller than necessary.
+  static R2Rect ExpandedByDistanceUV(const R2Rect& uv, S1Angle distance);
+
+  // Return the (face, si, ti) coordinates of the center of the cell.  Note
+  // that although (si,ti) coordinates span the range [0,2**31] in general,
+  // the cell center coordinates are always in the range [1,2**31-1] and
+  // therefore can be represented using a signed 32-bit integer.
+  int GetCenterSiTi(int* psi, int* pti) const;
+
+  // Return the S2LatLng corresponding to the center of the given cell.
+  S2LatLng ToLatLng() const;
+
+  // The 64-bit unique identifier for this cell.
+  uint64 id() const { return id_; }
+
+  // Return true if id() represents a valid cell.
+  //
+  // All methods require is_valid() to be true unless otherwise specified
+  // (although not all methods enforce this).
+  bool is_valid() const;
+
+  // Which cube face this cell belongs to, in the range 0..5.
+  int face() const;
+
+  // The position of the cell center along the Hilbert curve over this face,
+  // in the range 0..(2**kPosBits-1).
+  uint64 pos() const;
+
+  // Return the subdivision level of the cell (range 0..kMaxLevel).
+  int level() const;
+
+  // Return the edge length of this cell in (i,j)-space.
+  int GetSizeIJ() const;
+
+  // Like the above, but return the size of cells at the given level.
+  static int GetSizeIJ(int level);
+
+  // Return true if this is a leaf cell (more efficient than checking
+  // whether level() == kMaxLevel).
+  bool is_leaf() const;
+
+  // Return true if this is a top-level face cell (more efficient than
+  // checking whether level() == 0).
+  bool is_face() const;
+
+  // Return the child position (0..3) of this cell within its parent.
+  // REQUIRES: level() >= 1.
+  int child_position() const;
+
+  // Return the child position (0..3) of this cell's ancestor at the given
+  // level within its parent.  For example, child_position(1) returns the
+  // position of this cell's level-1 ancestor within its top-level face cell.
+  // REQUIRES: 1 <= level <= this->level().
+  int child_position(int level) const;
+
+  // These methods return the range of cell ids that are contained within this
+  // cell (including itself).  The range is *inclusive* (i.e. test using >=
+  // and <=) and the return values of both methods are valid leaf cell ids.
+  // In other words, a.contains(b) if and only if
+  //
+  //     (b >= a.range_min() && b <= a.range_max())
+  //
+  // If you want to iterate through all the descendants of this cell at a
+  // particular level, use child_begin(level) and child_end(level) instead.
+  // Also see maximum_tile(), which can be used to iterate through a range of
+  // cells using S2CellIds at different levels that are as large as possible.
+  //
+  // If you need to convert the range to a semi-open interval [min, limit)
+  // (e.g., in order to use a key-value store that only supports semi-open
+  // range queries), do not attempt to define "limit" as range_max.next().
+  // The problem is that leaf S2CellIds are 2 units apart, so the semi-open
+  // interval [min, limit) includes an additional value (range_max.id() + 1)
+  // which is happens to be a valid S2CellId about one-third of the time and
+  // is *never* contained by this cell.  (It always correpsonds to a cell that
+  // is larger than this one.)  You can define "limit" as (range_max.id() + 1)
+  // if necessary (which is not always a valid S2CellId but can still be used
+  // with FromToken/ToToken), or you can convert range_max() to the key space
+  // of your key-value store and define "limit" as Successor(key).
+  //
+  // Note that Sentinel().range_min() == Sentinel.range_max() == Sentinel().
+  S2CellId range_min() const;
+  S2CellId range_max() const;
+
+  // Return true if the given cell is contained within this one.
+  bool contains(S2CellId other) const;
+
+  // Return true if the given cell intersects this one.
+  bool intersects(S2CellId other) const;
+
+  // Return the cell at the previous level or at the given level (which must
+  // be less than or equal to the current level).
+  S2CellId parent() const;
+  S2CellId parent(int level) const;
+
+  // Return the immediate child of this cell at the given traversal order
+  // position (in the range 0 to 3).  This cell must not be a leaf cell.
+  S2CellId child(int position) const;
+
+  // Iterator-style methods for traversing the immediate children of a cell or
+  // all of the children at a given level (greater than or equal to the current
+  // level).  Note that the end value is exclusive, just like standard STL
+  // iterators, and may not even be a valid cell id.  You should iterate using
+  // code like this:
+  //
+  //   for(S2CellId c = id.child_begin(); c != id.child_end(); c = c.next())
+  //     ...
+  //
+  // The convention for advancing the iterator is "c = c.next()" rather
+  // than "++c" to avoid possible confusion with incrementing the
+  // underlying 64-bit cell id.
+  S2CellId child_begin() const;
+  S2CellId child_begin(int level) const;
+  S2CellId child_end() const;
+  S2CellId child_end(int level) const;
+
+  // Return the next/previous cell at the same level along the Hilbert curve.
+  // Works correctly when advancing from one face to the next, but
+  // does *not* wrap around from the last face to the first or vice versa.
+  S2CellId next() const;
+  S2CellId prev() const;
+
+  // This method advances or retreats the indicated number of steps along the
+  // Hilbert curve at the current level, and returns the new position.  The
+  // position is never advanced past End() or before Begin().
+  S2CellId advance(int64 steps) const;
+
+  // Returns the number of steps that this cell is from Begin(level()). The
+  // return value is always non-negative.
+  int64 distance_from_begin() const;
+
+  // Like next() and prev(), but these methods wrap around from the last face
+  // to the first and vice versa.  They should *not* be used for iteration in
+  // conjunction with child_begin(), child_end(), Begin(), or End().  The
+  // input must be a valid cell id.
+  S2CellId next_wrap() const;
+  S2CellId prev_wrap() const;
+
+  // This method advances or retreats the indicated number of steps along the
+  // Hilbert curve at the current level, and returns the new position.  The
+  // position wraps between the first and last faces as necessary.  The input
+  // must be a valid cell id.
+  S2CellId advance_wrap(int64 steps) const;
+
+  // Return the largest cell with the same range_min() and such that
+  // range_max() < limit.range_min().  Returns "limit" if no such cell exists.
+  // This method can be used to generate a small set of S2CellIds that covers
+  // a given range (a "tiling").  This example shows how to generate a tiling
+  // for a semi-open range of leaf cells [start, limit):
+  //
+  //   for (S2CellId id = start.maximum_tile(limit);
+  //        id != limit; id = id.next().maximum_tile(limit)) { ... }
+  //
+  // Note that in general the cells in the tiling will be of different sizes;
+  // they gradually get larger (near the middle of the range) and then
+  // gradually get smaller (as "limit" is approached).
+  S2CellId maximum_tile(S2CellId limit) const;
+
+  // Returns the level of the lowest common ancestor of this cell and "other",
+  // that is, the maximum level such that parent(level) == other.parent(level).
+  // Returns -1 if the two cells do not have any common ancestor (i.e., they
+  // are from different faces).
+  int GetCommonAncestorLevel(S2CellId other) const;
+
+  // Iterator-style methods for traversing all the cells along the Hilbert
+  // curve at a given level (across all 6 faces of the cube).  Note that the
+  // end value is exclusive (just like standard STL iterators), and is not a
+  // valid cell id.
+  static S2CellId Begin(int level);
+  static S2CellId End(int level);
+
+  // Methods to encode and decode cell ids to compact text strings suitable
+  // for display or indexing.  Cells at lower levels (i.e. larger cells) are
+  // encoded into fewer characters.  The maximum token length is 16.
+  //
+  // Tokens preserve ordering, i.e. ToToken(x) < ToToken(y) iff x < y.
+  //
+  // ToToken() returns a string by value for convenience; the compiler
+  // does this without intermediate copying in most cases.
+  //
+  // These methods guarantee that FromToken(ToToken(x)) == x even when
+  // "x" is an invalid cell id.  All tokens are alphanumeric strings.
+  // FromToken() returns S2CellId::None() for malformed inputs.
+  std::string ToToken() const;
+  static S2CellId FromToken(const char* token, size_t length);
+  static S2CellId FromToken(const std::string& token);
+
+  // Use encoder to generate a serialized representation of this cell id.
+  // Can also encode an invalid cell.
+  void Encode(Encoder* const encoder) const;
+
+  // Decodes an S2CellId encoded by Encode(). Returns true on success.
+  bool Decode(Decoder* const decoder);
+
+  // Creates a human readable debug string.  Used for << and available for
+  // direct usage as well.  The format is "f/dd..d" where "f" is a digit in
+  // the range [0-5] representing the S2CellId face, and "dd..d" is a string
+  // of digits in the range [0-3] representing each child's position with
+  // respect to its parent.  (Note that the latter string may be empty.)
+  //
+  // For example "4/" represents S2CellId::FromFace(4), and "3/02" represents
+  // S2CellId::FromFace(3).child(0).child(2).
+  std::string ToString() const;
+
+  // Converts a string in the format returned by ToString() to an S2CellId.
+  // Returns S2CellId::None() if the string could not be parsed.
+  //
+  // The method name includes "Debug" in order to avoid possible confusion
+  // with FromToken() above.
+  static S2CellId FromDebugString(absl::string_view str);
+
+  // Return the four cells that are adjacent across the cell's four edges.
+  // Neighbors are returned in the order defined by S2Cell::GetEdge.  All
+  // neighbors are guaranteed to be distinct.
+  void GetEdgeNeighbors(S2CellId neighbors[4]) const;
+
+  // Return the neighbors of closest vertex to this cell at the given level,
+  // by appending them to "output".  Normally there are four neighbors, but
+  // the closest vertex may only have three neighbors if it is one of the 8
+  // cube vertices.
+  //
+  // Requires: level < this->level(), so that we can determine which vertex is
+  // closest (in particular, level == kMaxLevel is not allowed).
+  void AppendVertexNeighbors(int level, std::vector<S2CellId>* output) const;
+
+  // Append all neighbors of this cell at the given level to "output".  Two
+  // cells X and Y are neighbors if their boundaries intersect but their
+  // interiors do not.  In particular, two cells that intersect at a single
+  // point are neighbors.  Note that for cells adjacent to a face vertex, the
+  // same neighbor may be appended more than once.
+  //
+  // REQUIRES: nbr_level >= this->level().
+  void AppendAllNeighbors(int nbr_level, std::vector<S2CellId>* output) const;
+
+  /////////////////////////////////////////////////////////////////////
+  // Low-level methods.
+
+  // Return a leaf cell given its cube face (range 0..5) and
+  // i- and j-coordinates (see s2coords.h).
+  static S2CellId FromFaceIJ(int face, int i, int j);
+
+  // Return the (face, i, j) coordinates for the leaf cell corresponding to
+  // this cell id.  Since cells are represented by the Hilbert curve position
+  // at the center of the cell, the returned (i,j) for non-leaf cells will be
+  // a leaf cell adjacent to the cell center.  If "orientation" is non-nullptr,
+  // also return the Hilbert curve orientation for the current cell.
+  int ToFaceIJOrientation(int* pi, int* pj, int* orientation) const;
+
+  // Return the lowest-numbered bit that is on for this cell id, which is
+  // equal to (uint64{1} << (2 * (kMaxLevel - level))).  So for example,
+  // a.lsb() <= b.lsb() if and only if a.level() >= b.level(), but the
+  // first test is more efficient.
+  uint64 lsb() const { return id_ & (~id_ + 1); }
+
+  // Return the lowest-numbered bit that is on for cells at the given level.
+  static uint64 lsb_for_level(int level) {
+    return uint64{1} << (2 * (kMaxLevel - level));
+  }
+
+  // Return the bound in (u,v)-space for the cell at the given level containing
+  // the leaf cell with the given (i,j)-coordinates.
+  static R2Rect IJLevelToBoundUV(int ij[2], int level);
+
+  // When S2CellId is used as a key in one of the btree container types
+  // (util/btree), indicate that linear rather than binary search should be
+  // used.  This is much faster when the comparison function is cheap.
+  typedef std::true_type absl_btree_prefer_linear_node_search;
+
+ private:
+  // This is the offset required to wrap around from the beginning of the
+  // Hilbert curve to the end or vice versa; see next_wrap() and prev_wrap().
+  // SWIG doesn't understand uint64{}, so use static_cast.
+  static const uint64 kWrapOffset = static_cast<uint64>(kNumFaces) << kPosBits;
+
+  // Given a face and a point (i,j) where either i or j is outside the valid
+  // range [0..kMaxSize-1], this function first determines which neighboring
+  // face "contains" (i,j), and then returns the leaf cell on that face which
+  // is adjacent to the given face and whose distance from (i,j) is minimal.
+  static S2CellId FromFaceIJWrap(int face, int i, int j);
+
+  // Inline helper function that calls FromFaceIJ if "same_face" is true,
+  // or FromFaceIJWrap if "same_face" is false.
+  static S2CellId FromFaceIJSame(int face, int i, int j, bool same_face);
+
+  uint64 id_;
+} ABSL_ATTRIBUTE_PACKED;  // Necessary so that structures containing S2CellId's
+                          // can be ABSL_ATTRIBUTE_PACKED.
+
+inline bool operator==(S2CellId x, S2CellId y) {
+  return x.id() == y.id();
+}
+
+inline bool operator!=(S2CellId x, S2CellId y) {
+  return x.id() != y.id();
+}
+
+inline bool operator<(S2CellId x, S2CellId y) {
+  return x.id() < y.id();
+}
+
+inline bool operator>(S2CellId x, S2CellId y) {
+  return x.id() > y.id();
+}
+
+inline bool operator<=(S2CellId x, S2CellId y) {
+  return x.id() <= y.id();
+}
+
+inline bool operator>=(S2CellId x, S2CellId y) {
+  return x.id() >= y.id();
+}
+
+inline S2CellId S2CellId::FromFace(int face) {
+  return S2CellId((static_cast<uint64>(face) << kPosBits) + lsb_for_level(0));
+}
+
+inline S2CellId S2CellId::FromFacePosLevel(int face, uint64 pos, int level) {
+  S2CellId cell((static_cast<uint64>(face) << kPosBits) + (pos | 1));
+  return cell.parent(level);
+}
+
+inline int S2CellId::GetCenterSiTi(int* psi, int* pti) const {
+  // First we compute the discrete (i,j) coordinates of a leaf cell contained
+  // within the given cell.  Given that cells are represented by the Hilbert
+  // curve position corresponding at their center, it turns out that the cell
+  // returned by ToFaceIJOrientation is always one of two leaf cells closest
+  // to the center of the cell (unless the given cell is a leaf cell itself,
+  // in which case there is only one possibility).
+  //
+  // Given a cell of size s >= 2 (i.e. not a leaf cell), and letting (imin,
+  // jmin) be the coordinates of its lower left-hand corner, the leaf cell
+  // returned by ToFaceIJOrientation() is either (imin + s/2, jmin + s/2)
+  // (imin + s/2 - 1, jmin + s/2 - 1).  The first case is the one we want.
+  // We can distinguish these two cases by looking at the low bit of "i" or
+  // "j".  In the second case the low bit is one, unless s == 2 (i.e. the
+  // level just above leaf cells) in which case the low bit is zero.
+  //
+  // In the code below, the expression ((i ^ (int(id_) >> 2)) & 1) is true
+  // if we are in the second case described above.
+  int i, j;
+  int face = ToFaceIJOrientation(&i, &j, nullptr);
+  int delta = is_leaf() ? 1 : ((i ^ (static_cast<int>(id_) >> 2)) & 1) ? 2 : 0;
+
+  // Note that (2 * {i,j} + delta) will never overflow a 32-bit integer.
+  *psi = 2 * i + delta;
+  *pti = 2 * j + delta;
+  return face;
+}
+
+inline bool S2CellId::is_valid() const {
+  return (face() < kNumFaces && (lsb() & 0x1555555555555555ULL));
+}
+
+inline int S2CellId::face() const {
+  return id_ >> kPosBits;
+}
+
+inline uint64 S2CellId::pos() const {
+  return id_ & (~uint64{0} >> kFaceBits);
+}
+
+inline int S2CellId::level() const {
+  // We can't just S2_DCHECK(is_valid()) because we want level() to be
+  // defined for end-iterators, i.e. S2CellId::End(kLevel).  However there is
+  // no good way to define S2CellId::None().level(), so we do prohibit that.
+  S2_DCHECK(id_ != 0);
+
+  // A special case for leaf cells is not worthwhile.
+  return kMaxLevel - (Bits::FindLSBSetNonZero64(id_) >> 1);
+}
+
+inline int S2CellId::GetSizeIJ() const {
+  return GetSizeIJ(level());
+}
+
+inline double S2CellId::GetSizeST() const {
+  return GetSizeST(level());
+}
+
+inline int S2CellId::GetSizeIJ(int level) {
+  return 1 << (kMaxLevel - level);
+}
+
+inline double S2CellId::GetSizeST(int level) {
+  return S2::IJtoSTMin(GetSizeIJ(level));
+}
+
+inline bool S2CellId::is_leaf() const {
+  return int(id_) & 1;
+}
+
+inline bool S2CellId::is_face() const {
+  return (id_ & (lsb_for_level(0) - 1)) == 0;
+}
+
+inline int S2CellId::child_position() const {
+  // No need for a special implementation; the compiler optimizes this well.
+  return child_position(level());
+}
+
+inline int S2CellId::child_position(int level) const {
+  S2_DCHECK(is_valid());
+  S2_DCHECK_GE(level, 1);
+  S2_DCHECK_LE(level, this->level());
+  return static_cast<int>(id_ >> (2 * (kMaxLevel - level) + 1)) & 3;
+}
+
+inline S2CellId S2CellId::range_min() const {
+  return S2CellId(id_ - (lsb() - 1));
+}
+
+inline S2CellId S2CellId::range_max() const {
+  return S2CellId(id_ + (lsb() - 1));
+}
+
+inline bool S2CellId::contains(S2CellId other) const {
+  S2_DCHECK(is_valid());
+  S2_DCHECK(other.is_valid());
+  return other >= range_min() && other <= range_max();
+}
+
+inline bool S2CellId::intersects(S2CellId other) const {
+  S2_DCHECK(is_valid());
+  S2_DCHECK(other.is_valid());
+  return other.range_min() <= range_max() && other.range_max() >= range_min();
+}
+
+inline S2CellId S2CellId::parent(int level) const {
+  S2_DCHECK(is_valid());
+  S2_DCHECK_GE(level, 0);
+  S2_DCHECK_LE(level, this->level());
+  uint64 new_lsb = lsb_for_level(level);
+  return S2CellId((id_ & (~new_lsb + 1)) | new_lsb);
+}
+
+inline S2CellId S2CellId::parent() const {
+  S2_DCHECK(is_valid());
+  S2_DCHECK(!is_face());
+  uint64 new_lsb = lsb() << 2;
+  return S2CellId((id_ & (~new_lsb + 1)) | new_lsb);
+}
+
+inline S2CellId S2CellId::child(int position) const {
+  S2_DCHECK(is_valid());
+  S2_DCHECK(!is_leaf());
+  // To change the level, we need to move the least-significant bit two
+  // positions downward.  We do this by subtracting (4 * new_lsb) and adding
+  // new_lsb.  Then to advance to the given child cell, we add
+  // (2 * position * new_lsb).
+  uint64 new_lsb = lsb() >> 2;
+  return S2CellId(id_ + (2 * position + 1 - 4) * new_lsb);
+}
+
+inline S2CellId S2CellId::child_begin() const {
+  S2_DCHECK(is_valid());
+  S2_DCHECK(!is_leaf());
+  uint64 old_lsb = lsb();
+  return S2CellId(id_ - old_lsb + (old_lsb >> 2));
+}
+
+inline S2CellId S2CellId::child_begin(int level) const {
+  S2_DCHECK(is_valid());
+  S2_DCHECK_GE(level, this->level());
+  S2_DCHECK_LE(level, kMaxLevel);
+  return S2CellId(id_ - lsb() + lsb_for_level(level));
+}
+
+inline S2CellId S2CellId::child_end() const {
+  S2_DCHECK(is_valid());
+  S2_DCHECK(!is_leaf());
+  uint64 old_lsb = lsb();
+  return S2CellId(id_ + old_lsb + (old_lsb >> 2));
+}
+
+inline S2CellId S2CellId::child_end(int level) const {
+  S2_DCHECK(is_valid());
+  S2_DCHECK_GE(level, this->level());
+  S2_DCHECK_LE(level, kMaxLevel);
+  return S2CellId(id_ + lsb() + lsb_for_level(level));
+}
+
+inline S2CellId S2CellId::next() const {
+  return S2CellId(id_ + (lsb() << 1));
+}
+
+inline S2CellId S2CellId::prev() const {
+  return S2CellId(id_ - (lsb() << 1));
+}
+
+inline S2CellId S2CellId::next_wrap() const {
+  S2_DCHECK(is_valid());
+  S2CellId n = next();
+  if (n.id_ < kWrapOffset) return n;
+  return S2CellId(n.id_ - kWrapOffset);
+}
+
+inline S2CellId S2CellId::prev_wrap() const {
+  S2_DCHECK(is_valid());
+  S2CellId p = prev();
+  if (p.id_ < kWrapOffset) return p;
+  return S2CellId(p.id_ + kWrapOffset);
+}
+
+inline S2CellId S2CellId::Begin(int level) {
+  return FromFace(0).child_begin(level);
+}
+
+inline S2CellId S2CellId::End(int level) {
+  return FromFace(5).child_end(level);
+}
+
+std::ostream& operator<<(std::ostream& os, S2CellId id);
+
+// Hasher for S2CellId.
+// Example use: std::unordered_map<S2CellId, int, S2CellIdHash>.
+struct S2CellIdHash {
+  size_t operator()(S2CellId id) const {
+    return std::hash<uint64>()(id.id());
+  }
+};
+
+#undef IFNDEF_SWIG
+
+#endif  // S2_S2CELL_ID_H_
diff --git a/src/s2/s2cell_index.cc b/src/s2/s2cell_index.cc
new file mode 100644 (file)
index 0000000..ce3e8cb
--- /dev/null
@@ -0,0 +1,149 @@
+// Copyright 2018 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// Author: ericv@google.com (Eric Veach)
+
+#include "s2/s2cell_index.h"
+
+using std::vector;
+
+using Label = S2CellIndex::Label;
+
+void S2CellIndex::RangeIterator::Seek(S2CellId target) {
+  S2_DCHECK(target.is_leaf());
+  it_ = std::upper_bound(range_nodes_->begin(), range_nodes_->end(),
+                         target) - 1;
+}
+
+void S2CellIndex::ContentsIterator::StartUnion(const RangeIterator& range) {
+  if (range.start_id() < prev_start_id_) {
+    node_cutoff_ = -1;  // Can't automatically eliminate duplicates.
+  }
+  prev_start_id_ = range.start_id();
+
+  // TODO(ericv): Since RangeNode only uses 12 of its 16 bytes, we could add a
+  // "label" field without using any extra space.  Then we could store a leaf
+  // node of cell_tree_ directly in each RangeNode, where the cell_id is
+  // implicitly defined as the one that covers the current leaf cell range.
+  // This would save quite a bit of space; e.g. if the given cells are
+  // non-overlapping, then cell_tree_ would be empty (since every node is a
+  // leaf node and could therefore be stored directly in a RangeNode).  It
+  // would also be faster because cell_tree_ would rarely be accessed.
+  int contents = range.it_->contents;
+  if (contents <= node_cutoff_) {
+    set_done();
+  } else {
+    node_ = (*cell_tree_)[contents];
+  }
+
+  // When visiting ancestors, we can stop as soon as the node index is smaller
+  // than any previously visited node index.  Because indexes are assigned
+  // using a preorder traversal, such nodes are guaranteed to have already
+  // been reported.
+  next_node_cutoff_ = contents;
+}
+
+S2CellIndex::S2CellIndex() {
+}
+
+void S2CellIndex::Add(const S2CellUnion& cell_ids, Label label) {
+  for (S2CellId cell_id : cell_ids) {
+    Add(cell_id, label);
+  }
+}
+
+void S2CellIndex::Build() {
+  // To build the cell tree and leaf cell ranges, we maintain a stack of
+  // (cell_id, label) pairs that contain the current leaf cell.  This class
+  // represents an instruction to push or pop a (cell_id, label) pair.
+  //
+  // If label >= 0, the (cell_id, label) pair is pushed on the stack.
+  // If cell_id == S2CellId::Sentinel(), a pair is popped from the stack.
+  // Otherwise the stack is unchanged but a RangeNode is still emitted.
+  struct Delta {
+    S2CellId start_id, cell_id;
+    Label label;
+
+    Delta(S2CellId _start_id, S2CellId _cell_id, Label _label)
+        : start_id(_start_id), cell_id(_cell_id), label(_label) {}
+
+    // Deltas are sorted first by start_id, then in reverse order by cell_id,
+    // and then by label.  This is necessary to ensure that (1) larger cells
+    // are pushed on the stack before smaller cells, and (2) cells are popped
+    // off the stack before any new cells are added.
+    bool operator<(const Delta& y) const {
+      if (start_id < y.start_id) return true;
+      if (y.start_id < start_id) return false;
+      if (y.cell_id < cell_id) return true;
+      if (cell_id < y.cell_id) return false;
+      return label < y.label;
+    }
+  };
+
+  vector<Delta> deltas;
+  deltas.reserve(2 * cell_tree_.size() + 2);
+  // Create two deltas for each (cell_id, label) pair: one to add the pair to
+  // the stack (at the start of its leaf cell range), and one to remove it from
+  // the stack (at the end of its leaf cell range).
+  for (const CellNode& node : cell_tree_) {
+    deltas.push_back(Delta(node.cell_id.range_min(), node.cell_id, node.label));
+    deltas.push_back(Delta(node.cell_id.range_max().next(),
+                           S2CellId::Sentinel(), -1));
+  }
+  // We also create two special deltas to ensure that a RangeNode is emitted at
+  // the beginning and end of the S2CellId range.
+  deltas.push_back(
+      Delta(S2CellId::Begin(S2CellId::kMaxLevel), S2CellId::None(), -1));
+  deltas.push_back(
+      Delta(S2CellId::End(S2CellId::kMaxLevel), S2CellId::None(), -1));
+  std::sort(deltas.begin(), deltas.end());
+
+  // Now walk through the deltas to build the leaf cell ranges and cell tree
+  // (which is essentially a permanent form of the "stack" described above).
+  cell_tree_.clear();
+  range_nodes_.reserve(deltas.size());
+  int contents = -1;
+  for (int i = 0; i < deltas.size(); ) {
+    S2CellId start_id = deltas[i].start_id;
+    // Process all the deltas associated with the current start_id.
+    for (; i < deltas.size() && deltas[i].start_id == start_id; ++i) {
+      if (deltas[i].label >= 0) {
+        cell_tree_.push_back({deltas[i].cell_id, deltas[i].label, contents});
+        contents = cell_tree_.size() - 1;
+      } else if (deltas[i].cell_id == S2CellId::Sentinel()) {
+        contents = cell_tree_[contents].parent;
+      }
+    }
+    range_nodes_.push_back({start_id, contents});
+  }
+}
+
+vector<Label> S2CellIndex::GetIntersectingLabels(const S2CellUnion& target)
+    const {
+  vector<Label> labels;
+  GetIntersectingLabels(target, &labels);
+  return labels;
+}
+
+void S2CellIndex::GetIntersectingLabels(const S2CellUnion& target,
+                                        std::vector<Label>* labels) const {
+  labels->clear();
+  VisitIntersectingCells(target, [labels](S2CellId cell_id, Label label) {
+      labels->push_back(label);
+      return true;
+    });
+  std::sort(labels->begin(), labels->end());
+  labels->erase(std::unique(labels->begin(), labels->end()), labels->end());
+}
diff --git a/src/s2/s2cell_index.h b/src/s2/s2cell_index.h
new file mode 100644 (file)
index 0000000..d47178b
--- /dev/null
@@ -0,0 +1,660 @@
+// Copyright 2018 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// Author: ericv@google.com (Eric Veach)
+
+#ifndef S2_S2CELL_INDEX_H_
+#define S2_S2CELL_INDEX_H_
+
+#include <vector>
+#include "s2/base/integral_types.h"
+#include "s2/base/logging.h"
+#include "s2/s2cell_id.h"
+#include "s2/s2cell_union.h"
+
+// S2CellIndex stores a collection of (cell_id, label) pairs.  The S2CellIds
+// may be overlapping or contain duplicate values.  For example, an
+// S2CellIndex could store a collection of S2CellUnions, where each
+// S2CellUnion has its own label.
+//
+// Labels are 32-bit non-negative integers, and are typically used to map the
+// results of queries back to client data structures.  Labels other than
+// integers can be supported by using a ValueLexicon, which maintains a set of
+// distinct labels and maps them to sequentially numbered integers.  For
+// example, the following code uses strings as labels:
+//
+//   ValueLexicon<string> my_label_lexicon;
+//   string label_str = ...;
+//   cell_index.Add(cell_id, my_label_lexicon.Add(label_str));
+//   ...
+//   int32 label = ...;
+//   string label_str = my_label_lexicon.value(label);
+//
+// To build an S2CellIndex, call Add() for each (cell_id, label) pair, and
+// then call the Build() method.  For example:
+//
+//   vector<S2CellId> contents = ...;
+//   for (int i = 0; i < contents.size(); ++i) {
+//     index.Add(contents[i], i /*label*/);
+//   }
+//   index.Build();
+//
+// There is also a convenience method that adds an S2CellUnion:
+//
+//     index.Add(cell_union, label);
+//
+// Note that the index is not dynamic; the contents of the index cannot be
+// changed once it has been built.
+//
+// There are several options for retrieving data from the index.  The simplest
+// is to use a built-in method such as GetIntersectingLabels (which returns
+// the labels of all cells that intersect a given target S2CellUnion):
+//
+//   vector<Label> labels = index.GetIntersectingLabels(target_union);
+//
+// Alternatively, you can use an external class such as S2ClosestCellQuery,
+// which computes the cell(s) that are closest to a given target geometry.
+// For example, here is how to find all cells that are closer than
+// "distance_limit" to a given target point:
+//
+//   S2ClosestCellQuery query(&index);
+//   query.mutable_options()->set_max_distance(distance_limit);
+//   S2ClosestCellQuery::PointTarget target(target_point);
+//   for (const auto& result : query.FindClosestCells(&target)) {
+//     // result.distance() is the distance to the target.
+//     // result.cell_id() is the indexed S2CellId.
+//     // result.label() is the integer label associated with the S2CellId.
+//     DoSomething(target_point, result);
+//   }
+//
+// Finally, you can access the index contents directly.  Internally, the index
+// consists of a set of non-overlapping leaf cell ranges that subdivide the
+// sphere and such that each range intersects a particular set of (cell_id,
+// label) pairs.  Data is accessed using the following iterator types:
+//
+//   RangeIterator:
+//    - used to seek and iterate over the non-overlapping leaf cell ranges.
+//   NonEmptyRangeIterator:
+//    - like RangeIterator, but skips ranges whose contents are empty.
+//   ContentsIterator:
+//    - iterates over the (cell_id, label) pairs that intersect a given range.
+//   CellIterator:
+//    - iterates over the entire set of (cell_id, label) pairs.
+//
+// Note that these are low-level, efficient types intended mainly for
+// implementing new query classes.  Most clients should use either the
+// built-in methods such as VisitIntersectingCells and GetIntersectingLabels,
+// or a helper such as S2ClosestCellQuery or S2Closest*Query::CellUnionTarget.
+class S2CellIndex {
+ public:
+  // Labels are 32-bit non-negative integers.  To support other label types,
+  // you can use ValueLexicon to map label values to integers:
+  //
+  //   ValueLexicon<MyLabel> my_label_lexicon;
+  //   index.Add(cell_id, my_label_lexicon.Add(label));
+  using Label = int32;
+
+  // Convenience class that represents a (cell_id, label) pair.
+  struct LabelledCell {
+    S2CellId cell_id;
+    Label label;
+
+    LabelledCell() : cell_id(S2CellId::None()), label(-1) {}
+
+    LabelledCell(S2CellId _cell_id, Label _label)
+        : cell_id(_cell_id), label(_label) {}
+
+    bool operator==(LabelledCell y) const {
+      return cell_id == y.cell_id && label == y.label;
+    }
+
+    bool operator<(LabelledCell y) const {
+      if (cell_id < y.cell_id) return true;
+      if (y.cell_id < cell_id) return false;
+      return label < y.label;
+    }
+  };
+
+  // Default constructor.
+  S2CellIndex();
+
+  // Returns the number of (cell_id, label) pairs in the index.
+  int num_cells() const;
+
+  // Adds the given (cell_id, label) pair to the index.  Note that the index
+  // is not valid until Build() is called.
+  //
+  // The S2CellIds in the index may overlap (including duplicate values).
+  // Duplicate (cell_id, label) pairs are also allowed, although be aware that
+  // S2ClosestCellQuery will eliminate such duplicates anyway.
+  //
+  // REQUIRES: cell_id.is_valid()
+  void Add(S2CellId cell_id, Label label);
+
+  // Convenience function that adds a collection of cells with the same label.
+  void Add(const S2CellUnion& cell_ids, Label label);
+
+  // Constructs the index.  This method may only be called once.  No iterators
+  // may be used until the index is built.
+  void Build();
+
+  // Clears the index so that it can be re-used.
+  void Clear();
+
+  // A function that is called with each (cell_id, label) pair to be visited.
+  // The function may return false in order to indicate that no further
+  // (cell_id, label) pairs are needed.
+  using CellVisitor = std::function<bool (S2CellId cell_id, Label label)>;
+
+  // Visits all (cell_id, label) pairs in the given index that intersect the
+  // given S2CellUnion "target", terminating early if the given CellVisitor
+  // function returns false (in which case VisitIntersectingCells returns false
+  // as well).  Each (cell_id, label) pair in the index is visited at most
+  // once.  (If the index contains duplicates, then each copy is visited.)
+  bool VisitIntersectingCells(const S2CellUnion& target,
+                              const CellVisitor& visitor) const;
+
+  // Convenience function that returns the labels of all indexed cells that
+  // intersect the given S2CellUnion "target".  The output contains each label
+  // at most once, but is not sorted.
+  std::vector<Label> GetIntersectingLabels(const S2CellUnion& target) const;
+
+  // This version can be more efficient when it is called many times, since it
+  // does not require allocating a new vector on each call.
+  void GetIntersectingLabels(const S2CellUnion& target,
+                             std::vector<Label>* labels) const;
+
+ private:
+  // Represents a node in the set of non-overlapping leaf cell ranges.
+  struct RangeNode;
+
+  // A special label indicating that ContentsIterator::done() is true.
+  static Label constexpr kDoneContents = -1;
+
+  // Represents a node in the (cell_id, label) tree.  Cells are organized in a
+  // tree such that the ancestors of a given node contain that node.
+  struct CellNode {
+    S2CellId cell_id;
+    Label label;
+    int32 parent;
+
+    CellNode(S2CellId _cell_id, Label _label, int32 _parent)
+        : cell_id(_cell_id), label(_label), parent(_parent) {
+    }
+    CellNode() : cell_id(S2CellId::None()), label(kDoneContents), parent(-1) {}
+  };
+
+ public:
+  class ContentsIterator;
+
+  // An iterator that visits the entire set of indexed (cell_id, label) pairs
+  // in an unspecified order.
+  class CellIterator {
+   public:
+    // Initializes a CellIterator for the given S2CellIndex, positioned at the
+    // first cell (if any).
+    explicit CellIterator(const S2CellIndex* index);
+
+    // The S2CellId of the current (cell_id, label) pair.
+    // REQUIRES: !done()
+    S2CellId cell_id() const;
+
+    // The Label of the current (cell_id, label) pair.
+    // REQUIRES: !done()
+    Label label() const;
+
+    // Returns the current (cell_id, label) pair.
+    LabelledCell labelled_cell() const;
+
+    // Returns true if all (cell_id, label) pairs have been visited.
+    bool done() const;
+
+    // Advances the iterator to the next (cell_id, label) pair.
+    // REQUIRES: !done()
+    void Next();
+
+   private:
+    // NOTE(ericv): There is a potential optimization that would require this
+    // class to iterate over both cell_tree_ *and* range_nodes_.
+    std::vector<CellNode>::const_iterator cell_it_, cell_end_;
+  };
+
+  // An iterator that seeks and iterates over a set of non-overlapping leaf
+  // cell ranges that cover the entire sphere.  The indexed (s2cell_id, label)
+  // pairs that intersect the current leaf cell range can be visited using
+  // ContentsIterator (see below).
+  class RangeIterator {
+   public:
+    // Initializes a RangeIterator for the given S2CellIndex.  The iterator is
+    // initially *unpositioned*; you must call a positioning method such as
+    // Begin() or Seek() before accessing its contents.
+    explicit RangeIterator(const S2CellIndex* index);
+
+    // The start of the current range of leaf S2CellIds.
+    //
+    // If done() is true, returns S2CellId::End(S2CellId::kMaxLevel).  This
+    // property means that most loops do not need to test done() explicitly.
+    S2CellId start_id() const;
+
+    // The (non-inclusive) end of the current range of leaf S2CellIds.
+    // REQUIRES: !done()
+    S2CellId limit_id() const;
+
+    // Returns true if the iterator is positioned beyond the last valid range.
+    bool done() const;
+
+    // Positions the iterator at the first range of leaf cells (if any).
+    void Begin();
+
+    // Positions the iterator so that done() is true.
+    void Finish();
+
+    // Advances the iterator to the next range of leaf cells.
+    // REQUIRES: !done()
+    void Next();
+
+    // If the iterator is already positioned at the beginning, returns false.
+    // Otherwise positions the iterator at the previous entry and returns true.
+    bool Prev();
+
+    // Positions the iterator at the first range with start_id() >= target.
+    // (Such an entry always exists as long as "target" is a valid leaf cell.
+    // Note that it is valid to access start_id() even when done() is true.)
+    //
+    // REQUIRES: target.is_leaf()
+    void Seek(S2CellId target);
+
+    // Returns true if no (s2cell_id, label) pairs intersect this range.
+    // Also returns true if done() is true.
+    bool is_empty() const;
+
+    // If advancing the iterator "n" times would leave it positioned on a
+    // valid range, does so and returns true.  Otherwise leaves the iterator
+    // unmodified and returns false.
+    bool Advance(int n);
+
+   private:
+    // A special value used to indicate that the RangeIterator has not yet
+    // been initialized by calling Begin() or Seek().
+    std::vector<RangeNode>::const_iterator kUninitialized() const {
+      // Note that since the last element of range_nodes_ is a sentinel value,
+      // it_ will never legitimately be positioned at range_nodes_->end().
+      return range_nodes_->end();
+    }
+
+    friend class ContentsIterator;
+    const std::vector<RangeNode>* range_nodes_;
+    std::vector<RangeNode>::const_iterator it_;
+  };
+
+  // Like RangeIterator, but only visits leaf cell ranges that overlap at
+  // least one (cell_id, label) pair.
+  class NonEmptyRangeIterator : public RangeIterator {
+   public:
+    // Initializes a NonEmptyRangeIterator for the given S2CellIndex.
+    // The iterator is initially *unpositioned*; you must call a positioning
+    // method such as Begin() or Seek() before accessing its contents.
+    explicit NonEmptyRangeIterator(const S2CellIndex* index);
+
+    // Positions the iterator at the first non-empty range of leaf cells.
+    void Begin();
+
+    // Advances the iterator to the next non-empty range of leaf cells.
+    // REQUIRES: !done()
+    void Next();
+
+    // If the iterator is already positioned at the beginning, returns false.
+    // Otherwise positions the iterator at the previous entry and returns true.
+    bool Prev();
+
+    // Positions the iterator at the first non-empty range with
+    // start_id() >= target.
+    //
+    // REQUIRES: target.is_leaf()
+    void Seek(S2CellId target);
+  };
+
+  // An iterator that visits the (cell_id, label) pairs that cover a set of
+  // leaf cell ranges (see RangeIterator).  Note that when multiple leaf cell
+  // ranges are visited, this class only guarantees that each result will be
+  // reported at least once, i.e. duplicate values may be suppressed.  If you
+  // want duplicate values to be reported again, be sure to call Clear() first.
+  //
+  // [In particular, the implementation guarantees that when multiple leaf
+  // cell ranges are visited in monotonically increasing order, then each
+  // (cell_id, label) pair is reported exactly once.]
+  class ContentsIterator {
+   public:
+    // Default constructor; must be followed by a call to Init().
+    ContentsIterator();
+
+    // Convenience constructor that calls Init().
+    explicit ContentsIterator(const S2CellIndex* index);
+
+    // Initializes the iterator.  Should be followed by a call to UnionWith()
+    // to visit the contents of each desired leaf cell range.
+    void Init(const S2CellIndex* index);
+
+    // Clears all state with respect to which range(s) have been visited.
+    void Clear();
+
+    // Positions the ContentsIterator at the first (cell_id, label) pair that
+    // covers the given leaf cell range.  Note that when multiple leaf cell
+    // ranges are visited using the same ContentsIterator, duplicate values
+    // may be suppressed.  If you don't want this behavior, call Clear() first.
+    void StartUnion(const RangeIterator& range);
+
+    // The S2CellId of the current (cell_id, label) pair.
+    // REQUIRES: !done()
+    S2CellId cell_id() const;
+
+    // The Label of the current (cell_id, label) pair.
+    // REQUIRES: !done()
+    Label label() const;
+
+    // Returns the current (cell_id, label) pair.
+    // REQUIRES: !done()
+    LabelledCell labelled_cell() const;
+
+    // Returns true if all (cell_id, label) pairs have been visited.
+    bool done() const;
+
+    // Advances the iterator to the next (cell_id, label) pair covered by the
+    // current leaf cell range.
+    // REQUIRES: !done()
+    void Next();
+
+   private:
+    // node_.label == kDoneContents indicates that done() is true.
+    void set_done() { node_.label = kDoneContents; }
+
+    // A pointer to the cell tree itself (owned by the S2CellIndex).
+    const std::vector<CellNode>* cell_tree_;
+
+    // The value of it.start_id() from the previous call to StartUnion().
+    // This is used to check whether these values are monotonically
+    // increasing.
+    S2CellId prev_start_id_;
+
+    // The maximum index within the cell_tree_ vector visited during the
+    // previous call to StartUnion().  This is used to eliminate duplicate
+    // values when StartUnion() is called multiple times.
+    int32 node_cutoff_;
+
+    // The maximum index within the cell_tree_ vector visited during the
+    // current call to StartUnion().  This is used to update node_cutoff_.
+    int32 next_node_cutoff_;
+
+    // A copy of the current node in the cell tree.
+    CellNode node_;
+  };
+
+ private:
+  friend class CellIterator;
+  friend class RangeIterator;
+  friend class ContentsIterator;
+
+  // A tree of (cell_id, label) pairs such that if X is an ancestor of Y, then
+  // X.cell_id contains Y.cell_id.  The contents of a given range of leaf
+  // cells can be represented by pointing to a node of this tree.
+  std::vector<CellNode> cell_tree_;
+
+  // A RangeNode represents a range of leaf S2CellIds.  The range starts at
+  // "start_id" (a leaf cell) and ends at the "start_id" field of the next
+  // RangeNode.  "contents" points to the node of cell_tree_ representing the
+  // cells that overlap this range.
+  struct RangeNode {
+    S2CellId start_id;  // First leaf cell contained by this range.
+    int32 contents;     // Contents of this node (an index within cell_tree_).
+
+    RangeNode(S2CellId _start_id, int32 _contents)
+        : start_id(_start_id), contents(_contents) {
+    }
+
+    // Comparison operator needed for std::upper_bound().
+    friend bool operator<(S2CellId x, const RangeNode& y) {
+      return x < y.start_id;
+    }
+  };
+  // The last element of range_nodes_ is a sentinel value, which is necessary
+  // in order to represent the range covered by the previous element.
+  std::vector<RangeNode> range_nodes_;
+
+  S2CellIndex(const S2CellIndex&) = delete;
+  void operator=(const S2CellIndex&) = delete;
+};
+std::ostream& operator<<(std::ostream& os, S2CellIndex::LabelledCell x);
+
+//////////////////   Implementation details follow   ////////////////////
+
+
+inline S2CellIndex::CellIterator::CellIterator(const S2CellIndex* index)
+    : cell_it_(index->cell_tree_.begin()),
+      cell_end_(index->cell_tree_.end()) {
+  S2_DCHECK(!index->range_nodes_.empty()) << "Call Build() first.";
+}
+
+inline S2CellId S2CellIndex::CellIterator::cell_id() const {
+  S2_DCHECK(!done());
+  return cell_it_->cell_id;
+}
+
+inline S2CellIndex::Label S2CellIndex::CellIterator::label() const {
+  S2_DCHECK(!done());
+  return cell_it_->label;
+}
+
+inline S2CellIndex::LabelledCell S2CellIndex::CellIterator::labelled_cell()
+    const {
+  S2_DCHECK(!done());
+  return LabelledCell(cell_it_->cell_id, cell_it_->label);
+}
+
+inline bool S2CellIndex::CellIterator::done() const {
+  return cell_it_ == cell_end_;
+}
+
+inline void S2CellIndex::CellIterator::Next() {
+  S2_DCHECK(!done());
+  ++cell_it_;
+}
+
+inline S2CellIndex::RangeIterator::RangeIterator(const S2CellIndex* index)
+    : range_nodes_(&index->range_nodes_), it_() {
+  S2_DCHECK(!range_nodes_->empty()) << "Call Build() first.";
+  if (google::DEBUG_MODE) it_ = kUninitialized();  // See done().
+}
+
+inline S2CellId S2CellIndex::RangeIterator::start_id() const {
+  return it_->start_id;
+}
+
+inline S2CellId S2CellIndex::RangeIterator::limit_id() const {
+  S2_DCHECK(!done());
+  return (it_ + 1)->start_id;
+}
+
+inline bool S2CellIndex::RangeIterator::done() const {
+  S2_DCHECK(it_ != kUninitialized()) << "Call Begin() or Seek() first.";
+
+  // Note that the last element of range_nodes_ is a sentinel value.
+  return it_ >= range_nodes_->end() - 1;
+}
+
+inline void S2CellIndex::RangeIterator::Begin() {
+  it_ = range_nodes_->begin();
+}
+
+inline void S2CellIndex::RangeIterator::Finish() {
+  // Note that the last element of range_nodes_ is a sentinel value.
+  it_ = range_nodes_->end() - 1;
+}
+
+inline void S2CellIndex::RangeIterator::Next() {
+  S2_DCHECK(!done());
+  ++it_;
+}
+
+inline bool S2CellIndex::RangeIterator::is_empty() const {
+  return it_->contents == kDoneContents;
+}
+
+inline bool S2CellIndex::RangeIterator::Advance(int n) {
+  // Note that the last element of range_nodes_ is a sentinel value.
+  if (n >= range_nodes_->end() - 1 - it_) return false;
+  it_ += n;
+  return true;
+}
+
+inline S2CellIndex::NonEmptyRangeIterator::NonEmptyRangeIterator(
+    const S2CellIndex* index)
+    : RangeIterator(index) {
+}
+
+inline void S2CellIndex::NonEmptyRangeIterator::Begin() {
+  RangeIterator::Begin();
+  while (is_empty() && !done()) RangeIterator::Next();
+}
+
+inline void S2CellIndex::NonEmptyRangeIterator::Next() {
+  do {
+    RangeIterator::Next();
+  } while (is_empty() && !done());
+}
+
+inline bool S2CellIndex::NonEmptyRangeIterator::Prev() {
+  while (RangeIterator::Prev()) {
+    if (!is_empty()) return true;
+  }
+  // Return the iterator to its original position.
+  if (is_empty() && !done()) Next();
+  return false;
+}
+
+inline void S2CellIndex::NonEmptyRangeIterator::Seek(S2CellId target) {
+  RangeIterator::Seek(target);
+  while (is_empty() && !done()) RangeIterator::Next();
+}
+
+inline bool S2CellIndex::RangeIterator::Prev() {
+  if (it_ == range_nodes_->begin()) return false;
+  --it_;
+  return true;
+}
+
+inline S2CellIndex::ContentsIterator::ContentsIterator()
+    : cell_tree_(nullptr) {
+}
+
+inline S2CellIndex::ContentsIterator::ContentsIterator(
+    const S2CellIndex* index) {
+    Init(index);
+}
+
+inline void S2CellIndex::ContentsIterator::Init(const S2CellIndex* index) {
+  cell_tree_ = &index->cell_tree_;
+  Clear();
+}
+
+inline void S2CellIndex::ContentsIterator::Clear() {
+  prev_start_id_ = S2CellId::None();
+  node_cutoff_ = -1;
+  next_node_cutoff_ = -1;
+  set_done();
+}
+
+inline S2CellId S2CellIndex::ContentsIterator::cell_id() const {
+  S2_DCHECK(!done());
+  return node_.cell_id;
+}
+
+inline S2CellIndex::Label S2CellIndex::ContentsIterator::label() const {
+  S2_DCHECK(!done());
+  return node_.label;
+}
+
+inline S2CellIndex::LabelledCell S2CellIndex::ContentsIterator::labelled_cell()
+    const {
+  S2_DCHECK(!done());
+  return LabelledCell(node_.cell_id, node_.label);
+}
+
+inline bool S2CellIndex::ContentsIterator::done() const {
+  return node_.label == kDoneContents;
+}
+
+inline void S2CellIndex::ContentsIterator::Next() {
+  S2_DCHECK(!done());
+  if (node_.parent <= node_cutoff_) {
+    // We have already processed this node and its ancestors.
+    node_cutoff_ = next_node_cutoff_;
+    set_done();
+  } else {
+    node_ = (*cell_tree_)[node_.parent];
+  }
+}
+
+inline int S2CellIndex::num_cells() const {
+  return cell_tree_.size();
+}
+
+inline void S2CellIndex::Add(S2CellId cell_id, Label label) {
+  S2_DCHECK(cell_id.is_valid());
+  S2_DCHECK_GE(label, 0);
+  cell_tree_.push_back(CellNode(cell_id, label, -1));
+}
+
+inline void S2CellIndex::Clear() {
+  cell_tree_.clear();
+  range_nodes_.clear();
+}
+
+inline bool S2CellIndex::VisitIntersectingCells(
+    const S2CellUnion& target, const CellVisitor& visitor) const {
+  if (target.empty()) return true;
+  auto it = target.begin();
+  ContentsIterator contents(this);
+  RangeIterator range(this);
+  range.Begin();
+  do {
+    if (range.limit_id() <= it->range_min()) {
+      range.Seek(it->range_min());  // Only seek when necessary.
+    }
+    for (; range.start_id() <= it->range_max(); range.Next()) {
+      for (contents.StartUnion(range); !contents.done(); contents.Next()) {
+        if (!visitor(contents.cell_id(), contents.label())) {
+          return false;
+        }
+      }
+    }
+    // Check whether the next target cell is also contained by the leaf cell
+    // range that we just processed.  If so, we can skip over all such cells
+    // using binary search.  This speeds up benchmarks by between 2x and 10x
+    // when the average number of intersecting cells is small (< 1).
+    if (++it != target.end() && it->range_max() < range.start_id()) {
+      // Skip to the first target cell that extends past the previous range.
+      it = std::lower_bound(it + 1, target.end(), range.start_id());
+      if ((it - 1)->range_max() >= range.start_id()) --it;
+    }
+  } while (it != target.end());
+  return true;
+}
+
+inline std::ostream& operator<<(std::ostream& os,
+                                S2CellIndex::LabelledCell x) {
+  return os << "(" << x.cell_id << ", " << x.label << ")";
+}
+
+#endif  // S2_S2CELL_INDEX_H_
diff --git a/src/s2/s2cell_union.cc b/src/s2/s2cell_union.cc
new file mode 100644 (file)
index 0000000..1ab532c
--- /dev/null
@@ -0,0 +1,515 @@
+// Copyright 2005 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// Author: ericv@google.com (Eric Veach)
+
+#include "s2/s2cell_union.h"
+
+#include <algorithm>
+#include <vector>
+
+#include "s2/base/integral_types.h"
+#include "s2/base/logging.h"
+#include "s2/s1angle.h"
+#include "s2/s2cap.h"
+#include "s2/s2cell.h"
+#include "s2/s2cell_id.h"
+#include "s2/s2latlng_rect.h"
+#include "s2/s2metrics.h"
+#include "s2/util/coding/coder.h"
+
+using std::is_sorted;
+using std::max;
+using std::min;
+using std::vector;
+
+DEFINE_int32(s2cell_union_decode_max_num_cells, 1000000,
+             "The maximum number of cells allowed by S2CellUnion::Decode");
+
+static const unsigned char kCurrentLosslessEncodingVersionNumber = 1;
+
+vector<S2CellId> S2CellUnion::ToS2CellIds(const vector<uint64>& ids) {
+  vector<S2CellId> cell_ids;
+  cell_ids.reserve(ids.size());
+  for (auto id : ids) cell_ids.push_back(S2CellId(id));
+  return cell_ids;
+}
+
+S2CellUnion::S2CellUnion(const vector<uint64>& cell_ids)
+    : cell_ids_(ToS2CellIds(cell_ids)) {
+  Normalize();
+}
+
+S2CellUnion S2CellUnion::WholeSphere() {
+  return S2CellUnion({S2CellId::FromFace(0), S2CellId::FromFace(1),
+                      S2CellId::FromFace(2), S2CellId::FromFace(3),
+                      S2CellId::FromFace(4), S2CellId::FromFace(5)});
+}
+
+S2CellUnion S2CellUnion::FromMinMax(S2CellId min_id, S2CellId max_id) {
+  S2CellUnion result;
+  result.InitFromMinMax(min_id, max_id);
+  return result;
+}
+
+S2CellUnion S2CellUnion::FromBeginEnd(S2CellId begin, S2CellId end) {
+  S2CellUnion result;
+  result.InitFromBeginEnd(begin, end);
+  return result;
+}
+
+void S2CellUnion::Init(const vector<uint64>& cell_ids) {
+  cell_ids_ = ToS2CellIds(cell_ids);
+  Normalize();
+}
+
+void S2CellUnion::InitFromMinMax(S2CellId min_id, S2CellId max_id) {
+  S2_DCHECK(max_id.is_valid());
+  InitFromBeginEnd(min_id, max_id.next());
+}
+
+void S2CellUnion::InitFromBeginEnd(S2CellId begin, S2CellId end) {
+  S2_DCHECK(begin.is_leaf());
+  S2_DCHECK(end.is_leaf());
+  S2_DCHECK_LE(begin, end);
+
+  // We repeatedly add the largest cell we can.
+  cell_ids_.clear();
+  for (S2CellId id = begin.maximum_tile(end);
+       id != end; id = id.next().maximum_tile(end)) {
+    cell_ids_.push_back(id);
+  }
+  // The output is already normalized.
+  S2_DCHECK(IsNormalized());
+}
+
+void S2CellUnion::Pack(int excess) {
+  if (cell_ids_.capacity() - cell_ids_.size() > excess) {
+    cell_ids_.shrink_to_fit();
+  }
+}
+
+S2CellUnion* S2CellUnion::Clone() const {
+  return new S2CellUnion(cell_ids_, VERBATIM);
+}
+
+// Returns true if the given four cells have a common parent.
+// REQUIRES: The four cells are distinct.
+inline static bool AreSiblings(S2CellId a, S2CellId b, S2CellId c, S2CellId d) {
+  // A necessary (but not sufficient) condition is that the XOR of the
+  // four cells must be zero.  This is also very fast to test.
+  if ((a.id() ^ b.id() ^ c.id()) != d.id()) return false;
+
+  // Now we do a slightly more expensive but exact test.  First, compute a
+  // mask that blocks out the two bits that encode the child position of
+  // "id" with respect to its parent, then check that the other three
+  // children all agree with "mask".
+  uint64 mask = d.lsb() << 1;
+  mask = ~(mask + (mask << 1));
+  uint64 id_masked = (d.id() & mask);
+  return ((a.id() & mask) == id_masked &&
+          (b.id() & mask) == id_masked &&
+          (c.id() & mask) == id_masked &&
+          !d.is_face());
+}
+
+bool S2CellUnion::IsValid() const {
+  if (num_cells() > 0 && !cell_id(0).is_valid()) return false;
+  for (int i = 1; i < num_cells(); ++i) {
+    if (!cell_id(i).is_valid()) return false;
+    if (cell_id(i - 1).range_max() >= cell_id(i).range_min()) return false;
+  }
+  return true;
+}
+
+bool S2CellUnion::IsNormalized() const {
+  if (num_cells() > 0 && !cell_id(0).is_valid()) return false;
+  for (int i = 1; i < num_cells(); ++i) {
+    if (!cell_id(i).is_valid()) return false;
+    if (cell_id(i - 1).range_max() >= cell_id(i).range_min()) return false;
+    if (i >= 3 && AreSiblings(cell_id(i - 3), cell_id(i - 2),
+                              cell_id(i - 1), cell_id(i))) {
+      return false;
+    }
+  }
+  return true;
+}
+
+bool S2CellUnion::Normalize() {
+  return Normalize(&cell_ids_);
+}
+
+/*static*/ bool S2CellUnion::Normalize(vector<S2CellId>* ids) {
+  // Optimize the representation by discarding cells contained by other cells,
+  // and looking for cases where all subcells of a parent cell are present.
+
+  std::sort(ids->begin(), ids->end());
+  int out = 0;
+  for (S2CellId id : *ids) {
+    // Check whether this cell is contained by the previous cell.
+    if (out > 0 && (*ids)[out-1].contains(id)) continue;
+
+    // Discard any previous cells contained by this cell.
+    while (out > 0 && id.contains((*ids)[out-1])) --out;
+
+    // Check whether the last 3 elements plus "id" can be collapsed into a
+    // single parent cell.
+    while (out >= 3 && AreSiblings((*ids)[out - 3], (*ids)[out - 2],
+                                   (*ids)[out - 1], id)) {
+      // Replace four children by their parent cell.
+      id = id.parent();
+      out -= 3;
+    }
+    (*ids)[out++] = id;
+  }
+  if (ids->size() == out) return false;
+  ids->resize(out);
+  return true;
+}
+
+void S2CellUnion::Denormalize(int min_level, int level_mod,
+                              vector<S2CellId>* out) const {
+  Denormalize(cell_ids_, min_level, level_mod, out);
+}
+
+void S2CellUnion::Denormalize(const vector<S2CellId>& in,
+                              int min_level, int level_mod,
+                              vector<S2CellId>* out) {
+  S2_DCHECK_GE(min_level, 0);
+  S2_DCHECK_LE(min_level, S2CellId::kMaxLevel);
+  S2_DCHECK_GE(level_mod, 1);
+  S2_DCHECK_LE(level_mod, 3);
+  S2_DCHECK_NE(out, &in);
+
+  out->clear();
+  out->reserve(in.size());
+  for (S2CellId id : in) {
+    int level = id.level();
+    int new_level = max(min_level, level);
+    if (level_mod > 1) {
+      // Round up so that (new_level - min_level) is a multiple of level_mod.
+      // (Note that S2CellId::kMaxLevel is a multiple of 1, 2, and 3.)
+      new_level += (S2CellId::kMaxLevel - (new_level - min_level)) % level_mod;
+      new_level = min(S2CellId::kMaxLevel, new_level);
+    }
+    if (new_level == level) {
+      out->push_back(id);
+    } else {
+      S2CellId end = id.child_end(new_level);
+      for (id = id.child_begin(new_level); id != end; id = id.next()) {
+        out->push_back(id);
+      }
+    }
+  }
+}
+
+S2Cap S2CellUnion::GetCapBound() const {
+  // Compute the approximate centroid of the region.  This won't produce the
+  // bounding cap of minimal area, but it should be close enough.
+  if (cell_ids_.empty()) return S2Cap::Empty();
+  S2Point centroid(0, 0, 0);
+  for (S2CellId id : *this) {
+    double area = S2Cell::AverageArea(id.level());
+    centroid += area * id.ToPoint();
+  }
+  if (centroid == S2Point(0, 0, 0)) {
+    centroid = S2Point(1, 0, 0);
+  } else {
+    centroid = centroid.Normalize();
+  }
+
+  // Use the centroid as the cap axis, and expand the cap angle so that it
+  // contains the bounding caps of all the individual cells.  Note that it is
+  // *not* sufficient to just bound all the cell vertices because the bounding
+  // cap may be concave (i.e. cover more than one hemisphere).
+  S2Cap cap = S2Cap::FromPoint(centroid);
+  for (S2CellId id : *this) {
+    cap.AddCap(S2Cell(id).GetCapBound());
+  }
+  return cap;
+}
+
+S2LatLngRect S2CellUnion::GetRectBound() const {
+  S2LatLngRect bound = S2LatLngRect::Empty();
+  for (S2CellId id : *this) {
+    bound = bound.Union(S2Cell(id).GetRectBound());
+  }
+  return bound;
+}
+
+bool S2CellUnion::Contains(S2CellId id) const {
+  // This is an exact test.  Each cell occupies a linear span of the S2
+  // space-filling curve, and the cell id is simply the position at the center
+  // of this span.  The cell union ids are sorted in increasing order along
+  // the space-filling curve.  So we simply find the pair of cell ids that
+  // surround the given cell id (using binary search).  There is containment
+  // if and only if one of these two cell ids contains this cell.
+
+  vector<S2CellId>::const_iterator i =
+      std::lower_bound(cell_ids_.begin(), cell_ids_.end(), id);
+  if (i != cell_ids_.end() && i->range_min() <= id) return true;
+  return i != cell_ids_.begin() && (--i)->range_max() >= id;
+}
+
+bool S2CellUnion::Intersects(S2CellId id) const {
+  // This is an exact test; see the comments for Contains() above.
+
+  vector<S2CellId>::const_iterator i =
+      std::lower_bound(cell_ids_.begin(), cell_ids_.end(), id);
+  if (i != cell_ids_.end() && i->range_min() <= id.range_max()) return true;
+  return i != cell_ids_.begin() && (--i)->range_max() >= id.range_min();
+}
+
+bool S2CellUnion::Contains(const S2CellUnion& y) const {
+  // TODO(ericv): A divide-and-conquer or alternating-skip-search
+  // approach may be sigificantly faster in both the average and worst case.
+
+  for (S2CellId y_id : y) {
+    if (!Contains(y_id)) return false;
+  }
+  return true;
+}
+
+bool S2CellUnion::Intersects(const S2CellUnion& y) const {
+  // TODO(ericv): A divide-and-conquer or alternating-skip-search
+  // approach may be sigificantly faster in both the average and worst case.
+
+  for (S2CellId y_id : y) {
+    if (Intersects(y_id)) return true;
+  }
+  return false;
+}
+
+S2CellUnion S2CellUnion::Union(const S2CellUnion& y) const {
+  vector<S2CellId> cell_ids;
+  cell_ids.reserve(num_cells() + y.num_cells());
+  cell_ids = cell_ids_;
+  cell_ids.insert(cell_ids.end(), y.cell_ids_.begin(), y.cell_ids_.end());
+  return S2CellUnion(std::move(cell_ids));
+}
+
+S2CellUnion S2CellUnion::Intersection(S2CellId id) const {
+  S2CellUnion result;
+  if (Contains(id)) {
+    result.cell_ids_.push_back(id);
+  } else {
+    vector<S2CellId>::const_iterator i = std::lower_bound(
+        cell_ids_.begin(), cell_ids_.end(), id.range_min());
+    S2CellId id_max = id.range_max();
+    while (i != cell_ids_.end() && *i <= id_max)
+      result.cell_ids_.push_back(*i++);
+  }
+  S2_DCHECK(result.IsNormalized() || !IsNormalized());
+  return result;
+}
+
+S2CellUnion S2CellUnion::Intersection(const S2CellUnion& y) const {
+  S2CellUnion result;
+  GetIntersection(cell_ids_, y.cell_ids_, &result.cell_ids_);
+  // The output is normalized as long as at least one input is normalized.
+  S2_DCHECK(result.IsNormalized() || (!IsNormalized() && !y.IsNormalized()));
+  return result;
+}
+
+/*static*/ void S2CellUnion::GetIntersection(const vector<S2CellId>& x,
+                                             const vector<S2CellId>& y,
+                                             vector<S2CellId>* out) {
+  S2_DCHECK_NE(out, &x);
+  S2_DCHECK_NE(out, &y);
+  S2_DCHECK(is_sorted(x.begin(), x.end()));
+  S2_DCHECK(is_sorted(y.begin(), y.end()));
+
+  // This is a fairly efficient calculation that uses binary search to skip
+  // over sections of both input vectors.  It takes logarithmic time if all the
+  // cells of "x" come before or after all the cells of "y" in S2CellId order.
+
+  out->clear();
+  vector<S2CellId>::const_iterator i = x.begin();
+  vector<S2CellId>::const_iterator j = y.begin();
+  while (i != x.end() && j != y.end()) {
+    S2CellId imin = i->range_min();
+    S2CellId jmin = j->range_min();
+    if (imin > jmin) {
+      // Either j->contains(*i) or the two cells are disjoint.
+      if (*i <= j->range_max()) {
+        out->push_back(*i++);
+      } else {
+        // Advance "j" to the first cell possibly contained by *i.
+        j = std::lower_bound(j + 1, y.end(), imin);
+        // The previous cell *(j-1) may now contain *i.
+        if (*i <= (j - 1)->range_max()) --j;
+      }
+    } else if (jmin > imin) {
+      // Identical to the code above with "i" and "j" reversed.
+      if (*j <= i->range_max()) {
+        out->push_back(*j++);
+      } else {
+        i = std::lower_bound(i + 1, x.end(), jmin);
+        if (*j <= (i - 1)->range_max()) --i;
+      }
+    } else {
+      // "i" and "j" have the same range_min(), so one contains the other.
+      if (*i < *j)
+        out->push_back(*i++);
+      else
+        out->push_back(*j++);
+    }
+  }
+  // The output is generated in sorted order.
+  S2_DCHECK(is_sorted(out->begin(), out->end()));
+}
+
+static void GetDifferenceInternal(S2CellId cell,
+                                  const S2CellUnion& y,
+                                  vector<S2CellId>* cell_ids) {
+  // Add the difference between cell and y to cell_ids.
+  // If they intersect but the difference is non-empty, divide and conquer.
+  if (!y.Intersects(cell)) {
+    cell_ids->push_back(cell);
+  } else if (!y.Contains(cell)) {
+    S2CellId child = cell.child_begin();
+    for (int i = 0; ; ++i) {
+      GetDifferenceInternal(child, y, cell_ids);
+      if (i == 3) break;  // Avoid unnecessary next() computation.
+      child = child.next();
+    }
+  }
+}
+
+S2CellUnion S2CellUnion::Difference(const S2CellUnion& y) const {
+  // TODO(ericv): this is approximately O(N*log(N)), but could probably
+  // use similar techniques as GetIntersection() to be more efficient.
+
+  S2CellUnion result;
+  for (S2CellId id : *this) {
+    GetDifferenceInternal(id, y, &result.cell_ids_);
+  }
+  // The output is normalized as long as the first argument is normalized.
+  S2_DCHECK(result.IsNormalized() || !IsNormalized());
+  return result;
+}
+
+void S2CellUnion::Expand(int expand_level) {
+  vector<S2CellId> output;
+  uint64 level_lsb = S2CellId::lsb_for_level(expand_level);
+  for (int i = num_cells(); --i >= 0; ) {
+    S2CellId id = cell_id(i);
+    if (id.lsb() < level_lsb) {
+      id = id.parent(expand_level);
+      // Optimization: skip over any cells contained by this one.  This is
+      // especially important when very small regions are being expanded.
+      while (i > 0 && id.contains(cell_id(i - 1))) --i;
+    }
+    output.push_back(id);
+    id.AppendAllNeighbors(expand_level, &output);
+  }
+  Init(std::move(output));
+}
+
+void S2CellUnion::Expand(S1Angle min_radius, int max_level_diff) {
+  int min_level = S2CellId::kMaxLevel;
+  for (S2CellId id : *this) {
+    min_level = min(min_level, id.level());
+  }
+  // Find the maximum level such that all cells are at least "min_radius" wide.
+  int radius_level = S2::kMinWidth.GetLevelForMinValue(min_radius.radians());
+  if (radius_level == 0 && min_radius.radians() > S2::kMinWidth.GetValue(0)) {
+    // The requested expansion is greater than the width of a face cell.
+    // The easiest way to handle this is to expand twice.
+    Expand(0);
+  }
+  Expand(min(min_level + max_level_diff, radius_level));
+}
+
+uint64 S2CellUnion::LeafCellsCovered() const {
+  uint64 num_leaves = 0;
+  for (S2CellId id : *this) {
+    const int inverted_level = S2CellId::kMaxLevel - id.level();
+    num_leaves += (1ULL << (inverted_level << 1));
+  }
+  return num_leaves;
+}
+
+double S2CellUnion::AverageBasedArea() const {
+  return S2Cell::AverageArea(S2CellId::kMaxLevel) * LeafCellsCovered();
+}
+
+double S2CellUnion::ApproxArea() const {
+  double area = 0;
+  for (S2CellId id : *this) {
+    area += S2Cell(id).ApproxArea();
+  }
+  return area;
+}
+
+double S2CellUnion::ExactArea() const {
+  double area = 0;
+  for (S2CellId id : *this) {
+    area += S2Cell(id).ExactArea();
+  }
+  return area;
+}
+
+bool operator==(const S2CellUnion& x, const S2CellUnion& y) {
+  return x.cell_ids() == y.cell_ids();
+}
+
+bool operator!=(const S2CellUnion& x, const S2CellUnion& y) {
+  return x.cell_ids() != y.cell_ids();
+}
+
+bool S2CellUnion::Contains(const S2Cell& cell) const {
+  return Contains(cell.id());
+}
+
+bool S2CellUnion::MayIntersect(const S2Cell& cell) const {
+  return Intersects(cell.id());
+}
+
+void S2CellUnion::Encode(Encoder* const encoder) const {
+  // Unsigned char for version number, and N+1 uint64's for N cell_ids
+  // (1 for vector length, N for the ids).
+  encoder->Ensure(sizeof(unsigned char) +
+                  sizeof(uint64) * (1 + cell_ids_.size()));
+
+  encoder->put8(kCurrentLosslessEncodingVersionNumber);
+  encoder->put64(uint64{cell_ids_.size()});
+  for (const S2CellId& cell_id : cell_ids_) {
+    cell_id.Encode(encoder);
+  }
+}
+
+bool S2CellUnion::Decode(Decoder* const decoder) {
+  // Should contain at least version and vector length.
+  if (decoder->avail() < sizeof(unsigned char) + sizeof(uint64)) return false;
+  unsigned char version = decoder->get8();
+  if (version > kCurrentLosslessEncodingVersionNumber) return false;
+
+  uint64 num_cells = decoder->get64();
+  if (num_cells > FLAGS_s2cell_union_decode_max_num_cells) {
+    return false;
+  }
+
+  vector<S2CellId> temp_cell_ids(num_cells);
+  for (int i = 0; i < num_cells; ++i) {
+    if (!temp_cell_ids[i].Decode(decoder)) return false;
+  }
+  cell_ids_.swap(temp_cell_ids);
+  return true;
+}
+
+bool S2CellUnion::Contains(const S2Point& p) const {
+  return Contains(S2CellId(p));
+}
diff --git a/src/s2/s2cell_union.h b/src/s2/s2cell_union.h
new file mode 100644 (file)
index 0000000..f89c9ac
--- /dev/null
@@ -0,0 +1,399 @@
+// Copyright 2005 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// Author: ericv@google.com (Eric Veach)
+
+#ifndef S2_S2CELL_UNION_H_
+#define S2_S2CELL_UNION_H_
+
+#include <vector>
+
+#include "s2/base/commandlineflags.h"
+#include "s2/base/integral_types.h"
+#include "s2/base/logging.h"
+#include "s2/_fp_contract_off.h"
+#include "s2/s2cell_id.h"
+#include "s2/s2region.h"
+#include "absl/base/macros.h"
+
+class Decoder;
+class Encoder;
+class S1Angle;
+class S2Cap;
+class S2Cell;
+class S2LatLngRect;
+
+DECLARE_bool(s2debug);
+DECLARE_int32(s2cell_union_decode_max_num_cells);
+
+// An S2CellUnion is a region consisting of cells of various sizes.  Typically
+// a cell union is used to approximate some other shape.  There is a tradeoff
+// between the accuracy of the approximation and how many cells are used.
+// Unlike polygons, cells have a fixed hierarchical structure.  This makes
+// them more suitable for optimizations based on preprocessing.
+//
+// An S2CellUnion is represented as a vector of sorted, non-overlapping
+// S2CellIds.  By default the vector is also "normalized", meaning that groups
+// of 4 child cells have been replaced by their parent cell whenever possible.
+// S2CellUnions are not required to be normalized, but certain operations will
+// return different results if they are not (e.g., Contains(S2CellUnion).)
+//
+// S2CellUnion is movable and copyable.
+class S2CellUnion final : public S2Region {
+ public:
+  // Creates an empty cell union.
+  S2CellUnion() {}
+
+  // Constructs a cell union with the given S2CellIds, then calls Normalize()
+  // to sort them, remove duplicates, and merge cells when possible.  (See
+  // FromNormalized if your vector is already normalized.)
+  //
+  // The argument is passed by value, so if you are passing a named variable
+  // and have no further use for it, consider using std::move().
+  //
+  // A cell union containing a single S2CellId may be constructed like this:
+  //
+  //     S2CellUnion example({cell_id});
+  explicit S2CellUnion(std::vector<S2CellId> cell_ids);
+
+  // Convenience constructor that accepts a vector of uint64.  Note that
+  // unlike the constructor above, this one makes a copy of "cell_ids".
+  explicit S2CellUnion(const std::vector<uint64>& cell_ids);
+
+  // Constructs a cell union for the whole sphere.
+  static S2CellUnion WholeSphere();
+
+  // Constructs a cell union from S2CellIds that have already been normalized
+  // (typically because they were extracted from another S2CellUnion).
+  //
+  // The argument is passed by value, so if you are passing a named variable
+  // and have no further use for it, consider using std::move().
+  //
+  // REQUIRES: "cell_ids" satisfies the requirements of IsNormalized().
+  static S2CellUnion FromNormalized(std::vector<S2CellId> cell_ids);
+
+  // Constructs a cell union from a vector of sorted, non-overlapping
+  // S2CellIds.  Unlike the other constructors, FromVerbatim does not require
+  // that groups of 4 child cells have been replaced by their parent cell.  In
+  // other words, "cell_ids" must satisfy the requirements of IsValid() but
+  // not necessarily IsNormalized().
+  //
+  // Note that if the cell union is not normalized, certain operations may
+  // return different results (e.g., Contains(S2CellUnion)).
+  //
+  // REQUIRES: "cell_ids" satisfies the requirements of IsValid().
+  static S2CellUnion FromVerbatim(std::vector<S2CellId> cell_ids);
+
+  // Constructs a cell union that corresponds to a continuous range of cell
+  // ids.  The output is a normalized collection of cell ids that covers the
+  // leaf cells between "min_id" and "max_id" inclusive.
+  //
+  // REQUIRES: min_id.is_leaf(), max_id.is_leaf(), min_id <= max_id.
+  static S2CellUnion FromMinMax(S2CellId min_id, S2CellId max_id);
+
+  // Like FromMinMax() except that the union covers the range of leaf cells
+  // from "begin" (inclusive) to "end" (exclusive), as with Python ranges or
+  // STL iterator ranges.  If (begin == end) the result is empty.
+  //
+  // REQUIRES: begin.is_leaf(), end.is_leaf(), begin <= end.
+  static S2CellUnion FromBeginEnd(S2CellId begin, S2CellId end);
+
+  // Init() methods corresponding to the constructors/factory methods above.
+  // TODO(ericv): Consider deprecating these methods in favor of using the
+  // constructors and move assignment operator.
+  void Init(std::vector<S2CellId> cell_ids);
+  void Init(const std::vector<uint64>& cell_ids);
+  void InitFromMinMax(S2CellId min_id, S2CellId max_id);
+  void InitFromBeginEnd(S2CellId begin, S2CellId end);
+
+  // Clears the contents of the cell union and minimizes memory usage.
+  void Clear();
+
+  // Gives ownership of the vector data to the client without copying, and
+  // clears the content of the cell union.  The original data in cell_ids
+  // is lost if there was any.
+  std::vector<S2CellId> Release();
+
+  // Convenience methods for accessing the individual cell ids.
+  int num_cells() const { return static_cast<int>(cell_ids_.size()); }
+  S2CellId cell_id(int i) const { return cell_ids_[i]; }
+
+  // Vector-like methods for accessing the individual cell ids.
+  size_t size() const { return cell_ids_.size(); }
+  bool empty() const { return cell_ids_.empty(); }
+  S2CellId operator[](int i) const { return cell_ids_[i]; }
+
+  // Standard begin/end methods, to allow range-based for loops:
+  //
+  //  for (S2CellId id : cell_union) { ... }
+  std::vector<S2CellId>::const_iterator begin() const;
+  std::vector<S2CellId>::const_iterator end() const;
+
+  // Direct access to the underlying vector for STL algorithms.
+  const std::vector<S2CellId>& cell_ids() const { return cell_ids_; }
+
+  // Returns true if the cell union is valid, meaning that the S2CellIds are
+  // valid, non-overlapping, and sorted in increasing order.
+  bool IsValid() const;
+
+  // Returns true if the cell union is normalized, meaning that it is
+  // satisfies IsValid() and that no four cells have a common parent.
+  // Certain operations such as Contains(S2CellUnion) will return a different
+  // result if the cell union is not normalized.
+  bool IsNormalized() const;
+
+  // Normalizes the cell union by discarding cells that are contained by other
+  // cells, replacing groups of 4 child cells by their parent cell whenever
+  // possible, and sorting all the cell ids in increasing order.
+  //
+  // Returns true if the number of cells was reduced.
+  // TODO(ericv): Change this method to return void.
+  bool Normalize();
+
+  // Replaces "output" with an expanded version of the cell union where any
+  // cells whose level is less than "min_level" or where (level - min_level)
+  // is not a multiple of "level_mod" are replaced by their children, until
+  // either both of these conditions are satisfied or the maximum level is
+  // reached.
+  //
+  // This method allows a covering generated by S2RegionCoverer using
+  // min_level() or level_mod() constraints to be stored as a normalized cell
+  // union (which allows various geometric computations to be done) and then
+  // converted back to the original list of cell ids that satisfies the
+  // desired constraints.
+  void Denormalize(int min_level, int level_mod,
+                   std::vector<S2CellId>* output) const;
+
+  // If there are more than "excess" elements of the cell_ids() vector that
+  // are allocated but unused, reallocates the array to eliminate the excess
+  // space.  This reduces memory usage when many cell unions need to be held
+  // in memory at once.
+  void Pack(int excess = 0);
+
+  // Returns true if the cell union contains the given cell id.  Containment
+  // is defined with respect to regions, e.g. a cell contains its 4 children.
+  // This is a fast operation (logarithmic in the size of the cell union).
+  //
+  // CAVEAT: If you have constructed a non-normalized S2CellUnion using
+  // FromVerbatim, note that groups of 4 child cells are *not* considered to
+  // contain their parent cell.  To get this behavior you must use one of the
+  // other constructors or call Normalize() explicitly.
+  bool Contains(S2CellId id) const;
+
+  // Returns true if the cell union intersects the given cell id.
+  // This is a fast operation (logarithmic in the size of the cell union).
+  bool Intersects(S2CellId id) const;
+
+  // Returns true if this cell union contains the given other cell union.
+  //
+  // CAVEAT: If you have constructed a non-normalized S2CellUnion using
+  // FromVerbatim, note that groups of 4 child cells are *not* considered to
+  // contain their parent cell.  To get this behavior you must use one of the
+  // other constructors or call Normalize() explicitly.
+  bool Contains(const S2CellUnion& y) const;
+
+  // Returns true if this cell union intersects the given other cell union.
+  bool Intersects(const S2CellUnion& y) const;
+
+  // Returns the union of the two given cell unions.
+  S2CellUnion Union(const S2CellUnion& y) const;
+
+  // Returns the intersection of the two given cell unions.
+  S2CellUnion Intersection(const S2CellUnion& y) const;
+
+  // Specialized version of GetIntersection() that returns the intersection of
+  // a cell union with an S2CellId.  This can be useful for splitting a cell
+  // union into pieces.
+  S2CellUnion Intersection(S2CellId id) const;
+
+  // Returns the difference of the two given cell unions.
+  S2CellUnion Difference(const S2CellUnion& y) const;
+
+  // Expands the cell union by adding a buffer of cells at "expand_level"
+  // around the union boundary.
+  //
+  // For each cell "c" in the union, we add all neighboring cells at level
+  // "expand_level" that are adjacent to "c".  Note that there can be many
+  // such cells if "c" is large compared to "expand_level".  If "c" is smaller
+  // than "expand_level", we first add the parent of "c" at "expand_level" and
+  // then add all the neighbors of that cell.
+  //
+  // Note that the size of the output is exponential in "expand_level".  For
+  // example, if expand_level == 20 and the input has a cell at level 10,
+  // there will be on the order of 4000 adjacent cells in the output.  For
+  // most applications the Expand(min_radius, max_level_diff) method below is
+  // easier to use.
+  void Expand(int expand_level);
+
+  // Expands the cell union such that it contains all points whose distance to
+  // the cell union is at most "min_radius", but do not use cells that are
+  // more than "max_level_diff" levels higher than the largest cell in the
+  // input.  The second parameter controls the tradeoff between accuracy and
+  // output size when a large region is being expanded by a small amount
+  // (e.g. expanding Canada by 1km).  For example, if max_level_diff == 4 the
+  // region will always be expanded by approximately 1/16 the width of its
+  // largest cell.  Note that in the worst case, the number of cells in the
+  // output can be up to 4 * (1 + 2 ** max_level_diff) times larger than the
+  // number of cells in the input.
+  void Expand(S1Angle min_radius, int max_level_diff);
+
+  // The number of leaf cells covered by the union.
+  // This will be no more than 6*2^60 for the whole sphere.
+  uint64 LeafCellsCovered() const;
+
+  // Approximates this cell union's area in steradians by summing the average
+  // area of each contained cell's average area, using the AverageArea method
+  // from the S2Cell class.  This is equivalent to the number of leaves covered,
+  // multiplied by the average area of a leaf.  Note that AverageArea does not
+  // take into account distortion of cell, and thus may be off by up to a
+  // factor of up to 1.7.
+  //
+  // NOTE: Since this is proportional to LeafCellsCovered(), it is
+  // always better to use that function if all you care about is
+  // the relative average area between objects.
+  double AverageBasedArea() const;
+
+  // Calculates this cell union's area in steradians by summing the approximate
+  // area for each contained cell, using the ApproxArea method from the S2Cell
+  // class.
+  double ApproxArea() const;
+
+  // Calculates this cell union's area in steradians by summing the exact area
+  // for each contained cell, using the Exact method from the S2Cell class.
+  double ExactArea() const;
+
+  // Return true if two cell unions are identical.
+  friend bool operator==(const S2CellUnion& x, const S2CellUnion& y);
+
+  // Return true if two cell unions are different.
+  friend bool operator!=(const S2CellUnion& x, const S2CellUnion& y);
+
+  ////////////////////////////////////////////////////////////////////////
+  // S2Region interface (see s2region.h for details):
+
+  S2CellUnion* Clone() const override;
+  S2Cap GetCapBound() const override;
+  S2LatLngRect GetRectBound() const override;
+
+  // This is a fast operation (logarithmic in the size of the cell union).
+  bool Contains(const S2Cell& cell) const override;
+
+  // This is a fast operation (logarithmic in the size of the cell union).
+  bool MayIntersect(const S2Cell& cell) const override;
+
+  // The point 'p' does not need to be normalized.
+  // This is a fast operation (logarithmic in the size of the cell union).
+  bool Contains(const S2Point& p) const override;
+
+  // Appends a serialized representation of the S2CellUnion to "encoder".
+  //
+  // REQUIRES: "encoder" uses the default constructor, so that its buffer
+  //           can be enlarged as necessary by calling Ensure(int).
+  void Encode(Encoder* const encoder) const;
+
+  // Decodes an S2CellUnion encoded with Encode().  Returns true on success.
+  bool Decode(Decoder* const decoder);
+
+  ////////////////////////////////////////////////////////////////////////
+  // Static methods intended for high-performance clients that prefer to
+  // manage their own storage.
+
+  // Like Normalize(), but works with a vector of S2CellIds.
+  // Equivalent to:
+  //   *cell_ids = S2CellUnion(std::move(*cell_ids)).Release();
+  static bool Normalize(std::vector<S2CellId>* cell_ids);
+
+  // Like Denormalize(), but works with a vector of S2CellIds.
+  // REQUIRES: out != &in
+  static void Denormalize(const std::vector<S2CellId>& in,
+                          int min_level, int level_mod,
+                          std::vector<S2CellId>* out);
+
+  // Like GetIntersection(), but works directly with vectors of S2CellIds,
+  // Equivalent to:
+  //
+  //    *out = S2CellUnion(x).Intersection(S2CellUnion(y)).Release()
+  //
+  // except that this method has slightly more relaxed normalization
+  // requirements: the input vectors may contain groups of 4 child cells that
+  // all have the same parent.  (In a normalized S2CellUnion, such groups are
+  // always replaced by the parent cell.)
+  static void GetIntersection(const std::vector<S2CellId>& x,
+                              const std::vector<S2CellId>& y,
+                              std::vector<S2CellId>* out);
+
+ private:
+  friend class S2CellUnionTestPeer;  // For creating invalid S2CellUnions.
+
+  // Internal constructor that does not check "cell_ids" for validity.
+  enum VerbatimFlag { VERBATIM };
+  S2CellUnion(std::vector<S2CellId> cell_ids, VerbatimFlag verbatim)
+      : cell_ids_(std::move(cell_ids)) {}
+
+  // Converts a vector of uint64 to a vector of S2CellIds.
+  static std::vector<S2CellId> ToS2CellIds(const std::vector<uint64>& ids);
+
+  std::vector<S2CellId> cell_ids_;
+};
+
+
+//////////////////   Implementation details follow   ////////////////////
+
+
+inline S2CellUnion::S2CellUnion(std::vector<S2CellId> cell_ids)
+    : cell_ids_(std::move(cell_ids)) {
+  Normalize();
+}
+
+inline S2CellUnion S2CellUnion::FromNormalized(std::vector<S2CellId> cell_ids) {
+  S2CellUnion result(std::move(cell_ids), VERBATIM);
+  S2_DCHECK(result.IsNormalized());
+  return result;
+}
+
+inline S2CellUnion S2CellUnion::FromVerbatim(std::vector<S2CellId> cell_ids) {
+  S2CellUnion result(std::move(cell_ids), VERBATIM);
+  S2_DCHECK(!FLAGS_s2debug || result.IsValid());
+  return result;
+}
+
+inline void S2CellUnion::Init(std::vector<S2CellId> cell_ids) {
+  cell_ids_ = std::move(cell_ids);
+  Normalize();
+}
+
+inline void S2CellUnion::Clear() {
+  // swap() guarantees to reduce the RHS vector's size and capacity
+  // to zero (as opposed to clear(), shrink_to_fit() sequence).
+  std::vector<S2CellId>().swap(cell_ids_);
+}
+
+inline std::vector<S2CellId> S2CellUnion::Release() {
+  // vector's rvalue reference constructor does not necessarily leave
+  // moved-from value in empty state, so swap instead.
+  std::vector<S2CellId> cell_ids;
+  cell_ids_.swap(cell_ids);
+  return cell_ids;
+}
+
+inline std::vector<S2CellId>::const_iterator S2CellUnion::begin() const {
+  return cell_ids_.begin();
+}
+
+inline std::vector<S2CellId>::const_iterator S2CellUnion::end() const {
+  return cell_ids_.end();
+}
+
+#endif  // S2_S2CELL_UNION_H_
diff --git a/src/s2/s2centroids.cc b/src/s2/s2centroids.cc
new file mode 100644 (file)
index 0000000..e6ec231
--- /dev/null
@@ -0,0 +1,84 @@
+// Copyright 2005 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// Author: ericv@google.com (Eric Veach)
+
+#include "s2/s2centroids.h"
+
+#include <cmath>
+
+#include "s2/s2pointutil.h"
+
+namespace S2 {
+
+S2Point PlanarCentroid(const S2Point& a, const S2Point& b, const S2Point& c) {
+  return (1./3) * (a + b + c);
+}
+
+S2Point TrueCentroid(const S2Point& a, const S2Point& b, const S2Point& c) {
+  S2_DCHECK(IsUnitLength(a));
+  S2_DCHECK(IsUnitLength(b));
+  S2_DCHECK(IsUnitLength(c));
+
+  // I couldn't find any references for computing the true centroid of a
+  // spherical triangle...  I have a truly marvellous demonstration of this
+  // formula which this margin is too narrow to contain :)
+
+  // Use Angle() in order to get accurate results for small triangles.
+  double angle_a = b.Angle(c);
+  double angle_b = c.Angle(a);
+  double angle_c = a.Angle(b);
+  double ra = (angle_a == 0) ? 1 : (angle_a / std::sin(angle_a));
+  double rb = (angle_b == 0) ? 1 : (angle_b / std::sin(angle_b));
+  double rc = (angle_c == 0) ? 1 : (angle_c / std::sin(angle_c));
+
+  // Now compute a point M such that:
+  //
+  //  [Ax Ay Az] [Mx]                       [ra]
+  //  [Bx By Bz] [My]  = 0.5 * det(A,B,C) * [rb]
+  //  [Cx Cy Cz] [Mz]                       [rc]
+  //
+  // To improve the numerical stability we subtract the first row (A) from the
+  // other two rows; this reduces the cancellation error when A, B, and C are
+  // very close together.  Then we solve it using Cramer's rule.
+  //
+  // The result is the true centroid of the triangle multiplied by the
+  // triangle's area.
+  //
+  // TODO(ericv): This code still isn't as numerically stable as it could be.
+  // The biggest potential improvement is to compute B-A and C-A more
+  // accurately so that (B-A)x(C-A) is always inside triangle ABC.
+  S2Point x(a.x(), b.x() - a.x(), c.x() - a.x());
+  S2Point y(a.y(), b.y() - a.y(), c.y() - a.y());
+  S2Point z(a.z(), b.z() - a.z(), c.z() - a.z());
+  S2Point r(ra, rb - ra, rc - ra);
+  return 0.5 * S2Point(y.CrossProd(z).DotProd(r),
+                       z.CrossProd(x).DotProd(r),
+                       x.CrossProd(y).DotProd(r));
+}
+
+S2Point TrueCentroid(const S2Point& a, const S2Point& b) {
+  // The centroid (multiplied by length) is a vector toward the midpoint
+  // of the edge, whose length is twice the sine of half the angle between
+  // the two vertices.  Defining theta to be this angle, we have:
+  S2Point vdiff = a - b;  // Length == 2*sin(theta)
+  S2Point vsum = a + b;   // Length == 2*cos(theta)
+  double sin2 = vdiff.Norm2();
+  double cos2 = vsum.Norm2();
+  if (cos2 == 0) return S2Point();  // Ignore antipodal edges.
+  return sqrt(sin2 / cos2) * vsum;  // Length == 2*sin(theta)
+}
+
+}  // namespace S2
diff --git a/src/s2/s2centroids.h b/src/s2/s2centroids.h
new file mode 100644 (file)
index 0000000..f5ecd7e
--- /dev/null
@@ -0,0 +1,87 @@
+// Copyright 2005 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// Author: ericv@google.com (Eric Veach)
+//
+// There are several notions of the "centroid" of a triangle.  First, there
+// is the planar centroid, which is simply the centroid of the ordinary
+// (non-spherical) triangle defined by the three vertices.  Second, there is
+// the surface centroid, which is defined as the intersection of the three
+// medians of the spherical triangle.  It is possible to show that this
+// point is simply the planar centroid projected to the surface of the
+// sphere.  Finally, there is the true centroid (mass centroid), which is
+// defined as the surface integral over the spherical triangle of (x,y,z)
+// divided by the triangle area.  This is the point that the triangle would
+// rotate around if it was spinning in empty space.
+//
+// The best centroid for most purposes is the true centroid.  Unlike the
+// planar and surface centroids, the true centroid behaves linearly as
+// regions are added or subtracted.  That is, if you split a triangle into
+// pieces and compute the average of their centroids (weighted by triangle
+// area), the result equals the centroid of the original triangle.  This is
+// not true of the other centroids.
+//
+// Also note that the surface centroid may be nowhere near the intuitive
+// "center" of a spherical triangle.  For example, consider the triangle
+// with vertices A=(1,eps,0), B=(0,0,1), C=(-1,eps,0) (a quarter-sphere).
+// The surface centroid of this triangle is at S=(0, 2*eps, 1), which is
+// within a distance of 2*eps of the vertex B.  Note that the median from A
+// (the segment connecting A to the midpoint of BC) passes through S, since
+// this is the shortest path connecting the two endpoints.  On the other
+// hand, the true centroid is at M=(0, 0.5, 0.5), which when projected onto
+// the surface is a much more reasonable interpretation of the "center" of
+// this triangle.
+
+#ifndef S2_S2CENTROIDS_H_
+#define S2_S2CENTROIDS_H_
+
+#include "s2/s2point.h"
+
+namespace S2 {
+
+// Returns the centroid of the planar triangle ABC.  This can be normalized to
+// unit length to obtain the "surface centroid" of the corresponding spherical
+// triangle, i.e. the intersection of the three medians.  However, note that
+// for large spherical triangles the surface centroid may be nowhere near the
+// intuitive "center" (see example above).
+S2Point PlanarCentroid(const S2Point& a, const S2Point& b, const S2Point& c);
+
+// Returns the true centroid of the spherical triangle ABC multiplied by the
+// signed area of spherical triangle ABC.  The reasons for multiplying by the
+// signed area are (1) this is the quantity that needs to be summed to compute
+// the centroid of a union or difference of triangles, and (2) it's actually
+// easier to calculate this way.  All points must have unit length.
+//
+// Note that the result of this function is defined to be S2Point(0, 0, 0) if
+// the triangle is degenerate (and that this is intended behavior).
+S2Point TrueCentroid(const S2Point& a, const S2Point& b, const S2Point& c);
+
+// Returns the true centroid of the spherical geodesic edge AB multiplied by
+// the length of the edge AB.  As with triangles, the true centroid of a
+// collection of edges may be computed simply by summing the result of this
+// method for each edge.
+//
+// Note that the planar centroid of a geodesic edge simply 0.5 * (a + b),
+// while the surface centroid is (a + b).Normalize().  However neither of
+// these values is appropriate for computing the centroid of a collection of
+// edges (such as a polyline).
+//
+// Also note that the result of this function is defined to be S2Point(0, 0, 0)
+// if the edge is degenerate (and that this is intended behavior).
+S2Point TrueCentroid(const S2Point& a, const S2Point& b);
+
+}  // namespace S2
+
+#endif  // S2_S2CENTROIDS_H_
diff --git a/src/s2/s2closest_cell_query.cc b/src/s2/s2closest_cell_query.cc
new file mode 100644 (file)
index 0000000..b69c866
--- /dev/null
@@ -0,0 +1,123 @@
+// Copyright 2018 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// Author: ericv@google.com (Eric Veach)
+
+#include "s2/s2closest_cell_query.h"
+
+#include <memory>
+#include "absl/memory/memory.h"
+#include "s2/s1angle.h"
+#include "s2/s2cap.h"
+#include "s2/s2cell.h"
+#include "s2/s2cell_id.h"
+#include "s2/s2cell_union.h"
+#include "s2/s2edge_distances.h"
+#include "s2/s2region_coverer.h"
+#include "s2/s2shape_index_region.h"
+
+void S2ClosestCellQuery::Options::set_conservative_max_distance(
+    S1ChordAngle max_distance) {
+  set_max_distance(Distance(max_distance.PlusError(
+      S2::GetUpdateMinDistanceMaxError(max_distance)).Successor()));
+}
+
+void S2ClosestCellQuery::Options::set_conservative_max_distance(
+    S1Angle max_distance) {
+  set_conservative_max_distance(S1ChordAngle(max_distance));
+}
+
+// The thresholds for using the brute force algorithm are generally tuned to
+// optimize IsDistanceLess (which compares the distance against a threshold)
+// rather than FindClosest (which actually computes the minimum distance).
+// This is because the former operation is (1) more common, (2) inherently
+// faster, and (3) closely related to finding all cells within a given
+// distance, which is also very common.
+
+int S2ClosestCellQuery::PointTarget::max_brute_force_index_size() const {
+  // Break-even points:                   Point cloud      Cap coverings
+  // BM_FindClosest                                18                 16
+  // BM_IsDistanceLess                              8                  9
+  return 9;
+}
+
+int S2ClosestCellQuery::EdgeTarget::max_brute_force_index_size() const {
+  // Break-even points:                   Point cloud      Cap coverings
+  // BM_FindClosestToLongEdge                      14                 16
+  // BM_IsDistanceLessToLongEdge                    5                  5
+  return 5;
+}
+
+int S2ClosestCellQuery::CellTarget::max_brute_force_index_size() const {
+  // Break-even points:                   Point cloud      Cap coverings
+  // BM_FindClosestToSmallCell                     12                 13
+  // BM_IsDistanceLessToSmallCell                   6                  6
+  //
+  // Note that the primary use of CellTarget is to implement CellUnionTarget,
+  // and therefore it is very important to optimize for the case where a
+  // distance limit has been specified.
+  return 6;
+}
+
+int S2ClosestCellQuery::CellUnionTarget::max_brute_force_index_size() const {
+  // Break-even points:                   Point cloud      Cap coverings
+  // BM_FindClosestToSmallCoarseCellUnion          12                 10
+  // BM_IsDistanceLessToSmallCoarseCellUnion        7                  6
+  return 8;
+}
+
+int S2ClosestCellQuery::ShapeIndexTarget::max_brute_force_index_size() const {
+  // Break-even points:                   Point cloud      Cap coverings
+  // BM_FindClosestToSmallCoarseShapeIndex         10                  8
+  // BM_IsDistanceLessToSmallCoarseShapeIndex       7                  6
+  return 7;
+}
+
+S2ClosestCellQuery::S2ClosestCellQuery() {
+  // Prevent inline constructor bloat by defining here.
+}
+
+S2ClosestCellQuery::~S2ClosestCellQuery() {
+  // Prevent inline destructor bloat by defining here.
+}
+
+bool S2ClosestCellQuery::IsDistanceLess(Target* target, S1ChordAngle limit) {
+  static_assert(sizeof(Options) <= 32, "Consider not copying Options here");
+  Options tmp_options = options_;
+  tmp_options.set_max_results(1);
+  tmp_options.set_max_distance(limit);
+  tmp_options.set_max_error(S1ChordAngle::Straight());
+  return !base_.FindClosestCell(target, tmp_options).is_empty();
+}
+
+bool S2ClosestCellQuery::IsDistanceLessOrEqual(Target* target,
+                                               S1ChordAngle limit) {
+  static_assert(sizeof(Options) <= 32, "Consider not copying Options here");
+  Options tmp_options = options_;
+  tmp_options.set_max_results(1);
+  tmp_options.set_inclusive_max_distance(limit);
+  tmp_options.set_max_error(S1ChordAngle::Straight());
+  return !base_.FindClosestCell(target, tmp_options).is_empty();
+}
+
+bool S2ClosestCellQuery::IsConservativeDistanceLessOrEqual(
+    Target* target, S1ChordAngle limit) {
+  static_assert(sizeof(Options) <= 32, "Consider not copying Options here");
+  Options tmp_options = options_;
+  tmp_options.set_max_results(1);
+  tmp_options.set_conservative_max_distance(limit);
+  tmp_options.set_max_error(S1ChordAngle::Straight());
+  return !base_.FindClosestCell(target, tmp_options).is_empty();
+}
diff --git a/src/s2/s2closest_cell_query.h b/src/s2/s2closest_cell_query.h
new file mode 100644 (file)
index 0000000..8a7141a
--- /dev/null
@@ -0,0 +1,385 @@
+// Copyright 2018 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// Author: ericv@google.com (Eric Veach)
+
+#ifndef S2_S2CLOSEST_CELL_QUERY_H_
+#define S2_S2CLOSEST_CELL_QUERY_H_
+
+#include <vector>
+
+#include "s2/base/logging.h"
+#include "s2/_fp_contract_off.h"
+#include "s2/s1angle.h"
+#include "s2/s1chord_angle.h"
+#include "s2/s2cell.h"
+#include "s2/s2cell_id.h"
+#include "s2/s2closest_cell_query_base.h"
+#include "s2/s2min_distance_targets.h"
+
+// S2ClosestCellQuery is a helper class for finding the closest cell(s) to a
+// given point, edge, S2Cell, S2CellUnion, or geometry collection.  A typical
+// use case would be to add a collection of S2Cell coverings to an S2CellIndex
+// (representing a collection of original geometry), and then use
+// S2ClosestCellQuery to find all coverings that are within a given distance
+// of some target geometry (which could be represented exactly, or could also
+// be a covering).  The distance to the original geometry corresponding to
+// each covering could then be measured more precisely if desired.
+//
+// For example, here is how to find all cells that are closer than
+// "distance_limit" to a given target point:
+//
+//   S2ClosestCellQuery query(&cell_index);
+//   query.mutable_options()->set_max_distance(distance_limit);
+//   S2ClosestCellQuery::PointTarget target(target_point);
+//   for (const auto& result : query.FindClosestCells(&target)) {
+//     // result.distance() is the distance to the target.
+//     // result.cell_id() is the indexed S2CellId.
+//     // result.label() is the integer label associated with the S2CellId.
+//     DoSomething(target_point, result);
+//   }
+//
+// You can find either the k closest cells, or all cells within a given
+// radius, or both (i.e., the k closest cells up to a given maximum radius).
+// By default *all* cells are returned, so you should always specify either
+// max_results() or max_distance() or both.  You can also restrict the results
+// to cells that intersect a given S2Region; for example:
+//
+//   S2LatLngRect rect(...);
+//   query.mutable_options()->set_region(&rect);  // Does *not* take ownership.
+//
+// There is a FindClosestCell() convenience method that returns the closest
+// cell.  However, if you only need to test whether the distance is above or
+// below a given threshold (e.g., 10 km), it is typically much faster to use
+// the IsDistanceLess() method instead.  Unlike FindClosestCell(), this method
+// stops as soon as it can prove that the minimum distance is either above or
+// below the threshold.  Example usage:
+//
+//   if (query.IsDistanceLess(&target, limit_distance)) ...
+//
+// To find the closest cells to a query edge rather than a point, use:
+//
+//   S2ClosestCellQuery::EdgeTarget target(v0, v1);
+//   query.FindClosestCells(&target);
+//
+// Similarly you can find the closest cells to an S2Cell using an
+// S2ClosestCellQuery::CellTarget, you can find the closest cells to an
+// S2CellUnion using an S2ClosestCellQuery::CellUnionTarget, and you can find
+// the closest cells to an arbitrary collection of points, polylines, and
+// polygons by using an S2ClosestCellQuery::ShapeIndexTarget.
+//
+// The implementation is designed to be fast for both simple and complex
+// geometric objects.
+class S2ClosestCellQuery {
+ public:
+  // See S2ClosestCellQueryBase for full documentation.
+
+  // S2MinDistance is a thin wrapper around S1ChordAngle that implements the
+  // Distance concept required by S2ClosestCellQueryBase.
+  using Distance = S2MinDistance;
+  using Base = S2ClosestCellQueryBase<Distance>;
+
+  // Each "Result" object represents a closest (s2cell_id, label) pair.  Here
+  // are its main methods (see S2ClosestCellQueryBase::Result for details):
+  //
+  //   // The distance from the target to this point.
+  //   S1ChordAngle distance() const;
+  //
+  //   // The S2CellId itself.
+  //   S2CellId cell_id() const;
+  //
+  //   // The label associated with this S2CellId.
+  //   const Label& label() const;
+  using Result = Base::Result;
+
+  // Options that control the set of cells returned.  Note that by default
+  // *all* cells are returned, so you will always want to set either the
+  // max_results() option or the max_distance() option (or both).
+  class Options : public Base::Options {
+   public:
+    // See S2ClosestCellQueryBase::Options for the full set of options.
+
+    // Specifies that only cells whose distance to the target is less than
+    // "max_distance" should be returned.
+    //
+    // Note that cells whose distance is exactly equal to "max_distance" are
+    // not returned.  Normally this doesn't matter, because distances are not
+    // computed exactly in the first place, but if such cells are needed then
+    // see set_inclusive_max_distance() below.
+    //
+    // DEFAULT: Distance::Infinity()
+    void set_max_distance(S1ChordAngle max_distance);
+
+    // Like set_max_distance(), except that cells whose distance is exactly
+    // equal to "max_distance" are also returned.  Equivalent to calling
+    // set_max_distance(max_distance.Successor()).
+    void set_inclusive_max_distance(S1ChordAngle max_distance);
+
+    // Like set_inclusive_max_distance(), except that "max_distance" is also
+    // increased by the maximum error in the distance calculation.  This
+    // ensures that all cells whose true distance is less than or equal to
+    // "max_distance" will be returned (along with some cells whose true
+    // distance is slightly greater).
+    //
+    // Algorithms that need to do exact distance comparisons can use this
+    // option to find a set of candidate cells that can then be filtered
+    // further (e.g., using s2pred::CompareDistance).
+    void set_conservative_max_distance(S1ChordAngle max_distance);
+
+    // Versions of set_max_distance that take an S1Angle argument.  (Note that
+    // these functions require a conversion, and that the S1ChordAngle versions
+    // are preferred.)
+    void set_max_distance(S1Angle max_distance);
+    void set_inclusive_max_distance(S1Angle max_distance);
+    void set_conservative_max_distance(S1Angle max_distance);
+
+    // See S2ClosestCellQueryBase::Options for documentation.
+    using Base::Options::set_max_error;     // S1Chordangle version
+    void set_max_error(S1Angle max_error);  // S1Angle version
+
+    // Inherited options (see s2closest_cell_query_base.h for details):
+    using Base::Options::set_max_results;
+    using Base::Options::set_region;
+    using Base::Options::set_use_brute_force;
+  };
+
+  // "Target" represents the geometry to which the distance is measured.
+  // There are subtypes for measuring the distance to a point, an edge, an
+  // S2Cell, or an S2ShapeIndex (an arbitrary collection of geometry).
+  using Target = S2MinDistanceTarget;
+
+  // Target subtype that computes the closest distance to a point.
+  class PointTarget final : public S2MinDistancePointTarget {
+   public:
+    explicit PointTarget(const S2Point& point);
+    int max_brute_force_index_size() const override;
+  };
+
+  // Target subtype that computes the closest distance to an edge.
+  class EdgeTarget final : public S2MinDistanceEdgeTarget {
+   public:
+    explicit EdgeTarget(const S2Point& a, const S2Point& b);
+    int max_brute_force_index_size() const override;
+  };
+
+  // Target subtype that computes the closest distance to an S2Cell
+  // (including the interior of the cell).
+  class CellTarget final : public S2MinDistanceCellTarget {
+   public:
+    explicit CellTarget(const S2Cell& cell);
+    int max_brute_force_index_size() const override;
+  };
+
+  // Target subtype that computes the closest distance to an S2CellUnion.
+  class CellUnionTarget final : public S2MinDistanceCellUnionTarget {
+   public:
+    explicit CellUnionTarget(S2CellUnion cell_union);
+    int max_brute_force_index_size() const override;
+  };
+
+  // Target subtype that computes the closest distance to an S2ShapeIndex
+  // (an arbitrary collection of points, polylines, and/or polygons).
+  //
+  // By default, distances are measured to the boundary and interior of
+  // polygons in the S2ShapeIndex rather than to polygon boundaries only.
+  // If you wish to change this behavior, you may call
+  //
+  //   target.set_include_interiors(false);
+  //
+  // (see S2MinDistanceShapeIndexTarget for details).
+  class ShapeIndexTarget final : public S2MinDistanceShapeIndexTarget {
+   public:
+    explicit ShapeIndexTarget(const S2ShapeIndex* index);
+    int max_brute_force_index_size() const override;
+  };
+
+  // Convenience constructor that calls Init().  Options may be specified here
+  // or changed at any time using the mutable_options() accessor method.
+  //
+  // REQUIRES: "index" must persist for the lifetime of this object.
+  // REQUIRES: ReInit() must be called if "index" is modified.
+  explicit S2ClosestCellQuery(const S2CellIndex* index,
+                              const Options& options = Options());
+
+  // Default constructor; requires Init() to be called.
+  S2ClosestCellQuery();
+  ~S2ClosestCellQuery();
+
+  // Initializes the query.  Options may be specified here or changed at any
+  // time using the mutable_options() accessor method.
+  //
+  // REQUIRES: "index" must persist for the lifetime of this object.
+  // REQUIRES: ReInit() must be called if "index" is modified.
+  void Init(const S2CellIndex* index, const Options& options = Options());
+
+  // Reinitializes the query.  This method must be called if the underlying
+  // S2CellIndex is modified (by calling Clear() and Build() again).
+  void ReInit();
+
+  // Returns a reference to the underlying S2CellIndex.
+  const S2CellIndex& index() const;
+
+  // Returns the query options.  Options can be modified between queries.
+  const Options& options() const;
+  Options* mutable_options();
+
+  // Returns the closest cells to the given target that satisfy the current
+  // options.  This method may be called multiple times.
+  std::vector<Result> FindClosestCells(Target* target);
+
+  // This version can be more efficient when this method is called many times,
+  // since it does not require allocating a new vector on each call.
+  void FindClosestCells(Target* target, std::vector<Result>* results);
+
+  //////////////////////// Convenience Methods ////////////////////////
+
+  // Returns the closest cell to the target.  If no cell satisfies the search
+  // criteria, then the Result object will have distance == Infinity() and
+  // is_empty() == true.
+  Result FindClosestCell(Target* target);
+
+  // Returns the minimum distance to the target.  If the index or target is
+  // empty, returns S1ChordAngle::Infinity().
+  //
+  // Use IsDistanceLess() if you only want to compare the distance against a
+  // threshold value, since it is often much faster.
+  S1ChordAngle GetDistance(Target* target);
+
+  // Returns true if the distance to "target" is less than "limit".
+  //
+  // This method is usually much faster than GetDistance(), since it is much
+  // less work to determine whether the minimum distance is above or below a
+  // threshold than it is to calculate the actual minimum distance.
+  bool IsDistanceLess(Target* target, S1ChordAngle limit);
+
+  // Like IsDistanceLess(), but also returns true if the distance to "target"
+  // is exactly equal to "limit".
+  bool IsDistanceLessOrEqual(Target* target, S1ChordAngle limit);
+
+  // Like IsDistanceLessOrEqual(), except that "limit" is increased by the
+  // maximum error in the distance calculation.  This ensures that this
+  // function returns true whenever the true, exact distance is less than
+  // or equal to "limit".
+  bool IsConservativeDistanceLessOrEqual(Target* target, S1ChordAngle limit);
+
+ private:
+  Options options_;
+  Base base_;
+
+  S2ClosestCellQuery(const S2ClosestCellQuery&) = delete;
+  void operator=(const S2ClosestCellQuery&) = delete;
+};
+
+
+//////////////////   Implementation details follow   ////////////////////
+
+
+inline void S2ClosestCellQuery::Options::set_max_distance(
+    S1ChordAngle max_distance) {
+  Base::Options::set_max_distance(Distance(max_distance));
+}
+
+inline void S2ClosestCellQuery::Options::set_max_distance(
+    S1Angle max_distance) {
+  Base::Options::set_max_distance(Distance(max_distance));
+}
+
+inline void S2ClosestCellQuery::Options::set_inclusive_max_distance(
+    S1ChordAngle max_distance) {
+  set_max_distance(max_distance.Successor());
+}
+
+inline void S2ClosestCellQuery::Options::set_inclusive_max_distance(
+    S1Angle max_distance) {
+  set_inclusive_max_distance(S1ChordAngle(max_distance));
+}
+
+inline void S2ClosestCellQuery::Options::set_max_error(S1Angle max_error) {
+  Base::Options::set_max_error(S1ChordAngle(max_error));
+}
+
+inline S2ClosestCellQuery::PointTarget::PointTarget(const S2Point& point)
+    : S2MinDistancePointTarget(point) {
+}
+
+inline S2ClosestCellQuery::EdgeTarget::EdgeTarget(const S2Point& a,
+                                                  const S2Point& b)
+    : S2MinDistanceEdgeTarget(a, b) {
+}
+
+inline S2ClosestCellQuery::CellTarget::CellTarget(const S2Cell& cell)
+    : S2MinDistanceCellTarget(cell) {
+}
+
+inline S2ClosestCellQuery::CellUnionTarget::CellUnionTarget(
+    S2CellUnion cell_union)
+    : S2MinDistanceCellUnionTarget(std::move(cell_union)) {
+}
+
+inline S2ClosestCellQuery::ShapeIndexTarget::ShapeIndexTarget(
+    const S2ShapeIndex* index)
+    : S2MinDistanceShapeIndexTarget(index) {
+}
+
+inline S2ClosestCellQuery::S2ClosestCellQuery(const S2CellIndex* index,
+                                              const Options& options) {
+  Init(index, options);
+}
+
+inline void S2ClosestCellQuery::Init(const S2CellIndex* index,
+                                     const Options& options) {
+  options_ = options;
+  base_.Init(index);
+}
+
+inline void S2ClosestCellQuery::ReInit() {
+  base_.ReInit();
+}
+
+inline const S2CellIndex& S2ClosestCellQuery::index() const {
+  return base_.index();
+}
+
+inline const S2ClosestCellQuery::Options& S2ClosestCellQuery::options() const {
+  return options_;
+}
+
+inline S2ClosestCellQuery::Options* S2ClosestCellQuery::mutable_options() {
+  return &options_;
+}
+
+inline std::vector<S2ClosestCellQuery::Result>
+S2ClosestCellQuery::FindClosestCells(Target* target) {
+  return base_.FindClosestCells(target, options_);
+}
+
+inline void S2ClosestCellQuery::FindClosestCells(Target* target,
+                                                 std::vector<Result>* results) {
+  base_.FindClosestCells(target, options_, results);
+}
+
+inline S2ClosestCellQuery::Result S2ClosestCellQuery::FindClosestCell(
+    Target* target) {
+  static_assert(sizeof(Options) <= 32, "Consider not copying Options here");
+  Options tmp_options = options_;
+  tmp_options.set_max_results(1);
+  return base_.FindClosestCell(target, tmp_options);
+}
+
+inline S1ChordAngle S2ClosestCellQuery::GetDistance(Target* target) {
+  return FindClosestCell(target).distance();
+}
+
+#endif  // S2_S2CLOSEST_CELL_QUERY_H_
diff --git a/src/s2/s2closest_cell_query_base.h b/src/s2/s2closest_cell_query_base.h
new file mode 100644 (file)
index 0000000..0294c12
--- /dev/null
@@ -0,0 +1,842 @@
+// Copyright 2018 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// Author: ericv@google.com (Eric Veach)
+//
+// See S2ClosestCellQueryBase (defined below) for an overview.
+
+#ifndef S2_S2CLOSEST_CELL_QUERY_BASE_H_
+#define S2_S2CLOSEST_CELL_QUERY_BASE_H_
+
+#include <vector>
+
+#include "s2/base/logging.h"
+#include "absl/container/btree_set.h"
+#include "absl/container/inlined_vector.h"
+#include "s2/s1chord_angle.h"
+#include "s2/s2cap.h"
+#include "s2/s2cell_id.h"
+#include "s2/s2cell_index.h"
+#include "s2/s2cell_union.h"
+#include "s2/s2distance_target.h"
+#include "s2/s2region_coverer.h"
+#include "s2/util/gtl/dense_hash_set.h"
+#include "s2/util/hash/mix.h"
+
+// S2ClosestCellQueryBase is a templatized class for finding the closest
+// (cell_id, label) pairs in an S2CellIndex to a given target.  It is not
+// intended to be used directly, but rather to serve as the implementation of
+// various specialized classes with more convenient APIs (such as
+// S2ClosestCellQuery).  It is flexible enough so that it can be adapted to
+// compute maximum distances and even potentially Hausdorff distances.
+//
+// By using the appropriate options, this class can answer questions such as:
+//
+//  - Find the minimum distance between a cell collection A and a target B.
+//  - Find all cells in collection A that are within a distance D of target B.
+//  - Find the k cells of collection A that are closest to a given point P.
+//
+// The target is any class that implements the S2DistanceTarget interface.
+// There are predefined targets for points, edges, S2Cells, S2CellUnions, and
+// S2ShapeIndexes (arbitrary collctions of points, polylines, and polygons).
+//
+// The Distance template argument is used to represent distances.  Usually it
+// is a thin wrapper around S1ChordAngle, but another distance type may be
+// used as long as it implements the Distance concept described in
+// s2distance_targets.h.  For example this can be used to measure maximum
+// distances, to get more accuracy, or to measure non-spheroidal distances.
+template <class Distance>
+class S2ClosestCellQueryBase {
+ public:
+  using Delta = typename Distance::Delta;
+  using Label = S2CellIndex::Label;
+  using LabelledCell = S2CellIndex::LabelledCell;
+
+  // Options that control the set of cells returned.  Note that by default
+  // *all* cells are returned, so you will always want to set either the
+  // max_results() option or the max_distance() option (or both).
+  //
+  // This class is also available as S2ClosestCellQueryBase<Data>::Options.
+  //
+  // The Distance template argument is described below.
+  class Options {
+   public:
+    Options();
+
+    // Specifies that at most "max_results" cells should be returned.
+    //
+    // REQUIRES: max_results >= 1
+    // DEFAULT: kMaxMaxResults
+    int max_results() const;
+    void set_max_results(int max_results);
+    static constexpr int kMaxMaxResults = std::numeric_limits<int>::max();
+
+    // Specifies that only cells whose distance to the target is less than
+    // "max_distance" should be returned.
+    //
+    // Note that cells whose distance is exactly equal to "max_distance" are
+    // not returned.  In most cases this doesn't matter (since distances are
+    // not computed exactly in the first place), but if such cells are needed
+    // then you can retrieve them by specifying "max_distance" as the next
+    // largest representable Distance.  For example, if Distance is an
+    // S1ChordAngle then you can specify max_distance.Successor().
+    //
+    // DEFAULT: Distance::Infinity()
+    Distance max_distance() const;
+    void set_max_distance(Distance max_distance);
+
+    // Specifies that cells up to max_error() further away than the true
+    // closest cells may be substituted in the result set, as long as such
+    // cells satisfy all the remaining search criteria (such as max_distance).
+    // This option only has an effect if max_results() is also specified;
+    // otherwise all cells closer than max_distance() will always be returned.
+    //
+    // Note that this does not affect how the distance between cells is
+    // computed; it simply gives the algorithm permission to stop the search
+    // early as soon as the best possible improvement drops below max_error().
+    //
+    // This can be used to implement distance predicates efficiently.  For
+    // example, to determine whether the minimum distance is less than D, the
+    // IsDistanceLess() method sets max_results() == 1 and max_distance() ==
+    // max_error() == D.  This causes the algorithm to terminate as soon as it
+    // finds any cell whose distance is less than D, rather than continuing to
+    // search for a cell that is even closer.
+    //
+    // DEFAULT: Distance::Delta::Zero()
+    Delta max_error() const;
+    void set_max_error(Delta max_error);
+
+    // Specifies that cells must intersect the given S2Region.  "region" is
+    // owned by the caller and must persist during the lifetime of this
+    // object.  The value may be changed between calls to FindClosestPoints(),
+    // or reset by calling set_region(nullptr).
+    //
+    // Note that if you want to set the region to a disc around a target
+    // point, it is faster to use a PointTarget with set_max_distance()
+    // instead.  You can also call both methods, e.g. to set a maximum
+    // distance and also require that cells lie within a given rectangle.
+    const S2Region* region() const;
+    void set_region(const S2Region* region);
+
+    // Specifies that distances should be computed by examining every cell
+    // rather than using the S2ShapeIndex.  This is useful for testing,
+    // benchmarking, and debugging.
+    //
+    // DEFAULT: false
+    bool use_brute_force() const;
+    void set_use_brute_force(bool use_brute_force);
+
+   private:
+    Distance max_distance_ = Distance::Infinity();
+    Delta max_error_ = Delta::Zero();
+    const S2Region* region_ = nullptr;
+    int max_results_ = kMaxMaxResults;
+    bool use_brute_force_ = false;
+  };
+
+  // The Target class represents the geometry to which the distance is
+  // measured.  For example, there can be subtypes for measuring the distance
+  // to a point, an edge, or to an S2ShapeIndex (an arbitrary collection of
+  // geometry).
+  //
+  // Implementations do *not* need to be thread-safe.  They may cache data or
+  // allocate temporary data structures in order to improve performance.
+  using Target = S2DistanceTarget<Distance>;
+
+  // Each "Result" object represents a closest (cell_id, label) pair.
+  class Result {
+   public:
+    // The default constructor yields an empty result, with a distance() of
+    // Infinity() and invalid cell_id() and label() values.
+    Result() : distance_(Distance::Infinity()), cell_id_(S2CellId::None()),
+               label_(-1) {}
+
+    // Constructs a Result object for the given (cell_id, label) pair.
+    Result(Distance distance, S2CellId cell_id, Label label)
+        : distance_(distance), cell_id_(cell_id), label_(label) {}
+
+    // The distance from the target to this cell.
+    Distance distance() const { return distance_; }
+
+    // The cell itself.
+    S2CellId cell_id() const { return cell_id_; }
+
+    // The label associated with this S2CellId.
+    Label label() const { return label_; }
+
+    // Returns true if this Result object does not refer to any cell.
+    // (The only case where an empty Result is returned is when the
+    // FindClosestCell() method does not find any cells that meet the
+    // specified criteria.)
+    bool is_empty() const { return cell_id_ == S2CellId::None(); }
+
+    // Returns true if two Result objects are identical.
+    friend bool operator==(const Result& x, const Result& y) {
+      return (x.distance_ == y.distance_ &&
+              x.cell_id_ == y.cell_id_ &&
+              x.label_ == y.label_);
+    }
+
+    // Compares two Result objects first by distance, then by cell_id and
+    // finally by label.
+    friend bool operator<(const Result& x, const Result& y) {
+      if (x.distance_ < y.distance_) return true;
+      if (y.distance_ < x.distance_) return false;
+      if (x.cell_id_ < y.cell_id_) return true;
+      if (y.cell_id_ < x.cell_id_) return false;
+      return x.label_ < y.label_;
+    }
+
+    // Indicates that linear rather than binary search should be used when this
+    // type is used as the key in gtl::btree data structures.
+    using absl_btree_prefer_linear_node_search = std::true_type;
+
+   private:
+    Distance distance_;
+    S2CellId cell_id_;
+    Label label_;
+  };
+
+  // The minimum number of ranges that a cell must contain to enqueue it
+  // rather than processing its contents immediately.
+  static constexpr int kMinRangesToEnqueue = 6;
+
+  // Default constructor; requires Init() to be called.
+  S2ClosestCellQueryBase();
+  ~S2ClosestCellQueryBase();
+
+  // Convenience constructor that calls Init().
+  explicit S2ClosestCellQueryBase(const S2CellIndex* index);
+
+  // S2ClosestCellQueryBase is not copyable.
+  S2ClosestCellQueryBase(const S2ClosestCellQueryBase&) = delete;
+  void operator=(const S2ClosestCellQueryBase&) = delete;
+
+  // Initializes the query.
+  // REQUIRES: ReInit() must be called if "index" is modified.
+  void Init(const S2CellIndex* index);
+
+  // Reinitializes the query.  This method must be called whenever the
+  // underlying index is modified.
+  void ReInit();
+
+  // Return a reference to the underlying S2CellIndex.
+  const S2CellIndex& index() const;
+
+  // Returns the closest (cell_id, label) pairs to the given target that
+  // satisfy the given options.  This method may be called multiple times.
+  std::vector<Result> FindClosestCells(Target* target, const Options& options);
+
+  // This version can be more efficient when this method is called many times,
+  // since it does not require allocating a new vector on each call.
+  void FindClosestCells(Target* target, const Options& options,
+                        std::vector<Result>* results);
+
+  // Convenience method that returns exactly one (cell_id, label) pair.  If no
+  // cells satisfy the given search criteria, then a Result with
+  // distance() == Infinity() and is_empty() == true is returned.
+  //
+  // REQUIRES: options.max_results() == 1
+  Result FindClosestCell(Target* target, const Options& options);
+
+ private:
+  using CellIterator = S2CellIndex::CellIterator;
+  using ContentsIterator = S2CellIndex::ContentsIterator;
+  using NonEmptyRangeIterator = S2CellIndex::NonEmptyRangeIterator;
+  using RangeIterator = S2CellIndex::RangeIterator;
+
+  const Options& options() const { return *options_; }
+  void FindClosestCellsInternal(Target* target, const Options& options);
+  void FindClosestCellsBruteForce();
+  void FindClosestCellsOptimized();
+  void InitQueue();
+  void InitCovering();
+  void AddInitialRange(S2CellId first_id, S2CellId last_id);
+  void MaybeAddResult(S2CellId cell_id, Label label);
+  bool ProcessOrEnqueue(S2CellId id, NonEmptyRangeIterator* iter, bool seek);
+  void AddRange(const RangeIterator& range);
+
+  const S2CellIndex* index_;
+  const Options* options_;
+  Target* target_;
+
+  // True if max_error() must be subtracted from priority queue cell distances
+  // in order to ensure that such distances are measured conservatively.  This
+  // is true only if the target takes advantage of max_error() in order to
+  // return faster results, and 0 < max_error() < distance_limit_.
+  bool use_conservative_cell_distance_;
+
+  // For the optimized algorithm we precompute the top-level S2CellIds that
+  // will be added to the priority queue.  There can be at most 6 of these
+  // cells.  Essentially this is just a covering of the indexed cells.
+  std::vector<S2CellId> index_covering_;
+
+  // The distance beyond which we can safely ignore further candidate cells.
+  // (Candidates that are exactly at the limit are ignored; this is more
+  // efficient for UpdateMinDistance() and should not affect clients since
+  // distance measurements have a small amount of error anyway.)
+  //
+  // Initially this is the same as the maximum distance specified by the user,
+  // but it can also be updated by the algorithm (see MaybeAddResult).
+  Distance distance_limit_;
+
+  // The current result set is stored in one of three ways:
+  //
+  //  - If max_results() == 1, the best result is kept in result_singleton_.
+  //
+  //  - If max_results() == kMaxMaxResults, results are appended to
+  //    result_vector_ and sorted/uniqued at the end.
+  //
+  //  - Otherwise results are kept in a btree_set so that we can progressively
+  //    reduce the distance limit once max_results() results have been found.
+  //    (A priority queue is not sufficient because we need to be able to
+  //    check whether a candidate cell is already in the result set.)
+  //
+  // TODO(ericv): Check whether it would be faster to use avoid_duplicates_
+  // when result_set_ is used so that we could use a priority queue instead.
+  Result result_singleton_;
+  std::vector<Result> result_vector_;
+  absl::btree_set<Result> result_set_;
+
+  // When the results are stored in a btree_set (see above), usually
+  // duplicates can be removed simply by inserting candidate cells in the
+  // current result set.  However this is not true if Options::max_error() > 0
+  // and the Target subtype takes advantage of this by returning suboptimal
+  // distances.  This is because when UpdateMinDistance() is called with
+  // different "min_dist" parameters (i.e., the distance to beat), the
+  // implementation may return a different distance for the same cell.  Since
+  // the btree_set is keyed by (distance, cell_id, label) this can create
+  // duplicate results.
+  //
+  // The flag below is true when duplicates must be avoided explicitly.  This
+  // is achieved by maintaining a separate set keyed by (cell_id, label) only,
+  // and checking whether each edge is in that set before computing the
+  // distance to it.
+  //
+  // TODO(ericv): Check whether it is faster to avoid duplicates by default
+  // (even when Options::max_results() == 1), rather than just when we need to.
+  bool avoid_duplicates_;
+  struct LabelledCellHash {
+    size_t operator()(LabelledCell x) const {
+      HashMix mix(x.cell_id.id());
+      mix.Mix(x.label);
+      return mix.get();
+    }
+  };
+  gtl::dense_hash_set<LabelledCell, LabelledCellHash> tested_cells_;
+
+  // The algorithm maintains a priority queue of unprocessed S2CellIds, sorted
+  // in increasing order of distance from the target.
+  struct QueueEntry {
+    // A lower bound on the distance from the target to "id".  This is the key
+    // of the priority queue.
+    Distance distance;
+
+    // The cell being queued.
+    S2CellId id;
+
+    QueueEntry(Distance _distance, S2CellId _id)
+        : distance(_distance), id(_id) {}
+
+    bool operator<(const QueueEntry& other) const {
+      // The priority queue returns the largest elements first, so we want the
+      // "largest" entry to have the smallest distance.
+      return other.distance < distance;
+    }
+  };
+  using CellQueue =
+      std::priority_queue<QueueEntry, absl::InlinedVector<QueueEntry, 16>>;
+  CellQueue queue_;
+
+  // Used to iterate over the contents of an S2CellIndex range.  It is defined
+  // here to take advantage of the fact that when multiple ranges are visited
+  // in increasing order, duplicates can automatically be eliminated.
+  S2CellIndex::ContentsIterator contents_it_;
+
+  // Temporaries, defined here to avoid multiple allocations / initializations.
+
+  std::vector<S2CellId> max_distance_covering_;
+  std::vector<S2CellId> intersection_with_max_distance_;
+  const LabelledCell* tmp_range_data_[kMinRangesToEnqueue - 1];
+};
+
+
+//////////////////   Implementation details follow   ////////////////////
+
+
+template <class Distance>
+inline S2ClosestCellQueryBase<Distance>::Options::Options() {
+}
+
+template <class Distance>
+inline int S2ClosestCellQueryBase<Distance>::Options::max_results() const {
+  return max_results_;
+}
+
+template <class Distance>
+inline void S2ClosestCellQueryBase<Distance>::Options::set_max_results(
+    int max_results) {
+  S2_DCHECK_GE(max_results, 1);
+  max_results_ = max_results;
+}
+
+template <class Distance>
+inline Distance S2ClosestCellQueryBase<Distance>::Options::max_distance()
+    const {
+  return max_distance_;
+}
+
+template <class Distance>
+inline void S2ClosestCellQueryBase<Distance>::Options::set_max_distance(
+    Distance max_distance) {
+  max_distance_ = max_distance;
+}
+
+template <class Distance>
+inline typename Distance::Delta
+S2ClosestCellQueryBase<Distance>::Options::max_error() const {
+  return max_error_;
+}
+
+template <class Distance>
+inline void S2ClosestCellQueryBase<Distance>::Options::set_max_error(
+    Delta max_error) {
+  max_error_ = max_error;
+}
+
+template <class Distance>
+inline const S2Region* S2ClosestCellQueryBase<Distance>::Options::region()
+    const {
+  return region_;
+}
+
+template <class Distance>
+inline void S2ClosestCellQueryBase<Distance>::Options::set_region(
+    const S2Region* region) {
+  region_ = region;
+}
+
+template <class Distance>
+inline bool S2ClosestCellQueryBase<Distance>::Options::use_brute_force() const {
+  return use_brute_force_;
+}
+
+template <class Distance>
+inline void S2ClosestCellQueryBase<Distance>::Options::set_use_brute_force(
+    bool use_brute_force) {
+  use_brute_force_ = use_brute_force;
+}
+
+template <class Distance>
+S2ClosestCellQueryBase<Distance>::S2ClosestCellQueryBase()
+    : tested_cells_(1) /* expected_max_elements*/ {
+  tested_cells_.set_empty_key(LabelledCell(S2CellId::None(), -1));
+}
+
+template <class Distance>
+S2ClosestCellQueryBase<Distance>::~S2ClosestCellQueryBase() {
+  // Prevent inline destructor bloat by providing a definition.
+}
+
+template <class Distance>
+inline S2ClosestCellQueryBase<Distance>::S2ClosestCellQueryBase(
+    const S2CellIndex* index) : S2ClosestCellQueryBase() {
+  Init(index);
+}
+
+template <class Distance>
+void S2ClosestCellQueryBase<Distance>::Init(
+    const S2CellIndex* index) {
+  index_ = index;
+  contents_it_.Init(index);
+  ReInit();
+}
+
+template <class Distance>
+void S2ClosestCellQueryBase<Distance>::ReInit() {
+  index_covering_.clear();
+}
+
+template <class Distance>
+inline const S2CellIndex&
+S2ClosestCellQueryBase<Distance>::index() const {
+  return *index_;
+}
+
+template <class Distance>
+inline std::vector<typename S2ClosestCellQueryBase<Distance>::Result>
+S2ClosestCellQueryBase<Distance>::FindClosestCells(
+    Target* target, const Options& options) {
+  std::vector<Result> results;
+  FindClosestCells(target, options, &results);
+  return results;
+}
+
+template <class Distance>
+typename S2ClosestCellQueryBase<Distance>::Result
+S2ClosestCellQueryBase<Distance>::FindClosestCell(
+    Target* target, const Options& options) {
+  S2_DCHECK_EQ(options.max_results(), 1);
+  FindClosestCellsInternal(target, options);
+  return result_singleton_;
+}
+
+template <class Distance>
+void S2ClosestCellQueryBase<Distance>::FindClosestCells(
+    Target* target, const Options& options, std::vector<Result>* results) {
+  FindClosestCellsInternal(target, options);
+  results->clear();
+  if (options.max_results() == 1) {
+    if (!result_singleton_.is_empty()) {
+      results->push_back(result_singleton_);
+    }
+  } else if (options.max_results() == Options::kMaxMaxResults) {
+    std::sort(result_vector_.begin(), result_vector_.end());
+    std::unique_copy(result_vector_.begin(), result_vector_.end(),
+                     std::back_inserter(*results));
+    result_vector_.clear();
+  } else {
+    results->assign(result_set_.begin(), result_set_.end());
+    result_set_.clear();
+  }
+}
+
+template <class Distance>
+void S2ClosestCellQueryBase<Distance>::FindClosestCellsInternal(
+    Target* target, const Options& options) {
+  target_ = target;
+  options_ = &options;
+
+  tested_cells_.clear();
+  contents_it_.Clear();
+  distance_limit_ = options.max_distance();
+  result_singleton_ = Result();
+  S2_DCHECK(result_vector_.empty());
+  S2_DCHECK(result_set_.empty());
+  S2_DCHECK_GE(target->max_brute_force_index_size(), 0);
+  if (distance_limit_ == Distance::Zero()) return;
+
+  if (options.max_results() == Options::kMaxMaxResults &&
+      options.max_distance() == Distance::Infinity() &&
+      options.region() == nullptr) {
+    S2_LOG(WARNING) << "Returning all cells "
+                    "(max_results/max_distance/region not set)";
+  }
+
+  // If max_error() > 0 and the target takes advantage of this, then we may
+  // need to adjust the distance estimates to the priority queue cells to
+  // ensure that they are always a lower bound on the true distance.  For
+  // example, suppose max_distance == 100, max_error == 30, and we compute the
+  // distance to the target from some cell C0 as d(C0) == 80.  Then because
+  // the target takes advantage of max_error(), the true distance could be as
+  // low as 50.  In order not to miss edges contained by such cells, we need
+  // to subtract max_error() from the distance estimates.  This behavior is
+  // controlled by the use_conservative_cell_distance_ flag.
+  //
+  // However there is one important case where this adjustment is not
+  // necessary, namely when max_distance() < max_error().  This is because
+  // max_error() only affects the algorithm once at least max_edges() edges
+  // have been found that satisfy the given distance limit.  At that point,
+  // max_error() is subtracted from distance_limit_ in order to ensure that
+  // any further matches are closer by at least that amount.  But when
+  // max_distance() < max_error(), this reduces the distance limit to 0,
+  // i.e. all remaining candidate cells and edges can safely be discarded.
+  // (Note that this is how IsDistanceLess() and friends are implemented.)
+  //
+  // Note that Distance::Delta only supports operator==.
+  bool target_uses_max_error = (!(options.max_error() == Delta::Zero()) &&
+                                target_->set_max_error(options.max_error()));
+
+  // Note that we can't compare max_error() and distance_limit_ directly
+  // because one is a Delta and one is a Distance.  Instead we subtract them.
+  use_conservative_cell_distance_ = target_uses_max_error &&
+      (distance_limit_ == Distance::Infinity() ||
+       Distance::Zero() < distance_limit_ - options.max_error());
+
+  // Use the brute force algorithm if the index is small enough.
+  if (options.use_brute_force() ||
+      index_->num_cells() <= target_->max_brute_force_index_size()) {
+    avoid_duplicates_ = false;
+    FindClosestCellsBruteForce();
+  } else {
+    // If the target takes advantage of max_error() then we need to avoid
+    // duplicate edges explicitly.  (Otherwise it happens automatically.)
+    avoid_duplicates_ = (target_uses_max_error && options.max_results() > 1);
+    FindClosestCellsOptimized();
+  }
+}
+
+template <class Distance>
+void S2ClosestCellQueryBase<Distance>::FindClosestCellsBruteForce() {
+  for (CellIterator it(index_); !it.done(); it.Next()) {
+    MaybeAddResult(it.cell_id(), it.label());
+  }
+}
+
+template <class Distance>
+void S2ClosestCellQueryBase<Distance>::FindClosestCellsOptimized() {
+  InitQueue();
+  while (!queue_.empty()) {
+    // We need to copy the top entry before removing it, and we need to remove
+    // it before adding any new entries to the queue.
+    QueueEntry entry = queue_.top();
+    queue_.pop();
+    // Work around weird parse error in gcc 4.9 by using a local variable for
+    // entry.distance.
+    Distance distance = entry.distance;
+    if (!(distance < distance_limit_)) {
+      queue_ = CellQueue();  // Clear any remaining entries.
+      break;
+    }
+    S2CellId child = entry.id.child_begin();
+    // We already know that it has too many cells, so process its children.
+    // Each child may either be processed directly or enqueued again.  The
+    // loop is optimized so that we don't seek unnecessarily.
+    bool seek = true;
+    NonEmptyRangeIterator range(index_);
+    for (int i = 0; i < 4; ++i, child = child.next()) {
+      seek = ProcessOrEnqueue(child, &range, seek);
+    }
+  }
+}
+
+template <class Distance>
+void S2ClosestCellQueryBase<Distance>::InitQueue() {
+  S2_DCHECK(queue_.empty());
+
+  // Optimization: rather than starting with the entire index, see if we can
+  // limit the search region to a small disc.  Then we can find a covering for
+  // that disc and intersect it with the covering for the index.  This can
+  // save a lot of work when the search region is small.
+  S2Cap cap = target_->GetCapBound();
+  if (cap.is_empty()) return;  // Empty target.
+  if (options().max_results() == 1) {
+    // If the user is searching for just the closest cell, we can compute an
+    // upper bound on search radius by seeking to the center of the target's
+    // bounding cap and looking at the contents of that leaf cell range.  If
+    // the range intersects any cells, then the distance is zero.  Otherwise
+    // we can still look at the two neighboring ranges, and use the minimum
+    // distance to any cell in those ranges as an upper bound on the search
+    // radius.  These cells may wind up being processed twice, but in general
+    // this is still faster.
+    //
+    // First check the range containing or immediately following "center".
+    NonEmptyRangeIterator range(index_);
+    S2CellId target(cap.center());
+    range.Seek(target);
+    AddRange(range);
+    if (distance_limit_ == Distance::Zero()) return;
+
+    // If the range immediately follows "center" (rather than containing it),
+    // then check the previous non-empty range as well.
+    if (range.start_id() > target && range.Prev()) {
+      AddRange(range);
+      if (distance_limit_ == Distance::Zero()) return;
+    }
+  }
+
+  // We start with a covering of the set of indexed cells, then intersect it
+  // with the maximum search radius disc (if any).
+  //
+  // Note that unlike S2ClosestPointQuery, we can't also intersect with the
+  // given region (if any).  This is because the index cells in the result are
+  // only required to intersect the region.  This means that an index cell that
+  // intersects the region's covering may be much closer to the target than the
+  // covering itself, which means that we cannot use the region's covering to
+  // restrict the search.
+  //
+  // TODO(ericv): If this feature becomes important, this could be fixed by
+  // (1) computing a covering of the region, (2) looking up any index cells
+  // that contain each covering cell by seeking to covering_cell.range_min(),
+  // (3) replacing each covering cell by the largest such cell (if any), and
+  // (4) normalizing the result.
+  if (index_covering_.empty()) InitCovering();
+  const std::vector<S2CellId>* initial_cells = &index_covering_;
+  if (distance_limit_ < Distance::Infinity()) {
+    S2RegionCoverer coverer;
+    coverer.mutable_options()->set_max_cells(4);
+    S1ChordAngle radius = cap.radius() + distance_limit_.GetChordAngleBound();
+    S2Cap search_cap(cap.center(), radius);
+    coverer.GetFastCovering(search_cap, &max_distance_covering_);
+    S2CellUnion::GetIntersection(*initial_cells, max_distance_covering_,
+                                 &intersection_with_max_distance_);
+    initial_cells = &intersection_with_max_distance_;
+  }
+  NonEmptyRangeIterator range(index_);
+  for (int i = 0; i < initial_cells->size(); ++i) {
+    S2CellId id = (*initial_cells)[i];
+    bool seek = (i == 0) || id.range_min() >= range.limit_id();
+    ProcessOrEnqueue(id, &range, seek);
+    if (range.done()) break;
+  }
+}
+
+template <class Distance>
+void S2ClosestCellQueryBase<Distance>::InitCovering() {
+  // Compute the "index covering", which is a small number of S2CellIds that
+  // cover the indexed cells.  There are two cases:
+  //
+  //  - If the index spans more than one face, then there is one covering cell
+  // per spanned face, just big enough to cover the indexed cells on that face.
+  //
+  //  - If the index spans only one face, then we find the smallest cell "C"
+  // that covers the indexed cells on that face (just like the case above).
+  // Then for each of the 4 children of "C", if the child contains any index
+  // cells then we create a covering cell that is big enough to just fit
+  // those indexed cells (i.e., shrinking the child as much as possible to fit
+  // its contents).  This essentially replicates what would happen if we
+  // started with "C" as the covering cell, since "C" would immediately be
+  // split, except that we take the time to prune the children further since
+  // this will save work on every subsequent query.
+  index_covering_.reserve(6);
+  NonEmptyRangeIterator it(index_), last(index_);
+  it.Begin();
+  last.Finish();
+  if (!last.Prev()) return;  // Empty index.
+  S2CellId index_last_id = last.limit_id().prev();
+  if (it.start_id() != last.start_id()) {
+    // The index contains at least two distinct S2CellIds (because otherwise
+    // there would only be one non-empty range).  Choose a level such that the
+    // entire index can be spanned with at most 6 cells (if the index spans
+    // multiple faces) or 4 cells (it the index spans a single face).
+    int level = it.start_id().GetCommonAncestorLevel(index_last_id) + 1;
+
+    // Visit each potential covering cell except the last (handled below).
+    S2CellId start_id = it.start_id().parent(level);
+    S2CellId last_id = index_last_id.parent(level);
+    for (S2CellId id = start_id; id != last_id; id = id.next()) {
+      // Skip any covering cells that don't contain an indexed range.
+      if (id.range_max() < it.start_id()) continue;
+
+      // Find the indexed range contained by this covering cell and then
+      // shrink the cell if necessary so that it just covers this range.
+      S2CellId cell_first_id = it.start_id();
+      it.Seek(id.range_max().next());
+      // Find the last leaf cell covered by the previous non-empty range.
+      last = it;
+      last.Prev();
+      AddInitialRange(cell_first_id, last.limit_id().prev());
+    }
+  }
+  AddInitialRange(it.start_id(), index_last_id);
+}
+
+// Adds a cell to index_covering_ that covers the given inclusive range.
+//
+// REQUIRES: "first" and "last" have a common ancestor.
+template <class Distance>
+void S2ClosestCellQueryBase<Distance>::AddInitialRange(
+    S2CellId first_id, S2CellId last_id) {
+  // Add the lowest common ancestor of the given range.
+  int level = first_id.GetCommonAncestorLevel(last_id);
+  S2_DCHECK_GE(level, 0);
+  index_covering_.push_back(first_id.parent(level));
+}
+
+// TODO(ericv): Consider having this method return false when distance_limit_
+// is reduced to zero, and terminating any calling loops early.
+template <class Distance>
+void S2ClosestCellQueryBase<Distance>::MaybeAddResult(S2CellId cell_id,
+                                                      Label label) {
+  if (avoid_duplicates_ &&
+      !tested_cells_.insert(LabelledCell(cell_id, label)).second) {
+    return;
+  }
+
+  // TODO(ericv): It may be relatively common to add the same S2CellId
+  // multiple times with different labels.  This could be optimized by
+  // remembering the last "cell_id" argument and its distance.  However this
+  // may not be beneficial when Options::max_results() == 1, for example.
+  S2Cell cell(cell_id);
+  Distance distance = distance_limit_;
+  if (!target_->UpdateMinDistance(cell, &distance)) return;
+
+  const S2Region* region = options().region();
+  if (region && !region->MayIntersect(cell)) return;
+
+  Result result(distance, cell_id, label);
+  if (options().max_results() == 1) {
+    // Optimization for the common case where only the closest cell is wanted.
+    result_singleton_ = result;
+    distance_limit_ = result.distance() - options().max_error();
+  } else if (options().max_results() == Options::kMaxMaxResults) {
+    result_vector_.push_back(result);  // Sort/unique at end.
+  } else {
+    // Add this cell to result_set_.  Note that even if we already have enough
+    // edges, we can't erase an element before insertion because the "new"
+    // edge might in fact be a duplicate.
+    result_set_.insert(result);
+    int size = result_set_.size();
+    if (size >= options().max_results()) {
+      if (size > options().max_results()) {
+        result_set_.erase(--result_set_.end());
+      }
+      distance_limit_ = (--result_set_.end())->distance() -
+                        options().max_error();
+    }
+  }
+}
+
+// Either process the contents of the given cell immediately, or add it to the
+// queue to be subdivided.  If "seek" is false, then "iter" must be positioned
+// at the first non-empty range (if any) with start_id() >= id.range_min().
+//
+// Returns "true" if the cell was added to the queue, and "false" if it was
+// processed immediately, in which case "iter" is positioned at the first
+// non-empty range (if any) with start_id() > id.range_max().
+template <class Distance>
+bool S2ClosestCellQueryBase<Distance>::ProcessOrEnqueue(
+    S2CellId id, NonEmptyRangeIterator* iter, bool seek) {
+  if (seek) iter->Seek(id.range_min());
+  S2CellId last = id.range_max();
+  if (iter->start_id() > last) {
+    return false;  // No need to seek to next child.
+  }
+  // If this cell intersects at least "kMinRangesToEnqueue" leaf cell ranges
+  // (including ranges whose contents are empty), then enqueue it.  We test
+  // this by advancing (n - 1) ranges and checking whether that range also
+  // intersects this cell.
+  RangeIterator max_it = *iter;
+  if (max_it.Advance(kMinRangesToEnqueue - 1) && max_it.start_id() <= last) {
+    // This cell intersects at least kMinRangesToEnqueue ranges, so enqueue it.
+    S2Cell cell(id);
+    Distance distance = distance_limit_;
+    // We check "region_" second because it may be relatively expensive.
+    if (target_->UpdateMinDistance(cell, &distance) &&
+        (!options().region() || options().region()->MayIntersect(cell))) {
+      if (use_conservative_cell_distance_) {
+        // Ensure that "distance" is a lower bound on distance to the cell.
+        distance = distance - options().max_error();
+      }
+      queue_.push(QueueEntry(distance, id));
+    }
+    return true;  // Seek to next child.
+  }
+  // There were few enough ranges that we might as well process them now.
+  for (; iter->start_id() <= last; iter->Next()) {
+    AddRange(*iter);
+  }
+  return false;  // No need to seek to next child.
+}
+
+template <class Distance>
+void S2ClosestCellQueryBase<Distance>::AddRange(const RangeIterator& range) {
+  for (contents_it_.StartUnion(range);
+       !contents_it_.done(); contents_it_.Next()) {
+    MaybeAddResult(contents_it_.cell_id(), contents_it_.label());
+  }
+}
+
+#endif  // S2_S2CLOSEST_CELL_QUERY_BASE_H_
diff --git a/src/s2/s2closest_edge_query.cc b/src/s2/s2closest_edge_query.cc
new file mode 100644 (file)
index 0000000..534cf45
--- /dev/null
@@ -0,0 +1,106 @@
+// Copyright 2013 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// Author: ericv@google.com (Eric Veach)
+
+#include "s2/s2closest_edge_query.h"
+
+#include <memory>
+#include "absl/memory/memory.h"
+#include "s2/s1angle.h"
+#include "s2/s2cap.h"
+#include "s2/s2cell.h"
+#include "s2/s2cell_id.h"
+#include "s2/s2cell_union.h"
+#include "s2/s2edge_distances.h"
+#include "s2/s2region_coverer.h"
+#include "s2/s2shape_index_region.h"
+
+void S2ClosestEdgeQuery::Options::set_conservative_max_distance(
+    S1ChordAngle max_distance) {
+  set_max_distance(Distance(max_distance.PlusError(
+      S2::GetUpdateMinDistanceMaxError(max_distance)).Successor()));
+}
+
+void S2ClosestEdgeQuery::Options::set_conservative_max_distance(
+    S1Angle max_distance) {
+  set_conservative_max_distance(S1ChordAngle(max_distance));
+}
+
+int S2ClosestEdgeQuery::PointTarget::max_brute_force_index_size() const {
+  // Using BM_FindClosest (which finds the single closest edge), the
+  // break-even points are approximately 80, 100, and 250 edges for point
+  // cloud, fractal, and regular loop geometry respectively.
+  return 120;
+}
+
+int S2ClosestEdgeQuery::EdgeTarget::max_brute_force_index_size() const {
+  // Using BM_FindClosestToEdge (which finds the single closest edge), the
+  // break-even points are approximately 40, 50, and 100 edges for point
+  // cloud, fractal, and regular loop geometry respectively.
+  return 60;
+}
+
+int S2ClosestEdgeQuery::CellTarget::max_brute_force_index_size() const {
+  // Using BM_FindClosestToCell (which finds the single closest edge), the
+  // break-even points are approximately 20, 25, and 40 edges for point cloud,
+  // fractal, and regular loop geometry respectively.
+  return 30;
+}
+
+int S2ClosestEdgeQuery::ShapeIndexTarget::max_brute_force_index_size() const {
+  // For BM_FindClosestToSameSizeAbuttingIndex (which uses two nearby indexes
+  // with similar edge counts), the break-even points are approximately 20,
+  // 30, and 40 edges for point cloud, fractal, and regular loop geometry
+  // respectively.
+  return 25;
+}
+
+S2ClosestEdgeQuery::S2ClosestEdgeQuery() {
+  // Prevent inline constructor bloat by defining here.
+}
+
+S2ClosestEdgeQuery::~S2ClosestEdgeQuery() {
+  // Prevent inline destructor bloat by defining here.
+}
+
+bool S2ClosestEdgeQuery::IsDistanceLess(Target* target, S1ChordAngle limit) {
+  static_assert(sizeof(Options) <= 32, "Consider not copying Options here");
+  Options tmp_options = options_;
+  tmp_options.set_max_results(1);
+  tmp_options.set_max_distance(limit);
+  tmp_options.set_max_error(S1ChordAngle::Straight());
+  return !base_.FindClosestEdge(target, tmp_options).is_empty();
+}
+
+bool S2ClosestEdgeQuery::IsDistanceLessOrEqual(Target* target,
+                                               S1ChordAngle limit) {
+  static_assert(sizeof(Options) <= 32, "Consider not copying Options here");
+  Options tmp_options = options_;
+  tmp_options.set_max_results(1);
+  tmp_options.set_inclusive_max_distance(limit);
+  tmp_options.set_max_error(S1ChordAngle::Straight());
+  return !base_.FindClosestEdge(target, tmp_options).is_empty();
+}
+
+bool S2ClosestEdgeQuery::IsConservativeDistanceLessOrEqual(
+    Target* target, S1ChordAngle limit) {
+  static_assert(sizeof(Options) <= 32, "Consider not copying Options here");
+  Options tmp_options = options_;
+  tmp_options.set_max_results(1);
+  tmp_options.set_conservative_max_distance(limit);
+  tmp_options.set_max_error(S1ChordAngle::Straight());
+  return !base_.FindClosestEdge(target, tmp_options).is_empty();
+}
diff --git a/src/s2/s2closest_edge_query.h b/src/s2/s2closest_edge_query.h
new file mode 100644 (file)
index 0000000..e689db9
--- /dev/null
@@ -0,0 +1,421 @@
+// Copyright 2013 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// Author: ericv@google.com (Eric Veach)
+
+#ifndef S2_S2CLOSEST_EDGE_QUERY_H_
+#define S2_S2CLOSEST_EDGE_QUERY_H_
+
+#include <memory>
+#include <queue>
+#include <type_traits>
+#include <vector>
+
+#include "s2/base/logging.h"
+#include "absl/base/macros.h"
+#include "absl/container/inlined_vector.h"
+#include "s2/_fp_contract_off.h"
+#include "s2/s1angle.h"
+#include "s2/s1chord_angle.h"
+#include "s2/s2cell.h"
+#include "s2/s2cell_id.h"
+#include "s2/s2closest_edge_query_base.h"
+#include "s2/s2edge_distances.h"
+#include "s2/s2min_distance_targets.h"
+#include "s2/s2shape_index.h"
+
+// S2ClosestEdgeQuery is a helper class for finding the closest edge(s) to a
+// given point, edge, S2Cell, or geometry collection.  For example, given a
+// set of polylines, the following code efficiently finds the closest 5 edges
+// to a query point:
+//
+// void Test(const vector<S2Polyline*>& polylines, const S2Point& point) {
+//   MutableS2ShapeIndex index;
+//   for (S2Polyline* polyline : polylines) {
+//     index.Add(new S2Polyline::Shape(polyline));
+//   }
+//   S2ClosestEdgeQuery query(&index);
+//   query.mutable_options()->set_max_results(5);
+//   S2ClosestEdgeQuery::PointTarget target(point);
+//   for (const auto& result : query.FindClosestEdges(&target)) {
+//     // The Result struct contains the following fields:
+//     //   "distance" is the distance to the edge.
+//     //   "shape_id" identifies the S2Shape containing the edge.
+//     //   "edge_id" identifies the edge with the given shape.
+//     // The following convenience methods may also be useful:
+//     //   query.GetEdge(result) returns the endpoints of the edge.
+//     //   query.Project(point, result) computes the closest point on the
+//     //       result edge to the given target point.
+//     int polyline_index = result.shape_id;
+//     int edge_index = result.edge_id;
+//     S1ChordAngle distance = result.distance;  // Use ToAngle() for S1Angle.
+//     S2Shape::Edge edge = query.GetEdge(result);
+//     S2Point closest_point = query.Project(point, result);
+//   }
+// }
+//
+// You can find either the k closest edges, or all edges within a given
+// radius, or both (i.e., the k closest edges up to a given maximum radius).
+// E.g. to find all the edges within 5 kilometers, call
+//
+//   query.mutable_options()->set_max_distance(
+//       S2Earth::ToAngle(util::units::Kilometers(5)));
+//
+// By default *all* edges are returned, so you should always specify either
+// max_results() or max_distance() or both.  There is also a FindClosestEdge()
+// convenience method that returns only the closest edge.
+//
+// Note that by default, distances are measured to the boundary and interior
+// of polygons.  For example, if a point is inside a polygon then its distance
+// is zero.  To change this behavior, call set_include_interiors(false).
+//
+// If you only need to test whether the distance is above or below a given
+// threshold (e.g., 10 km), you can use the IsDistanceLess() method.  This is
+// much faster than actually calculating the distance with FindClosestEdge(),
+// since the implementation can stop as soon as it can prove that the minimum
+// distance is either above or below the threshold.
+//
+// To find the closest edges to a query edge rather than a point, use:
+//
+//   S2ClosestEdgeQuery::EdgeTarget target(v0, v1);
+//   query.FindClosestEdges(&target);
+//
+// Similarly you can find the closest edges to an S2Cell by using an
+// S2ClosestEdgeQuery::CellTarget, and you can find the closest edges to an
+// arbitrary collection of points, polylines, and polygons by using an
+// S2ClosestEdgeQuery::ShapeIndexTarget.
+//
+// The implementation is designed to be fast for both simple and complex
+// geometric objects.
+class S2ClosestEdgeQuery {
+ public:
+  // See S2ClosestEdgeQueryBase for full documentation.
+
+  // S2MinDistance is a thin wrapper around S1ChordAngle that implements the
+  // Distance concept required by S2ClosestPointQueryBase.
+  using Distance = S2MinDistance;
+  using Base = S2ClosestEdgeQueryBase<Distance>;
+
+  // Each "Result" object represents a closest edge.  It has the following
+  // fields:
+  //
+  //   S1ChordAngle distance;  // The distance from the target to this edge.
+  //   int32 shape_id;         // Identifies an indexed shape.
+  //   int32 edge_id;          // Identifies an edge within the shape.
+  using Result = Base::Result;
+
+  // Options that control the set of edges returned.  Note that by default
+  // *all* edges are returned, so you will always want to set either the
+  // max_results() option or the max_distance() option (or both).
+  class Options : public Base::Options {
+   public:
+    // See S2ClosestEdgeQueryBase::Options for the full set of options.
+
+    // Specifies that only edges whose distance to the target is less than
+    // "max_distance" should be returned.
+    //
+    // Note that edges whose distance is exactly equal to "max_distance" are
+    // not returned.  Normally this doesn't matter, because distances are not
+    // computed exactly in the first place, but if such edges are needed then
+    // see set_inclusive_max_distance() below.
+    //
+    // DEFAULT: Distance::Infinity()
+    void set_max_distance(S1ChordAngle max_distance);
+
+    // Like set_max_distance(), except that edges whose distance is exactly
+    // equal to "max_distance" are also returned.  Equivalent to calling
+    // set_max_distance(max_distance.Successor()).
+    void set_inclusive_max_distance(S1ChordAngle max_distance);
+
+    // Like set_inclusive_max_distance(), except that "max_distance" is also
+    // increased by the maximum error in the distance calculation.  This
+    // ensures that all edges whose true distance is less than or equal to
+    // "max_distance" will be returned (along with some edges whose true
+    // distance is slightly greater).
+    //
+    // Algorithms that need to do exact distance comparisons can use this
+    // option to find a set of candidate edges that can then be filtered
+    // further (e.g., using s2pred::CompareDistance).
+    void set_conservative_max_distance(S1ChordAngle max_distance);
+
+    // Versions of set_max_distance that take an S1Angle argument.  (Note that
+    // these functions require a conversion, and that the S1ChordAngle versions
+    // are preferred.)
+    void set_max_distance(S1Angle max_distance);
+    void set_inclusive_max_distance(S1Angle max_distance);
+    void set_conservative_max_distance(S1Angle max_distance);
+
+    // See S2ClosestEdgeQueryBase::Options for documentation.
+    using Base::Options::set_max_error;     // S1Chordangle version
+    void set_max_error(S1Angle max_error);  // S1Angle version
+
+    // Inherited options (see s2closest_edge_query_base.h for details):
+    using Base::Options::set_max_results;
+    using Base::Options::set_include_interiors;
+    using Base::Options::set_use_brute_force;
+  };
+
+  // "Target" represents the geometry to which the distance is measured.
+  // There are subtypes for measuring the distance to a point, an edge, an
+  // S2Cell, or an S2ShapeIndex (an arbitrary collection of geometry).
+  using Target = S2MinDistanceTarget;
+
+  // Target subtype that computes the closest distance to a point.
+  class PointTarget final : public S2MinDistancePointTarget {
+   public:
+    explicit PointTarget(const S2Point& point);
+    int max_brute_force_index_size() const override;
+  };
+
+  // Target subtype that computes the closest distance to an edge.
+  class EdgeTarget final : public S2MinDistanceEdgeTarget {
+   public:
+    explicit EdgeTarget(const S2Point& a, const S2Point& b);
+    int max_brute_force_index_size() const override;
+  };
+
+  // Target subtype that computes the closest distance to an S2Cell
+  // (including the interior of the cell).
+  class CellTarget final : public S2MinDistanceCellTarget {
+   public:
+    explicit CellTarget(const S2Cell& cell);
+    int max_brute_force_index_size() const override;
+  };
+
+  // Target subtype that computes the closest distance to an S2ShapeIndex
+  // (an arbitrary collection of points, polylines, and/or polygons).
+  //
+  // By default, distances are measured to the boundary and interior of
+  // polygons in the S2ShapeIndex rather than to polygon boundaries only.
+  // If you wish to change this behavior, you may call
+  //
+  //   target.set_include_interiors(false);
+  //
+  // (see S2MinDistanceShapeIndexTarget for details).
+  class ShapeIndexTarget final : public S2MinDistanceShapeIndexTarget {
+   public:
+    explicit ShapeIndexTarget(const S2ShapeIndex* index);
+    int max_brute_force_index_size() const override;
+  };
+
+  // Convenience constructor that calls Init().  Options may be specified here
+  // or changed at any time using the mutable_options() accessor method.
+  explicit S2ClosestEdgeQuery(const S2ShapeIndex* index,
+                              const Options& options = Options());
+
+  // Default constructor; requires Init() to be called.
+  S2ClosestEdgeQuery();
+  ~S2ClosestEdgeQuery();
+
+  // Initializes the query.  Options may be specified here or changed at any
+  // time using the mutable_options() accessor method.
+  //
+  // REQUIRES: "index" must persist for the lifetime of this object.
+  // REQUIRES: ReInit() must be called if "index" is modified.
+  void Init(const S2ShapeIndex* index, const Options& options = Options());
+
+  // Reinitializes the query.  This method must be called whenever the
+  // underlying S2ShapeIndex is modified.
+  void ReInit();
+
+  // Returns a reference to the underlying S2ShapeIndex.
+  const S2ShapeIndex& index() const;
+
+  // Returns the query options.  Options can be modified between queries.
+  const Options& options() const;
+  Options* mutable_options();
+
+  // Returns the closest edges to the given target that satisfy the current
+  // options.  This method may be called multiple times.
+  //
+  // Note that if options().include_interiors() is true, the result vector may
+  // include some entries with edge_id == -1.  This indicates that the target
+  // intersects the indexed polygon with the given shape_id.
+  std::vector<Result> FindClosestEdges(Target* target);
+
+  // This version can be more efficient when this method is called many times,
+  // since it does not require allocating a new vector on each call.
+  void FindClosestEdges(Target* target, std::vector<Result>* results);
+
+  //////////////////////// Convenience Methods ////////////////////////
+
+  // Returns the closest edge to the target.  If no edge satisfies the search
+  // criteria, then the Result object will have distance == Infinity(),
+  // is_empty() == true, and shape_id == edge_id == -1.
+  //
+  // Note that if options.include_interiors() is true, edge_id == -1 is also
+  // used to indicate that the target intersects an indexed polygon (but in
+  // that case distance == Zero() and shape_id >= 0).
+  Result FindClosestEdge(Target* target);
+
+  // Returns the minimum distance to the target.  If the index or target is
+  // empty, returns S1ChordAngle::Infinity().
+  //
+  // Use IsDistanceLess() if you only want to compare the distance against a
+  // threshold value, since it is often much faster.
+  S1ChordAngle GetDistance(Target* target);
+
+  // Returns true if the distance to "target" is less than "limit".
+  //
+  // This method is usually much faster than GetDistance(), since it is much
+  // less work to determine whether the minimum distance is above or below a
+  // threshold than it is to calculate the actual minimum distance.
+  bool IsDistanceLess(Target* target, S1ChordAngle limit);
+
+  // Like IsDistanceLess(), but also returns true if the distance to "target"
+  // is exactly equal to "limit".
+  bool IsDistanceLessOrEqual(Target* target, S1ChordAngle limit);
+
+  // Like IsDistanceLessOrEqual(), except that "limit" is increased by the
+  // maximum error in the distance calculation.  This ensures that this
+  // function returns true whenever the true, exact distance is less than
+  // or equal to "limit".
+  //
+  // For example, suppose that we want to test whether two geometries might
+  // intersect each other after they are snapped together using S2Builder
+  // (using the IdentitySnapFunction with a given "snap_radius").  Since
+  // S2Builder uses exact distance predicates (s2predicates.h), we need to
+  // measure the distance between the two geometries conservatively.  If the
+  // distance is definitely greater than "snap_radius", then the geometries
+  // are guaranteed to not intersect after snapping.
+  bool IsConservativeDistanceLessOrEqual(Target* target, S1ChordAngle limit);
+
+  // Returns the endpoints of the given result edge.
+  //
+  // CAVEAT: If options().include_interiors() is true, then clients must not
+  // pass this method any Result objects that correspond to shape interiors,
+  // i.e. those where result.edge_id < 0.
+  //
+  // REQUIRES: result.edge_id >= 0
+  S2Shape::Edge GetEdge(const Result& result) const;
+
+  // Returns the point on given result edge that is closest to "point".
+  S2Point Project(const S2Point& point, const Result& result) const;
+
+ private:
+  Options options_;
+  Base base_;
+
+  S2ClosestEdgeQuery(const S2ClosestEdgeQuery&) = delete;
+  void operator=(const S2ClosestEdgeQuery&) = delete;
+};
+
+
+//////////////////   Implementation details follow   ////////////////////
+
+
+inline void S2ClosestEdgeQuery::Options::set_max_distance(
+    S1ChordAngle max_distance) {
+  Base::Options::set_max_distance(Distance(max_distance));
+}
+
+inline void S2ClosestEdgeQuery::Options::set_max_distance(
+    S1Angle max_distance) {
+  Base::Options::set_max_distance(Distance(max_distance));
+}
+
+inline void S2ClosestEdgeQuery::Options::set_inclusive_max_distance(
+    S1ChordAngle max_distance) {
+  set_max_distance(max_distance.Successor());
+}
+
+inline void S2ClosestEdgeQuery::Options::set_inclusive_max_distance(
+    S1Angle max_distance) {
+  set_inclusive_max_distance(S1ChordAngle(max_distance));
+}
+
+inline void S2ClosestEdgeQuery::Options::set_max_error(S1Angle max_error) {
+  Base::Options::set_max_error(S1ChordAngle(max_error));
+}
+
+inline S2ClosestEdgeQuery::PointTarget::PointTarget(const S2Point& point)
+    : S2MinDistancePointTarget(point) {
+}
+
+inline S2ClosestEdgeQuery::EdgeTarget::EdgeTarget(const S2Point& a,
+                                                  const S2Point& b)
+    : S2MinDistanceEdgeTarget(a, b) {
+}
+
+inline S2ClosestEdgeQuery::CellTarget::CellTarget(const S2Cell& cell)
+    : S2MinDistanceCellTarget(cell) {
+}
+
+inline S2ClosestEdgeQuery::ShapeIndexTarget::ShapeIndexTarget(
+    const S2ShapeIndex* index)
+    : S2MinDistanceShapeIndexTarget(index) {
+}
+
+inline S2ClosestEdgeQuery::S2ClosestEdgeQuery(const S2ShapeIndex* index,
+                                              const Options& options) {
+  Init(index, options);
+}
+
+inline void S2ClosestEdgeQuery::Init(const S2ShapeIndex* index,
+                                     const Options& options) {
+  options_ = options;
+  base_.Init(index);
+}
+
+inline void S2ClosestEdgeQuery::ReInit() {
+  base_.ReInit();
+}
+
+inline const S2ShapeIndex& S2ClosestEdgeQuery::index() const {
+  return base_.index();
+}
+
+inline const S2ClosestEdgeQuery::Options& S2ClosestEdgeQuery::options() const {
+  return options_;
+}
+
+inline S2ClosestEdgeQuery::Options* S2ClosestEdgeQuery::mutable_options() {
+  return &options_;
+}
+
+inline std::vector<S2ClosestEdgeQuery::Result>
+S2ClosestEdgeQuery::FindClosestEdges(Target* target) {
+  return base_.FindClosestEdges(target, options_);
+}
+
+inline void S2ClosestEdgeQuery::FindClosestEdges(Target* target,
+                                                 std::vector<Result>* results) {
+  base_.FindClosestEdges(target, options_, results);
+}
+
+inline S2ClosestEdgeQuery::Result S2ClosestEdgeQuery::FindClosestEdge(
+    Target* target) {
+  static_assert(sizeof(Options) <= 32, "Consider not copying Options here");
+  Options tmp_options = options_;
+  tmp_options.set_max_results(1);
+  return base_.FindClosestEdge(target, tmp_options);
+}
+
+inline S1ChordAngle S2ClosestEdgeQuery::GetDistance(Target* target) {
+  return FindClosestEdge(target).distance();
+}
+
+inline S2Shape::Edge S2ClosestEdgeQuery::GetEdge(const Result& result) const {
+  return index().shape(result.shape_id())->edge(result.edge_id());
+}
+
+inline S2Point S2ClosestEdgeQuery::Project(const S2Point& point,
+                                           const Result& result) const {
+  if (result.edge_id() < 0) return point;
+  auto edge = GetEdge(result);
+  return S2::Project(point, edge.v0, edge.v1);
+}
+
+#endif  // S2_S2CLOSEST_EDGE_QUERY_H_
diff --git a/src/s2/s2closest_edge_query_base.h b/src/s2/s2closest_edge_query_base.h
new file mode 100644 (file)
index 0000000..e1f047c
--- /dev/null
@@ -0,0 +1,946 @@
+// Copyright 2017 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// Author: ericv@google.com (Eric Veach)
+
+#ifndef S2_S2CLOSEST_EDGE_QUERY_BASE_H_
+#define S2_S2CLOSEST_EDGE_QUERY_BASE_H_
+
+#include <memory>
+#include <vector>
+
+#include "s2/base/logging.h"
+#include "absl/container/btree_set.h"
+#include "absl/container/inlined_vector.h"
+#include "s2/_fp_contract_off.h"
+#include "s2/s1angle.h"
+#include "s2/s1chord_angle.h"
+#include "s2/s2cap.h"
+#include "s2/s2cell.h"
+#include "s2/s2cell_id.h"
+#include "s2/s2cell_union.h"
+#include "s2/s2distance_target.h"
+#include "s2/s2region_coverer.h"
+#include "s2/s2shape_index.h"
+#include "s2/s2shapeutil_count_edges.h"
+#include "s2/s2shapeutil_shape_edge_id.h"
+#include "s2/util/gtl/dense_hash_set.h"
+
+// S2ClosestEdgeQueryBase is a templatized class for finding the closest
+// edge(s) between two geometries.  It is not intended to be used directly,
+// but rather to serve as the implementation of various specialized classes
+// with more convenient APIs (such as S2ClosestEdgeQuery).  It is flexible
+// enough so that it can be adapted to compute maximum distances and even
+// potentially Hausdorff distances.
+//
+// By using the appropriate options, this class can answer questions such as:
+//
+//  - Find the minimum distance between two geometries A and B.
+//  - Find all edges of geometry A that are within a distance D of geometry B.
+//  - Find the k edges of geometry A that are closest to a given point P.
+//
+// You can also specify whether polygons should include their interiors (i.e.,
+// if a point is contained by a polygon, should the distance be zero or should
+// it be measured to the polygon boundary?)
+//
+// The input geometries may consist of any number of points, polylines, and
+// polygons (collectively referred to as "shapes").  Shapes do not need to be
+// disjoint; they may overlap or intersect arbitrarily.  The implementation is
+// designed to be fast for both simple and complex geometries.
+//
+// The Distance template argument is used to represent distances.  Usually it
+// is a thin wrapper around S1ChordAngle, but another distance type may be
+// used as long as it implements the Distance concept described in
+// s2distance_targets.h.  For example this can be used to measure maximum
+// distances, to get more accuracy, or to measure non-spheroidal distances.
+template <class Distance>
+class S2ClosestEdgeQueryBase {
+ public:
+  using Delta = typename Distance::Delta;
+
+  // Options that control the set of edges returned.  Note that by default
+  // *all* edges are returned, so you will always want to set either the
+  // max_results() option or the max_distance() option (or both).
+  class Options {
+   public:
+    Options();
+
+    // Specifies that at most "max_results" edges should be returned.
+    //
+    // REQUIRES: max_results >= 1
+    // DEFAULT: kMaxMaxResults
+    int max_results() const;
+    void set_max_results(int max_results);
+    static constexpr int kMaxMaxResults = std::numeric_limits<int>::max();
+
+    // Specifies that only edges whose distance to the target is less than
+    // "max_distance" should be returned.
+    //
+    // Note that edges whose distance is exactly equal to "max_distance" are
+    // not returned.  In most cases this doesn't matter (since distances are
+    // not computed exactly in the first place), but if such edges are needed
+    // then you can retrieve them by specifying "max_distance" as the next
+    // largest representable Distance.  For example, if Distance is an
+    // S1ChordAngle then you can specify max_distance.Successor().
+    //
+    // DEFAULT: Distance::Infinity()
+    Distance max_distance() const;
+    void set_max_distance(Distance max_distance);
+
+    // Specifies that edges up to max_error() further away than the true
+    // closest edges may be substituted in the result set, as long as such
+    // edges satisfy all the remaining search criteria (such as max_distance).
+    // This option only has an effect if max_results() is also specified;
+    // otherwise all edges closer than max_distance() will always be returned.
+    //
+    // Note that this does not affect how the distance between edges is
+    // computed; it simply gives the algorithm permission to stop the search
+    // early as soon as the best possible improvement drops below max_error().
+    //
+    // This can be used to implement distance predicates efficiently.  For
+    // example, to determine whether the minimum distance is less than D, set
+    // max_results() == 1 and max_distance() == max_error() == D.  This causes
+    // the algorithm to terminate as soon as it finds any edge whose distance
+    // is less than D, rather than continuing to search for an edge that is
+    // even closer.
+    //
+    // DEFAULT: Distance::Delta::Zero()
+    Delta max_error() const;
+    void set_max_error(Delta max_error);
+
+    // Specifies that polygon interiors should be included when measuring
+    // distances.  In other words, polygons that contain the target should
+    // have a distance of zero.  (For targets consisting of multiple connected
+    // components, the distance is zero if any component is contained.)  This
+    // is indicated in the results by returning a (shape_id, edge_id) pair
+    // with edge_id == -1, i.e. this value denotes the polygons's interior.
+    //
+    // Note that for efficiency, any polygon that intersects the target may or
+    // may not have an (edge_id == -1) result.  Such results are optional
+    // because in that case the distance to the polygon is already zero.
+    //
+    // DEFAULT: true
+    bool include_interiors() const;
+    void set_include_interiors(bool include_interiors);
+
+    // Specifies that distances should be computed by examining every edge
+    // rather than using the S2ShapeIndex.  This is useful for testing,
+    // benchmarking, and debugging.
+    //
+    // DEFAULT: false
+    bool use_brute_force() const;
+    void set_use_brute_force(bool use_brute_force);
+
+   private:
+    Distance max_distance_ = Distance::Infinity();
+    Delta max_error_ = Delta::Zero();
+    int max_results_ = kMaxMaxResults;
+    bool include_interiors_ = true;
+    bool use_brute_force_ = false;
+  };
+
+  // The Target class represents the geometry to which the distance is
+  // measured.  For example, there can be subtypes for measuring the distance
+  // to a point, an edge, or to an S2ShapeIndex (an arbitrary collection of
+  // geometry).
+  //
+  // Implementations do *not* need to be thread-safe.  They may cache data or
+  // allocate temporary data structures in order to improve performance.
+  using Target = S2DistanceTarget<Distance>;
+
+  // Each "Result" object represents a closest edge.  Note the following
+  // special cases:
+  //
+  //  - (shape_id() >= 0) && (edge_id() < 0) represents the interior of a shape.
+  //    Such results may be returned when options.include_interiors() is true.
+  //    Such results can be identified using the is_interior() method.
+  //
+  //  - (shape_id() < 0) && (edge_id() < 0) is returned by `FindClosestEdge`
+  //    to indicate that no edge satisfies the given query options.  Such
+  //    results can be identified using is_empty() method.
+  class Result {
+   public:
+    // The default constructor yields an empty result, with a distance() of
+    // Infinity() and shape_id == edge_id == -1.
+    Result() : distance_(Distance::Infinity()), shape_id_(-1), edge_id_(-1) {}
+
+    // Constructs a Result object for the given arguments.
+    Result(Distance distance, int32 shape_id, int32 edge_id)
+        : distance_(distance), shape_id_(shape_id), edge_id_(edge_id) {}
+
+    // The distance from the target to this edge.
+    Distance distance() const { return distance_; }
+
+    // Identifies an indexed shape.
+    int32 shape_id() const { return shape_id_; }
+
+    // Identifies an edge within the shape.
+    int32 edge_id() const { return edge_id_; }
+
+    // Returns true if this Result object represents the interior of a shape.
+    // (Such results may be returned when options.include_interiors() is true.)
+    bool is_interior() const { return shape_id_ >= 0 && edge_id_ < 0; }
+
+    // Returns true if this Result object indicates that no edge satisfies the
+    // given query options.  (This result is only returned in one special
+    // case, namely when FindClosestEdge() does not find any suitable edges.
+    // It is never returned by methods that return a vector of results.)
+    bool is_empty() const { return shape_id_ < 0; }
+
+    // Returns true if two Result objects are identical.
+    friend bool operator==(const Result& x, const Result& y) {
+      return (x.distance_ == y.distance_ &&
+              x.shape_id_ == y.shape_id_ &&
+              x.edge_id_ == y.edge_id_);
+    }
+
+    // Compares edges first by distance, then by (shape_id, edge_id).
+    friend bool operator<(const Result& x, const Result& y) {
+      if (x.distance_ < y.distance_) return true;
+      if (y.distance_ < x.distance_) return false;
+      if (x.shape_id_ < y.shape_id_) return true;
+      if (y.shape_id_ < x.shape_id_) return false;
+      return x.edge_id_ < y.edge_id_;
+    }
+
+    // Indicates that linear rather than binary search should be used when this
+    // type is used as the key in gtl::btree data structures.
+    using absl_btree_prefer_linear_node_search = std::true_type;
+
+   private:
+    Distance distance_;  // The distance from the target to this edge.
+    int32 shape_id_;     // Identifies an indexed shape.
+    int32 edge_id_;      // Identifies an edge within the shape.
+  };
+
+  // Default constructor; requires Init() to be called.
+  S2ClosestEdgeQueryBase();
+  ~S2ClosestEdgeQueryBase();
+
+  // Convenience constructor that calls Init().
+  explicit S2ClosestEdgeQueryBase(const S2ShapeIndex* index);
+
+  // S2ClosestEdgeQueryBase is not copyable.
+  S2ClosestEdgeQueryBase(const S2ClosestEdgeQueryBase&) = delete;
+  void operator=(const S2ClosestEdgeQueryBase&) = delete;
+
+  // Initializes the query.
+  // REQUIRES: ReInit() must be called if "index" is modified.
+  void Init(const S2ShapeIndex* index);
+
+  // Reinitializes the query.  This method must be called whenever the
+  // underlying index is modified.
+  void ReInit();
+
+  // Returns a reference to the underlying S2ShapeIndex.
+  const S2ShapeIndex& index() const;
+
+  // Returns the closest edges to the given target that satisfy the given
+  // options.  This method may be called multiple times.
+  //
+  // Note that if options().include_interiors() is true, the result vector may
+  // include some entries with edge_id == -1.  This indicates that the target
+  // intersects the indexed polygon with the given shape_id.
+  std::vector<Result> FindClosestEdges(Target* target, const Options& options);
+
+  // This version can be more efficient when this method is called many times,
+  // since it does not require allocating a new vector on each call.
+  void FindClosestEdges(Target* target, const Options& options,
+                        std::vector<Result>* results);
+
+  // Convenience method that returns exactly one edge.  If no edges satisfy
+  // the given search criteria, then a Result with distance == Infinity() and
+  // shape_id == edge_id == -1 is returned.
+  //
+  // Note that if options.include_interiors() is true, edge_id == -1 is also
+  // used to indicate that the target intersects an indexed polygon (but in
+  // that case distance == Zero() and shape_id >= 0).
+  //
+  // REQUIRES: options.max_results() == 1
+  Result FindClosestEdge(Target* target, const Options& options);
+
+ private:
+  struct QueueEntry;
+
+  const Options& options() const { return *options_; }
+  void FindClosestEdgesInternal(Target* target, const Options& options);
+  void FindClosestEdgesBruteForce();
+  void FindClosestEdgesOptimized();
+  void InitQueue();
+  void InitCovering();
+  void AddInitialRange(const S2ShapeIndex::Iterator& first,
+                       const S2ShapeIndex::Iterator& last);
+  void MaybeAddResult(const S2Shape& shape, int edge_id);
+  void AddResult(const Result& result);
+  void ProcessEdges(const QueueEntry& entry);
+  void ProcessOrEnqueue(S2CellId id);
+  void ProcessOrEnqueue(S2CellId id, const S2ShapeIndexCell* index_cell);
+
+  const S2ShapeIndex* index_;
+  const Options* options_;
+  Target* target_;
+
+  // True if max_error() must be subtracted from priority queue cell distances
+  // in order to ensure that such distances are measured conservatively.  This
+  // is true only if the target takes advantage of max_error() in order to
+  // return faster results, and 0 < max_error() < distance_limit_.
+  bool use_conservative_cell_distance_;
+
+  // For the optimized algorihm we precompute the top-level S2CellIds that
+  // will be added to the priority queue.  There can be at most 6 of these
+  // cells.  Essentially this is just a covering of the indexed edges, except
+  // that we also store pointers to the corresponding S2ShapeIndexCells to
+  // reduce the number of index seeks required.
+  //
+  // The covering needs to be stored in a std::vector so that we can use
+  // S2CellUnion::GetIntersection().
+  std::vector<S2CellId> index_covering_;
+  absl::InlinedVector<const S2ShapeIndexCell*, 6> index_cells_;
+
+  // The decision about whether to use the brute force algorithm is based on
+  // counting the total number of edges in the index.  However if the index
+  // contains a large number of shapes, this in itself might take too long.
+  // So instead we only count edges up to (max_brute_force_index_size() + 1)
+  // for the current target type (stored as index_num_edges_limit_).
+  int index_num_edges_;
+  int index_num_edges_limit_;
+
+  // The distance beyond which we can safely ignore further candidate edges.
+  // (Candidates that are exactly at the limit are ignored; this is more
+  // efficient for UpdateMinDistance() and should not affect clients since
+  // distance measurements have a small amount of error anyway.)
+  //
+  // Initially this is the same as the maximum distance specified by the user,
+  // but it can also be updated by the algorithm (see MaybeAddResult).
+  Distance distance_limit_;
+
+  // The current result set is stored in one of three ways:
+  //
+  //  - If max_results() == 1, the best result is kept in result_singleton_.
+  //
+  //  - If max_results() == "infinity", results are appended to result_vector_
+  //    and sorted/uniqued at the end.
+  //
+  //  - Otherwise results are kept in a btree_set so that we can progressively
+  //    reduce the distance limit once max_results() results have been found.
+  //    (A priority queue is not sufficient because we need to be able to
+  //    check whether a candidate edge is already in the result set.)
+  //
+  // TODO(ericv): Check whether it would be faster to use avoid_duplicates_
+  // when result_set_ is used so that we could use a priority queue instead.
+  Result result_singleton_;
+  std::vector<Result> result_vector_;
+  absl::btree_set<Result> result_set_;
+
+  // When the result edges are stored in a btree_set (see above), usually
+  // duplicates can be removed simply by inserting candidate edges in the
+  // current set.  However this is not true if Options::max_error() > 0 and
+  // the Target subtype takes advantage of this by returning suboptimal
+  // distances.  This is because when UpdateMinDistance() is called with
+  // different "min_dist" parameters (i.e., the distance to beat), the
+  // implementation may return a different distance for the same edge.  Since
+  // the btree_set is keyed by (distance, shape_id, edge_id) this can create
+  // duplicate edges in the results.
+  //
+  // The flag below is true when duplicates must be avoided explicitly.  This
+  // is achieved by maintaining a separate set keyed by (shape_id, edge_id)
+  // only, and checking whether each edge is in that set before computing the
+  // distance to it.
+  //
+  // TODO(ericv): Check whether it is faster to avoid duplicates by default
+  // (even when Options::max_results() == 1), rather than just when we need to.
+  bool avoid_duplicates_;
+  using ShapeEdgeId = s2shapeutil::ShapeEdgeId;
+  gtl::dense_hash_set<ShapeEdgeId, s2shapeutil::ShapeEdgeIdHash> tested_edges_;
+
+  // The algorithm maintains a priority queue of unprocessed S2CellIds, sorted
+  // in increasing order of distance from the target.
+  struct QueueEntry {
+    // A lower bound on the distance from the target to "id".  This is the key
+    // of the priority queue.
+    Distance distance;
+
+    // The cell being queued.
+    S2CellId id;
+
+    // If "id" belongs to the index, this field stores the corresponding
+    // S2ShapeIndexCell.  Otherwise "id" is a proper ancestor of one or more
+    // S2ShapeIndexCells and this field stores nullptr.  The purpose of this
+    // field is to avoid an extra Seek() when the queue entry is processed.
+    const S2ShapeIndexCell* index_cell;
+
+    QueueEntry(Distance _distance, S2CellId _id,
+               const S2ShapeIndexCell* _index_cell)
+        : distance(_distance), id(_id), index_cell(_index_cell) {
+    }
+    bool operator<(const QueueEntry& other) const {
+      // The priority queue returns the largest elements first, so we want the
+      // "largest" entry to have the smallest distance.
+      return other.distance < distance;
+    }
+  };
+  using CellQueue =
+      std::priority_queue<QueueEntry, absl::InlinedVector<QueueEntry, 16>>;
+  CellQueue queue_;
+
+  // Temporaries, defined here to avoid multiple allocations / initializations.
+
+  S2ShapeIndex::Iterator iter_;
+  std::vector<S2CellId> max_distance_covering_;
+  std::vector<S2CellId> initial_cells_;
+};
+
+
+//////////////////   Implementation details follow   ////////////////////
+
+
+template <class Distance>
+inline S2ClosestEdgeQueryBase<Distance>::Options::Options() {
+}
+
+template <class Distance>
+inline int S2ClosestEdgeQueryBase<Distance>::Options::max_results() const {
+  return max_results_;
+}
+
+template <class Distance>
+inline void S2ClosestEdgeQueryBase<Distance>::Options::set_max_results(
+    int max_results) {
+  S2_DCHECK_GE(max_results, 1);
+  max_results_ = max_results;
+}
+
+template <class Distance>
+inline Distance S2ClosestEdgeQueryBase<Distance>::Options::max_distance()
+    const {
+  return max_distance_;
+}
+
+template <class Distance>
+inline void S2ClosestEdgeQueryBase<Distance>::Options::set_max_distance(
+    Distance max_distance) {
+  max_distance_ = max_distance;
+}
+
+template <class Distance>
+inline typename Distance::Delta
+S2ClosestEdgeQueryBase<Distance>::Options::max_error() const {
+  return max_error_;
+}
+
+template <class Distance>
+inline void S2ClosestEdgeQueryBase<Distance>::Options::set_max_error(
+    Delta max_error) {
+  max_error_ = max_error;
+}
+
+template <class Distance>
+inline bool S2ClosestEdgeQueryBase<Distance>::Options::include_interiors()
+    const {
+  return include_interiors_;
+}
+
+template <class Distance>
+inline void S2ClosestEdgeQueryBase<Distance>::Options::set_include_interiors(
+    bool include_interiors) {
+  include_interiors_ = include_interiors;
+}
+
+template <class Distance>
+inline bool S2ClosestEdgeQueryBase<Distance>::Options::use_brute_force() const {
+  return use_brute_force_;
+}
+
+template <class Distance>
+inline void S2ClosestEdgeQueryBase<Distance>::Options::set_use_brute_force(
+    bool use_brute_force) {
+  use_brute_force_ = use_brute_force;
+}
+
+template <class Distance>
+S2ClosestEdgeQueryBase<Distance>::S2ClosestEdgeQueryBase()
+    : tested_edges_(1) /* expected_max_elements*/ {
+  tested_edges_.set_empty_key(ShapeEdgeId(-1, -1));
+}
+
+template <class Distance>
+S2ClosestEdgeQueryBase<Distance>::~S2ClosestEdgeQueryBase() {
+  // Prevent inline destructor bloat by providing a definition.
+}
+
+template <class Distance>
+inline S2ClosestEdgeQueryBase<Distance>::S2ClosestEdgeQueryBase(
+    const S2ShapeIndex* index) : S2ClosestEdgeQueryBase() {
+  Init(index);
+}
+
+template <class Distance>
+void S2ClosestEdgeQueryBase<Distance>::Init(const S2ShapeIndex* index) {
+  index_ = index;
+  ReInit();
+}
+
+template <class Distance>
+void S2ClosestEdgeQueryBase<Distance>::ReInit() {
+  index_num_edges_ = 0;
+  index_num_edges_limit_ = 0;
+  index_covering_.clear();
+  index_cells_.clear();
+  // We don't initialize iter_ here to make queries on small indexes a bit
+  // faster (i.e., where brute force is used).
+}
+
+template <class Distance>
+inline const S2ShapeIndex& S2ClosestEdgeQueryBase<Distance>::index() const {
+  return *index_;
+}
+
+template <class Distance>
+inline std::vector<typename S2ClosestEdgeQueryBase<Distance>::Result>
+S2ClosestEdgeQueryBase<Distance>::FindClosestEdges(Target* target,
+                                                   const Options& options) {
+  std::vector<Result> results;
+  FindClosestEdges(target, options, &results);
+  return results;
+}
+
+template <class Distance>
+typename S2ClosestEdgeQueryBase<Distance>::Result
+S2ClosestEdgeQueryBase<Distance>::FindClosestEdge(Target* target,
+                                                  const Options& options) {
+  S2_DCHECK_EQ(options.max_results(), 1);
+  FindClosestEdgesInternal(target, options);
+  return result_singleton_;
+}
+
+template <class Distance>
+void S2ClosestEdgeQueryBase<Distance>::FindClosestEdges(
+    Target* target, const Options& options,
+    std::vector<Result>* results) {
+  FindClosestEdgesInternal(target, options);
+  results->clear();
+  if (options.max_results() == 1) {
+    if (result_singleton_.shape_id() >= 0) {
+      results->push_back(result_singleton_);
+    }
+  } else if (options.max_results() == Options::kMaxMaxResults) {
+    std::sort(result_vector_.begin(), result_vector_.end());
+    std::unique_copy(result_vector_.begin(), result_vector_.end(),
+                     std::back_inserter(*results));
+    result_vector_.clear();
+  } else {
+    results->assign(result_set_.begin(), result_set_.end());
+    result_set_.clear();
+  }
+}
+
+template <class Distance>
+void S2ClosestEdgeQueryBase<Distance>::FindClosestEdgesInternal(
+    Target* target, const Options& options) {
+  target_ = target;
+  options_ = &options;
+
+  tested_edges_.clear();
+  distance_limit_ = options.max_distance();
+  result_singleton_ = Result();
+  S2_DCHECK(result_vector_.empty());
+  S2_DCHECK(result_set_.empty());
+  S2_DCHECK_GE(target->max_brute_force_index_size(), 0);
+  if (distance_limit_ == Distance::Zero()) return;
+
+  if (options.max_results() == Options::kMaxMaxResults &&
+      options.max_distance() == Distance::Infinity()) {
+    S2_LOG(WARNING) << "Returning all edges (max_results/max_distance not set)";
+  }
+
+  if (options.include_interiors()) {
+    absl::btree_set<int32> shape_ids;
+    (void) target->VisitContainingShapes(
+        *index_, [&shape_ids, &options](S2Shape* containing_shape,
+                                        const S2Point& target_point) {
+          shape_ids.insert(containing_shape->id());
+          return shape_ids.size() < options.max_results();
+        });
+    for (int shape_id : shape_ids) {
+      AddResult(Result(Distance::Zero(), shape_id, -1));
+    }
+    if (distance_limit_ == Distance::Zero()) return;
+  }
+
+  // If max_error() > 0 and the target takes advantage of this, then we may
+  // need to adjust the distance estimates to the priority queue cells to
+  // ensure that they are always a lower bound on the true distance.  For
+  // example, suppose max_distance == 100, max_error == 30, and we compute the
+  // distance to the target from some cell C0 as d(C0) == 80.  Then because
+  // the target takes advantage of max_error(), the true distance could be as
+  // low as 50.  In order not to miss edges contained by such cells, we need
+  // to subtract max_error() from the distance estimates.  This behavior is
+  // controlled by the use_conservative_cell_distance_ flag.
+  //
+  // However there is one important case where this adjustment is not
+  // necessary, namely when max_distance() < max_error().  This is because
+  // max_error() only affects the algorithm once at least max_results() edges
+  // have been found that satisfy the given distance limit.  At that point,
+  // max_error() is subtracted from distance_limit_ in order to ensure that
+  // any further matches are closer by at least that amount.  But when
+  // max_distance() < max_error(), this reduces the distance limit to 0,
+  // i.e. all remaining candidate cells and edges can safely be discarded.
+  // (Note that this is how IsDistanceLess() and friends are implemented.)
+  //
+  // Note that Distance::Delta only supports operator==.
+  bool target_uses_max_error = (!(options.max_error() == Delta::Zero()) &&
+                                target_->set_max_error(options.max_error()));
+
+  // Note that we can't compare max_error() and distance_limit_ directly
+  // because one is a Delta and one is a Distance.  Instead we subtract them.
+  use_conservative_cell_distance_ = target_uses_max_error &&
+      (distance_limit_ == Distance::Infinity() ||
+       Distance::Zero() < distance_limit_ - options.max_error());
+
+  // Use the brute force algorithm if the index is small enough.  To avoid
+  // spending too much time counting edges when there are many shapes, we stop
+  // counting once there are too many edges.  We may need to recount the edges
+  // if we later see a target with a larger brute force edge threshold.
+  int min_optimized_edges = target_->max_brute_force_index_size() + 1;
+  if (min_optimized_edges > index_num_edges_limit_ &&
+      index_num_edges_ >= index_num_edges_limit_) {
+    index_num_edges_ = s2shapeutil::CountEdgesUpTo(*index_,
+                                                   min_optimized_edges);
+    index_num_edges_limit_ = min_optimized_edges;
+  }
+
+  if (options.use_brute_force() || index_num_edges_ < min_optimized_edges) {
+    // The brute force algorithm considers each edge exactly once.
+    avoid_duplicates_ = false;
+    FindClosestEdgesBruteForce();
+  } else {
+    // If the target takes advantage of max_error() then we need to avoid
+    // duplicate edges explicitly.  (Otherwise it happens automatically.)
+    avoid_duplicates_ = (target_uses_max_error && options.max_results() > 1);
+    FindClosestEdgesOptimized();
+  }
+}
+
+template <class Distance>
+void S2ClosestEdgeQueryBase<Distance>::FindClosestEdgesBruteForce() {
+  for (S2Shape* shape : *index_) {
+    if (shape == nullptr) continue;
+    int num_edges = shape->num_edges();
+    for (int e = 0; e < num_edges; ++e) {
+      MaybeAddResult(*shape, e);
+    }
+  }
+}
+
+template <class Distance>
+void S2ClosestEdgeQueryBase<Distance>::FindClosestEdgesOptimized() {
+  InitQueue();
+  // Repeatedly find the closest S2Cell to "target" and either split it into
+  // its four children or process all of its edges.
+  while (!queue_.empty()) {
+    // We need to copy the top entry before removing it, and we need to
+    // remove it before adding any new entries to the queue.
+    QueueEntry entry = queue_.top();
+    queue_.pop();
+    // Work around weird parse error in gcc 4.9 by using a local variable for
+    // entry.distance.
+    Distance distance = entry.distance;
+    if (!(distance < distance_limit_)) {
+      queue_ = CellQueue();  // Clear any remaining entries.
+      break;
+    }
+    // If this is already known to be an index cell, just process it.
+    if (entry.index_cell != nullptr) {
+      ProcessEdges(entry);
+      continue;
+    }
+    // Otherwise split the cell into its four children.  Before adding a
+    // child back to the queue, we first check whether it is empty.  We do
+    // this in two seek operations rather than four by seeking to the key
+    // between children 0 and 1 and to the key between children 2 and 3.
+    S2CellId id = entry.id;
+    iter_.Seek(id.child(1).range_min());
+    if (!iter_.done() && iter_.id() <= id.child(1).range_max()) {
+      ProcessOrEnqueue(id.child(1));
+    }
+    if (iter_.Prev() && iter_.id() >= id.range_min()) {
+      ProcessOrEnqueue(id.child(0));
+    }
+    iter_.Seek(id.child(3).range_min());
+    if (!iter_.done() && iter_.id() <= id.range_max()) {
+      ProcessOrEnqueue(id.child(3));
+    }
+    if (iter_.Prev() && iter_.id() >= id.child(2).range_min()) {
+      ProcessOrEnqueue(id.child(2));
+    }
+  }
+}
+
+template <class Distance>
+void S2ClosestEdgeQueryBase<Distance>::InitQueue() {
+  S2_DCHECK(queue_.empty());
+  if (index_covering_.empty()) {
+    // We delay iterator initialization until now to make queries on very
+    // small indexes a bit faster (i.e., where brute force is used).
+    iter_.Init(index_, S2ShapeIndex::UNPOSITIONED);
+  }
+
+  // Optimization: if the user is searching for just the closest edge, and the
+  // center of the target's bounding cap happens to intersect an index cell,
+  // then we try to limit the search region to a small disc by first
+  // processing the edges in that cell.  This sets distance_limit_ based on
+  // the closest edge in that cell, which we can then use to limit the search
+  // area.  This means that the cell containing "target" will be processed
+  // twice, but in general this is still faster.
+  //
+  // TODO(ericv): Even if the cap center is not contained, we could still
+  // process one or both of the adjacent index cells in S2CellId order,
+  // provided that those cells are closer than distance_limit_.
+  S2Cap cap = target_->GetCapBound();
+  if (cap.is_empty()) return;  // Empty target.
+  if (options().max_results() == 1 && iter_.Locate(cap.center())) {
+    ProcessEdges(QueueEntry(Distance::Zero(), iter_.id(), &iter_.cell()));
+    // Skip the rest of the algorithm if we found an intersecting edge.
+    if (distance_limit_ == Distance::Zero()) return;
+  }
+  if (index_covering_.empty()) InitCovering();
+  if (distance_limit_ == Distance::Infinity()) {
+    // Start with the precomputed index covering.
+    for (int i = 0; i < index_covering_.size(); ++i) {
+      ProcessOrEnqueue(index_covering_[i], index_cells_[i]);
+    }
+  } else {
+    // Compute a covering of the search disc and intersect it with the
+    // precomputed index covering.
+    S2RegionCoverer coverer;
+    coverer.mutable_options()->set_max_cells(4);
+    S1ChordAngle radius = cap.radius() + distance_limit_.GetChordAngleBound();
+    S2Cap search_cap(cap.center(), radius);
+    coverer.GetFastCovering(search_cap, &max_distance_covering_);
+    S2CellUnion::GetIntersection(index_covering_, max_distance_covering_,
+                                 &initial_cells_);
+
+    // Now we need to clean up the initial cells to ensure that they all
+    // contain at least one cell of the S2ShapeIndex.  (Some may not intersect
+    // the index at all, while other may be descendants of an index cell.)
+    for (int i = 0, j = 0; i < initial_cells_.size(); ) {
+      S2CellId id_i = initial_cells_[i];
+      // Find the top-level cell that contains this initial cell.
+      while (index_covering_[j].range_max() < id_i) ++j;
+      S2CellId id_j = index_covering_[j];
+      if (id_i == id_j) {
+        // This initial cell is one of the top-level cells.  Use the
+        // precomputed S2ShapeIndexCell pointer to avoid an index seek.
+        ProcessOrEnqueue(id_j, index_cells_[j]);
+        ++i, ++j;
+      } else {
+        // This initial cell is a proper descendant of a top-level cell.
+        // Check how it is related to the cells of the S2ShapeIndex.
+        S2ShapeIndex::CellRelation r = iter_.Locate(id_i);
+        if (r == S2ShapeIndex::INDEXED) {
+          // This cell is a descendant of an index cell.  Enqueue it and skip
+          // any other initial cells that are also descendants of this cell.
+          ProcessOrEnqueue(iter_.id(), &iter_.cell());
+          const S2CellId last_id = iter_.id().range_max();
+          while (++i < initial_cells_.size() && initial_cells_[i] <= last_id)
+            continue;
+        } else {
+          // Enqueue the cell only if it contains at least one index cell.
+          if (r == S2ShapeIndex::SUBDIVIDED) ProcessOrEnqueue(id_i, nullptr);
+          ++i;
+        }
+      }
+    }
+  }
+}
+
+template <class Distance>
+void S2ClosestEdgeQueryBase<Distance>::InitCovering() {
+  // Find the range of S2Cells spanned by the index and choose a level such
+  // that the entire index can be covered with just a few cells.  These are
+  // the "top-level" cells.  There are two cases:
+  //
+  //  - If the index spans more than one face, then there is one top-level cell
+  // per spanned face, just big enough to cover the index cells on that face.
+  //
+  //  - If the index spans only one face, then we find the smallest cell "C"
+  // that covers the index cells on that face (just like the case above).
+  // Then for each of the 4 children of "C", if the child contains any index
+  // cells then we create a top-level cell that is big enough to just fit
+  // those index cells (i.e., shrinking the child as much as possible to fit
+  // its contents).  This essentially replicates what would happen if we
+  // started with "C" as the top-level cell, since "C" would immediately be
+  // split, except that we take the time to prune the children further since
+  // this will save work on every subsequent query.
+
+  // Don't need to reserve index_cells_ since it is an InlinedVector.
+  index_covering_.reserve(6);
+
+  // TODO(ericv): Use a single iterator (iter_) below and save position
+  // information using pair<S2CellId, const S2ShapeIndexCell*> type.
+  S2ShapeIndex::Iterator next(index_, S2ShapeIndex::BEGIN);
+  S2ShapeIndex::Iterator last(index_, S2ShapeIndex::END);
+  last.Prev();
+  if (next.id() != last.id()) {
+    // The index has at least two cells.  Choose a level such that the entire
+    // index can be spanned with at most 6 cells (if the index spans multiple
+    // faces) or 4 cells (it the index spans a single face).
+    int level = next.id().GetCommonAncestorLevel(last.id()) + 1;
+
+    // Visit each potential top-level cell except the last (handled below).
+    S2CellId last_id = last.id().parent(level);
+    for (S2CellId id = next.id().parent(level); id != last_id; id = id.next()) {
+      // Skip any top-level cells that don't contain any index cells.
+      if (id.range_max() < next.id()) continue;
+
+      // Find the range of index cells contained by this top-level cell and
+      // then shrink the cell if necessary so that it just covers them.
+      S2ShapeIndex::Iterator cell_first = next;
+      next.Seek(id.range_max().next());
+      S2ShapeIndex::Iterator cell_last = next;
+      cell_last.Prev();
+      AddInitialRange(cell_first, cell_last);
+    }
+  }
+  AddInitialRange(next, last);
+}
+
+// Add an entry to index_covering_ and index_cells_ that covers the given
+// inclusive range of cells.
+//
+// REQUIRES: "first" and "last" have a common ancestor.
+template <class Distance>
+void S2ClosestEdgeQueryBase<Distance>::AddInitialRange(
+    const S2ShapeIndex::Iterator& first,
+    const S2ShapeIndex::Iterator& last) {
+  if (first.id() == last.id()) {
+    // The range consists of a single index cell.
+    index_covering_.push_back(first.id());
+    index_cells_.push_back(&first.cell());
+  } else {
+    // Add the lowest common ancestor of the given range.
+    int level = first.id().GetCommonAncestorLevel(last.id());
+    S2_DCHECK_GE(level, 0);
+    index_covering_.push_back(first.id().parent(level));
+    index_cells_.push_back(nullptr);
+  }
+}
+
+template <class Distance>
+void S2ClosestEdgeQueryBase<Distance>::MaybeAddResult(
+    const S2Shape& shape, int edge_id) {
+  if (avoid_duplicates_ &&
+      !tested_edges_.insert(ShapeEdgeId(shape.id(), edge_id)).second) {
+    return;
+  }
+  auto edge = shape.edge(edge_id);
+  Distance distance = distance_limit_;
+  if (target_->UpdateMinDistance(edge.v0, edge.v1, &distance)) {
+    AddResult(Result(distance, shape.id(), edge_id));
+  }
+}
+
+template <class Distance>
+void S2ClosestEdgeQueryBase<Distance>::AddResult(const Result& result) {
+  if (options().max_results() == 1) {
+    // Optimization for the common case where only the closest edge is wanted.
+    result_singleton_ = result;
+    distance_limit_ = result.distance() - options().max_error();
+  } else if (options().max_results() == Options::kMaxMaxResults) {
+    result_vector_.push_back(result);  // Sort/unique at end.
+  } else {
+    // Add this edge to result_set_.  Note that even if we already have enough
+    // edges, we can't erase an element before insertion because the "new"
+    // edge might in fact be a duplicate.
+    result_set_.insert(result);
+    int size = result_set_.size();
+    if (size >= options().max_results()) {
+      if (size > options().max_results()) {
+        result_set_.erase(--result_set_.end());
+      }
+      distance_limit_ = (--result_set_.end())->distance() -
+                        options().max_error();
+    }
+  }
+}
+
+// Return the number of edges in the given index cell.
+inline static int CountEdges(const S2ShapeIndexCell* cell) {
+  int count = 0;
+  for (int s = 0; s < cell->num_clipped(); ++s) {
+    count += cell->clipped(s).num_edges();
+  }
+  return count;
+}
+
+// Process all the edges of the given index cell.
+template <class Distance>
+void S2ClosestEdgeQueryBase<Distance>::ProcessEdges(const QueueEntry& entry) {
+  const S2ShapeIndexCell* index_cell = entry.index_cell;
+  for (int s = 0; s < index_cell->num_clipped(); ++s) {
+    const S2ClippedShape& clipped = index_cell->clipped(s);
+    const S2Shape* shape = index_->shape(clipped.shape_id());
+    for (int j = 0; j < clipped.num_edges(); ++j) {
+      MaybeAddResult(*shape, clipped.edge(j));
+    }
+  }
+}
+
+// Enqueue the given cell id.
+// REQUIRES: iter_ is positioned at a cell contained by "id".
+template <class Distance>
+inline void S2ClosestEdgeQueryBase<Distance>::ProcessOrEnqueue(
+    S2CellId id) {
+  S2_DCHECK(id.contains(iter_.id()));
+  if (iter_.id() == id) {
+    ProcessOrEnqueue(id, &iter_.cell());
+  } else {
+    ProcessOrEnqueue(id, nullptr);
+  }
+}
+
+// Add the given cell id to the queue.  "index_cell" is the corresponding
+// S2ShapeIndexCell, or nullptr if "id" is not an index cell.
+//
+// This version is called directly only by InitQueue().
+template <class Distance>
+void S2ClosestEdgeQueryBase<Distance>::ProcessOrEnqueue(
+    S2CellId id, const S2ShapeIndexCell* index_cell) {
+  if (index_cell) {
+    // If this index cell has only a few edges, then it is faster to check
+    // them directly rather than computing the minimum distance to the S2Cell
+    // and inserting it into the queue.
+    static const int kMinEdgesToEnqueue = 10;
+    int num_edges = CountEdges(index_cell);
+    if (num_edges == 0) return;
+    if (num_edges < kMinEdgesToEnqueue) {
+      // Set "distance" to zero to avoid the expense of computing it.
+      ProcessEdges(QueueEntry(Distance::Zero(), id, index_cell));
+      return;
+    }
+  }
+  // Otherwise compute the minimum distance to any point in the cell and add
+  // it to the priority queue.
+  S2Cell cell(id);
+  Distance distance = distance_limit_;
+  if (!target_->UpdateMinDistance(cell, &distance)) return;
+  if (use_conservative_cell_distance_) {
+    // Ensure that "distance" is a lower bound on the true distance to the cell.
+    distance = distance - options().max_error();  // operator-=() not defined.
+  }
+  queue_.push(QueueEntry(distance, id, index_cell));
+}
+
+#endif  // S2_S2CLOSEST_EDGE_QUERY_BASE_H_
diff --git a/src/s2/s2closest_edge_query_testing.h b/src/s2/s2closest_edge_query_testing.h
new file mode 100644 (file)
index 0000000..58c5770
--- /dev/null
@@ -0,0 +1,91 @@
+// Copyright Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// Common code for testing furthest/closest edge/point queries.
+
+#ifndef S2_S2CLOSEST_EDGE_QUERY_TESTING_H_
+#define S2_S2CLOSEST_EDGE_QUERY_TESTING_H_
+
+#include <vector>
+
+#include "s2/mutable_s2shape_index.h"
+#include "s2/s1angle.h"
+#include "s2/s2cap.h"
+#include "s2/s2cell.h"
+#include "s2/s2edge_distances.h"
+#include "s2/s2edge_vector_shape.h"
+#include "s2/s2loop.h"
+#include "s2/s2metrics.h"
+#include "s2/s2point.h"
+#include "s2/s2point_vector_shape.h"
+#include "s2/s2shapeutil_count_edges.h"
+#include "s2/s2shapeutil_shape_edge_id.h"
+#include "s2/s2testing.h"
+
+namespace s2testing {
+
+// An abstract class that adds edges to a MutableS2ShapeIndex for benchmarking.
+class ShapeIndexFactory {
+ public:
+  virtual ~ShapeIndexFactory() {}
+
+  // Requests that approximately "num_edges" edges located within the given
+  // S2Cap bound should be added to "index".
+  virtual void AddEdges(const S2Cap& index_cap, int num_edges,
+                        MutableS2ShapeIndex* index) const = 0;
+};
+
+// Generates a regular loop that approximately fills the given S2Cap.
+//
+// Regular loops are nearly the worst case for distance calculations, since
+// many edges are nearly equidistant from any query point that is not
+// immediately adjacent to the loop.
+class RegularLoopShapeIndexFactory : public ShapeIndexFactory {
+ public:
+  void AddEdges(const S2Cap& index_cap, int num_edges,
+                MutableS2ShapeIndex* index) const override {
+    index->Add(absl::make_unique<S2Loop::OwningShape>(S2Loop::MakeRegularLoop(
+        index_cap.center(), index_cap.GetRadius(), num_edges)));
+  }
+};
+
+// Generates a fractal loop that approximately fills the given S2Cap.
+class FractalLoopShapeIndexFactory : public ShapeIndexFactory {
+ public:
+  void AddEdges(const S2Cap& index_cap, int num_edges,
+                MutableS2ShapeIndex* index) const override {
+    S2Testing::Fractal fractal;
+    fractal.SetLevelForApproxMaxEdges(num_edges);
+    index->Add(absl::make_unique<S2Loop::OwningShape>(
+        fractal.MakeLoop(S2Testing::GetRandomFrameAt(index_cap.center()),
+                         index_cap.GetRadius())));
+  }
+};
+
+// Generates a cloud of points that approximately fills the given S2Cap.
+class PointCloudShapeIndexFactory : public ShapeIndexFactory {
+ public:
+  void AddEdges(const S2Cap& index_cap, int num_edges,
+                MutableS2ShapeIndex* index) const override {
+    std::vector<S2Point> points;
+    for (int i = 0; i < num_edges; ++i) {
+      points.push_back(S2Testing::SamplePoint(index_cap));
+    }
+    index->Add(absl::make_unique<S2PointVectorShape>(std::move(points)));
+  }
+};
+
+}  // namespace s2testing
+#endif  // S2_S2CLOSEST_EDGE_QUERY_TESTING_H_
diff --git a/src/s2/s2closest_point_query.cc b/src/s2/s2closest_point_query.cc
new file mode 100644 (file)
index 0000000..a43f7e9
--- /dev/null
@@ -0,0 +1,66 @@
+// Copyright 2013 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// Author: ericv@google.com (Eric Veach)
+
+#include "s2/s2closest_point_query.h"
+
+void S2ClosestPointQueryOptions::set_conservative_max_distance(
+    S1ChordAngle max_distance) {
+  set_max_distance(Distance(max_distance.PlusError(
+      S2::GetUpdateMinDistanceMaxError(max_distance)).Successor()));
+}
+
+void S2ClosestPointQueryOptions::set_conservative_max_distance(
+    S1Angle max_distance) {
+  set_conservative_max_distance(S1ChordAngle(max_distance));
+}
+
+int S2ClosestPointQueryPointTarget::max_brute_force_index_size() const {
+  // Using BM_FindClosest (which finds the single closest point), the
+  // break-even points are approximately X, Y, and Z points for grid,
+  // fractal, and regular loop geometry respectively.
+  //
+  // TODO(ericv): Adjust using benchmarks.
+  return 150;
+}
+
+int S2ClosestPointQueryEdgeTarget::max_brute_force_index_size() const {
+  // Using BM_FindClosestToEdge (which finds the single closest point), the
+  // break-even points are approximately X, Y, and Z points for grid,
+  // fractal, and regular loop geometry respectively.
+  //
+  // TODO(ericv): Adjust using benchmarks.
+  return 100;
+}
+
+int S2ClosestPointQueryCellTarget::max_brute_force_index_size() const {
+  // Using BM_FindClosestToCell (which finds the single closest point), the
+  // break-even points are approximately X, Y, and Z points for grid,
+  // fractal, and regular loop geometry respectively.
+  //
+  // TODO(ericv): Adjust using benchmarks.
+  return 50;
+}
+
+int S2ClosestPointQueryShapeIndexTarget::max_brute_force_index_size() const {
+  // For BM_FindClosestToSameSizeAbuttingIndex (which uses a nearby
+  // S2ShapeIndex target of similar complexity), the break-even points are
+  // approximately X, Y, and Z points for grid, fractal, and regular loop
+  // geometry respectively.
+  //
+  // TODO(ericv): Adjust using benchmarks.
+  return 30;
+}
diff --git a/src/s2/s2closest_point_query.h b/src/s2/s2closest_point_query.h
new file mode 100644 (file)
index 0000000..ca148e7
--- /dev/null
@@ -0,0 +1,465 @@
+// Copyright 2013 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// Author: ericv@google.com (Eric Veach)
+//
+// See S2ClosestPointQuery (defined below) for an overview.
+
+#ifndef S2_S2CLOSEST_POINT_QUERY_H_
+#define S2_S2CLOSEST_POINT_QUERY_H_
+
+#include <vector>
+
+#include "s2/base/logging.h"
+#include "s2/s1angle.h"
+#include "s2/s1chord_angle.h"
+#include "s2/s2closest_point_query_base.h"
+#include "s2/s2min_distance_targets.h"
+#include "s2/s2point_index.h"
+
+// Options that control the set of points returned.  Note that by default
+// *all* points are returned, so you will always want to set either the
+// max_results() option or the max_distance() option (or both).
+//
+// This class is also available as S2ClosestPointQuery<Data>::Options.
+// (It is defined here to avoid depending on the "Data" template argument.)
+class S2ClosestPointQueryOptions :
+    public S2ClosestPointQueryBaseOptions<S2MinDistance> {
+ public:
+  using Distance = S2MinDistance;
+  using Base = S2ClosestPointQueryBaseOptions<Distance>;
+
+  // See S2ClosestPointQueryBaseOptions for the full set of options.
+
+  // Specifies that only points whose distance to the target is less than
+  // "max_distance" should be returned.
+  //
+  // Note that points whose distance is exactly equal to "max_distance" are
+  // not returned.  Normally this doesn't matter, because distances are not
+  // computed exactly in the first place, but if such points are needed then
+  // see set_inclusive_max_distance() below.
+  //
+  // DEFAULT: Distance::Infinity()
+  void set_max_distance(S1ChordAngle max_distance);
+
+  // Like set_max_distance(), except that points whose distance is exactly
+  // equal to "max_distance" are also returned.  Equivalent to calling
+  // set_max_distance(max_distance.Successor()).
+  void set_inclusive_max_distance(S1ChordAngle max_distance);
+
+  // Like set_inclusive_max_distance(), except that "max_distance" is also
+  // increased by the maximum error in the distance calculation.  This ensures
+  // that all points whose true distance is less than or equal to
+  // "max_distance" will be returned (along with some points whose true
+  // distance is slightly greater).
+  //
+  // Algorithms that need to do exact distance comparisons can use this
+  // option to find a set of candidate points that can then be filtered
+  // further (e.g., using s2pred::CompareDistance).
+  void set_conservative_max_distance(S1ChordAngle max_distance);
+
+  // Versions of set_max_distance that take an S1Angle argument.  (Note that
+  // these functions require a conversion, and that the S1ChordAngle versions
+  // are preferred.)
+  void set_max_distance(S1Angle max_distance);
+  void set_inclusive_max_distance(S1Angle max_distance);
+  void set_conservative_max_distance(S1Angle max_distance);
+
+  // See S2ClosestPointQueryBaseOptions for documentation.
+  using Base::set_max_error;              // S1Chordangle version
+  void set_max_error(S1Angle max_error);  // S1Angle version
+
+  // Inherited options (see s2closest_point_query_base.h for details):
+  using Base::set_max_results;
+  using Base::set_region;
+  using Base::set_use_brute_force;
+};
+
+// S2ClosestPointQueryTarget represents the geometry to which the distance is
+// measured.  There are subtypes for measuring the distance to a point, an
+// edge, an S2Cell, or an S2ShapeIndex (an arbitrary collection of geometry).
+using S2ClosestPointQueryTarget = S2MinDistanceTarget;
+
+// Target subtype that computes the closest distance to a point.
+//
+// This class is also available as S2ClosestPointQuery<Data>::PointTarget.
+// (It is defined here to avoid depending on the "Data" template argument.)
+class S2ClosestPointQueryPointTarget final : public S2MinDistancePointTarget {
+ public:
+  explicit S2ClosestPointQueryPointTarget(const S2Point& point);
+  int max_brute_force_index_size() const override;
+};
+
+// Target subtype that computes the closest distance to an edge.
+//
+// This class is also available as S2ClosestPointQuery<Data>::EdgeTarget.
+// (It is defined here to avoid depending on the "Data" template argument.)
+class S2ClosestPointQueryEdgeTarget final : public S2MinDistanceEdgeTarget {
+ public:
+  explicit S2ClosestPointQueryEdgeTarget(const S2Point& a, const S2Point& b);
+  int max_brute_force_index_size() const override;
+};
+
+// Target subtype that computes the closest distance to an S2Cell
+// (including the interior of the cell).
+//
+// This class is also available as S2ClosestPointQuery<Data>::CellTarget.
+// (It is defined here to avoid depending on the "Data" template argument.)
+class S2ClosestPointQueryCellTarget final : public S2MinDistanceCellTarget {
+ public:
+  explicit S2ClosestPointQueryCellTarget(const S2Cell& cell);
+  int max_brute_force_index_size() const override;
+};
+
+// Target subtype that computes the closest distance to an S2ShapeIndex
+// (an arbitrary collection of points, polylines, and/or polygons).
+//
+// By default, distances are measured to the boundary and interior of
+// polygons in the S2ShapeIndex rather than to polygon boundaries only.
+// If you wish to change this behavior, you may call
+//
+//   target.set_include_interiors(false);
+//
+// (see S2MinDistanceShapeIndexTarget for details).
+//
+// This class is also available as S2ClosestPointQuery<Data>::ShapeIndexTarget.
+// (It is defined here to avoid depending on the "Data" template argument.)
+class S2ClosestPointQueryShapeIndexTarget final :
+    public S2MinDistanceShapeIndexTarget {
+ public:
+  explicit S2ClosestPointQueryShapeIndexTarget(const S2ShapeIndex* index);
+  int max_brute_force_index_size() const override;
+};
+
+// Given a set of points stored in an S2PointIndex, S2ClosestPointQuery
+// provides methods that find the closest point(s) to a given query point
+// or query edge.  Example usage:
+//
+// void Test(const vector<S2Point>& index_points,
+//           const vector<S2Point>& target_points) {
+//   // The template argument allows auxiliary data to be attached to each
+//   // point (in this case, the array index).
+//   S2PointIndex<int> index;
+//   for (int i = 0; i < index_points.size(); ++i) {
+//     index.Add(index_points[i], i);
+//   }
+//   S2ClosestPointQuery<int> query(&index);
+//   query.mutable_options()->set_max_results(5);
+//   for (const S2Point& target_point : target_points) {
+//     S2ClosestPointQueryPointTarget target(target_point);
+//     for (const auto& result : query.FindClosestPoints(&target)) {
+//       // The Result class contains the following methods:
+//       //   distance() is the distance to the target.
+//       //   point() is the indexed point.
+//       //   data() is the auxiliary data.
+//       DoSomething(target_point, result);
+//     }
+//   }
+// }
+//
+// You can find either the k closest points, or all points within a given
+// radius, or both (i.e., the k closest points up to a given maximum radius).
+// E.g. to find all the points within 5 kilometers, call
+//
+//   query.mutable_options()->set_max_distance(
+//       S2Earth::ToAngle(util::units::Kilometers(5)));
+//
+// By default *all* points are returned, so you should always specify either
+// max_results() or max_distance() or both.  There is also a FindClosestPoint()
+// convenience method that returns only the closest point.
+//
+// You can restrict the results to an arbitrary S2Region, for example:
+//
+//   S2LatLngRect rect(...);
+//   query.mutable_options()->set_region(&rect);  // Does *not* take ownership.
+//
+// To find the closest points to a query edge rather than a point, use:
+//
+//   S2ClosestPointQueryEdgeTarget target(v0, v1);
+//   query.FindClosestPoints(&target);
+//
+// Similarly you can find the closest points to an S2Cell by using an
+// S2ClosestPointQuery::CellTarget, and you can find the closest points to an
+// arbitrary collection of points, polylines, and polygons by using an
+// S2ClosestPointQuery::ShapeIndexTarget.
+//
+// The implementation is designed to be fast for both small and large
+// point sets.
+template <class Data>
+class S2ClosestPointQuery {
+ public:
+  // See S2ClosestPointQueryBase for full documentation.
+
+  using Index = S2PointIndex<Data>;
+  using PointData = typename Index::PointData;
+
+  // S2MinDistance is a thin wrapper around S1ChordAngle that implements the
+  // Distance concept required by S2ClosestPointQueryBase.
+  using Distance = S2MinDistance;
+  using Base = S2ClosestPointQueryBase<Distance, Data>;
+
+  // Each "Result" object represents a closest point.  Here are its main
+  // methods (see S2ClosestPointQueryBase::Result for details):
+  //
+  //   // The distance from the target to this point.
+  //   S1ChordAngle distance() const;
+  //
+  //   // The point itself.
+  //   const S2Point& point() const;
+  //
+  //   // The client-specified data associated with this point.
+  //   const Data& data() const;
+  using Result = typename Base::Result;
+
+  using Options = S2ClosestPointQueryOptions;
+
+  // The available target types (see definitions above).
+  using Target = S2ClosestPointQueryTarget;
+  using PointTarget = S2ClosestPointQueryPointTarget;
+  using EdgeTarget = S2ClosestPointQueryEdgeTarget;
+  using CellTarget = S2ClosestPointQueryCellTarget;
+  using ShapeIndexTarget = S2ClosestPointQueryShapeIndexTarget;
+
+  // Convenience constructor that calls Init().  Options may be specified here
+  // or changed at any time using the mutable_options() accessor method.
+  explicit S2ClosestPointQuery(const Index* index,
+                               const Options& options = Options());
+
+  // Default constructor; requires Init() to be called.
+  S2ClosestPointQuery();
+  ~S2ClosestPointQuery();
+
+  // Initializes the query.  Options may be specified here or changed at any
+  // time using the mutable_options() accessor method.
+  //
+  // REQUIRES: "index" must persist for the lifetime of this object.
+  // REQUIRES: ReInit() must be called if "index" is modified.
+  void Init(const Index* index, const Options& options = Options());
+
+  // Reinitializes the query.  This method must be called whenever the
+  // underlying index is modified.
+  void ReInit();
+
+  // Returns a reference to the underlying S2PointIndex.
+  const Index& index() const;
+
+  // Returns the query options.  Options can be modifed between queries.
+  const Options& options() const;
+  Options* mutable_options();
+
+  // Returns the closest points to the given target that satisfy the current
+  // options.  This method may be called multiple times.
+  std::vector<Result> FindClosestPoints(Target* target);
+
+  // This version can be more efficient when this method is called many times,
+  // since it does not require allocating a new vector on each call.
+  void FindClosestPoints(Target* target, std::vector<Result>* results);
+
+  //////////////////////// Convenience Methods ////////////////////////
+
+  // Returns the closest point to the target.  If no point satisfies the search
+  // criteria, then a Result object with distance() == Infinity() and
+  // is_empty() == true is returned.
+  Result FindClosestPoint(Target* target);
+
+  // Returns the minimum distance to the target.  If the index or target is
+  // empty, returns S1ChordAngle::Infinity().
+  //
+  // Use IsDistanceLess() if you only want to compare the distance against a
+  // threshold value, since it is often much faster.
+  S1ChordAngle GetDistance(Target* target);
+
+  // Returns true if the distance to "target" is less than "limit".
+  //
+  // This method is usually much faster than GetDistance(), since it is much
+  // less work to determine whether the minimum distance is above or below a
+  // threshold than it is to calculate the actual minimum distance.
+  bool IsDistanceLess(Target* target, S1ChordAngle limit);
+
+  // Like IsDistanceLess(), but also returns true if the distance to "target"
+  // is exactly equal to "limit".
+  bool IsDistanceLessOrEqual(Target* target, S1ChordAngle limit);
+
+  // Like IsDistanceLessOrEqual(), except that "limit" is increased by the
+  // maximum error in the distance calculation.  This ensures that this
+  // function returns true whenever the true, exact distance is less than
+  // or equal to "limit".
+  //
+  // For example, suppose that we want to test whether two geometries might
+  // intersect each other after they are snapped together using S2Builder
+  // (using the IdentitySnapFunction with a given "snap_radius").  Since
+  // S2Builder uses exact distance predicates (s2predicates.h), we need to
+  // measure the distance between the two geometries conservatively.  If the
+  // distance is definitely greater than "snap_radius", then the geometries
+  // are guaranteed to not intersect after snapping.
+  bool IsConservativeDistanceLessOrEqual(Target* target, S1ChordAngle limit);
+
+ private:
+  Options options_;
+  Base base_;
+};
+
+
+//////////////////   Implementation details follow   ////////////////////
+
+
+inline void S2ClosestPointQueryOptions::set_max_distance(
+    S1ChordAngle max_distance) {
+  Base::set_max_distance(Distance(max_distance));
+}
+
+inline void S2ClosestPointQueryOptions::set_max_distance(S1Angle max_distance) {
+  Base::set_max_distance(Distance(max_distance));
+}
+
+inline void S2ClosestPointQueryOptions::set_inclusive_max_distance(
+    S1ChordAngle max_distance) {
+  set_max_distance(max_distance.Successor());
+}
+
+inline void S2ClosestPointQueryOptions::set_inclusive_max_distance(
+    S1Angle max_distance) {
+  set_inclusive_max_distance(S1ChordAngle(max_distance));
+}
+
+inline void S2ClosestPointQueryOptions::set_max_error(S1Angle max_error) {
+  Base::set_max_error(S1ChordAngle(max_error));
+}
+
+inline S2ClosestPointQueryPointTarget::S2ClosestPointQueryPointTarget(
+    const S2Point& point)
+    : S2MinDistancePointTarget(point) {
+}
+
+inline S2ClosestPointQueryEdgeTarget::S2ClosestPointQueryEdgeTarget(
+    const S2Point& a, const S2Point& b)
+    : S2MinDistanceEdgeTarget(a, b) {
+}
+
+inline S2ClosestPointQueryCellTarget::S2ClosestPointQueryCellTarget(
+    const S2Cell& cell)
+    : S2MinDistanceCellTarget(cell) {
+}
+
+inline S2ClosestPointQueryShapeIndexTarget::S2ClosestPointQueryShapeIndexTarget(
+    const S2ShapeIndex* index)
+    : S2MinDistanceShapeIndexTarget(index) {
+}
+
+template <class Data>
+inline S2ClosestPointQuery<Data>::S2ClosestPointQuery(const Index* index,
+                                                      const Options& options) {
+  Init(index, options);
+}
+
+template <class Data>
+S2ClosestPointQuery<Data>::S2ClosestPointQuery() {
+  // Prevent inline constructor bloat by defining here.
+}
+
+template <class Data>
+S2ClosestPointQuery<Data>::~S2ClosestPointQuery() {
+  // Prevent inline destructor bloat by defining here.
+}
+
+template <class Data>
+void S2ClosestPointQuery<Data>::Init(const Index* index,
+                                     const Options& options) {
+  options_ = options;
+  base_.Init(index);
+}
+
+template <class Data>
+inline void S2ClosestPointQuery<Data>::ReInit() {
+  base_.ReInit();
+}
+
+template <class Data>
+inline const S2PointIndex<Data>& S2ClosestPointQuery<Data>::index() const {
+  return base_.index();
+}
+
+template <class Data>
+inline const S2ClosestPointQueryOptions& S2ClosestPointQuery<Data>::options()
+    const {
+  return options_;
+}
+
+template <class Data>
+inline S2ClosestPointQueryOptions*
+S2ClosestPointQuery<Data>::mutable_options() {
+  return &options_;
+}
+
+template <class Data>
+inline std::vector<typename S2ClosestPointQuery<Data>::Result>
+S2ClosestPointQuery<Data>::FindClosestPoints(Target* target) {
+  return base_.FindClosestPoints(target, options_);
+}
+
+template <class Data>
+inline void S2ClosestPointQuery<Data>::FindClosestPoints(
+    Target* target, std::vector<Result>* results) {
+  base_.FindClosestPoints(target, options_, results);
+}
+
+template <class Data>
+inline typename S2ClosestPointQuery<Data>::Result
+S2ClosestPointQuery<Data>::FindClosestPoint(Target* target) {
+  static_assert(sizeof(Options) <= 32, "Consider not copying Options here");
+  Options tmp_options = options_;
+  tmp_options.set_max_results(1);
+  return base_.FindClosestPoint(target, tmp_options);
+}
+
+template <class Data>
+inline S1ChordAngle S2ClosestPointQuery<Data>::GetDistance(Target* target) {
+  return FindClosestPoint(target).distance();
+}
+
+template <class Data>
+bool S2ClosestPointQuery<Data>::IsDistanceLess(
+    Target* target, S1ChordAngle limit) {
+  static_assert(sizeof(Options) <= 32, "Consider not copying Options here");
+  Options tmp_options = options_;
+  tmp_options.set_max_results(1);
+  tmp_options.set_max_distance(limit);
+  tmp_options.set_max_error(S1ChordAngle::Straight());
+  return !base_.FindClosestPoint(target, tmp_options).is_empty();
+}
+
+template <class Data>
+bool S2ClosestPointQuery<Data>::IsDistanceLessOrEqual(
+    Target* target, S1ChordAngle limit) {
+  static_assert(sizeof(Options) <= 32, "Consider not copying Options here");
+  Options tmp_options = options_;
+  tmp_options.set_max_results(1);
+  tmp_options.set_inclusive_max_distance(limit);
+  tmp_options.set_max_error(S1ChordAngle::Straight());
+  return !base_.FindClosestPoint(target, tmp_options).is_empty();
+}
+
+template <class Data>
+bool S2ClosestPointQuery<Data>::IsConservativeDistanceLessOrEqual(
+    Target* target, S1ChordAngle limit) {
+  static_assert(sizeof(Options) <= 32, "Consider not copying Options here");
+  Options tmp_options = options_;
+  tmp_options.set_max_results(1);
+  tmp_options.set_conservative_max_distance(limit);
+  tmp_options.set_max_error(S1ChordAngle::Straight());
+  return !base_.FindClosestPoint(target, tmp_options).is_empty();
+}
+
+#endif  // S2_S2CLOSEST_POINT_QUERY_H_
diff --git a/src/s2/s2closest_point_query_base.h b/src/s2/s2closest_point_query_base.h
new file mode 100644 (file)
index 0000000..7cb0c06
--- /dev/null
@@ -0,0 +1,767 @@
+// Copyright 2017 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// Author: ericv@google.com (Eric Veach)
+//
+// See S2ClosestPointQueryBase (defined below) for an overview.
+
+#ifndef S2_S2CLOSEST_POINT_QUERY_BASE_H_
+#define S2_S2CLOSEST_POINT_QUERY_BASE_H_
+
+#include <vector>
+
+#include "s2/base/logging.h"
+#include "absl/container/inlined_vector.h"
+#include "s2/s1chord_angle.h"
+#include "s2/s2cap.h"
+#include "s2/s2cell_id.h"
+#include "s2/s2cell_union.h"
+#include "s2/s2distance_target.h"
+#include "s2/s2edge_distances.h"
+#include "s2/s2point_index.h"
+#include "s2/s2region_coverer.h"
+
+// Options that control the set of points returned.  Note that by default
+// *all* points are returned, so you will always want to set either the
+// max_results() option or the max_distance() option (or both).
+//
+// This class is also available as S2ClosestPointQueryBase<Data>::Options.
+// (It is defined here to avoid depending on the "Data" template argument.)
+//
+// The Distance template argument is described below.
+template <class Distance>
+class S2ClosestPointQueryBaseOptions {
+ public:
+  using Delta = typename Distance::Delta;
+
+  S2ClosestPointQueryBaseOptions();
+
+  // Specifies that at most "max_results" points should be returned.
+  //
+  // REQUIRES: max_results >= 1
+  // DEFAULT: numeric_limits<int>::max()
+  int max_results() const;
+  void set_max_results(int max_results);
+  static constexpr int kMaxMaxResults = std::numeric_limits<int>::max();
+
+  // Specifies that only points whose distance to the target is less than
+  // "max_distance" should be returned.
+  //
+  // Note that points whose distance is exactly equal to "max_distance" are
+  // not returned.  In most cases this doesn't matter (since distances are
+  // not computed exactly in the first place), but if such points are needed
+  // then you can retrieve them by specifying "max_distance" as the next
+  // largest representable Distance.  For example, if Distance is an
+  // S1ChordAngle then you can specify max_distance.Successor().
+  //
+  // DEFAULT: Distance::Infinity()
+  Distance max_distance() const;
+  void set_max_distance(Distance max_distance);
+
+  // Specifies that points up to max_error() further away than the true
+  // closest points may be substituted in the result set, as long as such
+  // points satisfy all the remaining search criteria (such as max_distance).
+  // This option only has an effect if max_results() is also specified;
+  // otherwise all points closer than max_distance() will always be returned.
+  //
+  // Note that this does not affect how the distance between points is
+  // computed; it simply gives the algorithm permission to stop the search
+  // early as soon as the best possible improvement drops below max_error().
+  //
+  // This can be used to implement distance predicates efficiently.  For
+  // example, to determine whether the minimum distance is less than D, the
+  // IsDistanceLess() method sets max_results() == 1 and max_distance() ==
+  // max_error() == D.  This causes the algorithm to terminate as soon as it
+  // finds any point whose distance is less than D, rather than continuing to
+  // search for a point that is even closer.
+  //
+  // DEFAULT: Distance::Delta::Zero()
+  Delta max_error() const;
+  void set_max_error(Delta max_error);
+
+  // Specifies that points must be contained by the given S2Region.  "region"
+  // is owned by the caller and must persist during the lifetime of this
+  // object.  The value may be changed between calls to FindClosestPoints(),
+  // or reset by calling set_region(nullptr).
+  //
+  // Note that if you want to set the region to a disc around a target point,
+  // it is faster to use a PointTarget with set_max_distance() instead.  You
+  // can also call both methods, e.g. to set a maximum distance and also
+  // require that points lie within a given rectangle.
+  const S2Region* region() const;
+  void set_region(const S2Region* region);
+
+  // Specifies that distances should be computed by examining every point
+  // rather than using the S2ShapeIndex.  This is useful for testing,
+  // benchmarking, and debugging.
+  //
+  // DEFAULT: false
+  bool use_brute_force() const;
+  void set_use_brute_force(bool use_brute_force);
+
+ private:
+  Distance max_distance_ = Distance::Infinity();
+  Delta max_error_ = Delta::Zero();
+  const S2Region* region_ = nullptr;
+  int max_results_ = kMaxMaxResults;
+  bool use_brute_force_ = false;
+};
+
+// S2ClosestPointQueryBase is a templatized class for finding the closest
+// point(s) to a given target.  It is not intended to be used directly, but
+// rather to serve as the implementation of various specialized classes with
+// more convenient APIs (such as S2ClosestPointQuery).  It is flexible enough
+// so that it can be adapted to compute maximum distances and even potentially
+// Hausdorff distances.
+//
+// By using the appropriate options, this class can answer questions such as:
+//
+//  - Find the minimum distance between a point collection A and a target B.
+//  - Find all points in collection A that are within a distance D of target B.
+//  - Find the k points of collection A that are closest to a given point P.
+//
+// The target is any class that implements the S2DistanceTarget interface.
+// There are predefined targets for points, edges, S2Cells, and S2ShapeIndexes
+// (arbitrary collctions of points, polylines, and polygons).
+//
+// The Distance template argument is used to represent distances.  Usually it
+// is a thin wrapper around S1ChordAngle, but another distance type may be
+// used as long as it implements the Distance concept described in
+// s2distance_targets.h.  For example this can be used to measure maximum
+// distances, to get more accuracy, or to measure non-spheroidal distances.
+template <class Distance, class Data>
+class S2ClosestPointQueryBase {
+ public:
+  using Delta = typename Distance::Delta;
+  using Index = S2PointIndex<Data>;
+  using PointData = typename Index::PointData;
+  using Options = S2ClosestPointQueryBaseOptions<Distance>;
+
+  // The Target class represents the geometry to which the distance is
+  // measured.  For example, there can be subtypes for measuring the distance
+  // to a point, an edge, or to an S2ShapeIndex (an arbitrary collection of
+  // geometry).
+  //
+  // Implementations do *not* need to be thread-safe.  They may cache data or
+  // allocate temporary data structures in order to improve performance.
+  using Target = S2DistanceTarget<Distance>;
+
+  // Each "Result" object represents a closest point.
+  class Result {
+   public:
+    // The default constructor creates an "empty" result, with a distance() of
+    // Infinity() and non-dereferencable point() and data() values.
+    Result() : distance_(Distance::Infinity()), point_data_(nullptr) {}
+
+    // Constructs a Result object for the given point.
+    Result(Distance distance, const PointData* point_data)
+        : distance_(distance), point_data_(point_data) {}
+
+    // Returns true if this Result object does not refer to any data point.
+    // (The only case where an empty Result is returned is when the
+    // FindClosestPoint() method does not find any points that meet the
+    // specified criteria.)
+    bool is_empty() const { return point_data_ == nullptr; }
+
+    // The distance from the target to this point.
+    Distance distance() const { return distance_; }
+
+    // The point itself.
+    const S2Point& point() const { return point_data_->point(); }
+
+    // The client-specified data associated with this point.
+    const Data& data() const { return point_data_->data(); }
+
+    // Returns true if two Result objects are identical.
+    friend bool operator==(const Result& x, const Result& y) {
+      return (x.distance_ == y.distance_ && x.point_data_ == y.point_data_);
+    }
+
+    // Compares two Result objects first by distance, then by point_data().
+    friend bool operator<(const Result& x, const Result& y) {
+      if (x.distance_ < y.distance_) return true;
+      if (y.distance_ < x.distance_) return false;
+      return x.point_data_ < y.point_data_;
+    }
+
+   private:
+    Distance distance_;
+    const PointData* point_data_;
+  };
+
+  // The minimum number of points that a cell must contain to enqueue it
+  // rather than processing its contents immediately.
+  static constexpr int kMinPointsToEnqueue = 13;
+
+  // Default constructor; requires Init() to be called.
+  S2ClosestPointQueryBase();
+  ~S2ClosestPointQueryBase();
+
+  // Convenience constructor that calls Init().
+  explicit S2ClosestPointQueryBase(const Index* index);
+
+  // S2ClosestPointQueryBase is not copyable.
+  S2ClosestPointQueryBase(const S2ClosestPointQueryBase&) = delete;
+  void operator=(const S2ClosestPointQueryBase&) = delete;
+
+  // Initializes the query.
+  // REQUIRES: ReInit() must be called if "index" is modified.
+  void Init(const Index* index);
+
+  // Reinitializes the query.  This method must be called whenever the
+  // underlying index is modified.
+  void ReInit();
+
+  // Return a reference to the underlying S2PointIndex.
+  const Index& index() const;
+
+  // Returns the closest points to the given target that satisfy the given
+  // options.  This method may be called multiple times.
+  std::vector<Result> FindClosestPoints(Target* target, const Options& options);
+
+  // This version can be more efficient when this method is called many times,
+  // since it does not require allocating a new vector on each call.
+  void FindClosestPoints(Target* target, const Options& options,
+                         std::vector<Result>* results);
+
+  // Convenience method that returns exactly one point.  If no points satisfy
+  // the given search criteria, then a Result with distance() == Infinity()
+  // and is_empty() == true is returned.
+  //
+  // REQUIRES: options.max_results() == 1
+  Result FindClosestPoint(Target* target, const Options& options);
+
+ private:
+  using Iterator = typename Index::Iterator;
+
+  const Options& options() const { return *options_; }
+  void FindClosestPointsInternal(Target* target, const Options& options);
+  void FindClosestPointsBruteForce();
+  void FindClosestPointsOptimized();
+  void InitQueue();
+  void InitCovering();
+  void AddInitialRange(S2CellId first_id, S2CellId last_id);
+  void MaybeAddResult(const PointData* point_data);
+  bool ProcessOrEnqueue(S2CellId id, Iterator* iter, bool seek);
+
+  const Index* index_;
+  const Options* options_;
+  Target* target_;
+
+  // True if max_error() must be subtracted from priority queue cell distances
+  // in order to ensure that such distances are measured conservatively.  This
+  // is true only if the target takes advantage of max_error() in order to
+  // return faster results, and 0 < max_error() < distance_limit_.
+  bool use_conservative_cell_distance_;
+
+  // For the optimized algorihm we precompute the top-level S2CellIds that
+  // will be added to the priority queue.  There can be at most 6 of these
+  // cells.  Essentially this is just a covering of the indexed points.
+  std::vector<S2CellId> index_covering_;
+
+  // The distance beyond which we can safely ignore further candidate points.
+  // (Candidates that are exactly at the limit are ignored; this is more
+  // efficient for UpdateMinDistance() and should not affect clients since
+  // distance measurements have a small amount of error anyway.)
+  //
+  // Initially this is the same as the maximum distance specified by the user,
+  // but it can also be updated by the algorithm (see MaybeAddResult).
+  Distance distance_limit_;
+
+  // The current result set is stored in one of three ways:
+  //
+  //  - If max_results() == 1, the best result is kept in result_singleton_.
+  //
+  //  - If max_results() == "infinity", results are appended to result_vector_
+  //    and sorted/uniqued at the end.
+  //
+  //  - Otherwise results are kept in a priority queue so that we can
+  //    progressively reduce the distance limit once max_results() results
+  //    have been found.
+  Result result_singleton_;
+  std::vector<Result> result_vector_;
+  std::priority_queue<Result, absl::InlinedVector<Result, 16>> result_set_;
+
+  // The algorithm maintains a priority queue of unprocessed S2CellIds, sorted
+  // in increasing order of distance from the target.
+  struct QueueEntry {
+    // A lower bound on the distance from the target to "id".  This is the key
+    // of the priority queue.
+    Distance distance;
+
+    // The cell being queued.
+    S2CellId id;
+
+    QueueEntry(Distance _distance, S2CellId _id)
+        : distance(_distance), id(_id) {}
+
+    bool operator<(const QueueEntry& other) const {
+      // The priority queue returns the largest elements first, so we want the
+      // "largest" entry to have the smallest distance.
+      return other.distance < distance;
+    }
+  };
+  using CellQueue =
+      std::priority_queue<QueueEntry, absl::InlinedVector<QueueEntry, 16>>;
+  CellQueue queue_;
+
+  // Temporaries, defined here to avoid multiple allocations / initializations.
+
+  Iterator iter_;
+  std::vector<S2CellId> region_covering_;
+  std::vector<S2CellId> max_distance_covering_;
+  std::vector<S2CellId> intersection_with_region_;
+  std::vector<S2CellId> intersection_with_max_distance_;
+  const PointData* tmp_point_data_[kMinPointsToEnqueue - 1];
+};
+
+
+//////////////////   Implementation details follow   ////////////////////
+
+
+template <class Distance> inline
+S2ClosestPointQueryBaseOptions<Distance>::S2ClosestPointQueryBaseOptions() {
+}
+
+template <class Distance>
+inline int S2ClosestPointQueryBaseOptions<Distance>::max_results() const {
+  return max_results_;
+}
+
+template <class Distance>
+inline void S2ClosestPointQueryBaseOptions<Distance>::set_max_results(
+    int max_results) {
+  S2_DCHECK_GE(max_results, 1);
+  max_results_ = max_results;
+}
+
+template <class Distance>
+inline Distance S2ClosestPointQueryBaseOptions<Distance>::max_distance()
+    const {
+  return max_distance_;
+}
+
+template <class Distance>
+inline void S2ClosestPointQueryBaseOptions<Distance>::set_max_distance(
+    Distance max_distance) {
+  max_distance_ = max_distance;
+}
+
+template <class Distance>
+inline typename Distance::Delta
+S2ClosestPointQueryBaseOptions<Distance>::max_error() const {
+  return max_error_;
+}
+
+template <class Distance>
+inline void S2ClosestPointQueryBaseOptions<Distance>::set_max_error(
+    Delta max_error) {
+  max_error_ = max_error;
+}
+
+template <class Distance>
+inline const S2Region* S2ClosestPointQueryBaseOptions<Distance>::region()
+    const {
+  return region_;
+}
+
+template <class Distance>
+inline void S2ClosestPointQueryBaseOptions<Distance>::set_region(
+    const S2Region* region) {
+  region_ = region;
+}
+
+template <class Distance>
+inline bool S2ClosestPointQueryBaseOptions<Distance>::use_brute_force() const {
+  return use_brute_force_;
+}
+
+template <class Distance>
+inline void S2ClosestPointQueryBaseOptions<Distance>::set_use_brute_force(
+    bool use_brute_force) {
+  use_brute_force_ = use_brute_force;
+}
+
+template <class Distance, class Data>
+S2ClosestPointQueryBase<Distance, Data>::S2ClosestPointQueryBase() {
+}
+
+template <class Distance, class Data>
+S2ClosestPointQueryBase<Distance, Data>::~S2ClosestPointQueryBase() {
+  // Prevent inline destructor bloat by providing a definition.
+}
+
+template <class Distance, class Data>
+inline S2ClosestPointQueryBase<Distance, Data>::S2ClosestPointQueryBase(
+    const S2PointIndex<Data>* index) : S2ClosestPointQueryBase() {
+  Init(index);
+}
+
+template <class Distance, class Data>
+void S2ClosestPointQueryBase<Distance, Data>::Init(
+    const S2PointIndex<Data>* index) {
+  index_ = index;
+  ReInit();
+}
+
+template <class Distance, class Data>
+void S2ClosestPointQueryBase<Distance, Data>::ReInit() {
+  iter_.Init(index_);
+  index_covering_.clear();
+}
+
+template <class Distance, class Data>
+inline const S2PointIndex<Data>&
+S2ClosestPointQueryBase<Distance, Data>::index() const {
+  return *index_;
+}
+
+template <class Distance, class Data>
+inline std::vector<typename S2ClosestPointQueryBase<Distance, Data>::Result>
+S2ClosestPointQueryBase<Distance, Data>::FindClosestPoints(
+    Target* target, const Options& options) {
+  std::vector<Result> results;
+  FindClosestPoints(target, options, &results);
+  return results;
+}
+
+template <class Distance, class Data>
+typename S2ClosestPointQueryBase<Distance, Data>::Result
+S2ClosestPointQueryBase<Distance, Data>::FindClosestPoint(
+    Target* target, const Options& options) {
+  S2_DCHECK_EQ(options.max_results(), 1);
+  FindClosestPointsInternal(target, options);
+  return result_singleton_;
+}
+
+template <class Distance, class Data>
+void S2ClosestPointQueryBase<Distance, Data>::FindClosestPoints(
+    Target* target, const Options& options, std::vector<Result>* results) {
+  FindClosestPointsInternal(target, options);
+  results->clear();
+  if (options.max_results() == 1) {
+    if (!result_singleton_.is_empty()) {
+      results->push_back(result_singleton_);
+    }
+  } else if (options.max_results() == Options::kMaxMaxResults) {
+    std::sort(result_vector_.begin(), result_vector_.end());
+    std::unique_copy(result_vector_.begin(), result_vector_.end(),
+                     std::back_inserter(*results));
+    result_vector_.clear();
+  } else {
+    results->reserve(result_set_.size());
+    for (; !result_set_.empty(); result_set_.pop()) {
+      results->push_back(result_set_.top());
+    }
+    // The priority queue returns the largest elements first.
+    std::reverse(results->begin(), results->end());
+    S2_DCHECK(std::is_sorted(results->begin(), results->end()));
+  }
+}
+
+template <class Distance, class Data>
+void S2ClosestPointQueryBase<Distance, Data>::FindClosestPointsInternal(
+    Target* target, const Options& options) {
+  target_ = target;
+  options_ = &options;
+
+  distance_limit_ = options.max_distance();
+  result_singleton_ = Result();
+  S2_DCHECK(result_vector_.empty());
+  S2_DCHECK(result_set_.empty());
+  S2_DCHECK_GE(target->max_brute_force_index_size(), 0);
+  if (distance_limit_ == Distance::Zero()) return;
+
+  if (options.max_results() == Options::kMaxMaxResults &&
+      options.max_distance() == Distance::Infinity() &&
+      options.region() == nullptr) {
+    S2_LOG(WARNING) << "Returning all points "
+                    "(max_results/max_distance/region not set)";
+  }
+
+  // If max_error() > 0 and the target takes advantage of this, then we may
+  // need to adjust the distance estimates to the priority queue cells to
+  // ensure that they are always a lower bound on the true distance.  For
+  // example, suppose max_distance == 100, max_error == 30, and we compute the
+  // distance to the target from some cell C0 as d(C0) == 80.  Then because
+  // the target takes advantage of max_error(), the true distance could be as
+  // low as 50.  In order not to miss edges contained by such cells, we need
+  // to subtract max_error() from the distance estimates.  This behavior is
+  // controlled by the use_conservative_cell_distance_ flag.
+  //
+  // However there is one important case where this adjustment is not
+  // necessary, namely when max_distance() < max_error().  This is because
+  // max_error() only affects the algorithm once at least max_results() edges
+  // have been found that satisfy the given distance limit.  At that point,
+  // max_error() is subtracted from distance_limit_ in order to ensure that
+  // any further matches are closer by at least that amount.  But when
+  // max_distance() < max_error(), this reduces the distance limit to 0,
+  // i.e. all remaining candidate cells and edges can safely be discarded.
+  // (Note that this is how IsDistanceLess() and friends are implemented.)
+  //
+  // Note that Distance::Delta only supports operator==.
+  bool target_uses_max_error = (!(options.max_error() == Delta::Zero()) &&
+                                target_->set_max_error(options.max_error()));
+
+  // Note that we can't compare max_error() and distance_limit_ directly
+  // because one is a Delta and one is a Distance.  Instead we subtract them.
+  use_conservative_cell_distance_ = target_uses_max_error &&
+      (distance_limit_ == Distance::Infinity() ||
+       Distance::Zero() < distance_limit_ - options.max_error());
+
+  // Note that given point is processed only once (unlike S2ClosestEdgeQuery),
+  // and therefore we don't need to worry about the possibility of having
+  // duplicate points in the results.
+  if (options.use_brute_force() ||
+      index_->num_points() <= target_->max_brute_force_index_size()) {
+    FindClosestPointsBruteForce();
+  } else {
+    FindClosestPointsOptimized();
+  }
+}
+
+template <class Distance, class Data>
+void S2ClosestPointQueryBase<Distance, Data>::FindClosestPointsBruteForce() {
+  for (iter_.Begin(); !iter_.done(); iter_.Next()) {
+    MaybeAddResult(&iter_.point_data());
+  }
+}
+
+template <class Distance, class Data>
+void S2ClosestPointQueryBase<Distance, Data>::FindClosestPointsOptimized() {
+  InitQueue();
+  while (!queue_.empty()) {
+    // We need to copy the top entry before removing it, and we need to remove
+    // it before adding any new entries to the queue.
+    QueueEntry entry = queue_.top();
+    queue_.pop();
+    // Work around weird parse error in gcc 4.9 by using a local variable for
+    // entry.distance.
+    Distance distance = entry.distance;
+    if (!(distance < distance_limit_)) {
+      queue_ = CellQueue();  // Clear any remaining entries.
+      break;
+    }
+    S2CellId child = entry.id.child_begin();
+    // We already know that it has too many points, so process its children.
+    // Each child may either be processed directly or enqueued again.  The
+    // loop is optimized so that we don't seek unnecessarily.
+    bool seek = true;
+    for (int i = 0; i < 4; ++i, child = child.next()) {
+      seek = ProcessOrEnqueue(child, &iter_, seek);
+    }
+  }
+}
+
+template <class Distance, class Data>
+void S2ClosestPointQueryBase<Distance, Data>::InitQueue() {
+  S2_DCHECK(queue_.empty());
+
+  // Optimization: rather than starting with the entire index, see if we can
+  // limit the search region to a small disc.  Then we can find a covering for
+  // that disc and intersect it with the covering for the index.  This can
+  // save a lot of work when the search region is small.
+  S2Cap cap = target_->GetCapBound();
+  if (cap.is_empty()) return;  // Empty target.
+  if (options().max_results() == 1) {
+    // If the user is searching for just the closest point, we can compute an
+    // upper bound on search radius by seeking to the center of the target's
+    // bounding cap and looking at the adjacent index points (in S2CellId
+    // order).  The minimum distance to either of these points is an upper
+    // bound on the search radius.
+    //
+    // TODO(ericv): The same strategy would also work for small values of
+    // max_results() > 1, e.g. max_results() == 20, except that we would need to
+    // examine more neighbors (at least 20, and preferably 20 in each
+    // direction).  It's not clear whether this is a common case, though, and
+    // also this would require extending MaybeAddResult() so that it can
+    // remove duplicate entries.  (The points added here may be re-added by
+    // ProcessOrEnqueue(), but this is okay when max_results() == 1.)
+    iter_.Seek(S2CellId(cap.center()));
+    if (!iter_.done()) {
+      MaybeAddResult(&iter_.point_data());
+    }
+    if (iter_.Prev()) {
+      MaybeAddResult(&iter_.point_data());
+    }
+    // Skip the rest of the algorithm if we found a matching point.
+    if (distance_limit_ == Distance::Zero()) return;
+  }
+  // We start with a covering of the set of indexed points, then intersect it
+  // with the given region (if any) and maximum search radius disc (if any).
+  if (index_covering_.empty()) InitCovering();
+  const std::vector<S2CellId>* initial_cells = &index_covering_;
+  if (options().region()) {
+    S2RegionCoverer coverer;
+    coverer.mutable_options()->set_max_cells(4);
+    coverer.GetCovering(*options().region(), &region_covering_);
+    S2CellUnion::GetIntersection(index_covering_, region_covering_,
+                                 &intersection_with_region_);
+    initial_cells = &intersection_with_region_;
+  }
+  if (distance_limit_ < Distance::Infinity()) {
+    S2RegionCoverer coverer;
+    coverer.mutable_options()->set_max_cells(4);
+    S1ChordAngle radius = cap.radius() + distance_limit_.GetChordAngleBound();
+    S2Cap search_cap(cap.center(), radius);
+    coverer.GetFastCovering(search_cap, &max_distance_covering_);
+    S2CellUnion::GetIntersection(*initial_cells, max_distance_covering_,
+                                 &intersection_with_max_distance_);
+    initial_cells = &intersection_with_max_distance_;
+  }
+  iter_.Begin();
+  for (int i = 0; i < initial_cells->size() && !iter_.done(); ++i) {
+    S2CellId id = (*initial_cells)[i];
+    ProcessOrEnqueue(id, &iter_, id.range_min() > iter_.id() /*seek*/);
+  }
+}
+
+template <class Distance, class Data>
+void S2ClosestPointQueryBase<Distance, Data>::InitCovering() {
+  // Compute the "index covering", which is a small number of S2CellIds that
+  // cover the indexed points.  There are two cases:
+  //
+  //  - If the index spans more than one face, then there is one covering cell
+  // per spanned face, just big enough to cover the index cells on that face.
+  //
+  //  - If the index spans only one face, then we find the smallest cell "C"
+  // that covers the index cells on that face (just like the case above).
+  // Then for each of the 4 children of "C", if the child contains any index
+  // cells then we create a covering cell that is big enough to just fit
+  // those index cells (i.e., shrinking the child as much as possible to fit
+  // its contents).  This essentially replicates what would happen if we
+  // started with "C" as the covering cell, since "C" would immediately be
+  // split, except that we take the time to prune the children further since
+  // this will save work on every subsequent query.
+  index_covering_.reserve(6);
+  iter_.Finish();
+  if (!iter_.Prev()) return;  // Empty index.
+  S2CellId index_last_id = iter_.id();
+  iter_.Begin();
+  if (iter_.id() != index_last_id) {
+    // The index has at least two cells.  Choose a level such that the entire
+    // index can be spanned with at most 6 cells (if the index spans multiple
+    // faces) or 4 cells (it the index spans a single face).
+    int level = iter_.id().GetCommonAncestorLevel(index_last_id) + 1;
+
+    // Visit each potential covering cell except the last (handled below).
+    S2CellId last_id = index_last_id.parent(level);
+    for (S2CellId id = iter_.id().parent(level);
+         id != last_id; id = id.next()) {
+      // Skip any covering cells that don't contain any index cells.
+      if (id.range_max() < iter_.id()) continue;
+
+      // Find the range of index cells contained by this covering cell and
+      // then shrink the cell if necessary so that it just covers them.
+      S2CellId cell_first_id = iter_.id();
+      iter_.Seek(id.range_max().next());
+      iter_.Prev();
+      S2CellId cell_last_id = iter_.id();
+      iter_.Next();
+      AddInitialRange(cell_first_id, cell_last_id);
+    }
+  }
+  AddInitialRange(iter_.id(), index_last_id);
+}
+
+// Adds a cell to index_covering_ that covers the given inclusive range.
+//
+// REQUIRES: "first" and "last" have a common ancestor.
+template <class Distance, class Data>
+void S2ClosestPointQueryBase<Distance, Data>::AddInitialRange(
+    S2CellId first_id, S2CellId last_id) {
+  // Add the lowest common ancestor of the given range.
+  int level = first_id.GetCommonAncestorLevel(last_id);
+  S2_DCHECK_GE(level, 0);
+  index_covering_.push_back(first_id.parent(level));
+}
+
+template <class Distance, class Data>
+void S2ClosestPointQueryBase<Distance, Data>::MaybeAddResult(
+    const PointData* point_data) {
+  Distance distance = distance_limit_;
+  if (!target_->UpdateMinDistance(point_data->point(), &distance)) return;
+
+  const S2Region* region = options().region();
+  if (region && !region->Contains(point_data->point())) return;
+
+  Result result(distance, point_data);
+  if (options().max_results() == 1) {
+    // Optimization for the common case where only the closest point is wanted.
+    result_singleton_ = result;
+    distance_limit_ = result.distance() - options().max_error();
+  } else if (options().max_results() == Options::kMaxMaxResults) {
+    result_vector_.push_back(result);  // Sort/unique at end.
+  } else {
+    // Add this point to result_set_.  Note that with the current algorithm
+    // each candidate point is considered at most once (except for one special
+    // case where max_results() == 1, see InitQueue for details), so we don't
+    // need to worry about possibly adding a duplicate entry here.
+    if (result_set_.size() >= options().max_results()) {
+      result_set_.pop();  // Replace the furthest result point.
+    }
+    result_set_.push(result);
+    if (result_set_.size() >= options().max_results()) {
+      distance_limit_ = result_set_.top().distance() - options().max_error();
+    }
+  }
+}
+
+// Either process the contents of the given cell immediately, or add it to the
+// queue to be subdivided.  If "seek" is false, then "iter" must already be
+// positioned at the first indexed point within or after this cell.
+//
+// Returns "true" if the cell was added to the queue, and "false" if it was
+// processed immediately, in which case "iter" is left positioned at the next
+// cell in S2CellId order.
+template <class Distance, class Data>
+bool S2ClosestPointQueryBase<Distance, Data>::ProcessOrEnqueue(
+    S2CellId id, Iterator* iter, bool seek) {
+  if (seek) iter->Seek(id.range_min());
+  if (id.is_leaf()) {
+    // Leaf cells can't be subdivided.
+    for (; !iter->done() && iter->id() == id; iter->Next()) {
+      MaybeAddResult(&iter->point_data());
+    }
+    return false;  // No need to seek to next child.
+  }
+  S2CellId last = id.range_max();
+  int num_points = 0;
+  for (; !iter->done() && iter->id() <= last; iter->Next()) {
+    if (num_points == kMinPointsToEnqueue - 1) {
+      // This cell has too many points (including this one), so enqueue it.
+      S2Cell cell(id);
+      Distance distance = distance_limit_;
+      // We check "region_" second because it may be relatively expensive.
+      if (target_->UpdateMinDistance(cell, &distance) &&
+          (!options().region() || options().region()->MayIntersect(cell))) {
+        if (use_conservative_cell_distance_) {
+          // Ensure that "distance" is a lower bound on distance to the cell.
+          distance = distance - options().max_error();
+        }
+        queue_.push(QueueEntry(distance, id));
+      }
+      return true;  // Seek to next child.
+    }
+    tmp_point_data_[num_points++] = &iter->point_data();
+  }
+  // There were few enough points that we might as well process them now.
+  for (int i = 0; i < num_points; ++i) {
+    MaybeAddResult(tmp_point_data_[i]);
+  }
+  return false;  // No need to seek to next child.
+}
+
+#endif  // S2_S2CLOSEST_POINT_QUERY_BASE_H_
diff --git a/src/s2/s2contains_point_query.h b/src/s2/s2contains_point_query.h
new file mode 100644 (file)
index 0000000..70675a9
--- /dev/null
@@ -0,0 +1,328 @@
+// Copyright 2017 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// Author: ericv@google.com (Eric Veach)
+
+#ifndef S2_S2CONTAINS_POINT_QUERY_H_
+#define S2_S2CONTAINS_POINT_QUERY_H_
+
+#include <vector>
+
+#include "s2/s2edge_crosser.h"
+#include "s2/s2shape_index.h"
+#include "s2/s2shapeutil_shape_edge.h"
+
+// Defines whether shapes are considered to contain their vertices.  Note that
+// these definitions differ from the ones used by S2BooleanOperation.
+//
+//  - In the OPEN model, no shapes contain their vertices (not even points).
+//    Therefore Contains(S2Point) returns true if and only if the point is
+//    in the interior of some polygon.
+//
+//  - In the SEMI_OPEN model, polygon point containment is defined such that
+//    if several polygons tile the region around a vertex, then exactly one of
+//    those polygons contains that vertex.  Points and polylines still do not
+//    contain any vertices.
+//
+//  - In the CLOSED model, all shapes contain their vertices (including points
+//    and polylines).
+//
+// Note that points other than vertices are never contained by polylines.
+// If you want need this behavior, use S2ClosestEdgeQuery::IsDistanceLess()
+// with a suitable distance threshold instead.
+enum class S2VertexModel { OPEN, SEMI_OPEN, CLOSED };
+
+// This class defines the options supported by S2ContainsPointQuery.
+class S2ContainsPointQueryOptions {
+ public:
+  S2ContainsPointQueryOptions() {}
+
+  // Convenience constructor that sets the vertex_model() option.
+  explicit S2ContainsPointQueryOptions(S2VertexModel vertex_model);
+
+  // Controls whether shapes are considered to contain their vertices (see
+  // definitions above).  By default the SEMI_OPEN model is used.
+  //
+  // DEFAULT: S2VertexModel::SEMI_OPEN
+  S2VertexModel vertex_model() const;
+  void set_vertex_model(S2VertexModel model);
+
+ private:
+  S2VertexModel vertex_model_ = S2VertexModel::SEMI_OPEN;
+};
+
+// S2ContainsPointQuery determines whether one or more shapes in an
+// S2ShapeIndex contain a given S2Point.  The S2ShapeIndex may contain any
+// number of points, polylines, and/or polygons (possibly overlapping).
+// Shape boundaries may be modeled as OPEN, SEMI_OPEN, or CLOSED (this affects
+// whether or not shapes are considered to contain their vertices).
+//
+// Example usage:
+//   auto query = MakeS2ContainsPointQuery(&index, S2VertexModel::CLOSED);
+//   return query.Contains(point);
+//
+// This class is not thread-safe.  To use it in parallel, each thread should
+// construct its own instance (this is not expensive).
+//
+// However, note that if you need to do a large number of point containment
+// tests, it is more efficient to re-use the S2ContainsPointQuery object
+// rather than constructing a new one each time.
+template <class IndexType>
+class S2ContainsPointQuery {
+ private:
+  using Iterator = typename IndexType::Iterator;
+
+ public:
+  // Default constructor; requires Init() to be called.
+  S2ContainsPointQuery();
+
+  // Rather than calling this constructor, which requires specifying the
+  // IndexType template argument explicitly, the preferred idiom is to call
+  // MakeS2ContainsPointQuery() instead.  For example:
+  //
+  //   return MakeS2ContainsPointQuery(&index).Contains(p);
+  using Options = S2ContainsPointQueryOptions;
+  explicit S2ContainsPointQuery(const IndexType* index,
+                                const Options& options = Options());
+
+  // Convenience constructor that accepts the S2VertexModel directly.
+  S2ContainsPointQuery(const IndexType* index, S2VertexModel vertex_model);
+
+  const IndexType& index() const { return *index_; }
+  const Options& options() const { return options_; }
+
+  // Equivalent to the two-argument constructor above.
+  void Init(const IndexType* index, const Options& options = Options());
+
+  // Returns true if any shape in the given index() contains the point "p"
+  // under the vertex model specified (OPEN, SEMI_OPEN, or CLOSED).
+  bool Contains(const S2Point& p);
+
+  // Returns true if the given shape contains the point "p" under the vertex
+  // model specified (OPEN, SEMI_OPEN, or CLOSED).
+  //
+  // REQUIRES: "shape" belongs to index().
+  bool ShapeContains(const S2Shape& shape, const S2Point& p);
+
+  // Visits all shapes in the given index() that contain the given point "p",
+  // terminating early if the given ShapeVisitor function returns false (in
+  // which case VisitContainingShapes returns false as well).  Each shape is
+  // visited at most once.
+  //
+  // Note that the API allows non-const access to the visited shapes.
+  using ShapeVisitor = std::function<bool (S2Shape* shape)>;
+  bool VisitContainingShapes(const S2Point& p, const ShapeVisitor& visitor);
+
+  // Convenience function that returns all the shapes that contain the given
+  // point "p".
+  std::vector<S2Shape*> GetContainingShapes(const S2Point& p);
+
+  // Visits all edges in the given index() that are incident to the point "p"
+  // (i.e., "p" is one of the edge endpoints), terminating early if the given
+  // EdgeVisitor function returns false (in which case VisitIncidentEdges
+  // returns false as well).  Each edge is visited at most once.
+  using EdgeVisitor = std::function<bool (const s2shapeutil::ShapeEdge&)>;
+  bool VisitIncidentEdges(const S2Point& p, const EdgeVisitor& visitor);
+
+  /////////////////////////// Low-Level Methods ////////////////////////////
+  //
+  // Most clients will not need the following methods.  They can be slightly
+  // more efficient but are harder to use.
+
+  // Returns a pointer to the iterator used internally by this class, in order
+  // to avoid the need for clients to create their own iterator.  Clients are
+  // allowed to reposition this iterator arbitrarily between method calls.
+  Iterator* mutable_iter() { return &it_; }
+
+  // Low-level helper method that returns true if the given S2ClippedShape
+  // referred to by an S2ShapeIndex::Iterator contains the point "p".
+  bool ShapeContains(const Iterator& it, const S2ClippedShape& clipped,
+                     const S2Point& p) const;
+
+ private:
+  const IndexType* index_;
+  Options options_;
+  Iterator it_;
+};
+
+// Returns an S2ContainsPointQuery for the given S2ShapeIndex.  Note that
+// it is efficient to return S2ContainsPointQuery objects by value.
+template <class IndexType>
+inline S2ContainsPointQuery<IndexType> MakeS2ContainsPointQuery(
+    const IndexType* index,
+    const S2ContainsPointQueryOptions& options =
+    S2ContainsPointQueryOptions()) {
+  return S2ContainsPointQuery<IndexType>(index, options);
+}
+
+
+//////////////////   Implementation details follow   ////////////////////
+
+
+inline S2ContainsPointQueryOptions::S2ContainsPointQueryOptions(
+    S2VertexModel vertex_model)
+    : vertex_model_(vertex_model) {
+}
+
+inline S2VertexModel S2ContainsPointQueryOptions::vertex_model() const {
+  return vertex_model_;
+}
+
+inline void S2ContainsPointQueryOptions::set_vertex_model(S2VertexModel model) {
+  vertex_model_ = model;
+}
+
+template <class IndexType>
+inline S2ContainsPointQuery<IndexType>::S2ContainsPointQuery()
+    : index_(nullptr) {
+}
+
+template <class IndexType>
+inline S2ContainsPointQuery<IndexType>::S2ContainsPointQuery(
+    const IndexType* index, const Options& options)
+    : index_(index), options_(options), it_(index_) {
+}
+
+template <class IndexType>
+inline S2ContainsPointQuery<IndexType>::S2ContainsPointQuery(
+    const IndexType* index, S2VertexModel vertex_model)
+    : S2ContainsPointQuery(index, Options(vertex_model)) {
+}
+
+template <class IndexType>
+void S2ContainsPointQuery<IndexType>::Init(const IndexType* index,
+                                           const Options& options) {
+  index_ = index;
+  options_ = options;
+  it_.Init(index);
+}
+
+template <class IndexType>
+bool S2ContainsPointQuery<IndexType>::Contains(const S2Point& p) {
+  if (!it_.Locate(p)) return false;
+
+  const S2ShapeIndexCell& cell = it_.cell();
+  int num_clipped = cell.num_clipped();
+  for (int s = 0; s < num_clipped; ++s) {
+    if (ShapeContains(it_, cell.clipped(s), p)) return true;
+  }
+  return false;
+}
+
+template <class IndexType>
+bool S2ContainsPointQuery<IndexType>::ShapeContains(const S2Shape& shape,
+                                                    const S2Point& p) {
+  if (!it_.Locate(p)) return false;
+  const S2ClippedShape* clipped = it_.cell().find_clipped(shape.id());
+  if (clipped == nullptr) return false;
+  return ShapeContains(it_, *clipped, p);
+}
+
+template <class IndexType>
+bool S2ContainsPointQuery<IndexType>::VisitContainingShapes(
+    const S2Point& p, const ShapeVisitor& visitor) {
+  // This function returns "false" only if the algorithm terminates early
+  // because the "visitor" function returned false.
+  if (!it_.Locate(p)) return true;
+
+  const S2ShapeIndexCell& cell = it_.cell();
+  int num_clipped = cell.num_clipped();
+  for (int s = 0; s < num_clipped; ++s) {
+    const S2ClippedShape& clipped = cell.clipped(s);
+    if (ShapeContains(it_, clipped, p) &&
+        !visitor(index_->shape(clipped.shape_id()))) {
+      return false;
+    }
+  }
+  return true;
+}
+
+template <class IndexType>
+bool S2ContainsPointQuery<IndexType>::VisitIncidentEdges(
+    const S2Point& p, const EdgeVisitor& visitor) {
+  // This function returns "false" only if the algorithm terminates early
+  // because the "visitor" function returned false.
+  if (!it_.Locate(p)) return true;
+
+  const S2ShapeIndexCell& cell = it_.cell();
+  int num_clipped = cell.num_clipped();
+  for (int s = 0; s < num_clipped; ++s) {
+    const S2ClippedShape& clipped = cell.clipped(s);
+    int num_edges = clipped.num_edges();
+    if (num_edges == 0) continue;
+    const S2Shape& shape = *index_->shape(clipped.shape_id());
+    for (int i = 0; i < num_edges; ++i) {
+      int edge_id = clipped.edge(i);
+      auto edge = shape.edge(edge_id);
+      if ((edge.v0 == p || edge.v1 == p) &&
+          !visitor(s2shapeutil::ShapeEdge(shape.id(), edge_id, edge))) {
+        return false;
+      }
+    }
+  }
+  return true;
+}
+
+template <class IndexType>
+std::vector<S2Shape*> S2ContainsPointQuery<IndexType>::GetContainingShapes(
+    const S2Point& p) {
+  std::vector<S2Shape*> results;
+  VisitContainingShapes(p, [&results](S2Shape* shape) {
+      results.push_back(shape);
+      return true;
+    });
+  return results;
+}
+
+template <class IndexType>
+bool S2ContainsPointQuery<IndexType>::ShapeContains(
+    const Iterator& it, const S2ClippedShape& clipped, const S2Point& p) const {
+  bool inside = clipped.contains_center();
+  const int num_edges = clipped.num_edges();
+  if (num_edges > 0) {
+    const S2Shape& shape = *index_->shape(clipped.shape_id());
+    if (shape.dimension() < 2) {
+      // Points and polylines can be ignored unless the vertex model is CLOSED.
+      if (options_.vertex_model() != S2VertexModel::CLOSED) return false;
+
+      // Otherwise, the point is contained if and only if it matches a vertex.
+      for (int i = 0; i < num_edges; ++i) {
+        auto edge = shape.edge(clipped.edge(i));
+        if (edge.v0 == p || edge.v1 == p) return true;
+      }
+      return false;
+    }
+    // Test containment by drawing a line segment from the cell center to the
+    // given point and counting edge crossings.
+    S2CopyingEdgeCrosser crosser(it.center(), p);
+    for (int i = 0; i < num_edges; ++i) {
+      auto edge = shape.edge(clipped.edge(i));
+      int sign = crosser.CrossingSign(edge.v0, edge.v1);
+      if (sign < 0) continue;
+      if (sign == 0) {
+        // For the OPEN and CLOSED models, check whether "p" is a vertex.
+        if (options_.vertex_model() != S2VertexModel::SEMI_OPEN &&
+            (edge.v0 == p || edge.v1 == p)) {
+          return (options_.vertex_model() == S2VertexModel::CLOSED);
+        }
+        sign = S2::VertexCrossing(crosser.a(), crosser.b(), edge.v0, edge.v1);
+      }
+      inside ^= sign;
+    }
+  }
+  return inside;
+}
+
+#endif  // S2_S2CONTAINS_POINT_QUERY_H_
diff --git a/src/s2/s2contains_vertex_query.cc b/src/s2/s2contains_vertex_query.cc
new file mode 100644 (file)
index 0000000..bf5351e
--- /dev/null
@@ -0,0 +1,39 @@
+// Copyright 2017 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// Author: ericv@google.com (Eric Veach)
+
+#include "s2/s2contains_vertex_query.h"
+
+#include <cmath>
+#include <utility>
+#include "s2/s2pointutil.h"
+#include "s2/s2predicates.h"
+
+using std::abs;
+
+int S2ContainsVertexQuery::ContainsSign() {
+  // Find the unmatched edge that is immediately clockwise from S2::Ortho(P).
+  S2Point reference_dir = S2::Ortho(target_);
+  std::pair<S2Point, int> best(reference_dir, 0);
+  for (const auto& e : edge_map_) {
+    S2_DCHECK_LE(abs(e.second), 1);
+    if (e.second == 0) continue;  // This is a "matched" edge.
+    if (s2pred::OrderedCCW(reference_dir, best.first, e.first, target_)) {
+      best = e;
+    }
+  }
+  return best.second;
+}
diff --git a/src/s2/s2contains_vertex_query.h b/src/s2/s2contains_vertex_query.h
new file mode 100644 (file)
index 0000000..5109a9a
--- /dev/null
@@ -0,0 +1,66 @@
+// Copyright 2017 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// Author: ericv@google.com (Eric Veach)
+
+#ifndef S2_S2CONTAINS_VERTEX_QUERY_H_
+#define S2_S2CONTAINS_VERTEX_QUERY_H_
+
+#include "absl/container/btree_map.h"
+#include "s2/s2point.h"
+
+// This class determines whether a polygon contains one of its vertices given
+// the edges incident to that vertex.  The result is +1 if the vertex is
+// contained, -1 if it is not contained, and 0 if the incident edges consist
+// of matched sibling pairs (in which case the result cannot be determined
+// locally).
+//
+// Point containment is defined according to the "semi-open" boundary model
+// (see S2VertexModel), which means that if several polygons tile the region
+// around a vertex, then exactly one of those polygons contains that vertex.
+//
+// This class is not thread-safe.  To use it in parallel, each thread should
+// construct its own instance (this is not expensive).
+class S2ContainsVertexQuery {
+ public:
+  // "target" is the vertex whose containment will be determined.
+  explicit S2ContainsVertexQuery(const S2Point& target);
+
+  // Indicates that the polygon has an edge between "target" and "v" in the
+  // given direction (+1 = outgoing, -1 = incoming, 0 = degenerate).
+  void AddEdge(const S2Point& v, int direction);
+
+  // Returns +1 if the vertex is contained, -1 if it is not contained, and 0
+  // if the incident edges consisted of matched sibling pairs.
+  int ContainsSign();
+
+ private:
+  S2Point target_;
+  absl::btree_map<S2Point, int> edge_map_;
+};
+
+
+//////////////////   Implementation details follow   ////////////////////
+
+
+inline S2ContainsVertexQuery::S2ContainsVertexQuery(const S2Point& target)
+    : target_(target) {
+}
+
+inline void S2ContainsVertexQuery::AddEdge(const S2Point& v, int direction) {
+  edge_map_[v] += direction;
+}
+
+#endif  // S2_S2CONTAINS_VERTEX_QUERY_H_
diff --git a/src/s2/s2convex_hull_query.cc b/src/s2/s2convex_hull_query.cc
new file mode 100644 (file)
index 0000000..aaee545
--- /dev/null
@@ -0,0 +1,198 @@
+// Copyright 2015 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// Author: ericv@google.com (Eric Veach)
+//
+// This implement Andrew's monotone chain algorithm, which is a variant of the
+// Graham scan (see https://en.wikipedia.org/wiki/Graham_scan).  The time
+// complexity is O(n log n), and the space required is O(n).  In fact only the
+// call to "sort" takes O(n log n) time; the rest of the algorithm is linear.
+//
+// Demonstration of the algorithm and code:
+// en.wikibooks.org/wiki/Algorithm_Implementation/Geometry/Convex_hull/Monotone_chain
+
+#include "s2/s2convex_hull_query.h"
+
+#include "absl/memory/memory.h"
+#include "s2/s2pointutil.h"
+#include "s2/s2predicates.h"
+
+using absl::make_unique;
+using std::unique_ptr;
+using std::vector;
+
+S2ConvexHullQuery::S2ConvexHullQuery()
+    : bound_(S2LatLngRect::Empty()), points_() {
+}
+
+void S2ConvexHullQuery::AddPoint(const S2Point& point) {
+  bound_.AddPoint(point);
+  points_.push_back(point);
+}
+
+void S2ConvexHullQuery::AddPolyline(const S2Polyline& polyline) {
+  bound_ = bound_.Union(polyline.GetRectBound());
+  for (int i = 0; i < polyline.num_vertices(); ++i) {
+    points_.push_back(polyline.vertex(i));
+  }
+}
+
+void S2ConvexHullQuery::AddLoop(const S2Loop& loop) {
+  bound_ = bound_.Union(loop.GetRectBound());
+  if (loop.is_empty_or_full()) {
+    // The empty and full loops consist of a single fake "vertex" that should
+    // not be added to our point collection.
+    return;
+  }
+  for (int i = 0; i < loop.num_vertices(); ++i) {
+    points_.push_back(loop.vertex(i));
+  }
+}
+
+void S2ConvexHullQuery::AddPolygon(const S2Polygon& polygon) {
+  for (int i = 0; i < polygon.num_loops(); ++i) {
+    const S2Loop& loop = *polygon.loop(i);
+    // Only loops at depth 0 can contribute to the convex hull.
+    if (loop.depth() == 0) {
+      AddLoop(loop);
+    }
+  }
+}
+
+S2Cap S2ConvexHullQuery::GetCapBound() {
+  // We keep track of a rectangular bound rather than a spherical cap because
+  // it is easy to compute a tight bound for a union of rectangles, whereas it
+  // is quite difficult to compute a tight bound around a union of caps.
+  // Also, polygons and polylines implement GetCapBound() in terms of
+  // GetRectBound() for this same reason, so it is much better to keep track
+  // of a rectangular bound as we go along and convert it at the end.
+  //
+  // TODO(ericv): We could compute an optimal bound by implementing Welzl's
+  // algorithm.  However we would still need to have special handling of loops
+  // and polygons, since if a loop spans more than 180 degrees in any
+  // direction (i.e., if it contains two antipodal points), then it is not
+  // enough just to bound its vertices.  In this case the only convex bounding
+  // cap is S2Cap::Full(), and the only convex bounding loop is the full loop.
+  return bound_.GetCapBound();
+}
+
+// A comparator for sorting points in CCW around a central point "center".
+class OrderedCcwAround {
+ public:
+  explicit OrderedCcwAround(const S2Point& center) : center_(center) {}
+  bool operator()(const S2Point& x, const S2Point& y) const {
+    // If X and Y are equal, this will return false (as desired).
+    return s2pred::Sign(center_, x, y) > 0;
+  }
+ private:
+  S2Point center_;
+};
+
+unique_ptr<S2Loop> S2ConvexHullQuery::GetConvexHull() {
+  S2Cap cap = GetCapBound();
+  if (cap.height() >= 1) {
+    // The bounding cap is not convex.  The current bounding cap
+    // implementation is not optimal, but nevertheless it is likely that the
+    // input geometry itself is not contained by any convex polygon.  In any
+    // case, we need a convex bounding cap to proceed with the algorithm below
+    // (in order to construct a point "origin" that is definitely outside the
+    // convex hull).
+    return make_unique<S2Loop>(S2Loop::kFull());
+  }
+  // This code implements Andrew's monotone chain algorithm, which is a simple
+  // variant of the Graham scan.  Rather than sorting by x-coordinate, instead
+  // we sort the points in CCW order around an origin O such that all points
+  // are guaranteed to be on one side of some geodesic through O.  This
+  // ensures that as we scan through the points, each new point can only
+  // belong at the end of the chain (i.e., the chain is monotone in terms of
+  // the angle around O from the starting point).
+  S2Point origin = cap.center().Ortho();
+  std::sort(points_.begin(), points_.end(), OrderedCcwAround(origin));
+
+  // Remove duplicates.  We need to do this before checking whether there are
+  // fewer than 3 points.
+  points_.erase(std::unique(points_.begin(), points_.end()), points_.end());
+
+  // Special cases for fewer than 3 points.
+  if (points_.size() < 3) {
+    if (points_.empty()) {
+      return make_unique<S2Loop>(S2Loop::kEmpty());
+    } else if (points_.size() == 1) {
+      return GetSinglePointLoop(points_[0]);
+    } else {
+      return GetSingleEdgeLoop(points_[0], points_[1]);
+    }
+  }
+
+  // Verify that all points lie within a 180 degree span around the origin.
+  S2_DCHECK_GE(s2pred::Sign(origin, points_.front(), points_.back()), 0);
+
+  // Generate the lower and upper halves of the convex hull.  Each half
+  // consists of the maximal subset of vertices such that the edge chain makes
+  // only left (CCW) turns.
+  vector<S2Point> lower, upper;
+  GetMonotoneChain(&lower);
+  std::reverse(points_.begin(), points_.end());
+  GetMonotoneChain(&upper);
+
+  // Remove the duplicate vertices and combine the chains.
+  S2_DCHECK_EQ(lower.front(), upper.back());
+  S2_DCHECK_EQ(lower.back(), upper.front());
+  lower.pop_back();
+  upper.pop_back();
+  lower.insert(lower.end(), upper.begin(), upper.end());
+  return make_unique<S2Loop>(lower);
+}
+
+// Iterate through the given points, selecting the maximal subset of points
+// such that the edge chain makes only left (CCW) turns.
+void S2ConvexHullQuery::GetMonotoneChain(vector<S2Point>* output) {
+  S2_DCHECK(output->empty());
+  for (const S2Point& p : points_) {
+    // Remove any points that would cause the chain to make a clockwise turn.
+    while (output->size() >= 2 &&
+           s2pred::Sign(output->end()[-2], output->back(), p) <= 0) {
+      output->pop_back();
+    }
+    output->push_back(p);
+  }
+}
+
+unique_ptr<S2Loop> S2ConvexHullQuery::GetSinglePointLoop(const S2Point& p) {
+  // Construct a 3-vertex polygon consisting of "p" and two nearby vertices.
+  // Note that Contains(p) may be false for the resulting loop (see comments
+  // in header file).
+  static const double kOffset = 1e-15;
+  S2Point d0 = S2::Ortho(p);
+  S2Point d1 = p.CrossProd(d0);
+  vector<S2Point> vertices;
+  vertices.push_back(p);
+  vertices.push_back((p + kOffset * d0).Normalize());
+  vertices.push_back((p + kOffset * d1).Normalize());
+  return make_unique<S2Loop>(vertices);
+}
+
+unique_ptr<S2Loop> S2ConvexHullQuery::GetSingleEdgeLoop(const S2Point& a,
+                                                        const S2Point& b) {
+  // Construct a loop consisting of the two vertices and their midpoint.
+  vector<S2Point> vertices;
+  vertices.push_back(a);
+  vertices.push_back(b);
+  vertices.push_back((a + b).Normalize());
+  auto loop = make_unique<S2Loop>(vertices);
+  // The resulting loop may be clockwise, so invert it if necessary.
+  loop->Normalize();
+  return loop;
+}
diff --git a/src/s2/s2convex_hull_query.h b/src/s2/s2convex_hull_query.h
new file mode 100644 (file)
index 0000000..8fd43c8
--- /dev/null
@@ -0,0 +1,110 @@
+// Copyright 2015 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// Author: ericv@google.com (Eric Veach)
+
+#ifndef S2_S2CONVEX_HULL_QUERY_H_
+#define S2_S2CONVEX_HULL_QUERY_H_
+
+#include <memory>
+#include <vector>
+
+#include "s2/_fp_contract_off.h"
+#include "s2/s2cap.h"
+#include "s2/s2latlng_rect.h"
+#include "s2/s2loop.h"
+#include "s2/s2polygon.h"
+#include "s2/s2polyline.h"
+
+// S2ConvexHullQuery builds the convex hull of any collection of points,
+// polylines, loops, and polygons.  It returns a single convex loop.
+//
+// The convex hull is defined as the smallest convex region on the sphere that
+// contains all of your input geometry.  Recall that a region is "convex" if
+// for every pair of points inside the region, the straight edge between them
+// is also inside the region.  In our case, a "straight" edge is a geodesic,
+// i.e. the shortest path on the sphere between two points.
+//
+// Containment of input geometry is defined as follows:
+//
+//  - Each input loop and polygon is contained by the convex hull exactly
+//    (i.e., according to S2Polygon::Contains(S2Polygon)).
+//
+//  - Each input point is either contained by the convex hull or is a vertex
+//    of the convex hull. (Recall that S2Loops do not necessarily contain their
+//    vertices.)
+//
+//  - For each input polyline, the convex hull contains all of its vertices
+//    according to the rule for points above.  (The definition of convexity
+//    then ensures that the convex hull also contains the polyline edges.)
+//
+// To use this class, call the Add*() methods to add your input geometry, and
+// then call GetConvexHull().  Note that GetConvexHull() does *not* reset the
+// state; you can continue adding geometry if desired and compute the convex
+// hull again.  If you want to start from scratch, simply declare a new
+// S2ConvexHullQuery object (they are cheap to create).
+//
+// This class is not thread-safe.  There are no "const" methods.
+class S2ConvexHullQuery {
+ public:
+  S2ConvexHullQuery();
+
+  // Add a point to the input geometry.
+  void AddPoint(const S2Point& point);
+
+  // Add a polyline to the input geometry.
+  void AddPolyline(const S2Polyline& polyline);
+
+  // Add a loop to the input geometry.
+  void AddLoop(const S2Loop& loop);
+
+  // Add a polygon to the input geometry.
+  void AddPolygon(const S2Polygon& polygon);
+
+  // Compute a bounding cap for the input geometry provided.
+  //
+  // Note that this method does not clear the geometry; you can continue
+  // adding to it and call this method again if desired.
+  S2Cap GetCapBound();
+
+  // Compute the convex hull of the input geometry provided.
+  //
+  // If there is no geometry, this method returns an empty loop containing no
+  // points (see S2Loop::is_empty()).
+  //
+  // If the geometry spans more than half of the sphere, this method returns a
+  // full loop containing the entire sphere (see S2Loop::is_full()).
+  //
+  // If the geometry contains 1 or 2 points, or a single edge, this method
+  // returns a very small loop consisting of three vertices (which are a
+  // superset of the input vertices).
+  //
+  // Note that this method does not clear the geometry; you can continue
+  // adding to it and call this method again if desired.
+  std::unique_ptr<S2Loop> GetConvexHull();
+
+ private:
+  void GetMonotoneChain(std::vector<S2Point>* output);
+  std::unique_ptr<S2Loop> GetSinglePointLoop(const S2Point& p);
+  std::unique_ptr<S2Loop> GetSingleEdgeLoop(const S2Point& a, const S2Point& b);
+
+  S2LatLngRect bound_;
+  std::vector<S2Point> points_;
+
+  S2ConvexHullQuery(const S2ConvexHullQuery&) = delete;
+  void operator=(const S2ConvexHullQuery&) = delete;
+};
+
+#endif  // S2_S2CONVEX_HULL_QUERY_H_
diff --git a/src/s2/s2coords.cc b/src/s2/s2coords.cc
new file mode 100644 (file)
index 0000000..d16207d
--- /dev/null
@@ -0,0 +1,146 @@
+// Copyright 2005 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// Author: ericv@google.com (Eric Veach)
+
+#include "s2/s2coords.h"
+
+#include "s2/util/bits/bits.h"
+
+namespace S2 {
+
+namespace internal {
+
+// Define the "extern" constants in s2coords_internal.h.
+
+static_assert(kSwapMask == 0x01 && kInvertMask == 0x02, "masks changed");
+
+// kIJtoPos[orientation][ij] -> pos
+const int kIJtoPos[4][4] = {
+  // (0,0) (0,1) (1,0) (1,1)
+  {     0,    1,    3,    2  },  // canonical order
+  {     0,    3,    1,    2  },  // axes swapped
+  {     2,    3,    1,    0  },  // bits inverted
+  {     2,    1,    3,    0  },  // swapped & inverted
+};
+
+// kPosToIJ[orientation][pos] -> ij
+const int kPosToIJ[4][4] = {
+  // 0  1  2  3
+  {  0, 1, 3, 2 },    // canonical order:    (0,0), (0,1), (1,1), (1,0)
+  {  0, 2, 3, 1 },    // axes swapped:       (0,0), (1,0), (1,1), (0,1)
+  {  3, 2, 0, 1 },    // bits inverted:      (1,1), (1,0), (0,0), (0,1)
+  {  3, 1, 0, 2 },    // swapped & inverted: (1,1), (0,1), (0,0), (1,0)
+};
+
+// kPosToOrientation[pos] -> orientation_modifier
+const int kPosToOrientation[4] = {
+  kSwapMask,
+  0,
+  0,
+  kInvertMask + kSwapMask,
+};
+
+const int kFaceUVWFaces[6][3][2] = {
+  { { 4, 1 }, { 5, 2 }, { 3, 0 } },
+  { { 0, 3 }, { 5, 2 }, { 4, 1 } },
+  { { 0, 3 }, { 1, 4 }, { 5, 2 } },
+  { { 2, 5 }, { 1, 4 }, { 0, 3 } },
+  { { 2, 5 }, { 3, 0 }, { 1, 4 } },
+  { { 4, 1 }, { 3, 0 }, { 2, 5 } }
+};
+
+const double kFaceUVWAxes[6][3][3] = {
+  {
+    { 0,  1,  0 },
+    { 0,  0,  1 },
+    { 1,  0,  0 }
+  },
+  {
+    {-1,  0,  0 },
+    { 0,  0,  1 },
+    { 0,  1,  0 }
+  },
+  {
+    {-1,  0,  0 },
+    { 0, -1,  0 },
+    { 0,  0,  1 }
+  },
+  {
+    { 0,  0, -1 },
+    { 0, -1,  0 },
+    {-1,  0,  0 }
+  },
+  {
+    { 0,  0, -1 },
+    { 1,  0,  0 },
+    { 0, -1,  0 }
+  },
+  {
+    { 0,  1,  0 },
+    { 1,  0,  0 },
+    { 0,  0, -1 }
+  }
+};
+
+} // namespace internal
+
+
+
+S2Point FaceXYZtoUVW(int face, const S2Point& p) {
+  // The result coordinates are simply the dot products of P with the (u,v,w)
+  // axes for the given face (see kFaceUVWAxes).
+  switch (face) {
+    case 0:  return S2Point( p.y(),  p.z(),  p.x());
+    case 1:  return S2Point(-p.x(),  p.z(),  p.y());
+    case 2:  return S2Point(-p.x(), -p.y(),  p.z());
+    case 3:  return S2Point(-p.z(), -p.y(), -p.x());
+    case 4:  return S2Point(-p.z(),  p.x(), -p.y());
+    default: return S2Point( p.y(),  p.x(), -p.z());
+  }
+}
+
+int XYZtoFaceSiTi(const S2Point& p, int* face, unsigned int* si,
+                  unsigned int* ti) {
+  double u, v;
+  *face = XYZtoFaceUV(p, &u, &v);
+  *si = STtoSiTi(UVtoST(u));
+  *ti = STtoSiTi(UVtoST(v));
+  // If the levels corresponding to si,ti are not equal, then p is not a cell
+  // center.  The si,ti values 0 and kMaxSiTi need to be handled specially
+  // because they do not correspond to cell centers at any valid level; they
+  // are mapped to level -1 by the code below.
+  int level = kMaxCellLevel - Bits::FindLSBSetNonZero(*si | kMaxSiTi);
+  if (level < 0 ||
+      level != kMaxCellLevel - Bits::FindLSBSetNonZero(*ti | kMaxSiTi)) {
+    return -1;
+  }
+  S2_DCHECK_LE(level, kMaxCellLevel);
+  // In infinite precision, this test could be changed to ST == SiTi. However,
+  // due to rounding errors, UVtoST(XYZtoFaceUV(FaceUVtoXYZ(STtoUV(...)))) is
+  // not idempotent. On the other hand, center_raw is computed exactly the same
+  // way p was originally computed (if it is indeed the center of an S2Cell):
+  // the comparison can be exact.
+  S2Point center = FaceSiTitoXYZ(*face, *si, *ti).Normalize();
+  return p == center ? level : -1;
+}
+
+S2Point FaceSiTitoXYZ(int face, unsigned int si, unsigned int ti) {
+  double u = STtoUV(SiTitoST(si));
+  double v = STtoUV(SiTitoST(ti));
+  return FaceUVtoXYZ(face, u, v);
+}
+
+}  // namespace S2
diff --git a/src/s2/s2coords.h b/src/s2/s2coords.h
new file mode 100644 (file)
index 0000000..d9b6f09
--- /dev/null
@@ -0,0 +1,459 @@
+// Copyright 2005 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// Author: ericv@google.com (Eric Veach)
+//
+// This file contains documentation of the various coordinate systems used
+// throughout the library.  Most importantly, S2 defines a framework for
+// decomposing the unit sphere into a hierarchy of "cells".  Each cell is a
+// quadrilateral bounded by four geodesics.  The top level of the hierarchy is
+// obtained by projecting the six faces of a cube onto the unit sphere, and
+// lower levels are obtained by subdividing each cell into four children
+// recursively.  Cells are numbered such that sequentially increasing cells
+// follow a continuous space-filling curve over the entire sphere.  The
+// transformation is designed to make the cells at each level fairly uniform
+// in size.
+//
+//
+////////////////////////// S2Cell Decomposition /////////////////////////
+//
+// The following methods define the cube-to-sphere projection used by
+// the S2Cell decomposition.
+//
+// In the process of converting a latitude-longitude pair to a 64-bit cell
+// id, the following coordinate systems are used:
+//
+//  (id)
+//    An S2CellId is a 64-bit encoding of a face and a Hilbert curve position
+//    on that face.  The Hilbert curve position implicitly encodes both the
+//    position of a cell and its subdivision level (see s2cell_id.h).
+//
+//  (face, i, j)
+//    Leaf-cell coordinates.  "i" and "j" are integers in the range
+//    [0,(2**30)-1] that identify a particular leaf cell on the given face.
+//    The (i, j) coordinate system is right-handed on each face, and the
+//    faces are oriented such that Hilbert curves connect continuously from
+//    one face to the next.
+//
+//  (face, s, t)
+//    Cell-space coordinates.  "s" and "t" are real numbers in the range
+//    [0,1] that identify a point on the given face.  For example, the point
+//    (s, t) = (0.5, 0.5) corresponds to the center of the top-level face
+//    cell.  This point is also a vertex of exactly four cells at each
+//    subdivision level greater than zero.
+//
+//  (face, si, ti)
+//    Discrete cell-space coordinates.  These are obtained by multiplying
+//    "s" and "t" by 2**31 and rounding to the nearest unsigned integer.
+//    Discrete coordinates lie in the range [0,2**31].  This coordinate
+//    system can represent the edge and center positions of all cells with
+//    no loss of precision (including non-leaf cells).  In binary, each
+//    coordinate of a level-k cell center ends with a 1 followed by
+//    (30 - k) 0s.  The coordinates of its edges end with (at least)
+//    (31 - k) 0s.
+//
+//  (face, u, v)
+//    Cube-space coordinates in the range [-1,1].  To make the cells at each
+//    level more uniform in size after they are projected onto the sphere,
+//    we apply a nonlinear transformation of the form u=f(s), v=f(t).
+//    The (u, v) coordinates after this transformation give the actual
+//    coordinates on the cube face (modulo some 90 degree rotations) before
+//    it is projected onto the unit sphere.
+//
+//  (face, u, v, w)
+//    Per-face coordinate frame.  This is an extension of the (face, u, v)
+//    cube-space coordinates that adds a third axis "w" in the direction of
+//    the face normal.  It is always a right-handed 3D coordinate system.
+//    Cube-space coordinates can be converted to this frame by setting w=1,
+//    while (u,v,w) coordinates can be projected onto the cube face by
+//    dividing by w, i.e. (face, u/w, v/w).
+//
+//  (x, y, z)
+//    Direction vector (S2Point).  Direction vectors are not necessarily unit
+//    length, and are often chosen to be points on the biunit cube
+//    [-1,+1]x[-1,+1]x[-1,+1].  They can be be normalized to obtain the
+//    corresponding point on the unit sphere.
+//
+//  (lat, lng)
+//    Latitude and longitude (S2LatLng).  Latitudes must be between -90 and
+//    90 degrees inclusive, and longitudes must be between -180 and 180
+//    degrees inclusive.
+//
+// Note that the (i, j), (s, t), (si, ti), and (u, v) coordinate systems are
+// right-handed on all six faces.
+
+#ifndef S2_S2COORDS_H_
+#define S2_S2COORDS_H_
+
+#include <algorithm>
+#include <cmath>
+
+#include "s2/base/integral_types.h"
+#include "s2/base/logging.h"
+#include "s2/r2.h"
+#include "s2/s2coords_internal.h"
+#include "s2/s2point.h"
+#include "s2/util/math/mathutil.h"
+
+// S2 is a namespace for constants and simple utility functions that are used
+// throughout the S2 library.  The name "S2" is derived from the mathematical
+// symbol for the two-dimensional unit sphere (note that the "2" refers to the
+// dimension of the surface, not the space it is embedded in).
+namespace S2 {
+
+// This is the number of levels needed to specify a leaf cell.  This
+// constant is defined here so that the S2::Metric class and the conversion
+// functions below can be implemented without including s2cell_id.h.  Please
+// see s2cell_id.h for other useful constants and conversion functions.
+const int kMaxCellLevel = 30;
+
+// The maximum index of a valid leaf cell plus one.  The range of valid leaf
+// cell indices is [0..kLimitIJ-1].
+const int kLimitIJ = 1 << kMaxCellLevel;  // == S2CellId::kMaxSize
+
+// The maximum value of an si- or ti-coordinate.  The range of valid (si,ti)
+// values is [0..kMaxSiTi].
+unsigned const int kMaxSiTi = 1U << (kMaxCellLevel + 1);
+
+// Convert an s- or t-value to the corresponding u- or v-value.  This is
+// a non-linear transformation from [-1,1] to [-1,1] that attempts to
+// make the cell sizes more uniform.
+double STtoUV(double s);
+
+// The inverse of the STtoUV transformation.  Note that it is not always
+// true that UVtoST(STtoUV(x)) == x due to numerical errors.
+double UVtoST(double u);
+
+// Convert the i- or j-index of a leaf cell to the minimum corresponding s-
+// or t-value contained by that cell.  The argument must be in the range
+// [0..2**30], i.e. up to one position beyond the normal range of valid leaf
+// cell indices.
+double IJtoSTMin(int i);
+
+// Return the i- or j-index of the leaf cell containing the given
+// s- or t-value.  If the argument is outside the range spanned by valid
+// leaf cell indices, return the index of the closest valid leaf cell (i.e.,
+// return values are clamped to the range of valid leaf cell indices).
+int STtoIJ(double s);
+
+// Convert an si- or ti-value to the corresponding s- or t-value.
+double SiTitoST(unsigned int si);
+
+// Return the si- or ti-coordinate that is nearest to the given s- or
+// t-value.  The result may be outside the range of valid (si,ti)-values.
+unsigned int STtoSiTi(double s);
+
+// Convert (face, u, v) coordinates to a direction vector (not
+// necessarily unit length).
+S2Point FaceUVtoXYZ(int face, double u, double v);
+S2Point FaceUVtoXYZ(int face, const R2Point& uv);
+
+// If the dot product of p with the given face normal is positive,
+// set the corresponding u and v values (which may lie outside the range
+// [-1,1]) and return true.  Otherwise return false.
+bool FaceXYZtoUV(int face, const S2Point& p,
+                        double* pu, double* pv);
+bool FaceXYZtoUV(int face, const S2Point& p, R2Point* puv);
+
+// Given a *valid* face for the given point p (meaning that dot product
+// of p with the face normal is positive), return the corresponding
+// u and v values (which may lie outside the range [-1,1]).
+void ValidFaceXYZtoUV(int face, const S2Point& p,
+                             double* pu, double* pv);
+void ValidFaceXYZtoUV(int face, const S2Point& p, R2Point* puv);
+
+// Transform the given point P to the (u,v,w) coordinate frame of the given
+// face (where the w-axis represents the face normal).
+S2Point FaceXYZtoUVW(int face, const S2Point& p);
+
+// Return the face containing the given direction vector.  (For points on
+// the boundary between faces, the result is arbitrary but repeatable.)
+int GetFace(const S2Point& p);
+
+// Convert a direction vector (not necessarily unit length) to
+// (face, u, v) coordinates.
+int XYZtoFaceUV(const S2Point& p, double* pu, double* pv);
+int XYZtoFaceUV(const S2Point& p, R2Point* puv);
+
+// Convert a direction vector (not necessarily unit length) to
+// (face, si, ti) coordinates and, if p is exactly equal to the center of a
+// cell, return the level of this cell (-1 otherwise).
+int XYZtoFaceSiTi(const S2Point& p, int* face,
+                  unsigned int* si, unsigned int* ti);
+
+// Convert (face, si, ti) coordinates to a direction vector (not necessarily
+// unit length).
+S2Point FaceSiTitoXYZ(int face, unsigned int si, unsigned int ti);
+
+// Return the right-handed normal (not necessarily unit length) for an
+// edge in the direction of the positive v-axis at the given u-value on
+// the given face.  (This vector is perpendicular to the plane through
+// the sphere origin that contains the given edge.)
+S2Point GetUNorm(int face, double u);
+
+// Return the right-handed normal (not necessarily unit length) for an
+// edge in the direction of the positive u-axis at the given v-value on
+// the given face.
+S2Point GetVNorm(int face, double v);
+
+// Return the unit-length normal, u-axis, or v-axis for the given face.
+S2Point GetNorm(int face);
+S2Point GetUAxis(int face);
+S2Point GetVAxis(int face);
+
+// Return the given axis of the given face (u=0, v=1, w=2).
+S2Point GetUVWAxis(int face, int axis);
+
+// With respect to the (u,v,w) coordinate system of a given face, return the
+// face that lies in the given direction (negative=0, positive=1) of the
+// given axis (u=0, v=1, w=2).  For example, GetUVWFace(4, 0, 1) returns the
+// face that is adjacent to face 4 in the positive u-axis direction.
+int GetUVWFace(int face, int axis, int direction);
+
+
+//////////////////   Implementation details follow   ////////////////////
+
+
+// We have implemented three different projections from cell-space (s,t) to
+// cube-space (u,v): linear, quadratic, and tangent.  They have the following
+// tradeoffs:
+//
+//   Linear - This is the fastest transformation, but also produces the least
+//   uniform cell sizes.  Cell areas vary by a factor of about 5.2, with the
+//   largest cells at the center of each face and the smallest cells in
+//   the corners.
+//
+//   Tangent - Transforming the coordinates via atan() makes the cell sizes
+//   more uniform.  The areas vary by a maximum ratio of 1.4 as opposed to a
+//   maximum ratio of 5.2.  However, each call to atan() is about as expensive
+//   as all of the other calculations combined when converting from points to
+//   cell ids, i.e. it reduces performance by a factor of 3.
+//
+//   Quadratic - This is an approximation of the tangent projection that
+//   is much faster and produces cells that are almost as uniform in size.
+//   It is about 3 times faster than the tangent projection for converting
+//   cell ids to points or vice versa.  Cell areas vary by a maximum ratio of
+//   about 2.1.
+//
+// Here is a table comparing the cell uniformity using each projection.  "Area
+// ratio" is the maximum ratio over all subdivision levels of the largest cell
+// area to the smallest cell area at that level, "edge ratio" is the maximum
+// ratio of the longest edge of any cell to the shortest edge of any cell at
+// the same level, and "diag ratio" is the ratio of the longest diagonal of
+// any cell to the shortest diagonal of any cell at the same level.  "ToPoint"
+// and "FromPoint" are the times in microseconds required to convert cell ids
+// to and from points (unit vectors) respectively.  "ToPointRaw" is the time
+// to convert to a non-unit-length vector, which is all that is needed for
+// some purposes.
+//
+//               Area    Edge    Diag   ToPointRaw  ToPoint  FromPoint
+//              Ratio   Ratio   Ratio             (microseconds)
+// -------------------------------------------------------------------
+// Linear:      5.200   2.117   2.959      0.020     0.087     0.085
+// Tangent:     1.414   1.414   1.704      0.237     0.299     0.258
+// Quadratic:   2.082   1.802   1.932      0.033     0.096     0.108
+//
+// The worst-case cell aspect ratios are about the same with all three
+// projections.  The maximum ratio of the longest edge to the shortest edge
+// within the same cell is about 1.4 and the maximum ratio of the diagonals
+// within the same cell is about 1.7.
+//
+// This data was produced using s2cell_test and s2cell_id_test.
+
+#define S2_LINEAR_PROJECTION    0
+#define S2_TAN_PROJECTION       1
+#define S2_QUADRATIC_PROJECTION 2
+
+#define S2_PROJECTION S2_QUADRATIC_PROJECTION
+
+#if S2_PROJECTION == S2_LINEAR_PROJECTION
+
+inline double STtoUV(double s) {
+  return 2 * s - 1;
+}
+
+inline double UVtoST(double u) {
+  return 0.5 * (u + 1);
+}
+
+#elif S2_PROJECTION == S2_TAN_PROJECTION
+
+inline double STtoUV(double s) {
+  // Unfortunately, tan(M_PI_4) is slightly less than 1.0.  This isn't due to
+  // a flaw in the implementation of tan(), it's because the derivative of
+  // tan(x) at x=pi/4 is 2, and it happens that the two adjacent floating
+  // point numbers on either side of the infinite-precision value of pi/4 have
+  // tangents that are slightly below and slightly above 1.0 when rounded to
+  // the nearest double-precision result.
+
+  s = std::tan(M_PI_2 * s - M_PI_4);
+  return s + (1.0 / (int64{1} << 53)) * s;
+}
+
+inline double UVtoST(double u) {
+  volatile double a = std::atan(u);
+  return (2 * M_1_PI) * (a + M_PI_4);
+}
+
+#elif S2_PROJECTION == S2_QUADRATIC_PROJECTION
+
+inline double STtoUV(double s) {
+  if (s >= 0.5) return (1/3.) * (4*s*s - 1);
+  else          return (1/3.) * (1 - 4*(1-s)*(1-s));
+}
+
+inline double UVtoST(double u) {
+  if (u >= 0) return 0.5 * std::sqrt(1 + 3*u);
+  else        return 1 - 0.5 * std::sqrt(1 - 3*u);
+}
+
+#else
+
+#error Unknown value for S2_PROJECTION
+
+#endif
+
+inline double IJtoSTMin(int i) {
+  S2_DCHECK(i >= 0 && i <= kLimitIJ);
+  return (1.0 / kLimitIJ) * i;
+}
+
+inline int STtoIJ(double s) {
+  return std::max(0, std::min(kLimitIJ - 1,
+                              MathUtil::FastIntRound(kLimitIJ * s - 0.5)));
+}
+
+inline double SiTitoST(unsigned int si) {
+  S2_DCHECK_LE(si, kMaxSiTi);
+  return (1.0 / kMaxSiTi) * si;
+}
+
+inline unsigned int STtoSiTi(double s) {
+  // kMaxSiTi == 2^31, so the result doesn't fit in an int32 when s == 1.
+  return static_cast<unsigned int>(MathUtil::FastInt64Round(s * kMaxSiTi));
+}
+
+inline S2Point FaceUVtoXYZ(int face, double u, double v) {
+  switch (face) {
+    case 0:  return S2Point( 1,  u,  v);
+    case 1:  return S2Point(-u,  1,  v);
+    case 2:  return S2Point(-u, -v,  1);
+    case 3:  return S2Point(-1, -v, -u);
+    case 4:  return S2Point( v, -1, -u);
+    default: return S2Point( v,  u, -1);
+  }
+}
+
+inline S2Point FaceUVtoXYZ(int face, const R2Point& uv) {
+  return FaceUVtoXYZ(face, uv[0], uv[1]);
+}
+
+inline void ValidFaceXYZtoUV(int face, const S2Point& p,
+                             double* pu, double* pv) {
+  S2_DCHECK_GT(p.DotProd(GetNorm(face)), 0);
+  switch (face) {
+    case 0:  *pu =  p[1] / p[0]; *pv =  p[2] / p[0]; break;
+    case 1:  *pu = -p[0] / p[1]; *pv =  p[2] / p[1]; break;
+    case 2:  *pu = -p[0] / p[2]; *pv = -p[1] / p[2]; break;
+    case 3:  *pu =  p[2] / p[0]; *pv =  p[1] / p[0]; break;
+    case 4:  *pu =  p[2] / p[1]; *pv = -p[0] / p[1]; break;
+    default: *pu = -p[1] / p[2]; *pv = -p[0] / p[2]; break;
+  }
+}
+
+inline void ValidFaceXYZtoUV(int face, const S2Point& p, R2Point* puv) {
+  ValidFaceXYZtoUV(face, p, &(*puv)[0], &(*puv)[1]);
+}
+
+inline int GetFace(const S2Point& p) {
+  int face = p.LargestAbsComponent();
+  if (p[face] < 0) face += 3;
+  return face;
+}
+
+inline int XYZtoFaceUV(const S2Point& p, double* pu, double* pv) {
+  int face = GetFace(p);
+  ValidFaceXYZtoUV(face, p, pu, pv);
+  return face;
+}
+
+inline int XYZtoFaceUV(const S2Point& p, R2Point* puv) {
+  return XYZtoFaceUV(p, &(*puv)[0], &(*puv)[1]);
+}
+
+inline bool FaceXYZtoUV(int face, const S2Point& p,
+                        double* pu, double* pv) {
+  if (face < 3) {
+    if (p[face] <= 0) return false;
+  } else {
+    if (p[face-3] >= 0) return false;
+  }
+  ValidFaceXYZtoUV(face, p, pu, pv);
+  return true;
+}
+
+inline bool FaceXYZtoUV(int face, const S2Point& p, R2Point* puv) {
+  return FaceXYZtoUV(face, p, &(*puv)[0], &(*puv)[1]);
+}
+
+inline S2Point GetUNorm(int face, double u) {
+  switch (face) {
+    case 0:  return S2Point( u, -1,  0);
+    case 1:  return S2Point( 1,  u,  0);
+    case 2:  return S2Point( 1,  0,  u);
+    case 3:  return S2Point(-u,  0,  1);
+    case 4:  return S2Point( 0, -u,  1);
+    default: return S2Point( 0, -1, -u);
+  }
+}
+
+inline S2Point GetVNorm(int face, double v) {
+  switch (face) {
+    case 0:  return S2Point(-v,  0,  1);
+    case 1:  return S2Point( 0, -v,  1);
+    case 2:  return S2Point( 0, -1, -v);
+    case 3:  return S2Point( v, -1,  0);
+    case 4:  return S2Point( 1,  v,  0);
+    default: return S2Point( 1,  0,  v);
+  }
+}
+
+inline S2Point GetNorm(int face) {
+  return GetUVWAxis(face, 2);
+}
+
+inline S2Point GetUAxis(int face) {
+  return GetUVWAxis(face, 0);
+}
+
+inline S2Point GetVAxis(int face) {
+  return GetUVWAxis(face, 1);
+}
+
+inline S2Point GetUVWAxis(int face, int axis) {
+  const double* p = internal::kFaceUVWAxes[face][axis];
+  return S2Point(p[0], p[1], p[2]);
+}
+
+inline int GetUVWFace(int face, int axis, int direction) {
+  S2_DCHECK(face >= 0 && face <= 5);
+  S2_DCHECK(axis >= 0 && axis <= 2);
+  S2_DCHECK(direction >= 0 && direction <= 1);
+  return internal::kFaceUVWFaces[face][axis][direction];
+}
+
+}  // namespace S2
+
+#endif  // S2_S2COORDS_H_
diff --git a/src/s2/s2coords_internal.h b/src/s2/s2coords_internal.h
new file mode 100644 (file)
index 0000000..13cf723
--- /dev/null
@@ -0,0 +1,71 @@
+// Copyright 2005 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#ifndef S2_S2COORDS_INTERNAL_H_
+#define S2_S2COORDS_INTERNAL_H_
+// Author: ericv@google.com (Eric Veach)
+
+namespace S2 {
+namespace internal {
+
+// The canonical Hilbert traversal order looks like an inverted 'U':
+// the subcells are visited in the order (0,0), (0,1), (1,1), (1,0).
+// The following tables encode the traversal order for various
+// orientations of the Hilbert curve (axes swapped and/or directions
+// of the axes reversed).
+
+// Together these flags define a cell orientation.  If 'kSwapMask'
+// is true, then canonical traversal order is flipped around the
+// diagonal (i.e. i and j are swapped with each other).  If
+// 'kInvertMask' is true, then the traversal order is rotated by 180
+// degrees (i.e. the bits of i and j are inverted, or equivalently,
+// the axis directions are reversed).
+int constexpr kSwapMask = 0x01;
+int constexpr kInvertMask = 0x02;
+
+// kIJtoPos[orientation][ij] -> pos
+//
+// Given a cell orientation and the (i,j)-index of a subcell (0=(0,0),
+// 1=(0,1), 2=(1,0), 3=(1,1)), return the order in which this subcell is
+// visited by the Hilbert curve (a position in the range [0..3]).
+extern const int kIJtoPos[4][4];
+
+// kPosToIJ[orientation][pos] -> ij
+//
+// Return the (i,j) index of the subcell at the given position 'pos' in the
+// Hilbert curve traversal order with the given orientation.  This is the
+// inverse of the previous table:
+//
+//   kPosToIJ[r][kIJtoPos[r][ij]] == ij
+extern const int kPosToIJ[4][4];
+
+// kPosToOrientation[pos] -> orientation_modifier
+//
+// Return a modifier indicating how the orientation of the child subcell
+// with the given traversal position [0..3] is related to the orientation
+// of the parent cell.  The modifier should be XOR-ed with the parent
+// orientation to obtain the curve orientation in the child.
+extern const int kPosToOrientation[4];
+
+// The U,V,W axes for each face.
+extern const double kFaceUVWAxes[6][3][3];
+
+// The precomputed neighbors of each face (see GetUVWFace).
+extern const int kFaceUVWFaces[6][3][2];
+
+}  // namespace internal
+}  // namespace S2
+
+#endif  // S2_S2COORDS_INTERNAL_H_
diff --git a/src/s2/s2crossing_edge_query.cc b/src/s2/s2crossing_edge_query.cc
new file mode 100644 (file)
index 0000000..dcaa88c
--- /dev/null
@@ -0,0 +1,380 @@
+// Copyright 2013 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// Author: ericv@google.com (Eric Veach)
+
+#include "s2/s2crossing_edge_query.h"
+
+#include <algorithm>
+#include <vector>
+
+#include "s2/base/logging.h"
+#include "s2/r1interval.h"
+#include "s2/s2cell_id.h"
+#include "s2/s2edge_clipping.h"
+#include "s2/s2edge_crosser.h"
+#include "s2/s2shapeutil_count_edges.h"
+
+using s2shapeutil::ShapeEdge;
+using s2shapeutil::ShapeEdgeId;
+using std::vector;
+
+// For small loops it is faster to use brute force.  The threshold below was
+// determined using the benchmarks in the unit test.
+static const int kMaxBruteForceEdges = 27;
+
+S2CrossingEdgeQuery::S2CrossingEdgeQuery() {
+}
+
+S2CrossingEdgeQuery::~S2CrossingEdgeQuery() {
+}
+
+void S2CrossingEdgeQuery::Init(const S2ShapeIndex* index) {
+  index_ = index;
+  iter_.Init(index);
+}
+
+vector<s2shapeutil::ShapeEdge> S2CrossingEdgeQuery::GetCrossingEdges(
+    const S2Point& a0, const S2Point& a1, CrossingType type) {
+  vector<s2shapeutil::ShapeEdge> edges;
+  GetCrossingEdges(a0, a1, type, &edges);
+  return edges;
+}
+
+vector<s2shapeutil::ShapeEdge> S2CrossingEdgeQuery::GetCrossingEdges(
+    const S2Point& a0, const S2Point& a1, const S2Shape& shape,
+    CrossingType type) {
+  vector<s2shapeutil::ShapeEdge> edges;
+  GetCrossingEdges(a0, a1, shape, type, &edges);
+  return edges;
+}
+
+void S2CrossingEdgeQuery::GetCrossingEdges(
+    const S2Point& a0, const S2Point& a1, CrossingType type,
+    vector<ShapeEdge>* edges) {
+  edges->clear();
+  GetCandidates(a0, a1, &tmp_candidates_);
+  int min_sign = (type == CrossingType::ALL) ? 0 : 1;
+  S2CopyingEdgeCrosser crosser(a0, a1);
+  int shape_id = -1;
+  const S2Shape* shape = nullptr;
+  for (ShapeEdgeId candidate : tmp_candidates_) {
+    if (candidate.shape_id != shape_id) {
+      shape_id = candidate.shape_id;
+      shape = index_->shape(shape_id);
+    }
+    int edge_id = candidate.edge_id;
+    S2Shape::Edge b = shape->edge(edge_id);
+    if (crosser.CrossingSign(b.v0, b.v1) >= min_sign) {
+      edges->push_back(ShapeEdge(shape_id, edge_id, b));
+    }
+  }
+}
+
+void S2CrossingEdgeQuery::GetCrossingEdges(
+    const S2Point& a0, const S2Point& a1, const S2Shape& shape,
+    CrossingType type, vector<ShapeEdge>* edges) {
+  edges->clear();
+  GetCandidates(a0, a1, shape, &tmp_candidates_);
+  int min_sign = (type == CrossingType::ALL) ? 0 : 1;
+  S2CopyingEdgeCrosser crosser(a0, a1);
+  for (ShapeEdgeId candidate : tmp_candidates_) {
+    int edge_id = candidate.edge_id;
+    S2Shape::Edge b = shape.edge(edge_id);
+    if (crosser.CrossingSign(b.v0, b.v1) >= min_sign) {
+      edges->push_back(ShapeEdge(shape.id(), edge_id, b));
+    }
+  }
+}
+
+vector<ShapeEdgeId> S2CrossingEdgeQuery::GetCandidates(
+    const S2Point& a0, const S2Point& a1) {
+  vector<ShapeEdgeId> edges;
+  GetCandidates(a0, a1, &edges);
+  return edges;
+}
+
+vector<ShapeEdgeId> S2CrossingEdgeQuery::GetCandidates(
+    const S2Point& a0, const S2Point& a1, const S2Shape& shape) {
+  vector<ShapeEdgeId> edges;
+  GetCandidates(a0, a1, shape, &edges);
+  return edges;
+}
+
+void S2CrossingEdgeQuery::GetCandidates(const S2Point& a0, const S2Point& a1,
+                                        vector<ShapeEdgeId>* edges) {
+  edges->clear();
+  int num_edges = s2shapeutil::CountEdgesUpTo(*index_, kMaxBruteForceEdges + 1);
+  if (num_edges <= kMaxBruteForceEdges) {
+    edges->reserve(num_edges);
+  }
+  VisitRawCandidates(a0, a1, [edges](ShapeEdgeId id) {
+      edges->push_back(id);
+      return true;
+    });
+  if (edges->size() > 1) {
+    std::sort(edges->begin(), edges->end());
+    edges->erase(std::unique(edges->begin(), edges->end()), edges->end());
+  }
+}
+
+void S2CrossingEdgeQuery::GetCandidates(const S2Point& a0, const S2Point& a1,
+                                        const S2Shape& shape,
+                                        vector<ShapeEdgeId>* edges) {
+  edges->clear();
+  int num_edges = shape.num_edges();
+  if (num_edges <= kMaxBruteForceEdges) {
+    edges->reserve(num_edges);
+  }
+  VisitRawCandidates(a0, a1, shape, [edges](ShapeEdgeId id) {
+      edges->push_back(id);
+      return true;
+    });
+  if (edges->size() > 1) {
+    std::sort(edges->begin(), edges->end());
+    edges->erase(std::unique(edges->begin(), edges->end()), edges->end());
+  }
+}
+
+bool S2CrossingEdgeQuery::VisitRawCandidates(
+    const S2Point& a0, const S2Point& a1, const ShapeEdgeIdVisitor& visitor) {
+  int num_edges = s2shapeutil::CountEdgesUpTo(*index_, kMaxBruteForceEdges + 1);
+  if (num_edges <= kMaxBruteForceEdges) {
+    int num_shape_ids = index_->num_shape_ids();
+    for (int s = 0; s < num_shape_ids; ++s) {
+      const S2Shape* shape = index_->shape(s);
+      if (shape == nullptr) continue;
+      int num_shape_edges = shape->num_edges();
+      for (int e = 0; e < num_shape_edges; ++e) {
+        if (!visitor(ShapeEdgeId(s, e))) return false;
+      }
+    }
+    return true;
+  }
+  return VisitCells(a0, a1, [&visitor](const S2ShapeIndexCell& cell) {
+      for (int s = 0; s < cell.num_clipped(); ++s) {
+        const S2ClippedShape& clipped = cell.clipped(s);
+        for (int j = 0; j < clipped.num_edges(); ++j) {
+          if (!visitor(ShapeEdgeId(clipped.shape_id(), clipped.edge(j)))) {
+            return false;
+          }
+        }
+      }
+      return true;
+    });
+}
+
+bool S2CrossingEdgeQuery::VisitRawCandidates(
+    const S2Point& a0, const S2Point& a1, const S2Shape& shape,
+    const ShapeEdgeIdVisitor& visitor) {
+  int num_edges = shape.num_edges();
+  if (num_edges <= kMaxBruteForceEdges) {
+    for (int e = 0; e < num_edges; ++e) {
+      if (!visitor(ShapeEdgeId(shape.id(), e))) return false;
+    }
+    return true;
+  }
+  return VisitCells(a0, a1, [&shape, &visitor](const S2ShapeIndexCell& cell) {
+      const S2ClippedShape* clipped = cell.find_clipped(shape.id());
+      if (clipped == nullptr) return true;
+      for (int j = 0; j < clipped->num_edges(); ++j) {
+        if (!visitor(ShapeEdgeId(shape.id(), clipped->edge(j)))) return false;
+      }
+      return true;
+    });
+}
+
+bool S2CrossingEdgeQuery::VisitCells(const S2Point& a0, const S2Point& a1,
+                                     const CellVisitor& visitor) {
+  visitor_ = &visitor;
+  S2::FaceSegmentVector segments;
+  S2::GetFaceSegments(a0, a1, &segments);
+  for (const auto& segment : segments) {
+    a0_ = segment.a;
+    a1_ = segment.b;
+
+    // Optimization: rather than always starting the recursive subdivision at
+    // the top level face cell, instead we start at the smallest S2CellId that
+    // contains the edge (the "edge root cell").  This typically lets us skip
+    // quite a few levels of recursion since most edges are short.
+    R2Rect edge_bound = R2Rect::FromPointPair(a0_, a1_);
+    S2PaddedCell pcell(S2CellId::FromFace(segment.face), 0);
+    S2CellId edge_root = pcell.ShrinkToFit(edge_bound);
+
+    // Now we need to determine how the edge root cell is related to the cells
+    // in the spatial index (cell_map_).  There are three cases:
+    //
+    //  1. edge_root is an index cell or is contained within an index cell.
+    //     In this case we only need to look at the contents of that cell.
+    //  2. edge_root is subdivided into one or more index cells.  In this case
+    //     we recursively subdivide to find the cells intersected by a0a1.
+    //  3. edge_root does not intersect any index cells.  In this case there
+    //     is nothing to do.
+    S2ShapeIndex::CellRelation relation = iter_.Locate(edge_root);
+    if (relation == S2ShapeIndex::INDEXED) {
+      // edge_root is an index cell or is contained by an index cell (case 1).
+      S2_DCHECK(iter_.id().contains(edge_root));
+      if (!visitor(iter_.cell())) return false;
+    } else if (relation == S2ShapeIndex::SUBDIVIDED) {
+      // edge_root is subdivided into one or more index cells (case 2).  We
+      // find the cells intersected by a0a1 using recursive subdivision.
+      if (!edge_root.is_face()) pcell = S2PaddedCell(edge_root, 0);
+      if (!VisitCells(pcell, edge_bound)) return false;
+    }
+  }
+  return true;
+}
+
+bool S2CrossingEdgeQuery::VisitCells(
+    const S2Point& a0, const S2Point& a1, const S2PaddedCell& root,
+    const CellVisitor& visitor) {
+  S2_DCHECK_EQ(root.padding(), 0);
+  visitor_ = &visitor;
+  // We use padding when clipping to ensure that the result is non-empty
+  // whenever the edge (a0, a1) intersects the given root cell.
+  if (S2::ClipToPaddedFace(a0, a1, root.id().face(),
+                           S2::kFaceClipErrorUVCoord, &a0_, &a1_)) {
+    R2Rect edge_bound = R2Rect::FromPointPair(a0_, a1_);
+    if (root.bound().Intersects(edge_bound)) {
+      return VisitCells(root, edge_bound);
+    }
+  }
+  return true;
+}
+
+// Computes the index cells intersected by the current edge that are
+// descendants of "pcell" and calls visitor_ for each one.
+//
+// WARNING: This function is recursive with a maximum depth of 30.  The frame
+// size is about 2K in versions of GCC prior to 4.7 due to poor overlapping
+// of storage for temporaries.  This is fixed in GCC 4.7, reducing the frame
+// size to about 350 bytes (i.e., worst-case total stack usage of about 10K).
+bool S2CrossingEdgeQuery::VisitCells(const S2PaddedCell& pcell,
+                                     const R2Rect& edge_bound) {
+  // This code uses S2PaddedCell because it has the methods we need for
+  // efficient splitting, however the actual padding is required to be zero.
+  S2_DCHECK_EQ(pcell.padding(), 0);
+
+  iter_.Seek(pcell.id().range_min());
+  if (iter_.done() || iter_.id() > pcell.id().range_max()) {
+    // The index does not contain "pcell" or any of its descendants.
+    return true;
+  }
+  if (iter_.id() == pcell.id()) {
+    return (*visitor_)(iter_.cell());
+  }
+
+  // Otherwise, split the edge among the four children of "pcell".
+  R2Point center = pcell.middle().lo();
+  if (edge_bound[0].hi() < center[0]) {
+    // Edge is entirely contained in the two left children.
+    return ClipVAxis(edge_bound, center[1], 0, pcell);
+  } else if (edge_bound[0].lo() >= center[0]) {
+    // Edge is entirely contained in the two right children.
+    return ClipVAxis(edge_bound, center[1], 1, pcell);
+  } else {
+    R2Rect child_bounds[2];
+    SplitUBound(edge_bound, center[0], child_bounds);
+    if (edge_bound[1].hi() < center[1]) {
+      // Edge is entirely contained in the two lower children.
+      return (VisitCells(S2PaddedCell(pcell, 0, 0), child_bounds[0]) &&
+              VisitCells(S2PaddedCell(pcell, 1, 0), child_bounds[1]));
+    } else if (edge_bound[1].lo() >= center[1]) {
+      // Edge is entirely contained in the two upper children.
+      return (VisitCells(S2PaddedCell(pcell, 0, 1), child_bounds[0]) &&
+              VisitCells(S2PaddedCell(pcell, 1, 1), child_bounds[1]));
+    } else {
+      // The edge bound spans all four children.  The edge itself intersects
+      // at most three children (since no padding is being used).
+      return (ClipVAxis(child_bounds[0], center[1], 0, pcell) &&
+              ClipVAxis(child_bounds[1], center[1], 1, pcell));
+    }
+  }
+}
+
+// Given either the left (i=0) or right (i=1) side of a padded cell "pcell",
+// determine whether the current edge intersects the lower child, upper child,
+// or both children, and call VisitCells() recursively on those children.
+// "center" is the v-coordinate at the center of "pcell".
+inline bool S2CrossingEdgeQuery::ClipVAxis(const R2Rect& edge_bound,
+                                           double center, int i,
+                                           const S2PaddedCell& pcell) {
+  if (edge_bound[1].hi() < center) {
+    // Edge is entirely contained in the lower child.
+    return VisitCells(S2PaddedCell(pcell, i, 0), edge_bound);
+  } else if (edge_bound[1].lo() >= center) {
+    // Edge is entirely contained in the upper child.
+    return VisitCells(S2PaddedCell(pcell, i, 1), edge_bound);
+  } else {
+    // The edge intersects both children.
+    R2Rect child_bounds[2];
+    SplitVBound(edge_bound, center, child_bounds);
+    return (VisitCells(S2PaddedCell(pcell, i, 0), child_bounds[0]) &&
+            VisitCells(S2PaddedCell(pcell, i, 1), child_bounds[1]));
+  }
+}
+
+// Split the current edge into two child edges at the given u-value "u" and
+// return the bound for each child.
+void S2CrossingEdgeQuery::SplitUBound(const R2Rect& edge_bound, double u,
+                                      R2Rect child_bounds[2]) const {
+  // See comments in MutableS2ShapeIndex::ClipUBound.
+  double v = edge_bound[1].Project(
+      S2::InterpolateDouble(u, a0_[0], a1_[0], a0_[1], a1_[1]));
+
+  // "diag_" indicates which diagonal of the bounding box is spanned by a0a1:
+  // it is 0 if a0a1 has positive slope, and 1 if a0a1 has negative slope.
+  int diag = (a0_[0] > a1_[0]) != (a0_[1] > a1_[1]);
+  SplitBound(edge_bound, 0, u, diag, v, child_bounds);
+}
+
+// Split the current edge into two child edges at the given v-value "v" and
+// return the bound for each child.
+void S2CrossingEdgeQuery::SplitVBound(const R2Rect& edge_bound, double v,
+                                      R2Rect child_bounds[2]) const {
+  double u = edge_bound[0].Project(
+      S2::InterpolateDouble(v, a0_[1], a1_[1], a0_[0], a1_[0]));
+  int diag = (a0_[0] > a1_[0]) != (a0_[1] > a1_[1]);
+  SplitBound(edge_bound, diag, u, 0, v, child_bounds);
+}
+
+// Split the current edge into two child edges at the given point (u,v) and
+// return the bound for each child.  "u_end" and "v_end" indicate which bound
+// endpoints of child 1 will be updated.
+inline void S2CrossingEdgeQuery::SplitBound(const R2Rect& edge_bound, int u_end,
+                                            double u, int v_end, double v,
+                                            R2Rect child_bounds[2]) {
+  child_bounds[0] = edge_bound;
+  child_bounds[0][0][1 - u_end] = u;
+  child_bounds[0][1][1 - v_end] = v;
+  S2_DCHECK(!child_bounds[0].is_empty());
+  S2_DCHECK(edge_bound.Contains(child_bounds[0]));
+
+  child_bounds[1] = edge_bound;
+  child_bounds[1][0][u_end] = u;
+  child_bounds[1][1][v_end] = v;
+  S2_DCHECK(!child_bounds[1].is_empty());
+  S2_DCHECK(edge_bound.Contains(child_bounds[1]));
+}
+
+void S2CrossingEdgeQuery::GetCells(const S2Point& a0, const S2Point& a1,
+                                   const S2PaddedCell& root,
+                                   vector<const S2ShapeIndexCell*>* cells) {
+  cells->clear();
+  VisitCells(a0, a1, root, [cells](const S2ShapeIndexCell& cell) {
+      cells->push_back(&cell);
+      return true;
+    });
+}
diff --git a/src/s2/s2crossing_edge_query.h b/src/s2/s2crossing_edge_query.h
new file mode 100644 (file)
index 0000000..1c34988
--- /dev/null
@@ -0,0 +1,220 @@
+// Copyright 2013 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// Author: ericv@google.com (Eric Veach)
+
+#ifndef S2_S2CROSSING_EDGE_QUERY_H_
+#define S2_S2CROSSING_EDGE_QUERY_H_
+
+#include <type_traits>
+#include <vector>
+
+#include "absl/base/macros.h"
+#include "absl/container/inlined_vector.h"
+#include "s2/_fp_contract_off.h"
+#include "s2/r2.h"
+#include "s2/r2rect.h"
+#include "s2/s2padded_cell.h"
+#include "s2/s2shape_index.h"
+#include "s2/s2shapeutil_shape_edge.h"
+#include "s2/s2shapeutil_shape_edge_id.h"
+
+// A parameter that controls the reporting of edge intersections.
+//
+//  - CrossingType::INTERIOR reports intersections that occur at a point
+//    interior to both edges (i.e., not at a vertex).
+//
+//  - CrossingType::ALL reports all intersections, even those where two edges
+//    intersect only because they share a common vertex.
+namespace s2shapeutil {
+enum class CrossingType { INTERIOR, ALL };
+}  // namespace s2shapeutil
+
+// S2CrossingEdgeQuery is used to find edges or shapes that are crossed by
+// an edge.  Here is an example showing how to index a set of polylines,
+// and then find the polylines that are crossed by a given edge AB:
+//
+// void Test(const vector<S2Polyline*>& polylines,`
+//           const S2Point& a0, const S2Point &a1) {
+//   MutableS2ShapeIndex index;
+//   for (S2Polyline* polyline : polylines) {
+//     index.Add(absl::make_unique<S2Polyline::Shape>(polyline));
+//   }
+//   S2CrossingEdgeQuery query(&index);
+//   for (const auto& edge : query.GetCrossingEdges(a, b, CrossingType::ALL)) {
+//     S2_CHECK_GE(S2::CrossingSign(a0, a1, edge.v0(), edge.v1()), 0);
+//   }
+// }
+//
+// Note that if you need to query many edges, it is more efficient to declare
+// a single S2CrossingEdgeQuery object and reuse it so that temporary storage
+// does not need to be reallocated each time.
+//
+// If you want to find *all* pairs of crossing edges, use
+// s2shapeutil::VisitCrossingEdgePairs() instead.
+class S2CrossingEdgeQuery {
+ public:
+  using CrossingType = s2shapeutil::CrossingType;  // Defined above.
+
+  // Convenience constructor that calls Init().
+  explicit S2CrossingEdgeQuery(const S2ShapeIndex* index);
+
+  // Default constructor; requires Init() to be called.
+  S2CrossingEdgeQuery();
+  ~S2CrossingEdgeQuery();
+
+  S2CrossingEdgeQuery(const S2CrossingEdgeQuery&) = delete;
+  void operator=(const S2CrossingEdgeQuery&) = delete;
+
+  const S2ShapeIndex& index() const { return *index_; }
+
+  // REQUIRES: "index" is not modified after this method is called.
+  void Init(const S2ShapeIndex* index);
+
+  // Returns all edges that intersect the given query edge (a0,a1) and that
+  // have the given CrossingType (ALL or INTERIOR).  Edges are sorted and
+  // unique.
+  std::vector<s2shapeutil::ShapeEdge> GetCrossingEdges(
+      const S2Point& a0, const S2Point& a1, CrossingType type);
+
+  // A specialized version of GetCrossingEdges() that only returns the edges
+  // that belong to a particular S2Shape.
+  std::vector<s2shapeutil::ShapeEdge> GetCrossingEdges(
+      const S2Point& a0, const S2Point& a1,
+      const S2Shape& shape, CrossingType type);
+
+  // These versions can be more efficient when they are called many times,
+  // since they do not require allocating a new vector on each call.
+  void GetCrossingEdges(const S2Point& a0, const S2Point& a1, CrossingType type,
+                        std::vector<s2shapeutil::ShapeEdge>* edges);
+
+  void GetCrossingEdges(const S2Point& a0, const S2Point& a1,
+                        const S2Shape& shape, CrossingType type,
+                        std::vector<s2shapeutil::ShapeEdge>* edges);
+
+
+  /////////////////////////// Low-Level Methods ////////////////////////////
+  //
+  // Most clients will not need the following methods.  They can be slightly
+  // more efficient but are harder to use, since they require the client to do
+  // all the actual crossing tests.
+
+  // Returns a superset of the edges that intersect a query edge (a0, a1).
+  // This method is useful for clients that want to test intersections in some
+  // other way, e.g. using S2::EdgeOrVertexCrossing().
+  std::vector<s2shapeutil::ShapeEdgeId> GetCandidates(const S2Point& a0,
+                                                      const S2Point& a1);
+
+  // A specialized version of GetCandidates() that only returns the edges that
+  // belong to a particular S2Shape.
+  std::vector<s2shapeutil::ShapeEdgeId> GetCandidates(const S2Point& a0,
+                                                      const S2Point& a1,
+                                                      const S2Shape& shape);
+
+  // These versions can be more efficient when they are called many times,
+  // since they do not require allocating a new vector on each call.
+  void GetCandidates(const S2Point& a0, const S2Point& a1,
+                     std::vector<s2shapeutil::ShapeEdgeId>* edges);
+
+  void GetCandidates(const S2Point& a0, const S2Point& a1, const S2Shape& shape,
+                     std::vector<s2shapeutil::ShapeEdgeId>* edges);
+
+  // A function that is called with each candidate intersecting edge.  The
+  // function may return false in order to request that the algorithm should
+  // be terminated, i.e. no further crossings are needed.
+  using ShapeEdgeIdVisitor =
+      std::function<bool (const s2shapeutil::ShapeEdgeId& id)>;
+
+  // Visits a superset of the edges that intersect the query edge (a0, a1),
+  // terminating early if the given ShapeEdgeIdVisitor returns false (in which
+  // case this function returns false as well).
+  //
+  // CAVEAT: Edges may be visited more than once.
+  bool VisitRawCandidates(const S2Point& a0, const S2Point& a1,
+                          const ShapeEdgeIdVisitor& visitor);
+
+  bool VisitRawCandidates(const S2Point& a0, const S2Point& a1,
+                          const S2Shape& shape,
+                          const ShapeEdgeIdVisitor& visitor);
+
+  // A function that is called with each S2ShapeIndexCell that might contain
+  // edges intersecting the given query edge.  The function may return false
+  // in order to request that the algorithm should be terminated, i.e. no
+  // further crossings are needed.
+  using CellVisitor = std::function<bool (const S2ShapeIndexCell& cell)>;
+
+  // Visits all S2ShapeIndexCells that might contain edges intersecting the
+  // given query edge (a0, a1), terminating early if the given CellVisitor
+  // returns false (in which case this function returns false as well).
+  //
+  // NOTE: Each candidate cell is visited exactly once.
+  bool VisitCells(const S2Point& a0, const S2Point& a1,
+                  const CellVisitor& visitor);
+
+  // Visits all S2ShapeIndexCells within "root" that might contain edges
+  // intersecting the given query edge (a0, a1), terminating early if the
+  // given CellVisitor returns false (in which case this function returns
+  // false as well).
+  //
+  // NOTE: Each candidate cell is visited exactly once.
+  //
+  // REQUIRES: root.padding() == 0
+  //   [This low-level method does not support padding; the argument is supplied
+  //    as an S2PaddedCell in order to avoid constructing it repeatedly when
+  //    this method is called using different query edges with the same root.]
+  bool VisitCells(const S2Point& a0, const S2Point& a1,
+                  const S2PaddedCell& root, const CellVisitor& visitor);
+
+
+  // Given a query edge AB and a cell "root", returns all S2ShapeIndex cells
+  // within "root" that might contain edges intersecting AB.
+  //
+  // REQUIRES: root.padding() == 0 (see above)
+  void GetCells(const S2Point& a0, const S2Point& a1, const S2PaddedCell& root,
+                std::vector<const S2ShapeIndexCell*>* cells);
+
+ private:
+  // Internal methods are documented with their definitions.
+  bool VisitCells(const S2PaddedCell& pcell, const R2Rect& edge_bound);
+  bool ClipVAxis(const R2Rect& edge_bound, double center, int i,
+                 const S2PaddedCell& pcell);
+  void SplitUBound(const R2Rect& edge_bound, double u,
+                   R2Rect child_bounds[2]) const;
+  void SplitVBound(const R2Rect& edge_bound, double v,
+                   R2Rect child_bounds[2]) const;
+  static void SplitBound(const R2Rect& edge_bound, int u_end, double u,
+                         int v_end, double v, R2Rect child_bounds[2]);
+
+  const S2ShapeIndex* index_ = nullptr;
+
+  //////////// Temporary storage used while processing a query ///////////
+
+  R2Point a0_, a1_;
+  S2ShapeIndex::Iterator iter_;
+  const CellVisitor* visitor_;
+
+  // Avoids repeated allocation when methods are called many times.
+  std::vector<s2shapeutil::ShapeEdgeId> tmp_candidates_;
+};
+
+
+//////////////////   Implementation details follow   ////////////////////
+
+
+inline S2CrossingEdgeQuery::S2CrossingEdgeQuery(const S2ShapeIndex* index) {
+  Init(index);
+}
+
+#endif  // S2_S2CROSSING_EDGE_QUERY_H_
diff --git a/src/s2/s2debug.cc b/src/s2/s2debug.cc
new file mode 100644 (file)
index 0000000..029a863
--- /dev/null
@@ -0,0 +1,23 @@
+// Copyright 2005 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// Author: ericv@google.com (Eric Veach)
+
+#include "s2/s2debug.h"
+
+#include "s2/base/logging.h"
+
+DEFINE_bool(s2debug, !!google::DEBUG_MODE,
+            "Enable automatic validity checking in S2 code");
diff --git a/src/s2/s2debug.h b/src/s2/s2debug.h
new file mode 100644 (file)
index 0000000..224ed97
--- /dev/null
@@ -0,0 +1,69 @@
+// Copyright 2005 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// Author: ericv@google.com (Eric Veach)
+//
+// The S2 library defines extra validity checks throughout the code that can
+// optionally be enabled or disabled.  By default, these validity checks are
+// enabled in debug-mode builds (including fastbuild) and disabled in
+// optimized builds.
+//
+// There are two ways to change the default behavior:
+//
+//  - The command line --s2debug flag, which changes the global default.
+//
+//  - The S2Debug enum, which allows validity checks to be enabled or disabled
+//    for specific objects (e.g., an S2Polygon).
+//
+// If you want to intentionally create invalid geometry (e.g., in a test), the
+// S2Debug enum is preferable.  For example, to create an invalid S2Polygon,
+// you can do this:
+//
+//   S2Polygon invalid;
+//   invalid.set_s2debug_override(S2Debug::DISABLE);
+//
+// There is also a convenience constructor:
+//
+//   vector<unique_ptr<S2Loop>> loops = ...;
+//   S2Polygon invalid(loops, S2Debug::DISABLE);
+//
+// There are a few checks that cannot be disabled this way (e.g., internal
+// functions that require S2Points to be unit length).  If you absolutely need
+// to disable these checks, you can set FLAGS_s2debug for the duration of a
+// specific test like this:
+//
+// TEST(MyClass, InvalidGeometry) {
+//   FLAGS_s2debug = false;  // Automatically restored between tests
+//   ...
+// }
+
+#ifndef S2_S2DEBUG_H_
+#define S2_S2DEBUG_H_
+
+#include "s2/base/commandlineflags.h"
+#include "s2/base/integral_types.h"
+
+// Command line flag that enables extra validity checking throughout the S2
+// code.  It is turned on by default in debug-mode builds.
+DECLARE_bool(s2debug);
+
+// Class that allows the --s2debug validity checks to be enabled or disabled
+// for specific objects (e.g., see S2Polygon).
+enum class S2Debug : uint8 {
+  ALLOW,    // Validity checks are controlled by --s2debug
+  DISABLE   // No validity checks even when --s2debug is true
+};
+
+#endif  // S2_S2DEBUG_H_
diff --git a/src/s2/s2distance_target.h b/src/s2/s2distance_target.h
new file mode 100644 (file)
index 0000000..b36e766
--- /dev/null
@@ -0,0 +1,165 @@
+// Copyright 2017 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// Author: ericv@google.com (Eric Veach)
+
+#ifndef S2_S2DISTANCE_TARGET_H_
+#define S2_S2DISTANCE_TARGET_H_
+
+#include "s2/s2cap.h"
+#include "s2/s2cell.h"
+#include "s2/s2shape_index.h"
+
+// S2DistanceTarget represents a geometric object to which distances are
+// measured.  For example, there are subtypes for measuring distances to a
+// point, an edge, or to an S2ShapeIndex (an arbitrary collection of
+// geometry).  S2DistanceTarget objects are provided for the benefit of
+// classes that measure distances and/or find nearby geometry, such as
+// S2ClosestEdgeQuery, S2ClosestPointQuery, and S2ClosestCellQuery.
+//
+// Implementations do *not* need to be thread-safe.  They may cache data or
+// allocate temporary data structures in order to improve performance.  For
+// this reason, S2DistanceTarget objects are typically passed as pointers
+// rather than as const references.
+//
+// The Distance template argument is used to represent distances.  Usually
+// this type is a thin wrapper around S1ChordAngle, but another distance type
+// may be substituted as long as it implements the API below.  This can be
+// used to change the comparison function (e.g., to find the furthest edges
+// from the target), to get more accuracy, or to measure non-spheroidal
+// distances (e.g., using the WGS84 ellipsoid).
+//
+// The Distance concept is as follows:
+//
+// class Distance {
+//  public:
+//   // Default and copy constructors, assignment operator:
+//   Distance();
+//   Distance(const Distance&);
+//   Distance& operator=(const Distance&);
+//
+//   // Factory methods:
+//   static Distance Zero();      // Returns a zero distance.
+//   static Distance Infinity();  // Larger than any valid distance.
+//   static Distance Negative();  // Smaller than any valid distance.
+//
+//   // Comparison operators:
+//   friend bool operator==(Distance x, Distance y);
+//   friend bool operator<(Distance x, Distance y);
+//
+//   // Delta represents the positive difference between two distances.
+//   // It is used together with operator-() to implement Options::max_error().
+//   // Typically Distance::Delta is simply S1ChordAngle.
+//   class Delta {
+//    public:
+//     Delta();
+//     Delta(const Delta&);
+//     Delta& operator=(const Delta&);
+//     friend bool operator==(Delta x, Delta y);
+//     static Delta Zero();
+//   };
+//
+//   // Subtraction operator.  Note that the second argument represents a
+//   // delta between two distances.  This distinction is important for
+//   // classes that compute maximum distances (e.g., S2FurthestEdgeQuery).
+//   friend Distance operator-(Distance x, Delta delta);
+//
+//   // Method that returns an upper bound on the S1ChordAngle corresponding
+//   // to this Distance (needed to implement Options::max_distance
+//   // efficiently).  For example, if Distance measures WGS84 ellipsoid
+//   // distance then the corresponding angle needs to be 0.56% larger.
+//   S1ChordAngle GetChordAngleBound() const;
+// };
+template <class Distance>
+class S2DistanceTarget {
+ public:
+  using Delta = typename Distance::Delta;
+
+  virtual ~S2DistanceTarget() {}
+
+  // Returns an S2Cap that bounds the set of points whose distance to the
+  // target is Distance::Zero().
+  virtual S2Cap GetCapBound() = 0;
+
+  // If the distance to the point "p" "min_dist", then updates "min_dist" and
+  // returns true.  Otherwise returns false.
+  virtual bool UpdateMinDistance(const S2Point& p, Distance* min_dist) = 0;
+
+  // If the distance to the edge (v0, v1) is less than "min_dist", then
+  // updates "min_dist" and returns true.  Otherwise returns false.
+  virtual bool UpdateMinDistance(const S2Point& v0, const S2Point& v1,
+                                 Distance* min_dist) = 0;
+
+  // If the distance to the given S2Cell (including its interior) is less
+  // than "min_dist", then updates "min_dist" and returns true.  Otherwise
+  // returns false.
+  virtual bool UpdateMinDistance(const S2Cell& cell, Distance* min_dist) = 0;
+
+  // Finds all polygons in the given "query_index" that completely contain a
+  // connected component of the target geometry.  (For example, if the
+  // target consists of 10 points, this method finds polygons that contain
+  // any of those 10 points.)  For each such polygon, "visitor" is called
+  // with the S2Shape of the polygon along with a point of the target
+  // geometry that is contained by that polygon.
+  //
+  // Optionally, any polygon that intersects the target geometry may also be
+  // returned.  In other words, this method returns all polygons that
+  // contain any connected component of the target, along with an arbitrary
+  // subset of the polygons that intersect the target.
+  //
+  // For example, suppose that "query_index" contains two abutting polygons
+  // A and B.  If the target consists of two points "a" contained by A and
+  // "b" contained by B, then both A and B are returned.  But if the target
+  // consists of the edge "ab", then any subset of {A, B} could be returned
+  // (because both polygons intersect the target but neither one contains
+  // the edge "ab").
+  //
+  // If "visitor" returns false, this method terminates early and returns
+  // false as well.  Otherwise returns true.
+  //
+  // NOTE(ericv): This method exists only for the purpose of implementing
+  // S2ClosestEdgeQuery::Options::include_interiors() efficiently.  Its API is
+  // unlikely to be useful for other purposes.
+  using ShapeVisitor = std::function<bool (S2Shape* containing_shape,
+                                           const S2Point& target_point)>;
+  virtual bool VisitContainingShapes(const S2ShapeIndex& query_index,
+                                     const ShapeVisitor& visitor) = 0;
+
+  // Specifies that whenever one of the UpdateMinDistance() methods above
+  // returns "true", the returned distance is allowed to be up to "max_error"
+  // larger than the true minimum distance.  In other words, it gives this
+  // target object permission to terminate its distance calculation as soon as
+  // it has determined that (1) the minimum distance is less than "min_dist"
+  // and (2) the best possible further improvement is less than "max_error".
+  //
+  // If the target takes advantage of "max_error" to optimize its distance
+  // calculation, this method must return "true".  (Most target types can use
+  // the default implementation which simply returns false.)
+  virtual bool set_max_error(const Delta& max_error) { return false; }
+
+  // The following method is provided as a convenience for classes that
+  // compute distances to a collection of indexed geometry, such as
+  // S2ClosestPointQuery, S2ClosestEdgeQuery, and S2ClosestCellQuery.  It
+  // returns the maximum number of indexed objects for which it is faster to
+  // compute the distance by brute force (e.g., by testing every edge) rather
+  // than by using an index.  (The appropriate value is different for each
+  // index type and can be estimated for a given (distance target, index type)
+  // pair by running benchmarks.)
+  //
+  // By default this method returns -1, indicating that it is not implemented.
+  virtual int max_brute_force_index_size() const { return -1; }
+};
+
+#endif  // S2_S2DISTANCE_TARGET_H_
diff --git a/src/s2/s2earth.cc b/src/s2/s2earth.cc
new file mode 100644 (file)
index 0000000..414c146
--- /dev/null
@@ -0,0 +1,52 @@
+// Copyright Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#include "s2/s2earth.h"
+
+#include <cmath>
+#include <algorithm>
+
+namespace {
+
+// http://en.wikipedia.org/wiki/Haversine_formula
+// Haversine(x) has very good numerical stability around zero.
+// Haversine(x) == (1-cos(x))/2 == sin(x/2)^2; must be implemented with the
+// second form to reap the numerical benefits.
+double Haversine(const double radians) {
+  const double sinHalf = sin(radians / 2);
+  return sinHalf * sinHalf;
+}
+
+}  // namespace
+
+double S2Earth::ToLongitudeRadians(const util::units::Meters& distance,
+                                   double latitude_radians) {
+  double scalar = cos(latitude_radians);
+  if (scalar == 0) return M_PI * 2;
+  return std::min(ToRadians(distance) / scalar, M_PI * 2);
+}
+
+// Sourced from http://www.movable-type.co.uk/scripts/latlong.html.
+S1Angle S2Earth::GetInitialBearing(const S2LatLng& a, const S2LatLng& b) {
+  const double lat1 = a.lat().radians();
+  const double cosLat2 = cos(b.lat().radians());
+  const double lat_diff = b.lat().radians() - a.lat().radians();
+  const double lng_diff = b.lng().radians() - a.lng().radians();
+
+  const double x =
+      sin(lat_diff) + sin(lat1) * cosLat2 * 2 * Haversine(lng_diff);
+  const double y = sin(lng_diff) * cosLat2;
+  return S1Angle::Radians(atan2(y, x));
+}
diff --git a/src/s2/s2earth.h b/src/s2/s2earth.h
new file mode 100644 (file)
index 0000000..82dab66
--- /dev/null
@@ -0,0 +1,268 @@
+// Copyright 2005 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// Author: ericv@google.com (Eric Veach)
+//
+// The earth modeled as a sphere.  There are lots of convenience
+// functions so that it doesn't take 2 lines of code just to do
+// a single conversion.
+
+#ifndef S2_S2EARTH_H_
+#define S2_S2EARTH_H_
+
+#include "s2/s1angle.h"
+#include "s2/s1chord_angle.h"
+#include "s2/s2latlng.h"
+#include "s2/s2point.h"
+#include "s2/util/units/length-units.h"
+
+class S2Earth {
+ public:
+  // These functions convert between distances on the unit sphere
+  // (expressed as angles subtended from the sphere's center) and
+  // distances on the Earth's surface.  This is possible only because
+  // the Earth is modeled as a sphere; otherwise a given angle would
+  // correspond to a range of distances depending on where the
+  // corresponding line segment was located.
+  //
+  // Note that you will lose precision if you use the ToDistance() method,
+  // since Meters is a single-precision type.  If you need more precision,
+  // use one of the direct conversion methods below.
+  inline static S1Angle ToAngle(const util::units::Meters& distance);
+  inline static S1ChordAngle ToChordAngle(const util::units::Meters& distance);
+  inline static util::units::Meters ToDistance(const S1Angle& angle);
+  inline static util::units::Meters ToDistance(const S1ChordAngle& cangle);
+
+  // Convenience functions.  These methods also return a double-precision
+  // result, unlike the generic ToDistance() method.
+  inline static double ToRadians(const util::units::Meters& distance);
+  inline static double ToMeters(const S1Angle& angle);
+  inline static double ToMeters(const S1ChordAngle& cangle);
+  inline static double ToKm(const S1Angle& angle);
+  inline static double ToKm(const S1ChordAngle& cangle);
+  inline static double KmToRadians(double km);
+  inline static double RadiansToKm(double radians);
+  inline static double MetersToRadians(double meters);
+  inline static double RadiansToMeters(double radians);
+
+  // These functions convert between areas on the unit sphere
+  // (as returned by the S2 library) and areas on the Earth's surface.
+  // Note that the area of a region on the unit sphere is equal to the
+  // solid angle it subtends from the sphere's center (measured in steradians).
+  inline static double SquareKmToSteradians(double km2);
+  inline static double SquareMetersToSteradians(double m2);
+  inline static double SteradiansToSquareKm(double steradians);
+  inline static double SteradiansToSquareMeters(double steradians);
+
+  // Convenience function for the frequent case where you need to call
+  // ToRadians in order to convert an east-west distance on the globe to
+  // radians. The output is a function of how close to the poles you are
+  // (i.e. at the bulge at the equator, one unit of longitude represents a
+  // much farther distance). The function will never return more than 2*PI
+  // radians, even if you're trying to go 100 million miles west at the north
+  // pole.
+  static double ToLongitudeRadians(const util::units::Meters& distance,
+                                   double latitude_radians);
+
+  // Computes the initial bearing from a to b. This is the bearing an observer
+  // at point a has when facing point b. A bearing of 0 degrees is north, and it
+  // increases clockwise (90 degrees is east, etc).
+  // If a == b, a == -b, or a is one of the Earths' poles, the return value is
+  // undefined.
+  static S1Angle GetInitialBearing(const S2LatLng& a, const S2LatLng& b);
+
+  // Returns the distance between two points.  Example:
+  // double miles = Miles(geostore::S2Earth::GetDistance(a, b)).value();
+  //
+  // Note that these methods only have single-precision accuracy, since
+  // Meters is a single-precision type.  If you ned more precision, use one
+  // of the methods below.
+  inline static util::units::Meters GetDistance(const S2Point& a,
+                                                const S2Point& b);
+  inline static util::units::Meters GetDistance(const S2LatLng& a,
+                                                const S2LatLng& b);
+
+  // Convenience functions.  These methods also return a double-precision
+  // result, unlike the generic GetDistance() method.
+  inline static double GetDistanceKm(const S2Point& a, const S2Point& b);
+  inline static double GetDistanceKm(const S2LatLng& a, const S2LatLng& b);
+  inline static double GetDistanceMeters(const S2Point& a, const S2Point& b);
+  inline static double GetDistanceMeters(const S2LatLng& a, const S2LatLng& b);
+
+  // Returns the Earth's mean radius, which is the radius of the equivalent
+  // sphere with the same surface area.  According to NASA, this value is
+  // 6371.01 +/- 0.02 km.  The equatorial radius is 6378.136 km, and the polar
+  // radius is 6356.752 km.  They differ by one part in 298.257.
+  //
+  // Reference: http://ssd.jpl.nasa.gov/phys_props_earth.html, which quotes
+  // Yoder, C.F. 1995. "Astrometric and Geodetic Properties of Earth and the
+  // Solar System" in Global Earth Physics, A Handbook of Physical Constants,
+  // AGU Reference Shelf 1, American Geophysical Union, Table 2.
+  inline static util::units::Meters Radius();
+
+  // Convenience functions.
+  inline static double RadiusKm();
+  inline static double RadiusMeters();
+
+  // Returns the altitude of the lowest known point on Earth. The lowest known
+  // point on Earth is the Challenger Deep with an altitude of -10898 meters
+  // above the surface of the spherical earth.
+  inline static util::units::Meters LowestAltitude();
+
+  // Convenience functions.
+  inline static double LowestAltitudeKm();
+  inline static double LowestAltitudeMeters();
+
+  // Returns the altitude of the highest known point on Earth. The highest
+  // known point on Earth is Mount Everest with an altitude of 8846 meters
+  // above the surface of the spherical earth.
+  inline static util::units::Meters HighestAltitude();
+
+  // Convenience functions.
+  inline static double HighestAltitudeKm();
+  inline static double HighestAltitudeMeters();
+};
+
+inline S1Angle S2Earth::ToAngle(const util::units::Meters& distance) {
+  return S1Angle::Radians(ToRadians(distance));
+}
+
+inline S1ChordAngle S2Earth::ToChordAngle(const util::units::Meters& distance) {
+  return S1ChordAngle(ToAngle(distance));
+}
+
+inline util::units::Meters S2Earth::ToDistance(const S1Angle& angle) {
+  return util::units::Meters(ToMeters(angle));
+}
+
+inline util::units::Meters S2Earth::ToDistance(const S1ChordAngle& cangle) {
+  return util::units::Meters(ToMeters(cangle));
+}
+
+inline double S2Earth::ToRadians(const util::units::Meters& distance) {
+  return distance.value() / RadiusMeters();
+}
+
+inline double S2Earth::ToMeters(const S1Angle& angle) {
+  return angle.radians() * RadiusMeters();
+}
+
+inline double S2Earth::ToKm(const S1Angle& angle) {
+  return angle.radians() * RadiusKm();
+}
+
+inline double S2Earth::ToMeters(const S1ChordAngle& cangle) {
+  return ToMeters(cangle.ToAngle());
+}
+
+inline double S2Earth::ToKm(const S1ChordAngle& cangle) {
+  return ToKm(cangle.ToAngle());
+}
+
+inline double S2Earth::KmToRadians(double km) {
+  return km / RadiusKm();
+}
+
+inline double S2Earth::RadiansToKm(double radians) {
+  return radians * RadiusKm();
+}
+
+inline double S2Earth::MetersToRadians(double meters) {
+  return meters / RadiusMeters();
+}
+
+inline double S2Earth::RadiansToMeters(double radians) {
+  return radians * RadiusMeters();
+}
+
+inline double S2Earth::SquareKmToSteradians(double km2) {
+  return km2 / (RadiusKm() * RadiusKm());
+}
+
+inline double S2Earth::SquareMetersToSteradians(double m2) {
+  return m2 / (RadiusMeters() * RadiusMeters());
+}
+
+inline double S2Earth::SteradiansToSquareKm(double steradians) {
+  return steradians * RadiusKm() * RadiusKm();
+}
+
+inline double S2Earth::SteradiansToSquareMeters(double steradians) {
+  return steradians * RadiusMeters() * RadiusMeters();
+}
+
+inline util::units::Meters S2Earth::GetDistance(const S2Point& a,
+                                                const S2Point& b) {
+  return ToDistance(S1Angle(a, b));
+}
+
+inline util::units::Meters S2Earth::GetDistance(const S2LatLng& a,
+                                                const S2LatLng& b) {
+  return ToDistance(a.GetDistance(b));
+}
+
+inline double S2Earth::GetDistanceKm(const S2Point& a, const S2Point& b) {
+  return RadiansToKm(a.Angle(b));
+}
+
+inline double S2Earth::GetDistanceKm(const S2LatLng& a, const S2LatLng& b) {
+  return ToKm(a.GetDistance(b));
+}
+
+inline double S2Earth::GetDistanceMeters(const S2Point& a, const S2Point& b) {
+  return RadiansToMeters(a.Angle(b));
+}
+
+inline double S2Earth::GetDistanceMeters(const S2LatLng& a, const S2LatLng& b) {
+  return ToMeters(a.GetDistance(b));
+}
+
+inline util::units::Meters S2Earth::Radius() {
+  return util::units::Meters(RadiusMeters());
+}
+
+inline double S2Earth::RadiusKm() {
+  return 0.001 * RadiusMeters();
+}
+
+inline double S2Earth::RadiusMeters() {
+  return 6371010.0;
+}
+
+inline util::units::Meters S2Earth::LowestAltitude() {
+  return util::units::Meters(LowestAltitudeMeters());
+}
+
+inline double S2Earth::LowestAltitudeKm() {
+  return 0.001 * LowestAltitudeMeters();
+}
+
+inline double S2Earth::LowestAltitudeMeters() {
+  return -10898;
+}
+
+inline util::units::Meters S2Earth::HighestAltitude() {
+  return util::units::Meters(HighestAltitudeMeters());
+}
+
+inline double S2Earth::HighestAltitudeKm() {
+  return 0.001 * HighestAltitudeMeters();
+}
+
+inline double S2Earth::HighestAltitudeMeters() {
+  return 8846;
+}
+
+#endif  // S2_S2EARTH_H_
diff --git a/src/s2/s2edge_clipping.cc b/src/s2/s2edge_clipping.cc
new file mode 100644 (file)
index 0000000..69380ec
--- /dev/null
@@ -0,0 +1,462 @@
+// Copyright 2005 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// Author: ericv@google.com (Eric Veach)
+
+#include "s2/s2edge_clipping.h"
+
+#include <cfloat>
+#include <cmath>
+
+#include "s2/base/logging.h"
+#include "s2/r1interval.h"
+#include "s2/s2coords.h"
+#include "s2/s2pointutil.h"
+#include "s2/util/math/vector.h"
+
+namespace S2 {
+
+using std::fabs;
+using std::max;
+using std::min;
+
+// Error constant definitions.  See the header file for details.
+const double kFaceClipErrorRadians = 3 * DBL_EPSILON;
+const double kFaceClipErrorUVDist = 9 * DBL_EPSILON;
+const double kFaceClipErrorUVCoord = 9 * M_SQRT1_2 * DBL_EPSILON;
+const double kIntersectsRectErrorUVDist = 3 * M_SQRT2 * DBL_EPSILON;
+const double kEdgeClipErrorUVCoord = 2.25 * DBL_EPSILON;
+const double kEdgeClipErrorUVDist = 2.25 * DBL_EPSILON;
+
+// S2PointUVW is used to document that a given S2Point is expressed in the
+// (u,v,w) coordinates of some cube face.
+using S2PointUVW = S2Point;
+
+// The three functions below all compare a sum (u + v) to a third value w.
+// They are implemented in such a way that they produce an exact result even
+// though all calculations are done with ordinary floating-point operations.
+// Here are the principles on which these functions are based:
+//
+// A. If u + v < w in floating-point, then u + v < w in exact arithmetic.
+//
+// B. If u + v < w in exact arithmetic, then at least one of the following
+//    expressions is true in floating-point:
+//       u + v < w
+//       u < w - v
+//       v < w - u
+//
+//    Proof: By rearranging terms and substituting ">" for "<", we can assume
+//    that all values are non-negative.  Now clearly "w" is not the smallest
+//    value, so assume WLOG that "u" is the smallest.  We want to show that
+//    u < w - v in floating-point.  If v >= w/2, the calculation of w - v is
+//    exact since the result is smaller in magnitude than either input value,
+//    so the result holds.  Otherwise we have u <= v < w/2 and w - v >= w/2
+//    (even in floating point), so the result also holds.
+
+// Return true if u + v == w exactly.
+inline static bool SumEquals(double u, double v, double w) {
+  return (u + v == w) && (u == w - v) && (v == w - u);
+}
+
+// Return true if a given directed line L intersects the cube face F.  The
+// line L is defined by its normal N in the (u,v,w) coordinates of F.
+inline static bool IntersectsFace(const S2PointUVW& n) {
+  // L intersects the [-1,1]x[-1,1] square in (u,v) if and only if the dot
+  // products of N with the four corner vertices (-1,-1,1), (1,-1,1), (1,1,1),
+  // and (-1,1,1) do not all have the same sign.  This is true exactly when
+  // |Nu| + |Nv| >= |Nw|.  The code below evaluates this expression exactly
+  // (see comments above).
+  double u = fabs(n[0]), v = fabs(n[1]), w = fabs(n[2]);
+  // We only need to consider the cases where u or v is the smallest value,
+  // since if w is the smallest then both expressions below will have a
+  // positive LHS and a negative RHS.
+  return (v >= w - u) && (u >= w - v);
+}
+
+// Given a directed line L intersecting a cube face F, return true if L
+// intersects two opposite edges of F (including the case where L passes
+// exactly through a corner vertex of F).  The line L is defined by its
+// normal N in the (u,v,w) coordinates of F.
+inline static bool IntersectsOppositeEdges(const S2PointUVW& n) {
+  // The line L intersects opposite edges of the [-1,1]x[-1,1] (u,v) square if
+  // and only exactly two of the corner vertices lie on each side of L.  This
+  // is true exactly when ||Nu| - |Nv|| >= |Nw|.  The code below evaluates this
+  // expression exactly (see comments above).
+  double u = fabs(n[0]), v = fabs(n[1]), w = fabs(n[2]);
+  // If w is the smallest, the following line returns an exact result.
+  if (fabs(u - v) != w) return fabs(u - v) >= w;
+  // Otherwise u - v = w exactly, or w is not the smallest value.  In either
+  // case the following line returns the correct result.
+  return (u >= v) ? (u - w >= v) : (v - w >= u);
+}
+
+// Given cube face F and a directed line L (represented by its CCW normal N in
+// the (u,v,w) coordinates of F), compute the axis of the cube face edge where
+// L exits the face: return 0 if L exits through the u=-1 or u=+1 edge, and 1
+// if L exits through the v=-1 or v=+1 edge.  Either result is acceptable if L
+// exits exactly through a corner vertex of the cube face.
+static int GetExitAxis(const S2PointUVW& n) {
+  S2_DCHECK(IntersectsFace(n));
+  if (IntersectsOppositeEdges(n)) {
+    // The line passes through through opposite edges of the face.
+    // It exits through the v=+1 or v=-1 edge if the u-component of N has a
+    // larger absolute magnitude than the v-component.
+    return (fabs(n[0]) >= fabs(n[1])) ? 1 : 0;
+  } else {
+    // The line passes through through two adjacent edges of the face.
+    // It exits the v=+1 or v=-1 edge if an even number of the components of N
+    // are negative.  We test this using signbit() rather than multiplication
+    // to avoid the possibility of underflow.
+    S2_DCHECK(n[0] != 0 && n[1] != 0  && n[2] != 0);
+    using std::signbit;
+    return ((signbit(n[0]) ^ signbit(n[1]) ^ signbit(n[2])) == 0) ? 1 : 0;
+  }
+}
+
+// Given a cube face F, a directed line L (represented by its CCW normal N in
+// the (u,v,w) coordinates of F), and result of GetExitAxis(N), return the
+// (u,v) coordinates of the point where L exits the cube face.
+static R2Point GetExitPoint(const S2PointUVW& n, int axis) {
+  if (axis == 0) {
+    double u = (n[1] > 0) ? 1.0 : -1.0;
+    return R2Point(u, (-u * n[0] - n[2]) / n[1]);
+  } else {
+    double v = (n[0] < 0) ? 1.0 : -1.0;
+    return R2Point((-v * n[1] - n[2]) / n[0], v);
+  }
+}
+
+// Given a line segment AB whose origin A has been projected onto a given cube
+// face, determine whether it is necessary to project A onto a different face
+// instead.  This can happen because the normal of the line AB is not computed
+// exactly, so that the line AB (defined as the set of points perpendicular to
+// the normal) may not intersect the cube face containing A.  Even if it does
+// intersect the face, the "exit point" of the line from that face may be on
+// the wrong side of A (i.e., in the direction away from B).  If this happens,
+// we reproject A onto the adjacent face where the line AB approaches A most
+// closely.  This moves the origin by a small amount, but never more than the
+// error tolerances documented in the header file.
+static int MoveOriginToValidFace(int face, const S2Point& a,
+                                 const S2Point& ab, R2Point* a_uv) {
+  // Fast path: if the origin is sufficiently far inside the face, it is
+  // always safe to use it.
+  const double kMaxSafeUVCoord = 1 - kFaceClipErrorUVCoord;
+  if (max(fabs((*a_uv)[0]), fabs((*a_uv)[1])) <= kMaxSafeUVCoord) {
+    return face;
+  }
+  // Otherwise check whether the normal AB even intersects this face.
+  S2PointUVW n = S2::FaceXYZtoUVW(face, ab);
+  if (IntersectsFace(n)) {
+    // Check whether the point where the line AB exits this face is on the
+    // wrong side of A (by more than the acceptable error tolerance).
+    S2Point exit = S2::FaceUVtoXYZ(face, GetExitPoint(n, GetExitAxis(n)));
+    S2Point a_tangent = ab.Normalize().CrossProd(a);
+    if ((exit - a).DotProd(a_tangent) >= -kFaceClipErrorRadians) {
+      return face;  // We can use the given face.
+    }
+  }
+  // Otherwise we reproject A to the nearest adjacent face.  (If line AB does
+  // not pass through a given face, it must pass through all adjacent faces.)
+  if (fabs((*a_uv)[0]) >= fabs((*a_uv)[1])) {
+    face = S2::GetUVWFace(face, 0 /*U axis*/, (*a_uv)[0] > 0);
+  } else {
+    face = S2::GetUVWFace(face, 1 /*V axis*/, (*a_uv)[1] > 0);
+  }
+  S2_DCHECK(IntersectsFace(S2::FaceXYZtoUVW(face, ab)));
+  S2::ValidFaceXYZtoUV(face, a, a_uv);
+  (*a_uv)[0] = max(-1.0, min(1.0, (*a_uv)[0]));
+  (*a_uv)[1] = max(-1.0, min(1.0, (*a_uv)[1]));
+  return face;
+}
+
+// Return the next face that should be visited by GetFaceSegments, given that
+// we have just visited "face" and we are following the line AB (represented
+// by its normal N in the (u,v,w) coordinates of that face).  The other
+// arguments include the point where AB exits "face", the corresponding
+// exit axis, and the "target face" containing the destination point B.
+static int GetNextFace(int face, const R2Point& exit, int axis,
+                       const S2PointUVW& n, int target_face) {
+  // We return the face that is adjacent to the exit point along the given
+  // axis.  If line AB exits *exactly* through a corner of the face, there are
+  // two possible next faces.  If one is the "target face" containing B, then
+  // we guarantee that we advance to that face directly.
+  //
+  // The three conditions below check that (1) AB exits approximately through
+  // a corner, (2) the adjacent face along the non-exit axis is the target
+  // face, and (3) AB exits *exactly* through the corner.  (The SumEquals()
+  // code checks whether the dot product of (u,v,1) and "n" is exactly zero.)
+  if (fabs(exit[1 - axis]) == 1 &&
+      S2::GetUVWFace(face, 1 - axis, exit[1 - axis] > 0) == target_face &&
+      SumEquals(exit[0] * n[0], exit[1] * n[1], -n[2])) {
+    return target_face;
+  }
+  // Otherwise return the face that is adjacent to the exit point in the
+  // direction of the exit axis.
+  return S2::GetUVWFace(face, axis, exit[axis] > 0);
+}
+
+void GetFaceSegments(const S2Point& a, const S2Point& b,
+                     FaceSegmentVector* segments) {
+  S2_DCHECK(S2::IsUnitLength(a));
+  S2_DCHECK(S2::IsUnitLength(b));
+  segments->clear();
+
+  // Fast path: both endpoints are on the same face.
+  FaceSegment segment;
+  int a_face = S2::XYZtoFaceUV(a, &segment.a);
+  int b_face = S2::XYZtoFaceUV(b, &segment.b);
+  if (a_face == b_face) {
+    segment.face = a_face;
+    segments->push_back(segment);
+    return;
+  }
+  // Starting at A, we follow AB from face to face until we reach the face
+  // containing B.  The following code is designed to ensure that we always
+  // reach B, even in the presence of numerical errors.
+  //
+  // First we compute the normal to the plane containing A and B.  This normal
+  // becomes the ultimate definition of the line AB; it is used to resolve all
+  // questions regarding where exactly the line goes.  Unfortunately due to
+  // numerical errors, the line may not quite intersect the faces containing
+  // the original endpoints.  We handle this by moving A and/or B slightly if
+  // necessary so that they are on faces intersected by the line AB.
+  S2Point ab = S2::RobustCrossProd(a, b);
+  a_face = MoveOriginToValidFace(a_face, a, ab, &segment.a);
+  b_face = MoveOriginToValidFace(b_face, b, -ab, &segment.b);
+
+  // Now we simply follow AB from face to face until we reach B.
+  segment.face = a_face;
+  R2Point b_saved = segment.b;
+  for (int face = a_face; face != b_face; ) {
+    // Complete the current segment by finding the point where AB exits the
+    // current face.
+    S2PointUVW n = S2::FaceXYZtoUVW(face, ab);
+    int exit_axis = GetExitAxis(n);
+    segment.b = GetExitPoint(n, exit_axis);
+    segments->push_back(segment);
+
+    // Compute the next face intersected by AB, and translate the exit point
+    // of the current segment into the (u,v) coordinates of the next face.
+    // This becomes the first point of the next segment.
+    S2Point exit_xyz = S2::FaceUVtoXYZ(face, segment.b);
+    face = GetNextFace(face, segment.b, exit_axis, n, b_face);
+    S2PointUVW exit_uvw = S2::FaceXYZtoUVW(face, exit_xyz);
+    segment.face = face;
+    segment.a = R2Point(exit_uvw[0], exit_uvw[1]);
+  }
+  // Finish the last segment.
+  segment.b = b_saved;
+  segments->push_back(segment);
+}
+
+// This helper function does two things.  First, it clips the line segment AB
+// to find the clipped destination B' on a given face.  (The face is specified
+// implicitly by expressing *all arguments* in the (u,v,w) coordinates of that
+// face.)  Second, it partially computes whether the segment AB intersects
+// this face at all.  The actual condition is fairly complicated, but it turns
+// out that it can be expressed as a "score" that can be computed
+// independently when clipping the two endpoints A and B.  This function
+// returns the score for the given endpoint, which is an integer ranging from
+// 0 to 3.  If the sum of the two scores is 3 or more, then AB does not
+// intersect this face.  See the calling function for the meaning of the
+// various parameters.
+static int ClipDestination(
+    const S2PointUVW& a, const S2PointUVW& b, const S2PointUVW& scaled_n,
+    const S2PointUVW& a_tangent, const S2PointUVW& b_tangent, double scale_uv,
+    R2Point* uv) {
+  S2_DCHECK(IntersectsFace(scaled_n));
+
+  // Optimization: if B is within the safe region of the face, use it.
+  const double kMaxSafeUVCoord = 1 - kFaceClipErrorUVCoord;
+  if (b[2] > 0) {
+    *uv = R2Point(b[0] / b[2], b[1] / b[2]);
+    if (max(fabs((*uv)[0]), fabs((*uv)[1])) <= kMaxSafeUVCoord)
+      return 0;
+  }
+  // Otherwise find the point B' where the line AB exits the face.
+  *uv = scale_uv * GetExitPoint(scaled_n, GetExitAxis(scaled_n));
+  S2PointUVW p((*uv)[0], (*uv)[1], 1.0);
+
+  // Determine if the exit point B' is contained within the segment.  We do this
+  // by computing the dot products with two inward-facing tangent vectors at A
+  // and B.  If either dot product is negative, we say that B' is on the "wrong
+  // side" of that point.  As the point B' moves around the great circle AB past
+  // the segment endpoint B, it is initially on the wrong side of B only; as it
+  // moves further it is on the wrong side of both endpoints; and then it is on
+  // the wrong side of A only.  If the exit point B' is on the wrong side of
+  // either endpoint, we can't use it; instead the segment is clipped at the
+  // original endpoint B.
+  //
+  // We reject the segment if the sum of the scores of the two endpoints is 3
+  // or more.  Here is what that rule encodes:
+  //  - If B' is on the wrong side of A, then the other clipped endpoint A'
+  //    must be in the interior of AB (otherwise AB' would go the wrong way
+  //    around the circle).  There is a similar rule for A'.
+  //  - If B' is on the wrong side of either endpoint (and therefore we must
+  //    use the original endpoint B instead), then it must be possible to
+  //    project B onto this face (i.e., its w-coordinate must be positive).
+  //    This rule is only necessary to handle certain zero-length edges (A=B).
+  int score = 0;
+  if ((p - a).DotProd(a_tangent) < 0) {
+    score = 2;  // B' is on wrong side of A.
+  } else if ((p - b).DotProd(b_tangent) < 0) {
+    score = 1;  // B' is on wrong side of B.
+  }
+  if (score > 0) {  // B' is not in the interior of AB.
+    if (b[2] <= 0) {
+      score = 3;    // B cannot be projected onto this face.
+    } else {
+      *uv = R2Point(b[0] / b[2], b[1] / b[2]);
+    }
+  }
+  return score;
+}
+
+bool ClipToPaddedFace(const S2Point& a_xyz, const S2Point& b_xyz, int face,
+                      double padding, R2Point* a_uv, R2Point* b_uv) {
+  S2_DCHECK_GE(padding, 0);
+  // Fast path: both endpoints are on the given face.
+  if (S2::GetFace(a_xyz) == face && S2::GetFace(b_xyz) == face) {
+    S2::ValidFaceXYZtoUV(face, a_xyz, a_uv);
+    S2::ValidFaceXYZtoUV(face, b_xyz, b_uv);
+    return true;
+  }
+  // Convert everything into the (u,v,w) coordinates of the given face.  Note
+  // that the cross product *must* be computed in the original (x,y,z)
+  // coordinate system because RobustCrossProd (unlike the mathematical cross
+  // product) can produce different results in different coordinate systems
+  // when one argument is a linear multiple of the other, due to the use of
+  // symbolic perturbations.
+  S2PointUVW n = S2::FaceXYZtoUVW(face, S2::RobustCrossProd(a_xyz, b_xyz));
+  S2PointUVW a = S2::FaceXYZtoUVW(face, a_xyz);
+  S2PointUVW b = S2::FaceXYZtoUVW(face, b_xyz);
+
+  // Padding is handled by scaling the u- and v-components of the normal.
+  // Letting R=1+padding, this means that when we compute the dot product of
+  // the normal with a cube face vertex (such as (-1,-1,1)), we will actually
+  // compute the dot product with the scaled vertex (-R,-R,1).  This allows
+  // methods such as IntersectsFace(), GetExitAxis(), etc, to handle padding
+  // with no further modifications.
+  const double scale_uv = 1 + padding;
+  S2PointUVW scaled_n(scale_uv * n[0], scale_uv * n[1], n[2]);
+  if (!IntersectsFace(scaled_n)) return false;
+
+  // TODO(ericv): This is a temporary hack until I rewrite S2::RobustCrossProd;
+  // it avoids loss of precision in Normalize() when the vector is so small
+  // that it underflows.
+  if (max(fabs(n[0]), max(fabs(n[1]), fabs(n[2]))) < ldexp(1.0, -511)) {
+    n *= ldexp(1.0, 563);
+  }  // END OF HACK
+  n = n.Normalize();
+  S2PointUVW a_tangent = n.CrossProd(a);
+  S2PointUVW b_tangent = b.CrossProd(n);
+  // As described above, if the sum of the scores from clipping the two
+  // endpoints is 3 or more, then the segment does not intersect this face.
+  int a_score = ClipDestination(b, a, -scaled_n, b_tangent, a_tangent,
+                                scale_uv, a_uv);
+  int b_score = ClipDestination(a, b, scaled_n, a_tangent, b_tangent,
+                                scale_uv, b_uv);
+  return a_score + b_score < 3;
+}
+
+bool IntersectsRect(const R2Point& a, const R2Point& b, const R2Rect& rect) {
+  // First check whether the bound of AB intersects "rect".
+  R2Rect bound = R2Rect::FromPointPair(a, b);
+  if (!rect.Intersects(bound)) return false;
+
+  // Otherwise AB intersects "rect" if and only if all four vertices of "rect"
+  // do not lie on the same side of the extended line AB.  We test this by
+  // finding the two vertices of "rect" with minimum and maximum projections
+  // onto the normal of AB, and computing their dot products with the edge
+  // normal.
+  R2Point n = (b - a).Ortho();
+  int i = (n[0] >= 0) ? 1 : 0;
+  int j = (n[1] >= 0) ? 1 : 0;
+  double max = n.DotProd(rect.GetVertex(i, j) - a);
+  double min = n.DotProd(rect.GetVertex(1-i, 1-j) - a);
+  return (max >= 0) && (min <= 0);
+}
+
+inline static bool UpdateEndpoint(R1Interval* bound, int end, double value) {
+  if (end == 0) {
+    if (bound->hi() < value) return false;
+    if (bound->lo() < value) bound->set_lo(value);
+  } else {
+    if (bound->lo() > value) return false;
+    if (bound->hi() > value) bound->set_hi(value);
+  }
+  return true;
+}
+
+// Given a line segment from (a0,a1) to (b0,b1) and a bounding interval for
+// each axis, clip the segment further if necessary so that "bound0" does not
+// extend outside the given interval "clip".  "diag" is a a precomputed helper
+// variable that indicates which diagonal of the bounding box is spanned by AB:
+// it is 0 if AB has positive slope, and 1 if AB has negative slope.
+inline static bool ClipBoundAxis(double a0, double b0, R1Interval* bound0,
+                                 double a1, double b1, R1Interval* bound1,
+                                 int diag, const R1Interval& clip0) {
+  if (bound0->lo() < clip0.lo()) {
+    if (bound0->hi() < clip0.lo()) return false;
+    (*bound0)[0] = clip0.lo();
+    if (!UpdateEndpoint(bound1, diag,
+                        InterpolateDouble(clip0.lo(), a0, b0, a1, b1)))
+      return false;
+  }
+  if (bound0->hi() > clip0.hi()) {
+    if (bound0->lo() > clip0.hi()) return false;
+    (*bound0)[1] = clip0.hi();
+    if (!UpdateEndpoint(bound1, 1-diag,
+                        InterpolateDouble(clip0.hi(), a0, b0, a1, b1)))
+      return false;
+  }
+  return true;
+}
+
+R2Rect GetClippedEdgeBound(const R2Point& a, const R2Point& b,
+                           const R2Rect& clip) {
+  R2Rect bound = R2Rect::FromPointPair(a, b);
+  if (ClipEdgeBound(a, b, clip, &bound)) return bound;
+  return R2Rect::Empty();
+}
+
+bool ClipEdgeBound(const R2Point& a, const R2Point& b, const R2Rect& clip,
+                   R2Rect* bound) {
+  // "diag" indicates which diagonal of the bounding box is spanned by AB: it
+  // is 0 if AB has positive slope, and 1 if AB has negative slope.  This is
+  // used to determine which interval endpoints need to be updated each time
+  // the edge is clipped.
+  int diag = (a[0] > b[0]) != (a[1] > b[1]);
+  return (ClipBoundAxis(a[0], b[0], &(*bound)[0], a[1], b[1], &(*bound)[1],
+                        diag, clip[0]) &&
+          ClipBoundAxis(a[1], b[1], &(*bound)[1], a[0], b[0], &(*bound)[0],
+                        diag, clip[1]));
+}
+
+bool ClipEdge(const R2Point& a, const R2Point& b, const R2Rect& clip,
+              R2Point* a_clipped, R2Point* b_clipped) {
+  // Compute the bounding rectangle of AB, clip it, and then extract the new
+  // endpoints from the clipped bound.
+  R2Rect bound = R2Rect::FromPointPair(a, b);
+  if (ClipEdgeBound(a, b, clip, &bound)) {
+    int ai = (a[0] > b[0]), aj = (a[1] > b[1]);
+    *a_clipped = bound.GetVertex(ai, aj);
+    *b_clipped = bound.GetVertex(1-ai, 1-aj);
+    return true;
+  }
+  return false;
+}
+
+}  // namespace S2
diff --git a/src/s2/s2edge_clipping.h b/src/s2/s2edge_clipping.h
new file mode 100644 (file)
index 0000000..4ce308b
--- /dev/null
@@ -0,0 +1,183 @@
+// Copyright 2005 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// Author: ericv@google.com (Eric Veach)
+//
+// Defines a collection of functions for:
+//
+//   (1) Robustly clipping geodesic edges to the faces of the S2 biunit cube
+//       (see s2coords.h), and
+//
+//   (2) Robustly clipping 2D edges against 2D rectangles.
+//
+// These functions can be used to efficiently find the set of S2CellIds that
+// are intersected by a geodesic edge (e.g., see S2CrossingEdgeQuery).
+
+#ifndef S2_S2EDGE_CLIPPING_H_
+#define S2_S2EDGE_CLIPPING_H_
+
+#include <cmath>
+
+#include "s2/base/logging.h"
+#include "absl/container/inlined_vector.h"
+#include "s2/_fp_contract_off.h"
+#include "s2/r2.h"
+#include "s2/r2rect.h"
+#include "s2/s2point.h"
+
+namespace S2 {
+
+// FaceSegment represents an edge AB clipped to an S2 cube face.  It is
+// represented by a face index and a pair of (u,v) coordinates.
+struct FaceSegment {
+  int face;
+  R2Point a, b;
+};
+using FaceSegmentVector = absl::InlinedVector<FaceSegment, 6>;
+
+// Subdivides the given edge AB at every point where it crosses the boundary
+// between two S2 cube faces and returns the corresponding FaceSegments.  The
+// segments are returned in order from A toward B.  The input points must be
+// unit length.
+//
+// This method guarantees that the returned segments form a continuous path
+// from A to B, and that all vertices are within kFaceClipErrorUVDist of the
+// line AB.  All vertices lie within the [-1,1]x[-1,1] cube face rectangles.
+// The results are consistent with s2pred::Sign(), i.e. the edge is
+// well-defined even its endpoints are antipodal.  [TODO(ericv): Extend the
+// implementation of S2::RobustCrossProd so that this statement is true.]
+void GetFaceSegments(const S2Point& a, const S2Point& b,
+                     FaceSegmentVector* segments);
+
+// Given an edge AB and a face, returns the (u,v) coordinates for the portion
+// of AB that intersects that face.  This method guarantees that the clipped
+// vertices lie within the [-1,1]x[-1,1] cube face rectangle and are within
+// kFaceClipErrorUVDist of the line AB, but the results may differ from
+// those produced by GetFaceSegments.  Returns false if AB does not
+// intersect the given face.
+bool ClipToFace(const S2Point& a, const S2Point& b, int face,
+                R2Point* a_uv, R2Point* b_uv);
+
+// Like ClipToFace, but rather than clipping to the square [-1,1]x[-1,1]
+// in (u,v) space, this method clips to [-R,R]x[-R,R] where R=(1+padding).
+bool ClipToPaddedFace(const S2Point& a, const S2Point& b, int face,
+                      double padding, R2Point* a_uv, R2Point* b_uv);
+
+// The maximum error in the vertices returned by GetFaceSegments and
+// ClipToFace (compared to an exact calculation):
+//
+//  - kFaceClipErrorRadians is the maximum angle between a returned vertex
+//    and the nearest point on the exact edge AB.  It is equal to the
+//    maximum directional error in S2::RobustCrossProd, plus the error when
+//    projecting points onto a cube face.
+//
+//  - kFaceClipErrorDist is the same angle expressed as a maximum distance
+//    in (u,v)-space.  In other words, a returned vertex is at most this far
+//    from the exact edge AB projected into (u,v)-space.
+
+//  - kFaceClipErrorUVCoord is the same angle expressed as the maximum error
+//    in an individual u- or v-coordinate.  In other words, for each
+//    returned vertex there is a point on the exact edge AB whose u- and
+//    v-coordinates differ from the vertex by at most this amount.
+
+extern const double kFaceClipErrorRadians;
+extern const double kFaceClipErrorUVDist;
+extern const double kFaceClipErrorUVCoord;
+
+// Returns true if the edge AB intersects the given (closed) rectangle to
+// within the error bound below.
+bool IntersectsRect(const R2Point& a, const R2Point& b, const R2Rect& rect);
+
+// The maximum error in IntersectRect.  If some point of AB is inside the
+// rectangle by at least this distance, the result is guaranteed to be true;
+// if all points of AB are outside the rectangle by at least this distance,
+// the result is guaranteed to be false.  This bound assumes that "rect" is
+// a subset of the rectangle [-1,1]x[-1,1] or extends slightly outside it
+// (e.g., by 1e-10 or less).
+extern const double kIntersectsRectErrorUVDist;
+
+// Given an edge AB, returns the portion of AB that is contained by the given
+// rectangle "clip".  Returns false if there is no intersection.
+bool ClipEdge(const R2Point& a, const R2Point& b, const R2Rect& clip,
+              R2Point* a_clipped, R2Point* b_clipped);
+
+// Given an edge AB and a rectangle "clip", returns the bounding rectangle of
+// the portion of AB intersected by "clip".  The resulting bound may be
+// empty.  This is a convenience function built on top of ClipEdgeBound.
+R2Rect GetClippedEdgeBound(const R2Point& a, const R2Point& b,
+                           const R2Rect& clip);
+
+// This function can be used to clip an edge AB to sequence of rectangles
+// efficiently.  It represents the clipped edges by their bounding boxes
+// rather than as a pair of endpoints.  Specifically, let A'B' be some
+// portion of an edge AB, and let "bound" be a tight bound of A'B'.  This
+// function updates "bound" (in place) to be a tight bound of A'B'
+// intersected with a given rectangle "clip".  If A'B' does not intersect
+// "clip", returns false and does not necessarily update "bound".
+//
+// REQUIRES: "bound" is a tight bounding rectangle for some portion of AB.
+// (This condition is automatically satisfied if you start with the bounding
+// box of AB and clip to a sequence of rectangles, stopping when the method
+// returns false.)
+bool ClipEdgeBound(const R2Point& a, const R2Point& b,
+                   const R2Rect& clip, R2Rect* bound);
+
+// The maximum error in the vertices generated by ClipEdge and the bounds
+// generated by ClipEdgeBound (compared to an exact calculation):
+//
+//  - kEdgeClipErrorUVCoord is the maximum error in a u- or v-coordinate
+//    compared to the exact result, assuming that the points A and B are in
+//    the rectangle [-1,1]x[1,1] or slightly outside it (by 1e-10 or less).
+//
+//  - kEdgeClipErrorUVDist is the maximum distance from a clipped point to
+//    the corresponding exact result.  It is equal to the error in a single
+//    coordinate because at most one coordinate is subject to error.
+
+extern const double kEdgeClipErrorUVCoord;
+extern const double kEdgeClipErrorUVDist;
+
+// Given a value x that is some linear combination of a and b, returns the
+// value x1 that is the same linear combination of a1 and b1.  This function
+// makes the following guarantees:
+//  - If x == a, then x1 = a1 (exactly).
+//  - If x == b, then x1 = b1 (exactly).
+//  - If a <= x <= b, then a1 <= x1 <= b1 (even if a1 == b1).
+// REQUIRES: a != b
+double InterpolateDouble(double x, double a, double b, double a1, double b1);
+
+
+//////////////////   Implementation details follow   ////////////////////
+
+
+inline bool ClipToFace(const S2Point& a, const S2Point& b, int face,
+                       R2Point* a_uv, R2Point* b_uv) {
+  return ClipToPaddedFace(a, b, face, 0.0, a_uv, b_uv);
+}
+
+inline double InterpolateDouble(double x, double a, double b,
+                                double a1, double b1) {
+  S2_DCHECK_NE(a, b);
+  // To get results that are accurate near both A and B, we interpolate
+  // starting from the closer of the two points.
+  if (std::fabs(a - x) <= std::fabs(b - x)) {
+    return a1 + (b1 - a1) * (x - a) / (b - a);
+  } else {
+    return b1 + (a1 - b1) * (x - b) / (a - b);
+  }
+}
+
+}  // namespace S2
+
+#endif  // S2_S2EDGE_CLIPPING_H_
diff --git a/src/s2/s2edge_crosser.cc b/src/s2/s2edge_crosser.cc
new file mode 100644 (file)
index 0000000..53fe48c
--- /dev/null
@@ -0,0 +1,85 @@
+// Copyright 2005 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// Author: ericv@google.com (Eric Veach)
+
+#include "s2/s2edge_crosser.h"
+
+#include "s2/base/logging.h"
+#include "s2/s2pointutil.h"
+#include "s2/s2predicates.h"
+
+int S2EdgeCrosser::CrossingSignInternal(const S2Point* d) {
+  // Compute the actual result, and then save the current vertex D as the next
+  // vertex C, and save the orientation of the next triangle ACB (which is
+  // opposite to the current triangle BDA).
+  int result = CrossingSignInternal2(*d);
+  c_ = d;
+  acb_ = -bda_;
+  return result;
+}
+
+inline int S2EdgeCrosser::CrossingSignInternal2(const S2Point& d) {
+  // At this point, a very common situation is that A,B,C,D are four points on
+  // a line such that AB does not overlap CD.  (For example, this happens when
+  // a line or curve is sampled finely, or when geometry is constructed by
+  // computing the union of S2CellIds.)  Most of the time, we can determine
+  // that AB and CD do not intersect by computing the two outward-facing
+  // tangents at A and B (parallel to AB) and testing whether AB and CD are on
+  // opposite sides of the plane perpendicular to one of these tangents.  This
+  // is moderately expensive but still much cheaper than s2pred::ExpensiveSign.
+  if (!have_tangents_) {
+    S2Point norm = S2::RobustCrossProd(*a_, *b_).Normalize();
+    a_tangent_ = a_->CrossProd(norm);
+    b_tangent_ = norm.CrossProd(*b_);
+    have_tangents_ = true;
+  }
+  // The error in RobustCrossProd() is insignificant.  The maximum error in
+  // the call to CrossProd() (i.e., the maximum norm of the error vector) is
+  // (0.5 + 1/sqrt(3)) * DBL_EPSILON.  The maximum error in each call to
+  // DotProd() below is DBL_EPSILON.  (There is also a small relative error
+  // term that is insignificant because we are comparing the result against a
+  // constant that is very close to zero.)
+  static const double kError = (1.5 + 1/sqrt(3.0)) * DBL_EPSILON;
+  if ((c_->DotProd(a_tangent_) > kError && d.DotProd(a_tangent_) > kError) ||
+      (c_->DotProd(b_tangent_) > kError && d.DotProd(b_tangent_) > kError)) {
+    return -1;
+  }
+
+  // Otherwise, eliminate the cases where two vertices from different edges
+  // are equal.  (These cases could be handled in the code below, but we would
+  // rather avoid calling ExpensiveSign whenever possible.)
+  if (*a_ == *c_ || *a_ == d || *b_ == *c_ || *b_ == d) return 0;
+
+  // Eliminate cases where an input edge is degenerate.  (Note that in most
+  // cases, if CD is degenerate then this method is not even called because
+  // acb_ and bda have different signs.)
+  if (*a_ == *b_ || *c_ == d) return -1;
+
+  // Otherwise it's time to break out the big guns.
+  if (acb_ == 0) acb_ = -s2pred::ExpensiveSign(*a_, *b_, *c_);
+  S2_DCHECK_NE(acb_, 0);
+  if (bda_ == 0) bda_ = s2pred::ExpensiveSign(*a_, *b_, d);
+  S2_DCHECK_NE(bda_, 0);
+  if (bda_ != acb_) return -1;
+
+  Vector3_d c_cross_d = c_->CrossProd(d);
+  int cbd = -s2pred::Sign(*c_, d, *b_, c_cross_d);
+  S2_DCHECK_NE(cbd, 0);
+  if (cbd != acb_) return -1;
+  int dac = s2pred::Sign(*c_, d, *a_, c_cross_d);
+  S2_DCHECK_NE(dac, 0);
+  return (dac != acb_) ? -1 : 1;
+}
diff --git a/src/s2/s2edge_crosser.h b/src/s2/s2edge_crosser.h
new file mode 100644 (file)
index 0000000..c2005e6
--- /dev/null
@@ -0,0 +1,343 @@
+// Copyright 2005 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// Author: ericv@google.com (Eric Veach)
+
+#ifndef S2_S2EDGE_CROSSER_H_
+#define S2_S2EDGE_CROSSER_H_
+
+#include "s2/base/logging.h"
+#include "s2/_fp_contract_off.h"
+#include "s2/s2edge_crossings.h"
+#include "s2/s2pointutil.h"
+#include "s2/s2predicates.h"
+
+class S2CopyingEdgeCrosser;  // Forward declaration
+
+// This class allows edges to be efficiently tested for intersection with a
+// given fixed edge AB.  It is especially efficient when testing for
+// intersection with an edge chain connecting vertices v0, v1, v2, ...
+//
+// Example usage:
+//
+//   void CountIntersections(const S2Point& a, const S2Point& b,
+//                           const vector<pair<S2Point, S2Point>>& edges) {
+//     int count = 0;
+//     S2EdgeCrosser crosser(&a, &b);
+//     for (const auto& edge : edges) {
+//       if (crosser.CrossingSign(&edge.first, &edge.second) >= 0) {
+//         ++count;
+//       }
+//     }
+//     return count;
+//   }
+//
+// This class expects that the client already has all the necessary vertices
+// stored in memory, so that this class can refer to them with pointers and
+// does not need to make its own copies.  If this is not the case (e.g., you
+// want to pass temporary objects as vertices), see S2CopyingEdgeCrosser.
+class S2EdgeCrosser {
+ public:
+  // Default constructor; must be followed by a call to Init().
+  S2EdgeCrosser() {}
+
+  // Convenience constructor that calls Init() with the given fixed edge AB.
+  // The arguments "a" and "b" must point to values that persist for the
+  // lifetime of the S2EdgeCrosser object (or until the next Init() call).
+  S2EdgeCrosser(const S2Point* a, const S2Point* b);
+
+  // Accessors for the constructor arguments.
+  const S2Point* a() { return a_; }
+  const S2Point* b() { return b_; }
+
+  // Initialize the S2EdgeCrosser with the given fixed edge AB.  The arguments
+  // "a" and "b" must point to values that persist for the lifetime of the
+  // S2EdgeCrosser object (or until the next Init() call).
+  void Init(const S2Point* a, const S2Point* b);
+
+  // This function determines whether the edge AB intersects the edge CD.
+  // Returns +1 if AB crosses CD at a point that is interior to both edges.
+  // Returns  0 if any two vertices from different edges are the same.
+  // Returns -1 otherwise.
+  //
+  // Note that if an edge is degenerate (A == B or C == D), the return value
+  // is 0 if two vertices from different edges are the same and -1 otherwise.
+  //
+  // Properties of CrossingSign:
+  //
+  //  (1) CrossingSign(b,a,c,d) == CrossingSign(a,b,c,d)
+  //  (2) CrossingSign(c,d,a,b) == CrossingSign(a,b,c,d)
+  //  (3) CrossingSign(a,b,c,d) == 0 if a==c, a==d, b==c, b==d
+  //  (3) CrossingSign(a,b,c,d) <= 0 if a==b or c==d (see above)
+  //
+  // This function implements an exact, consistent perturbation model such
+  // that no three points are ever considered to be collinear.  This means
+  // that even if you have 4 points A, B, C, D that lie exactly in a line
+  // (say, around the equator), C and D will be treated as being slightly to
+  // one side or the other of AB.  This is done in a way such that the
+  // results are always consistent (see s2pred::Sign).
+  //
+  // Note that if you want to check an edge against a chain of other edges,
+  // it is slightly more efficient to use the single-argument version of
+  // CrossingSign below.
+  //
+  // The arguments must point to values that persist until the next call.
+  int CrossingSign(const S2Point* c, const S2Point* d);
+
+  // This method extends the concept of a "crossing" to the case where AB
+  // and CD have a vertex in common.  The two edges may or may not cross,
+  // according to the rules defined in VertexCrossing() below.  The rules
+  // are designed so that point containment tests can be implemented simply
+  // by counting edge crossings.  Similarly, determining whether one edge
+  // chain crosses another edge chain can be implemented by counting.
+  //
+  // Returns true if CrossingSign(c, d) > 0, or AB and CD share a vertex
+  // and VertexCrossing(a, b, c, d) returns true.
+  //
+  // The arguments must point to values that persist until the next call.
+  bool EdgeOrVertexCrossing(const S2Point* c, const S2Point* d);
+
+  ///////////////////////// Edge Chain Methods ///////////////////////////
+  //
+  // You don't need to use these unless you're trying to squeeze out every
+  // last drop of performance.  Essentially all you are saving is a test
+  // whether the first vertex of the current edge is the same as the second
+  // vertex of the previous edge.  Example usage:
+  //
+  //   vector<S2Point> chain;
+  //   crosser.RestartAt(&chain[0]);
+  //   for (int i = 1; i < chain.size(); ++i) {
+  //     if (crosser.EdgeOrVertexCrossing(&chain[i])) { ++count; }
+  //   }
+
+  // Convenience constructor that uses AB as the fixed edge, and C as the
+  // first vertex of the vertex chain (equivalent to calling RestartAt(c)).
+  //
+  // The arguments must point to values that persist until the next call.
+  S2EdgeCrosser(const S2Point* a, const S2Point* b, const S2Point* c);
+
+  // Call this method when your chain 'jumps' to a new place.
+  // The argument must point to a value that persists until the next call.
+  void RestartAt(const S2Point* c);
+
+  // Like CrossingSign above, but uses the last vertex passed to one of
+  // the crossing methods (or RestartAt) as the first vertex of the current
+  // edge.
+  //
+  // The argument must point to a value that persists until the next call.
+  int CrossingSign(const S2Point* d);
+
+  // Like EdgeOrVertexCrossing above, but uses the last vertex passed to one
+  // of the crossing methods (or RestartAt) as the first vertex of the
+  // current edge.
+  //
+  // The argument must point to a value that persists until the next call.
+  bool EdgeOrVertexCrossing(const S2Point* d);
+
+  // Returns the last vertex of the current edge chain being tested, i.e. the
+  // C vertex that will be used to construct the edge CD when one of the
+  // methods above is called.
+  const S2Point* c() { return c_; }
+
+ private:
+  friend class S2CopyingEdgeCrosser;
+
+  // These functions handle the "slow path" of CrossingSign().
+  int CrossingSignInternal(const S2Point* d);
+  int CrossingSignInternal2(const S2Point& d);
+
+  // Used internally by S2CopyingEdgeCrosser.  Updates "c_" only.
+  void set_c(const S2Point* c) { c_ = c; }
+
+  // The fields below are constant after the call to Init().
+  const S2Point* a_;
+  const S2Point* b_;
+  Vector3_d a_cross_b_;
+
+  // To reduce the number of calls to s2pred::ExpensiveSign(), we compute an
+  // outward-facing tangent at A and B if necessary.  If the plane
+  // perpendicular to one of these tangents separates AB from CD (i.e., one
+  // edge on each side) then there is no intersection.
+  bool have_tangents_;  // True if the tangents have been computed.
+  S2Point a_tangent_;   // Outward-facing tangent at A.
+  S2Point b_tangent_;   // Outward-facing tangent at B.
+
+  // The fields below are updated for each vertex in the chain.
+  const S2Point* c_;       // Previous vertex in the vertex chain.
+  int acb_;                // The orientation of triangle ACB.
+
+  // The field below is a temporary used by CrossingSignInternal().
+  int bda_;                // The orientation of triangle BDA.
+
+  S2EdgeCrosser(const S2EdgeCrosser&) = delete;
+  void operator=(const S2EdgeCrosser&) = delete;
+};
+
+// S2CopyingEdgeCrosser is exactly like S2EdgeCrosser, except that it makes its
+// own copy of all arguments so that they do not need to persist between
+// calls.  This is less efficient, but makes it possible to use points that
+// are generated on demand and cannot conveniently be stored by the client.
+class S2CopyingEdgeCrosser {
+ public:
+  // These methods are all exactly like S2EdgeCrosser, except that the
+  // arguments can be temporaries.
+  S2CopyingEdgeCrosser() {}
+  S2CopyingEdgeCrosser(const S2Point& a, const S2Point& b);
+  const S2Point& a() { return a_; }
+  const S2Point& b() { return b_; }
+  const S2Point& c() { return c_; }
+  void Init(const S2Point& a, const S2Point& b);
+  int CrossingSign(const S2Point& c, const S2Point& d);
+  bool EdgeOrVertexCrossing(const S2Point& c, const S2Point& d);
+  S2CopyingEdgeCrosser(const S2Point& a, const S2Point& b, const S2Point& c);
+  void RestartAt(const S2Point& c);
+  int CrossingSign(const S2Point& d);
+  bool EdgeOrVertexCrossing(const S2Point& d);
+
+ private:
+  S2Point a_, b_, c_;
+  // TODO(ericv): It would be more efficient to implement S2CopyingEdgeCrosser
+  // directly rather than as a wrapper around S2EdgeCrosser.
+  S2EdgeCrosser crosser_;
+
+  S2CopyingEdgeCrosser(const S2CopyingEdgeCrosser&) = delete;
+  void operator=(const S2CopyingEdgeCrosser&) = delete;
+};
+
+
+//////////////////   Implementation details follow   ////////////////////
+
+
+inline S2EdgeCrosser::S2EdgeCrosser(const S2Point* a, const S2Point* b)
+    : a_(a), b_(b), a_cross_b_(a_->CrossProd(*b_)), have_tangents_(false),
+      c_(nullptr) {
+  S2_DCHECK(S2::IsUnitLength(*a));
+  S2_DCHECK(S2::IsUnitLength(*b));
+}
+
+inline void S2EdgeCrosser::Init(const S2Point* a, const S2Point* b) {
+  a_ = a;
+  b_ = b;
+  a_cross_b_ = a->CrossProd(*b_);
+  have_tangents_ = false;
+  c_ = nullptr;
+}
+
+inline int S2EdgeCrosser::CrossingSign(const S2Point* c, const S2Point* d) {
+  if (c != c_) RestartAt(c);
+  return CrossingSign(d);
+}
+
+inline bool S2EdgeCrosser::EdgeOrVertexCrossing(const S2Point* c,
+                                                const S2Point* d) {
+  if (c != c_) RestartAt(c);
+  return EdgeOrVertexCrossing(d);
+}
+
+inline S2EdgeCrosser::S2EdgeCrosser(
+    const S2Point* a, const S2Point* b, const S2Point* c)
+    : a_(a), b_(b), a_cross_b_(a_->CrossProd(*b_)), have_tangents_(false) {
+  S2_DCHECK(S2::IsUnitLength(*a));
+  S2_DCHECK(S2::IsUnitLength(*b));
+  RestartAt(c);
+}
+
+inline void S2EdgeCrosser::RestartAt(const S2Point* c) {
+  S2_DCHECK(S2::IsUnitLength(*c));
+  c_ = c;
+  acb_ = -s2pred::TriageSign(*a_, *b_, *c_, a_cross_b_);
+}
+
+inline int S2EdgeCrosser::CrossingSign(const S2Point* d) {
+  S2_DCHECK(S2::IsUnitLength(*d));
+  // For there to be an edge crossing, the triangles ACB, CBD, BDA, DAC must
+  // all be oriented the same way (CW or CCW).  We keep the orientation of ACB
+  // as part of our state.  When each new point D arrives, we compute the
+  // orientation of BDA and check whether it matches ACB.  This checks whether
+  // the points C and D are on opposite sides of the great circle through AB.
+
+  // Recall that TriageSign is invariant with respect to rotating its
+  // arguments, i.e. ABD has the same orientation as BDA.
+  int bda = s2pred::TriageSign(*a_, *b_, *d, a_cross_b_);
+  if (acb_ == -bda && bda != 0) {
+    // The most common case -- triangles have opposite orientations.  Save the
+    // current vertex D as the next vertex C, and also save the orientation of
+    // the new triangle ACB (which is opposite to the current triangle BDA).
+    c_ = d;
+    acb_ = -bda;
+    return -1;
+  }
+  bda_ = bda;
+  return CrossingSignInternal(d);
+}
+
+inline bool S2EdgeCrosser::EdgeOrVertexCrossing(const S2Point* d) {
+  // We need to copy c_ since it is clobbered by CrossingSign().
+  const S2Point* c = c_;
+  int crossing = CrossingSign(d);
+  if (crossing < 0) return false;
+  if (crossing > 0) return true;
+  return S2::VertexCrossing(*a_, *b_, *c, *d);
+}
+
+inline S2CopyingEdgeCrosser::S2CopyingEdgeCrosser(const S2Point& a,
+                                                  const S2Point& b)
+    : a_(a), b_(b), c_(S2Point()), crosser_(&a_, &b_) {
+}
+
+inline void S2CopyingEdgeCrosser::Init(const S2Point& a, const S2Point& b) {
+  a_ = a;
+  b_ = b;
+  c_ = S2Point();
+  crosser_.Init(&a_, &b_);
+}
+
+inline int S2CopyingEdgeCrosser::CrossingSign(const S2Point& c,
+                                              const S2Point& d) {
+  if (c != c_ || crosser_.c_ == nullptr) RestartAt(c);
+  return CrossingSign(d);
+}
+
+inline bool S2CopyingEdgeCrosser::EdgeOrVertexCrossing(
+    const S2Point& c, const S2Point& d) {
+  if (c != c_ || crosser_.c_ == nullptr) RestartAt(c);
+  return EdgeOrVertexCrossing(d);
+}
+
+inline S2CopyingEdgeCrosser::S2CopyingEdgeCrosser(
+    const S2Point& a, const S2Point& b, const S2Point& c)
+    : a_(a), b_(b), c_(c), crosser_(&a_, &b_, &c) {
+}
+
+inline void S2CopyingEdgeCrosser::RestartAt(const S2Point& c) {
+  c_ = c;
+  crosser_.RestartAt(&c_);
+}
+
+inline int S2CopyingEdgeCrosser::CrossingSign(const S2Point& d) {
+  int result = crosser_.CrossingSign(&d);
+  c_ = d;
+  crosser_.set_c(&c_);
+  return result;
+}
+
+inline bool S2CopyingEdgeCrosser::EdgeOrVertexCrossing(const S2Point& d) {
+  bool result = crosser_.EdgeOrVertexCrossing(&d);
+  c_ = d;
+  crosser_.set_c(&c_);
+  return result;
+}
+
+#endif  // S2_S2EDGE_CROSSER_H_
diff --git a/src/s2/s2edge_crossings.cc b/src/s2/s2edge_crossings.cc
new file mode 100644 (file)
index 0000000..95d69d2
--- /dev/null
@@ -0,0 +1,515 @@
+// Copyright 2005 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// Author: ericv@google.com (Eric Veach)
+
+#include "s2/s2edge_crossings.h"
+#include "s2/s2edge_crossings_internal.h"
+
+#include <cmath>
+
+#include "s2/base/logging.h"
+#include "s2/s1angle.h"
+#include "s2/s2edge_crosser.h"
+#include "s2/s2pointutil.h"
+#include "s2/s2predicates.h"
+#include "s2/s2predicates_internal.h"
+#include "s2/util/math/exactfloat/exactfloat.h"
+
+namespace S2 {
+
+using internal::GetIntersectionExact;
+using internal::IntersectionMethod;
+using internal::intersection_method_tally_;
+using std::fabs;
+using std::sqrt;
+
+// All error bounds in this file are expressed in terms of the maximum
+// rounding error for a floating-point type.  The rounding error is half of
+// the numeric_limits<T>::epsilon() value.
+static constexpr double DBL_ERR = s2pred::rounding_epsilon<double>();
+
+// kIntersectionError can be set somewhat arbitrarily, because the algorithm
+// uses more precision when necessary in order to achieve the specified error.
+// The only strict requirement is that kIntersectionError >= 2 * DBL_ERR
+// radians.  However, using a larger error tolerance makes the algorithm more
+// efficient because it reduces the number of cases where exact arithmetic is
+// needed.
+const S1Angle kIntersectionError = S1Angle::Radians(8 * DBL_ERR);
+
+const S1Angle kIntersectionMergeRadius = 2 * kIntersectionError;
+
+namespace internal {
+
+const S1Angle kIntersectionExactError = S1Angle::Radians(2 * DBL_ERR);
+
+int* intersection_method_tally_ = nullptr;
+
+const char* GetIntersectionMethodName(IntersectionMethod method) {
+  switch (method) {
+    case IntersectionMethod::SIMPLE:    return "Simple";
+    case IntersectionMethod::SIMPLE_LD: return "Simple_ld";
+    case IntersectionMethod::STABLE:    return "Stable";
+    case IntersectionMethod::STABLE_LD: return "Stable_ld";
+    case IntersectionMethod::EXACT:     return "Exact";
+    default:                            return "Unknown";
+  }
+}
+
+}  // namespace internal
+
+int CrossingSign(const S2Point& a, const S2Point& b,
+                 const S2Point& c, const S2Point& d) {
+  S2EdgeCrosser crosser(&a, &b, &c);
+  return crosser.CrossingSign(&d);
+}
+
+bool VertexCrossing(const S2Point& a, const S2Point& b,
+                    const S2Point& c, const S2Point& d) {
+  // If A == B or C == D there is no intersection.  We need to check this
+  // case first in case 3 or more input points are identical.
+  if (a == b || c == d) return false;
+
+  // If any other pair of vertices is equal, there is a crossing if and only
+  // if OrderedCCW() indicates that the edge AB is further CCW around the
+  // shared vertex O (either A or B) than the edge CD, starting from an
+  // arbitrary fixed reference point.
+  //
+  // Optimization: if AB=CD or AB=DC, we can avoid most of the calculations.
+  if (a == c) return (b == d) || s2pred::OrderedCCW(S2::Ortho(a), d, b, a);
+  if (b == d) return s2pred::OrderedCCW(S2::Ortho(b), c, a, b);
+
+  if (a == d) return (b == c) || s2pred::OrderedCCW(S2::Ortho(a), c, b, a);
+  if (b == c) return s2pred::OrderedCCW(S2::Ortho(b), d, a, b);
+
+  S2_LOG(DFATAL) << "VertexCrossing called with 4 distinct vertices";
+  return false;
+}
+
+bool EdgeOrVertexCrossing(const S2Point& a, const S2Point& b,
+                          const S2Point& c, const S2Point& d) {
+  int crossing = CrossingSign(a, b, c, d);
+  if (crossing < 0) return false;
+  if (crossing > 0) return true;
+  return VertexCrossing(a, b, c, d);
+}
+
+using Vector3_ld = Vector3<long double>;
+using Vector3_xf = Vector3<ExactFloat>;
+
+// Computes the cross product of "x" and "y", normalizes it to be unit length,
+// and stores the result in "result".  Also returns the length of the cross
+// product before normalization, which is useful for estimating the amount of
+// error in the result.  For numerical stability, "x" and "y" should both be
+// approximately unit length.
+template <class T>
+static T RobustNormalWithLength(const Vector3<T>& x, const Vector3<T>& y,
+                                Vector3<T>* result) {
+  // This computes 2 * (x.CrossProd(y)), but has much better numerical
+  // stability when "x" and "y" are unit length.
+  Vector3<T> tmp = (x - y).CrossProd(x + y);
+  T length = tmp.Norm();
+  if (length != 0) {
+    *result = (1 / length) * tmp;
+  }
+  return 0.5 * length;  // Since tmp == 2 * (x.CrossProd(y))
+}
+
+// If the intersection point of the edges (a0,a1) and (b0,b1) can be computed
+// to within an error of at most kIntersectionError by this function, then set
+// "result" to the intersection point and return true.
+//
+// The intersection point is not guaranteed to have the correct sign
+// (i.e., it may be either "result" or "-result").
+template <class T>
+static bool GetIntersectionSimple(const Vector3<T>& a0, const Vector3<T>& a1,
+                                  const Vector3<T>& b0, const Vector3<T>& b1,
+                                  Vector3<T>* result) {
+  // The code below computes the intersection point as
+  //
+  //    (a0.CrossProd(a1)).CrossProd(b0.CrossProd(b1))
+  //
+  // except that it has better numerical stability and also computes a
+  // guaranteed error bound.
+  //
+  // Each cross product is computed as (X-Y).CrossProd(X+Y) using unit-length
+  // input vectors, which eliminates most of the cancellation error.  However
+  // the error in the direction of the cross product can still become large if
+  // the two points are extremely close together.  We can show that as long as
+  // the length of the cross product is at least (16 * sqrt(3) + 24) * DBL_ERR
+  // (about 6e-15), then the directional error is at most 5 * T_ERR (about
+  // 3e-19 when T == "long double").  (DBL_ERR appears in the first formula
+  // because the inputs are assumed to be normalized in double precision
+  // rather than in the given type T.)
+  //
+  // The third cross product is different because its inputs already have some
+  // error.  Letting "result_len" be the length of the cross product, it can
+  // be shown that the error is at most
+  //
+  //   (2 + 2 * sqrt(3) + 12 / result_len) * T_ERR
+  //
+  // We want this error to be at most kIntersectionError, which is true as
+  // long as "result_len" is at least kMinResultLen defined below.
+
+  constexpr T T_ERR = s2pred::rounding_epsilon<T>();
+  static const T kMinNormalLength = (16 * sqrt(3.0) + 24) * DBL_ERR;
+  static const T kMinResultLen =
+      12 / (kIntersectionError.radians() / T_ERR - (2 + 2 * sqrt(3.0)));
+
+  // On some platforms "long double" is the same as "double", and on these
+  // platforms this method always returns false (e.g. ARM, Win32).  Rather
+  // than testing this directly, instead we look at kMinResultLen since this
+  // is a direct measure of whether "long double" has sufficient accuracy to
+  // be useful.  If kMinResultLen > 0.5, it means that this method will fail
+  // even for edges that meet at an angle of 30 degrees.  (On Intel platforms
+  // kMinResultLen corresponds to an intersection angle of about 0.04
+  // degrees.)
+  S2_DCHECK_LE(kMinResultLen, 0.5);
+
+  Vector3<T> a_norm, b_norm;
+  if (RobustNormalWithLength(a0, a1, &a_norm) >= kMinNormalLength &&
+      RobustNormalWithLength(b0, b1, &b_norm) >= kMinNormalLength &&
+      RobustNormalWithLength(a_norm, b_norm, result) >= kMinResultLen) {
+    return true;
+  }
+  return false;
+}
+
+static bool GetIntersectionSimpleLD(const S2Point& a0, const S2Point& a1,
+                                    const S2Point& b0, const S2Point& b1,
+                                    S2Point* result) {
+  Vector3_ld result_ld;
+  if (GetIntersectionSimple(Vector3_ld::Cast(a0), Vector3_ld::Cast(a1),
+                            Vector3_ld::Cast(b0), Vector3_ld::Cast(b1),
+                            &result_ld)) {
+    *result = S2Point::Cast(result_ld);
+    return true;
+  }
+  return false;
+}
+
+// Given a point X and a vector "a_norm" (not necessarily unit length),
+// compute x.DotProd(a_norm) and return a bound on the error in the result.
+// The remaining parameters allow this dot product to be computed more
+// accurately and efficiently.  They include the length of "a_norm"
+// ("a_norm_len") and the edge endpoints "a0" and "a1".
+template <class T>
+static T GetProjection(const Vector3<T>& x,
+                       const Vector3<T>& a_norm, T a_norm_len,
+                       const Vector3<T>& a0, const Vector3<T>& a1,
+                       T* error) {
+  // The error in the dot product is proportional to the lengths of the input
+  // vectors, so rather than using "x" itself (a unit-length vector) we use
+  // the vectors from "x" to the closer of the two edge endpoints.  This
+  // typically reduces the error by a huge factor.
+  Vector3<T> x0 = x - a0;
+  Vector3<T> x1 = x - a1;
+  T x0_dist2 = x0.Norm2();
+  T x1_dist2 = x1.Norm2();
+
+  // If both distances are the same, we need to be careful to choose one
+  // endpoint deterministically so that the result does not change if the
+  // order of the endpoints is reversed.
+  T dist, result;
+  if (x0_dist2 < x1_dist2 || (x0_dist2 == x1_dist2 && x0 < x1)) {
+    dist = sqrt(x0_dist2);
+    result = x0.DotProd(a_norm);
+  } else {
+    dist = sqrt(x1_dist2);
+    result = x1.DotProd(a_norm);
+  }
+  // This calculation bounds the error from all sources: the computation of
+  // the normal, the subtraction of one endpoint, and the dot product itself.
+  // (DBL_ERR appears because the input points are assumed to be normalized in
+  // double precision rather than in the given type T.)
+  //
+  // For reference, the bounds that went into this calculation are:
+  // ||N'-N|| <= ((1 + 2 * sqrt(3))||N|| + 32 * sqrt(3) * DBL_ERR) * T_ERR
+  // |(A.B)'-(A.B)| <= (1.5 * (A.B) + 1.5 * ||A|| * ||B||) * T_ERR
+  // ||(X-Y)'-(X-Y)|| <= ||X-Y|| * T_ERR
+  constexpr T T_ERR = s2pred::rounding_epsilon<T>();
+  *error = (((3.5 + 2 * sqrt(3.0)) * a_norm_len + 32 * sqrt(3.0) * DBL_ERR)
+            * dist + 1.5 * fabs(result)) * T_ERR;
+  return result;
+}
+
+// Helper function for GetIntersectionStable().  It expects that the edges
+// (a0,a1) and (b0,b1) have been sorted so that the first edge is longer.
+template <class T>
+static bool GetIntersectionStableSorted(
+    const Vector3<T>& a0, const Vector3<T>& a1,
+    const Vector3<T>& b0, const Vector3<T>& b1, Vector3<T>* result) {
+  S2_DCHECK_GE((a1 - a0).Norm2(), (b1 - b0).Norm2());
+
+  // Compute the normal of the plane through (a0, a1) in a stable way.
+  Vector3<T> a_norm = (a0 - a1).CrossProd(a0 + a1);
+  T a_norm_len = a_norm.Norm();
+  T b_len = (b1 - b0).Norm();
+
+  // Compute the projection (i.e., signed distance) of b0 and b1 onto the
+  // plane through (a0, a1).  Distances are scaled by the length of a_norm.
+  T b0_error, b1_error;
+  T b0_dist = GetProjection(b0, a_norm, a_norm_len, a0, a1, &b0_error);
+  T b1_dist = GetProjection(b1, a_norm, a_norm_len, a0, a1, &b1_error);
+
+  // The total distance from b0 to b1 measured perpendicularly to (a0,a1) is
+  // |b0_dist - b1_dist|.  Note that b0_dist and b1_dist generally have
+  // opposite signs because b0 and b1 are on opposite sides of (a0, a1).  The
+  // code below finds the intersection point by interpolating along the edge
+  // (b0, b1) to a fractional distance of b0_dist / (b0_dist - b1_dist).
+  //
+  // It can be shown that the maximum error in the interpolation fraction is
+  //
+  //     (b0_dist * b1_error - b1_dist * b0_error) /
+  //        (dist_sum * (dist_sum - error_sum))
+  //
+  // We save ourselves some work by scaling the result and the error bound by
+  // "dist_sum", since the result is normalized to be unit length anyway.
+  T dist_sum = fabs(b0_dist - b1_dist);
+  T error_sum = b0_error + b1_error;
+  if (dist_sum <= error_sum) {
+    return false;  // Error is unbounded in this case.
+  }
+  Vector3<T> x = b0_dist * b1 - b1_dist * b0;
+  constexpr T T_ERR = s2pred::rounding_epsilon<T>();
+  T error = b_len * fabs(b0_dist * b1_error - b1_dist * b0_error) /
+      (dist_sum - error_sum) + 2 * T_ERR * dist_sum;
+
+  // Finally we normalize the result, compute the corresponding error, and
+  // check whether the total error is acceptable.
+  T x_len2 = x.Norm2();
+  if (x_len2 < std::numeric_limits<T>::min()) {
+    // If x.Norm2() is less than the minimum normalized value of T, x_len might
+    // lose precision and the result might fail to satisfy S2::IsUnitLength().
+    // TODO(ericv): Implement S2::RobustNormalize().
+    return false;
+  }
+  T x_len = sqrt(x_len2);
+  const T kMaxError = kIntersectionError.radians();
+  if (error > (kMaxError - T_ERR) * x_len) {
+    return false;
+  }
+  *result = (1 / x_len) * x;
+  return true;
+}
+
+// Returns whether (a0,a1) is less than (b0,b1) with respect to a total
+// ordering on edges that is invariant under edge reversals.
+template <class T>
+static bool CompareEdges(const Vector3<T>& a0, const Vector3<T>& a1,
+                         const Vector3<T>& b0, const Vector3<T>& b1) {
+  const Vector3<T> *pa0 = &a0, *pa1 = &a1;
+  const Vector3<T> *pb0 = &b0, *pb1 = &b1;
+  if (*pa0 >= *pa1) std::swap(pa0, pa1);
+  if (*pb0 >= *pb1) std::swap(pb0, pb1);
+  return *pa0 < *pb0 || (*pa0 == *pb0 && *pb0 < *pb1);
+}
+
+// If the intersection point of the edges (a0,a1) and (b0,b1) can be computed
+// to within an error of at most kIntersectionError by this function, then set
+// "result" to the intersection point and return true.
+//
+// The intersection point is not guaranteed to have the correct sign
+// (i.e., it may be either "result" or "-result").
+template <class T>
+static bool GetIntersectionStable(const Vector3<T>& a0, const Vector3<T>& a1,
+                                  const Vector3<T>& b0, const Vector3<T>& b1,
+                                  Vector3<T>* result) {
+  // Sort the two edges so that (a0,a1) is longer, breaking ties in a
+  // deterministic way that does not depend on the ordering of the endpoints.
+  // This is desirable for two reasons:
+  //  - So that the result doesn't change when edges are swapped or reversed.
+  //  - It reduces error, since the first edge is used to compute the edge
+  //    normal (where a longer edge means less error), and the second edge
+  //    is used for interpolation (where a shorter edge means less error).
+  T a_len2 = (a1 - a0).Norm2();
+  T b_len2 = (b1 - b0).Norm2();
+  if (a_len2 < b_len2 || (a_len2 == b_len2 && CompareEdges(a0, a1, b0, b1))) {
+    return GetIntersectionStableSorted(b0, b1, a0, a1, result);
+  } else {
+    return GetIntersectionStableSorted(a0, a1, b0, b1, result);
+  }
+}
+
+static bool GetIntersectionStableLD(const S2Point& a0, const S2Point& a1,
+                                    const S2Point& b0, const S2Point& b1,
+                                    S2Point* result) {
+  Vector3_ld result_ld;
+  if (GetIntersectionStable(Vector3_ld::Cast(a0), Vector3_ld::Cast(a1),
+                            Vector3_ld::Cast(b0), Vector3_ld::Cast(b1),
+                            &result_ld)) {
+    *result = S2Point::Cast(result_ld);
+    return true;
+  }
+  return false;
+}
+
+static S2Point S2PointFromExact(const Vector3_xf& xf) {
+  // If all components of "x" have absolute value less than about 1e-154,
+  // then x.Norm2() is zero in double precision due to underflow.  Therefore
+  // we need to scale "x" by an appropriate power of 2 before the conversion.
+  S2Point x(xf[0].ToDouble(), xf[1].ToDouble(), xf[2].ToDouble());
+  if (x.Norm2() > 0) return x.Normalize();
+
+  // Scale so that the largest component magnitude is in the range [0.5, 1).
+  int exp = ExactFloat::kMinExp - 1;
+  for (int i = 0; i < 3; ++i) {
+    if (xf[i].is_normal()) exp = std::max(exp, xf[i].exp());
+  }
+  if (exp < ExactFloat::kMinExp) {
+    return S2Point(0, 0, 0);
+  }
+  return S2Point(ldexp(xf[0], -exp).ToDouble(),
+                 ldexp(xf[1], -exp).ToDouble(),
+                 ldexp(xf[2], -exp).ToDouble()).Normalize();
+}
+
+namespace internal {
+
+// Compute the intersection point of (a0, a1) and (b0, b1) using exact
+// arithmetic.  Note that the result is not exact because it is rounded to
+// double precision.  Also, the intersection point is not guaranteed to have
+// the correct sign (i.e., the return value may need to be negated).
+S2Point GetIntersectionExact(const S2Point& a0, const S2Point& a1,
+                             const S2Point& b0, const S2Point& b1) {
+  // Since we are using exact arithmetic, we don't need to worry about
+  // numerical stability.
+  Vector3_xf a0_xf = Vector3_xf::Cast(a0);
+  Vector3_xf a1_xf = Vector3_xf::Cast(a1);
+  Vector3_xf b0_xf = Vector3_xf::Cast(b0);
+  Vector3_xf b1_xf = Vector3_xf::Cast(b1);
+  Vector3_xf a_norm_xf = a0_xf.CrossProd(a1_xf);
+  Vector3_xf b_norm_xf = b0_xf.CrossProd(b1_xf);
+  Vector3_xf x_xf = a_norm_xf.CrossProd(b_norm_xf);
+
+  // The final Normalize() call is done in double precision, which creates a
+  // directional error of up to 2 * DBL_ERR.  (ToDouble() and Normalize() each
+  // contribute up to DBL_ERR of directional error.)
+  S2Point x = S2PointFromExact(x_xf);
+
+  if (x == S2Point(0, 0, 0)) {
+    // The two edges are exactly collinear, but we still consider them to be
+    // "crossing" because of simulation of simplicity.  Out of the four
+    // endpoints, exactly two lie in the interior of the other edge.  Of
+    // those two we return the one that is lexicographically smallest.
+    x = S2Point(10, 10, 10);  // Greater than any valid S2Point
+    S2Point a_norm = S2PointFromExact(a_norm_xf);
+    S2Point b_norm = S2PointFromExact(b_norm_xf);
+    if (a_norm == S2Point(0, 0, 0) || b_norm == S2Point(0, 0, 0)) {
+      // TODO(ericv): To support antipodal edges properly, we would need to
+      // add an s2pred::CrossProd() function that computes the cross product
+      // using simulation of simplicity and rounds the result to the nearest
+      // floating-point representation.
+      S2_LOG(DFATAL) << "Exactly antipodal edges not supported by GetIntersection";
+    }
+    if (s2pred::OrderedCCW(b0, a0, b1, b_norm) && a0 < x) x = a0;
+    if (s2pred::OrderedCCW(b0, a1, b1, b_norm) && a1 < x) x = a1;
+    if (s2pred::OrderedCCW(a0, b0, a1, a_norm) && b0 < x) x = b0;
+    if (s2pred::OrderedCCW(a0, b1, a1, a_norm) && b1 < x) x = b1;
+  }
+  S2_DCHECK(S2::IsUnitLength(x));
+  return x;
+}
+
+}  // namespace internal
+
+// Given three points "a", "x", "b", returns true if these three points occur
+// in the given order along the edge (a,b) to within the given tolerance.
+// More precisely, either "x" must be within "tolerance" of "a" or "b", or
+// when "x" is projected onto the great circle through "a" and "b" it must lie
+// along the edge (a,b) (i.e., the shortest path from "a" to "b").
+static bool ApproximatelyOrdered(const S2Point& a, const S2Point& x,
+                                 const S2Point& b, double tolerance) {
+  if ((x - a).Norm2() <= tolerance * tolerance) return true;
+  if ((x - b).Norm2() <= tolerance * tolerance) return true;
+  return s2pred::OrderedCCW(a, x, b, S2::RobustCrossProd(a, b).Normalize());
+}
+
+S2Point GetIntersection(const S2Point& a0, const S2Point& a1,
+                        const S2Point& b0, const S2Point& b1) {
+  S2_DCHECK_GT(CrossingSign(a0, a1, b0, b1), 0);
+
+  // It is difficult to compute the intersection point of two edges accurately
+  // when the angle between the edges is very small.  Previously we handled
+  // this by only guaranteeing that the returned intersection point is within
+  // kIntersectionError of each edge.  However, this means that when the edges
+  // cross at a very small angle, the computed result may be very far from the
+  // true intersection point.
+  //
+  // Instead this function now guarantees that the result is always within
+  // kIntersectionError of the true intersection.  This requires using more
+  // sophisticated techniques and in some cases extended precision.
+  //
+  // Three different techniques are implemented, but only two are used:
+  //
+  //  - GetIntersectionSimple() computes the intersection point using
+  //    numerically stable cross products in "long double" precision.
+  //
+  //  - GetIntersectionStable() computes the intersection point using
+  //    projection and interpolation, taking care to minimize cancellation
+  //    error.  This method exists in "double" and "long double" versions.
+  //
+  //  - GetIntersectionExact() computes the intersection point using exact
+  //    arithmetic and converts the final result back to an S2Point.
+  //
+  // We don't actually use the first method (GetIntersectionSimple) because it
+  // turns out that GetIntersectionStable() is twice as fast and also much
+  // more accurate (even in double precision).  The "long double" version
+  // (only available on Intel platforms) uses 80-bit precision and is about
+  // twice as slow.  The exact arithmetic version is about 100x slower.
+  //
+  // So our strategy is to first call GetIntersectionStable() in double
+  // precision; if that doesn't work and this platform supports "long double",
+  // then we try again in "long double"; if that doesn't work then we fall
+  // back to exact arithmetic.
+
+  static const bool kUseSimpleMethod = false;
+  static const bool kHasLongDouble = (s2pred::rounding_epsilon<long double>() <
+                                      s2pred::rounding_epsilon<double>());
+  S2Point result;
+  IntersectionMethod method;
+  if (kUseSimpleMethod && GetIntersectionSimple(a0, a1, b0, b1, &result)) {
+    method = IntersectionMethod::SIMPLE;
+  } else if (kUseSimpleMethod && kHasLongDouble &&
+             GetIntersectionSimpleLD(a0, a1, b0, b1, &result)) {
+    method = IntersectionMethod::SIMPLE_LD;
+  } else if (GetIntersectionStable(a0, a1, b0, b1, &result)) {
+    method = IntersectionMethod::STABLE;
+  } else if (kHasLongDouble &&
+             GetIntersectionStableLD(a0, a1, b0, b1, &result)) {
+    method = IntersectionMethod::STABLE_LD;
+  } else {
+    result = GetIntersectionExact(a0, a1, b0, b1);
+    method = IntersectionMethod::EXACT;
+  }
+  if (intersection_method_tally_) {
+    ++intersection_method_tally_[static_cast<int>(method)];
+  }
+
+  // Make sure the intersection point is on the correct side of the sphere.
+  // Since all vertices are unit length, and edges are less than 180 degrees,
+  // (a0 + a1) and (b0 + b1) both have positive dot product with the
+  // intersection point.  We use the sum of all vertices to make sure that the
+  // result is unchanged when the edges are swapped or reversed.
+  if (result.DotProd((a0 + a1) + (b0 + b1)) < 0) result = -result;
+
+  // Make sure that the intersection point lies on both edges.
+  S2_DCHECK(ApproximatelyOrdered(a0, result, a1, kIntersectionError.radians()));
+  S2_DCHECK(ApproximatelyOrdered(b0, result, b1, kIntersectionError.radians()));
+
+  return result;
+}
+
+}  // namespace S2
diff --git a/src/s2/s2edge_crossings.h b/src/s2/s2edge_crossings.h
new file mode 100644 (file)
index 0000000..78f6961
--- /dev/null
@@ -0,0 +1,138 @@
+// Copyright 2005 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// Author: ericv@google.com (Eric Veach)
+//
+// Defines functions related to determining whether two geodesic edges cross
+// and for computing intersection points.
+//
+// The predicates CrossingSign(), VertexCrossing(), and EdgeOrVertexCrossing()
+// are robust, meaning that they produce correct, consistent results even in
+// pathological cases.  See s2predicates.h for additional robust predicates.
+//
+// See also S2EdgeCrosser (which efficiently tests an edge against a sequence
+// of other edges) and S2CrossingEdgeQuery (which uses an index to speed up
+// the process).
+
+#ifndef S2_S2EDGE_CROSSINGS_H_
+#define S2_S2EDGE_CROSSINGS_H_
+
+#include <cmath>
+
+#include "s2/base/logging.h"
+#include "absl/base/macros.h"
+#include "absl/container/inlined_vector.h"
+#include "s2/_fp_contract_off.h"
+#include "s2/r2.h"
+#include "s2/r2rect.h"
+#include "s2/s1angle.h"
+#include "s2/s1chord_angle.h"
+#include "s2/s1interval.h"
+#include "s2/s2latlng.h"
+#include "s2/s2latlng_rect.h"
+#include "s2/s2pointutil.h"
+#include "s2/s2predicates.h"
+#include "s2/util/math/vector.h"
+
+namespace S2 {
+
+// This function determines whether the edge AB intersects the edge CD.
+// Returns +1 if AB crosses CD at a point that is interior to both edges.
+// Returns  0 if any two vertices from different edges are the same.
+// Returns -1 otherwise.
+//
+// Note that if an edge is degenerate (A == B or C == D), the return value
+// is 0 if two vertices from different edges are the same and -1 otherwise.
+//
+// Properties of CrossingSign:
+//
+//  (1) CrossingSign(b,a,c,d) == CrossingSign(a,b,c,d)
+//  (2) CrossingSign(c,d,a,b) == CrossingSign(a,b,c,d)
+//  (3) CrossingSign(a,b,c,d) == 0 if a==c, a==d, b==c, b==d
+//  (3) CrossingSign(a,b,c,d) <= 0 if a==b or c==d (see above)
+//
+// This function implements an exact, consistent perturbation model such
+// that no three points are ever considered to be collinear.  This means
+// that even if you have 4 points A, B, C, D that lie exactly in a line
+// (say, around the equator), C and D will be treated as being slightly to
+// one side or the other of AB.  This is done in a way such that the
+// results are always consistent (see s2pred::Sign).
+//
+// Note that if you want to check an edge against a collection of other edges,
+// it is much more efficient to use an S2EdgeCrosser (see s2edge_crosser.h).
+int CrossingSign(const S2Point& a, const S2Point& b,
+                 const S2Point& c, const S2Point& d);
+
+// Given two edges AB and CD where at least two vertices are identical
+// (i.e. CrossingSign(a,b,c,d) == 0), this function defines whether the
+// two edges "cross" in a such a way that point-in-polygon containment tests
+// can be implemented by counting the number of edge crossings.  The basic
+// rule is that a "crossing" occurs if AB is encountered after CD during a
+// CCW sweep around the shared vertex starting from a fixed reference point.
+//
+// Note that according to this rule, if AB crosses CD then in general CD
+// does not cross AB.  However, this leads to the correct result when
+// counting polygon edge crossings.  For example, suppose that A,B,C are
+// three consecutive vertices of a CCW polygon.  If we now consider the edge
+// crossings of a segment BP as P sweeps around B, the crossing number
+// changes parity exactly when BP crosses BA or BC.
+//
+// Useful properties of VertexCrossing (VC):
+//
+//  (1) VC(a,a,c,d) == VC(a,b,c,c) == false
+//  (2) VC(a,b,a,b) == VC(a,b,b,a) == true
+//  (3) VC(a,b,c,d) == VC(a,b,d,c) == VC(b,a,c,d) == VC(b,a,d,c)
+//  (3) If exactly one of a,b equals one of c,d, then exactly one of
+//      VC(a,b,c,d) and VC(c,d,a,b) is true
+//
+// It is an error to call this method with 4 distinct vertices.
+bool VertexCrossing(const S2Point& a, const S2Point& b,
+                    const S2Point& c, const S2Point& d);
+
+// A convenience function that calls CrossingSign() to handle cases
+// where all four vertices are distinct, and VertexCrossing() to handle
+// cases where two or more vertices are the same.  This defines a crossing
+// function such that point-in-polygon containment tests can be implemented
+// by simply counting edge crossings.
+bool EdgeOrVertexCrossing(const S2Point& a, const S2Point& b,
+                          const S2Point& c, const S2Point& d);
+
+// Given two edges AB and CD such that CrossingSign(A, B, C, D) > 0, returns
+// their intersection point.  Useful properties of GetIntersection (GI):
+//
+//  (1) GI(b,a,c,d) == GI(a,b,d,c) == GI(a,b,c,d)
+//  (2) GI(c,d,a,b) == GI(a,b,c,d)
+//
+// The returned intersection point X is guaranteed to be very close to the
+// true intersection point of AB and CD, even if the edges intersect at a
+// very small angle.  See "kIntersectionError" below for details.
+S2Point GetIntersection(const S2Point& a, const S2Point& b,
+                        const S2Point& c, const S2Point& d);
+
+// kIntersectionError is an upper bound on the distance from the intersection
+// point returned by GetIntersection() to the true intersection point.
+extern const S1Angle kIntersectionError;
+
+// This value can be used as the S2Builder snap_radius() to ensure that edges
+// that have been displaced by up to kIntersectionError are merged back
+// together again.  For example this can happen when geometry is intersected
+// with a set of tiles and then unioned.  It is equal to twice the
+// intersection error because input edges might have been displaced in
+// opposite directions.
+extern const S1Angle kIntersectionMergeRadius;  // 2 * kIntersectionError
+
+}  // namespace S2
+
+#endif  // S2_S2EDGE_CROSSINGS_H_
diff --git a/src/s2/s2edge_crossings_internal.h b/src/s2/s2edge_crossings_internal.h
new file mode 100644 (file)
index 0000000..9852faa
--- /dev/null
@@ -0,0 +1,59 @@
+// Copyright 2005 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// Author: ericv@google.com (Eric Veach)
+//
+// The following functions are not part of the public API.  Currently they are
+// only used internally for testing purposes.
+
+#ifndef S2_S2EDGE_CROSSINGS_INTERNAL_H_
+#define S2_S2EDGE_CROSSINGS_INTERNAL_H_
+
+#include "s2/s1angle.h"
+#include "s2/s2point.h"
+
+namespace S2 {
+namespace internal {
+
+// Returns the intersection point of two edges computed using exact arithmetic
+// and rounded to the nearest representable S2Point.
+S2Point GetIntersectionExact(const S2Point& a0, const S2Point& a1,
+                             const S2Point& b0, const S2Point& b1);
+
+// The maximum error in the method above.
+extern const S1Angle kIntersectionExactError;
+
+// The following field is used exclusively by S2EdgeUtilTesting in order to
+// measure how often each intersection method is used by GetIntersection().
+// If non-nullptr, then it points to an array of integers indexed by an
+// IntersectionMethod enum value.  Each call to GetIntersection() increments
+// the array entry corresponding to the intersection method that was used.
+extern int* intersection_method_tally_;
+
+// The list of intersection methods implemented by GetIntersection().
+enum class IntersectionMethod {
+  SIMPLE,
+  SIMPLE_LD,
+  STABLE,
+  STABLE_LD,
+  EXACT,
+  NUM_METHODS
+};
+const char* GetIntersectionMethodName(IntersectionMethod method);
+
+}  // namespace internal
+}  // namespace S2
+
+#endif  // S2_S2EDGE_CROSSINGS_INTERNAL_H_
diff --git a/src/s2/s2edge_distances.cc b/src/s2/s2edge_distances.cc
new file mode 100644 (file)
index 0000000..d0caf6a
--- /dev/null
@@ -0,0 +1,419 @@
+// Copyright 2005 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// Author: ericv@google.com (Eric Veach)
+
+#include "s2/s2edge_distances.h"
+
+#include <cfloat>
+#include <cmath>
+
+#include "s2/base/logging.h"
+#include "s2/s1chord_angle.h"
+#include "s2/s2edge_crossings.h"
+#include "s2/s2pointutil.h"
+#include "s2/s2predicates.h"
+
+using std::max;
+using std::min;
+
+namespace S2 {
+
+double GetDistanceFraction(const S2Point& x,
+                             const S2Point& a0, const S2Point& a1) {
+  S2_DCHECK_NE(a0, a1);
+  double d0 = x.Angle(a0);
+  double d1 = x.Angle(a1);
+  return d0 / (d0 + d1);
+}
+
+S2Point InterpolateAtDistance(S1Angle ax_angle,
+                              const S2Point& a, const S2Point& b) {
+  double ax = ax_angle.radians();
+
+  S2_DCHECK(S2::IsUnitLength(a));
+  S2_DCHECK(S2::IsUnitLength(b));
+
+  // Use RobustCrossProd() to compute the tangent vector at A towards B.  The
+  // result is always perpendicular to A, even if A=B or A=-B, but it is not
+  // necessarily unit length.  (We effectively normalize it below.)
+  Vector3_d normal = S2::RobustCrossProd(a, b);
+  Vector3_d tangent = normal.CrossProd(a);
+  S2_DCHECK(tangent != S2Point(0, 0, 0));
+
+  // Now compute the appropriate linear combination of A and "tangent".  With
+  // infinite precision the result would always be unit length, but we
+  // normalize it anyway to ensure that the error is within acceptable bounds.
+  // (Otherwise errors can build up when the result of one interpolation is
+  // fed into another interpolation.)
+  return (cos(ax) * a + (sin(ax) / tangent.Norm()) * tangent).Normalize();
+}
+
+S2Point Interpolate(double t, const S2Point& a, const S2Point& b) {
+  if (t == 0) return a;
+  if (t == 1) return b;
+  S1Angle ab(a, b);
+  return InterpolateAtDistance(t * ab, a, b);
+}
+
+// If the minimum distance from X to AB is attained at an interior point of AB
+// (i.e., not an endpoint), and that distance is less than "min_dist" or
+// "always_update" is true, then update "min_dist" and return true.  Otherwise
+// return false.
+//
+// The "Always" in the function name refers to the template argument, i.e.
+// AlwaysUpdateMinInteriorDistance<true> always updates the given distance,
+// while AlwaysUpdateMinInteriorDistance<false> does not.  This optimization
+// increases the speed of GetDistance() by about 10% without creating code
+// duplication.
+template <bool always_update>
+inline bool AlwaysUpdateMinInteriorDistance(
+    const S2Point& x, const S2Point& a, const S2Point& b,
+    double xa2, double xb2, S1ChordAngle* min_dist) {
+  S2_DCHECK(S2::IsUnitLength(x) && S2::IsUnitLength(a) && S2::IsUnitLength(b));
+  S2_DCHECK_EQ(xa2, (x-a).Norm2());
+  S2_DCHECK_EQ(xb2, (x-b).Norm2());
+
+  // The closest point on AB could either be one of the two vertices (the
+  // "vertex case") or in the interior (the "interior case").  Let C = A x B.
+  // If X is in the spherical wedge extending from A to B around the axis
+  // through C, then we are in the interior case.  Otherwise we are in the
+  // vertex case.
+  //
+  // Check whether we might be in the interior case.  For this to be true, XAB
+  // and XBA must both be acute angles.  Checking this condition exactly is
+  // expensive, so instead we consider the planar triangle ABX (which passes
+  // through the sphere's interior).  The planar angles XAB and XBA are always
+  // less than the corresponding spherical angles, so if we are in the
+  // interior case then both of these angles must be acute.
+  //
+  // We check this by computing the squared edge lengths of the planar
+  // triangle ABX, and testing acuteness using the law of cosines:
+  //
+  //             max(XA^2, XB^2) < min(XA^2, XB^2) + AB^2
+  //
+  if (max(xa2, xb2) >= min(xa2, xb2) + (a-b).Norm2()) {
+    return false;
+  }
+  // The minimum distance might be to a point on the edge interior.  Let R
+  // be closest point to X that lies on the great circle through AB.  Rather
+  // than computing the geodesic distance along the surface of the sphere,
+  // instead we compute the "chord length" through the sphere's interior.
+  // If the squared chord length exceeds min_dist.length2() then we can
+  // return "false" immediately.
+  //
+  // The squared chord length XR^2 can be expressed as XQ^2 + QR^2, where Q
+  // is the point X projected onto the plane through the great circle AB.
+  // The distance XQ^2 can be written as (X.C)^2 / |C|^2 where C = A x B.
+  // We ignore the QR^2 term and instead use XQ^2 as a lower bound, since it
+  // is faster and the corresponding distance on the Earth's surface is
+  // accurate to within 1% for distances up to about 1800km.
+  S2Point c = S2::RobustCrossProd(a, b);
+  double c2 = c.Norm2();
+  double x_dot_c = x.DotProd(c);
+  double x_dot_c2 = x_dot_c * x_dot_c;
+  if (!always_update && x_dot_c2 > c2 * min_dist->length2()) {
+    // The closest point on the great circle AB is too far away.  We need to
+    // test this using ">" rather than ">=" because the actual minimum bound
+    // on the distance is (x_dot_c2 / c2), which can be rounded differently
+    // than the (more efficient) multiplicative test above.
+    return false;
+  }
+  // Otherwise we do the exact, more expensive test for the interior case.
+  // This test is very likely to succeed because of the conservative planar
+  // test we did initially.
+  S2Point cx = c.CrossProd(x);
+  if (a.DotProd(cx) >= 0 || b.DotProd(cx) <= 0) {
+    return false;
+  }
+  // Compute the squared chord length XR^2 = XQ^2 + QR^2 (see above).
+  // This calculation has good accuracy for all chord lengths since it
+  // is based on both the dot product and cross product (rather than
+  // deriving one from the other).  However, note that the chord length
+  // representation itself loses accuracy as the angle approaches Pi.
+  double qr = 1 - sqrt(cx.Norm2() / c2);
+  double dist2 = (x_dot_c2 / c2) + (qr * qr);
+  if (!always_update && dist2 >= min_dist->length2()) {
+    return false;
+  }
+  *min_dist = S1ChordAngle::FromLength2(dist2);
+  return true;
+}
+
+// This function computes the distance from a point X to a line segment AB.
+// If the distance is less than "min_dist" or "always_update" is true, it
+// updates "min_dist" and returns true.  Otherwise it returns false.
+//
+// The "Always" in the function name refers to the template argument, i.e.
+// AlwaysUpdateMinDistance<true> always updates the given distance, while
+// AlwaysUpdateMinDistance<false> does not.  This optimization increases the
+// speed of GetDistance() by about 10% without creating code duplication.
+template <bool always_update>
+inline bool AlwaysUpdateMinDistance(const S2Point& x,
+                                    const S2Point& a, const S2Point& b,
+                                    S1ChordAngle* min_dist) {
+  S2_DCHECK(S2::IsUnitLength(x) && S2::IsUnitLength(a) && S2::IsUnitLength(b));
+
+  double xa2 = (x-a).Norm2(), xb2 = (x-b).Norm2();
+  if (AlwaysUpdateMinInteriorDistance<always_update>(x, a, b, xa2, xb2,
+                                                     min_dist)) {
+    return true;  // Minimum distance is attained along the edge interior.
+  }
+  // Otherwise the minimum distance is to one of the endpoints.
+  double dist2 = min(xa2, xb2);
+  if (!always_update && dist2 >= min_dist->length2()) {
+    return false;
+  }
+  *min_dist = S1ChordAngle::FromLength2(dist2);
+  return true;
+}
+
+S1Angle GetDistance(const S2Point& x, const S2Point& a, const S2Point& b) {
+  S1ChordAngle min_dist;
+  AlwaysUpdateMinDistance<true>(x, a, b, &min_dist);
+  return min_dist.ToAngle();
+}
+
+bool UpdateMinDistance(const S2Point& x, const S2Point& a, const S2Point& b,
+                       S1ChordAngle* min_dist) {
+  return AlwaysUpdateMinDistance<false>(x, a, b, min_dist);
+}
+
+bool UpdateMaxDistance(const S2Point& x, const S2Point& a, const S2Point& b,
+                       S1ChordAngle* max_dist) {
+  auto dist = max(S1ChordAngle(x, a), S1ChordAngle(x, b));
+  if (dist > S1ChordAngle::Right()) {
+    AlwaysUpdateMinDistance<true>(-x, a, b, &dist);
+    dist = S1ChordAngle::Straight() - dist;
+  }
+  if (*max_dist < dist) {
+    *max_dist = dist;
+    return true;
+  }
+
+  return false;
+}
+
+
+bool UpdateMinInteriorDistance(const S2Point& x,
+                               const S2Point& a, const S2Point& b,
+                               S1ChordAngle* min_dist) {
+  double xa2 = (x-a).Norm2(), xb2 = (x-b).Norm2();
+  return AlwaysUpdateMinInteriorDistance<false>(x, a, b, xa2, xb2, min_dist);
+}
+
+// Returns the maximum error in the result of UpdateMinInteriorDistance,
+// assuming that all input points are normalized to within the bounds
+// guaranteed by S2Point::Normalize().  The error can be added or subtracted
+// from an S1ChordAngle "x" using x.PlusError(error).
+static double GetUpdateMinInteriorDistanceMaxError(S1ChordAngle dist) {
+  // If a point is more than 90 degrees from an edge, then the minimum
+  // distance is always to one of the endpoints, not to the edge interior.
+  if (dist >= S1ChordAngle::Right()) return 0.0;
+
+  // This bound includes all source of error, assuming that the input points
+  // are normalized to within the bounds guaranteed to S2Point::Normalize().
+  // "a" and "b" are components of chord length that are perpendicular and
+  // parallel to the plane containing the edge respectively.
+  double b = min(1.0, 0.5 * dist.length2());
+  double a = sqrt(b * (2 - b));
+  return ((2.5 + 2 * sqrt(3.0) + 8.5 * a) * a +
+          (2 + 2 * sqrt(3.0) / 3 + 6.5 * (1 - b)) * b +
+          (23 + 16 / sqrt(3.0)) * DBL_EPSILON) * DBL_EPSILON;
+}
+
+double GetUpdateMinDistanceMaxError(S1ChordAngle dist) {
+  // There are two cases for the maximum error in UpdateMinDistance(),
+  // depending on whether the closest point is interior to the edge.
+  return max(GetUpdateMinInteriorDistanceMaxError(dist),
+             dist.GetS2PointConstructorMaxError());
+}
+
+S2Point Project(const S2Point& x, const S2Point& a, const S2Point& b,
+                const Vector3_d& a_cross_b) {
+  S2_DCHECK(S2::IsUnitLength(a));
+  S2_DCHECK(S2::IsUnitLength(b));
+  S2_DCHECK(S2::IsUnitLength(x));
+
+  // Find the closest point to X along the great circle through AB.
+  S2Point p = x - (x.DotProd(a_cross_b) / a_cross_b.Norm2()) * a_cross_b;
+
+  // If this point is on the edge AB, then it's the closest point.
+  if (S2::SimpleCCW(a_cross_b, a, p) && S2::SimpleCCW(p, b, a_cross_b)) {
+    return p.Normalize();
+  }
+  // Otherwise, the closest point is either A or B.
+  return ((x - a).Norm2() <= (x - b).Norm2()) ? a : b;
+}
+
+S2Point Project(const S2Point& x, const S2Point& a, const S2Point& b) {
+  return Project(x, a, b, S2::RobustCrossProd(a, b));
+}
+
+bool UpdateEdgePairMinDistance(
+    const S2Point& a0, const S2Point& a1,
+    const S2Point& b0, const S2Point& b1,
+    S1ChordAngle* min_dist) {
+  if (*min_dist == S1ChordAngle::Zero()) {
+    return false;
+  }
+  if (S2::CrossingSign(a0, a1, b0, b1) > 0) {
+    *min_dist = S1ChordAngle::Zero();
+    return true;
+  }
+  // Otherwise, the minimum distance is achieved at an endpoint of at least
+  // one of the two edges.  We use "|" rather than "||" below to ensure that
+  // all four possibilities are always checked.
+  //
+  // The calculation below computes each of the six vertex-vertex distances
+  // twice (this could be optimized).
+  return (UpdateMinDistance(a0, b0, b1, min_dist) |
+          UpdateMinDistance(a1, b0, b1, min_dist) |
+          UpdateMinDistance(b0, a0, a1, min_dist) |
+          UpdateMinDistance(b1, a0, a1, min_dist));
+}
+
+bool UpdateEdgePairMaxDistance(
+    const S2Point& a0, const S2Point& a1,
+    const S2Point& b0, const S2Point& b1,
+    S1ChordAngle* max_dist) {
+  if (*max_dist == S1ChordAngle::Straight()) {
+    return false;
+  }
+  if (S2::CrossingSign(a0, a1, -b0, -b1) > 0) {
+    *max_dist = S1ChordAngle::Straight();
+    return true;
+  }
+  // Otherwise, the maximum distance is achieved at an endpoint of at least
+  // one of the two edges.  We use "|" rather than "||" below to ensure that
+  // all four possibilities are always checked.
+  //
+  // The calculation below computes each of the six vertex-vertex distances
+  // twice (this could be optimized).
+  return (UpdateMaxDistance(a0, b0, b1, max_dist) |
+          UpdateMaxDistance(a1, b0, b1, max_dist) |
+          UpdateMaxDistance(b0, a0, a1, max_dist) |
+          UpdateMaxDistance(b1, a0, a1, max_dist));
+}
+
+std::pair<S2Point, S2Point> GetEdgePairClosestPoints(
+      const S2Point& a0, const S2Point& a1,
+      const S2Point& b0, const S2Point& b1) {
+  if (S2::CrossingSign(a0, a1, b0, b1) > 0) {
+    S2Point x = S2::GetIntersection(a0, a1, b0, b1);
+    return std::make_pair(x, x);
+  }
+  // We save some work by first determining which vertex/edge pair achieves
+  // the minimum distance, and then computing the closest point on that edge.
+  S1ChordAngle min_dist;
+  AlwaysUpdateMinDistance<true>(a0, b0, b1, &min_dist);
+  enum { A0, A1, B0, B1 } closest_vertex = A0;
+  if (UpdateMinDistance(a1, b0, b1, &min_dist)) { closest_vertex = A1; }
+  if (UpdateMinDistance(b0, a0, a1, &min_dist)) { closest_vertex = B0; }
+  if (UpdateMinDistance(b1, a0, a1, &min_dist)) { closest_vertex = B1; }
+  switch (closest_vertex) {
+    case A0: return std::make_pair(a0, Project(a0, b0, b1));
+    case A1: return std::make_pair(a1, Project(a1, b0, b1));
+    case B0: return std::make_pair(Project(b0, a0, a1), b0);
+    case B1: return std::make_pair(Project(b1, a0, a1), b1);
+    default: S2_LOG(FATAL) << "Unreached (to suppress Android compiler warning)";
+  }
+}
+
+bool IsEdgeBNearEdgeA(const S2Point& a0, const S2Point& a1,
+                      const S2Point& b0, const S2Point& b1,
+                      S1Angle tolerance) {
+  S2_DCHECK_LT(tolerance.radians(), M_PI / 2);
+  S2_DCHECK_GT(tolerance.radians(), 0);
+  // The point on edge B=b0b1 furthest from edge A=a0a1 is either b0, b1, or
+  // some interior point on B.  If it is an interior point on B, then it must be
+  // one of the two points where the great circle containing B (circ(B)) is
+  // furthest from the great circle containing A (circ(A)).  At these points,
+  // the distance between circ(B) and circ(A) is the angle between the planes
+  // containing them.
+
+  Vector3_d a_ortho = S2::RobustCrossProd(a0, a1).Normalize();
+  const S2Point a_nearest_b0 = Project(b0, a0, a1, a_ortho);
+  const S2Point a_nearest_b1 = Project(b1, a0, a1, a_ortho);
+  // If a_nearest_b0 and a_nearest_b1 have opposite orientation from a0 and a1,
+  // we invert a_ortho so that it points in the same direction as a_nearest_b0 x
+  // a_nearest_b1.  This helps us handle the case where A and B are oppositely
+  // oriented but otherwise might be near each other.  We check orientation and
+  // invert rather than computing a_nearest_b0 x a_nearest_b1 because those two
+  // points might be equal, and have an unhelpful cross product.
+  if (s2pred::Sign(a_ortho, a_nearest_b0, a_nearest_b1) < 0) a_ortho *= -1;
+
+  // To check if all points on B are within tolerance of A, we first check to
+  // see if the endpoints of B are near A.  If they are not, B is not near A.
+  const S1Angle b0_distance(b0, a_nearest_b0);
+  const S1Angle b1_distance(b1, a_nearest_b1);
+  if (b0_distance > tolerance || b1_distance > tolerance)
+    return false;
+
+  // If b0 and b1 are both within tolerance of A, we check to see if the angle
+  // between the planes containing B and A is greater than tolerance.  If it is
+  // not, no point on B can be further than tolerance from A (recall that we
+  // already know that b0 and b1 are close to A, and S2Edges are all shorter
+  // than 180 degrees).  The angle between the planes containing circ(A) and
+  // circ(B) is the angle between their normal vectors.
+  const Vector3_d b_ortho = S2::RobustCrossProd(b0, b1).Normalize();
+  const S1Angle planar_angle(a_ortho, b_ortho);
+  if (planar_angle <= tolerance)
+    return true;
+
+
+  // As planar_angle approaches M_PI, the projection of a_ortho onto the plane
+  // of B approaches the null vector, and normalizing it is numerically
+  // unstable.  This makes it unreliable or impossible to identify pairs of
+  // points where circ(A) is furthest from circ(B).  At this point in the
+  // algorithm, this can only occur for two reasons:
+  //
+  //  1.) b0 and b1 are closest to A at distinct endpoints of A, in which case
+  //      the opposite orientation of a_ortho and b_ortho means that A and B are
+  //      in opposite hemispheres and hence not close to each other.
+  //
+  //  2.) b0 and b1 are closest to A at the same endpoint of A, in which case
+  //      the orientation of a_ortho was chosen arbitrarily to be that of a0
+  //      cross a1.  B must be shorter than 2*tolerance and all points in B are
+  //      close to one endpoint of A, and hence to A.
+  //
+  // The logic applies when planar_angle is robustly greater than M_PI/2, but
+  // may be more computationally expensive than the logic beyond, so we choose a
+  // value close to M_PI.
+  if (planar_angle >= S1Angle::Radians(M_PI - 0.01)) {
+    return (S1Angle(b0, a0) < S1Angle(b0, a1)) ==
+        (S1Angle(b1, a0) < S1Angle(b1, a1));
+  }
+
+  // Finally, if either of the two points on circ(B) where circ(B) is furthest
+  // from circ(A) lie on edge B, edge B is not near edge A.
+  //
+  // The normalized projection of a_ortho onto the plane of circ(B) is one of
+  // the two points along circ(B) where it is furthest from circ(A).  The other
+  // is -1 times the normalized projection.
+  S2Point furthest = (a_ortho - a_ortho.DotProd(b_ortho) * b_ortho).Normalize();
+  S2_DCHECK(S2::IsUnitLength(furthest));
+  S2Point furthest_inv = -1 * furthest;
+
+  // A point p lies on B if you can proceed from b_ortho to b0 to p to b1 and
+  // back to b_ortho without ever turning right.  We test this for furthest and
+  // furthest_inv, and return true if neither point lies on B.
+  return !((s2pred::Sign(b_ortho, b0, furthest) > 0 &&
+            s2pred::Sign(furthest, b1, b_ortho) > 0) ||
+           (s2pred::Sign(b_ortho, b0, furthest_inv) > 0 &&
+            s2pred::Sign(furthest_inv, b1, b_ortho) > 0));
+}
+
+}  // namespace S2
diff --git a/src/s2/s2edge_distances.h b/src/s2/s2edge_distances.h
new file mode 100644 (file)
index 0000000..57df6f3
--- /dev/null
@@ -0,0 +1,192 @@
+// Copyright 2005 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// Author: ericv@google.com (Eric Veach)
+//
+// Defines a collection of functions for computing the distance to an edge,
+// interpolating along an edge, projecting points onto edges, etc.
+
+#ifndef S2_S2EDGE_DISTANCES_H_
+#define S2_S2EDGE_DISTANCES_H_
+
+#include <utility>
+
+#include "s2/s1angle.h"
+#include "s2/s1chord_angle.h"
+#include "s2/s2point.h"
+
+namespace S2 {
+
+/////////////////////////////////////////////////////////////////////////////
+///////////////            (point, edge) functions            ///////////////
+
+// Returns the minimum distance from X to any point on the edge AB.  All
+// arguments should be unit length.  The result is very accurate for small
+// distances but may have some numerical error if the distance is large
+// (approximately Pi/2 or greater).  The case A == B is handled correctly.
+//
+// If you want to compare a distance against a fixed threshold, e.g.
+//    if (S2::GetDistance(x, a, b) < limit)
+// then it is significantly faster to use UpdateMinDistance() below.
+S1Angle GetDistance(const S2Point& x, const S2Point& a, const S2Point& b);
+
+// Returns true if the distance from X to the edge AB is less than "limit".
+// (Specify limit.Successor() for "less than or equal to".)  This method is
+// significantly faster than GetDistance().  If you want to compare against a
+// fixed S1Angle, you should convert it to an S1ChordAngle once and save the
+// value, since this step is relatively expensive.
+//
+// See s2pred::CompareEdgeDistance() for an exact version of this predicate.
+bool IsDistanceLess(const S2Point& x, const S2Point& a, const S2Point& b,
+                    S1ChordAngle limit);
+
+// If the distance from X to the edge AB is less than "min_dist", this
+// method updates "min_dist" and returns true.  Otherwise it returns false.
+// The case A == B is handled correctly.
+//
+// Use this method when you want to compute many distances and keep track of
+// the minimum.  It is significantly faster than using GetDistance(),
+// because (1) using S1ChordAngle is much faster than S1Angle, and (2) it
+// can save a lot of work by not actually computing the distance when it is
+// obviously larger than the current minimum.
+bool UpdateMinDistance(const S2Point& x, const S2Point& a, const S2Point& b,
+                       S1ChordAngle* min_dist);
+
+// If the maximum distance from X to the edge AB is greater than "max_dist",
+// this method updates "max_dist" and returns true.  Otherwise it returns false.
+// The case A == B is handled correctly.
+bool UpdateMaxDistance(const S2Point& x, const S2Point& a, const S2Point& b,
+                       S1ChordAngle* max_dist);
+
+// Returns the maximum error in the result of UpdateMinDistance (and
+// associated functions such as UpdateMinInteriorDistance, IsDistanceLess,
+// etc), assuming that all input points are normalized to within the bounds
+// guaranteed by S2Point::Normalize().  The error can be added or subtracted
+// from an S1ChordAngle "x" using x.PlusError(error).
+//
+// Note that accuracy goes down as the distance approaches 0 degrees or 180
+// degrees (for different reasons).  Near 0 degrees the error is acceptable
+// for all practical purposes (about 1.2e-15 radians ~= 8 nanometers).  For
+// exactly antipodal points the maximum error is quite high (0.5 meters), but
+// this error drops rapidly as the points move away from antipodality
+// (approximately 1 millimeter for points that are 50 meters from antipodal,
+// and 1 micrometer for points that are 50km from antipodal).
+//
+// TODO(ericv): Currently the error bound does not hold for edges whose
+// endpoints are antipodal to within about 1e-15 radians (less than 1 micron).
+// This could be fixed by extending S2::RobustCrossProd to use higher
+// precision when necessary.
+double GetUpdateMinDistanceMaxError(S1ChordAngle dist);
+
+// Returns true if the minimum distance from X to the edge AB is attained at
+// an interior point of AB (i.e., not an endpoint), and that distance is less
+// than "limit".  (Specify limit.Successor() for "less than or equal to".)
+bool IsInteriorDistanceLess(const S2Point& x,
+                            const S2Point& a, const S2Point& b,
+                            S1ChordAngle limit);
+
+// If the minimum distance from X to AB is attained at an interior point of AB
+// (i.e., not an endpoint), and that distance is less than "min_dist", then
+// this method updates "min_dist" and returns true.  Otherwise returns false.
+bool UpdateMinInteriorDistance(const S2Point& x,
+                               const S2Point& a, const S2Point& b,
+                               S1ChordAngle* min_dist);
+
+// Returns the point along the edge AB that is closest to the point X.
+// The fractional distance of this point along the edge AB can be obtained
+// using GetDistanceFraction() above.  Requires that all vectors have
+// unit length.
+S2Point Project(const S2Point& x, const S2Point& a, const S2Point& b);
+
+// A slightly more efficient version of Project() where the cross product of
+// the two endpoints has been precomputed.  The cross product does not need to
+// be normalized, but should be computed using S2::RobustCrossProd() for the
+// most accurate results.  Requires that x, a, and b have unit length.
+S2Point Project(const S2Point& x, const S2Point& a, const S2Point& b,
+                const Vector3_d& a_cross_b);
+
+
+/////////////////////////////////////////////////////////////////////////////
+///////////////         (point along edge) functions          ///////////////
+
+
+// Given a point X and an edge AB, returns the distance ratio AX / (AX + BX).
+// If X happens to be on the line segment AB, this is the fraction "t" such
+// that X == Interpolate(t, A, B).  Requires that A and B are distinct.
+double GetDistanceFraction(const S2Point& x,
+                           const S2Point& a, const S2Point& b);
+
+// Returns the point X along the line segment AB whose distance from A is the
+// given fraction "t" of the distance AB.  Does NOT require that "t" be
+// between 0 and 1.  Note that all distances are measured on the surface of
+// the sphere, so this is more complicated than just computing (1-t)*a + t*b
+// and normalizing the result.
+S2Point Interpolate(double t, const S2Point& a, const S2Point& b);
+
+// Like Interpolate(), except that the parameter "ax" represents the desired
+// distance from A to the result X rather than a fraction between 0 and 1.
+S2Point InterpolateAtDistance(S1Angle ax, const S2Point& a, const S2Point& b);
+
+
+/////////////////////////////////////////////////////////////////////////////
+///////////////            (edge, edge) functions             ///////////////
+
+
+// Like UpdateMinDistance(), but computes the minimum distance between the
+// given pair of edges.  (If the two edges cross, the distance is zero.)
+// The cases a0 == a1 and b0 == b1 are handled correctly.
+bool UpdateEdgePairMinDistance(const S2Point& a0, const S2Point& a1,
+                               const S2Point& b0, const S2Point& b1,
+                               S1ChordAngle* min_dist);
+
+// As above, but for maximum distances.  If one edge crosses the antipodal
+// reflection of the other, the distance is Pi.
+bool UpdateEdgePairMaxDistance(const S2Point& a0, const S2Point& a1,
+                               const S2Point& b0, const S2Point& b1,
+                               S1ChordAngle* max_dist);
+
+// Returns the pair of points (a, b) that achieves the minimum distance
+// between edges a0a1 and b0b1, where "a" is a point on a0a1 and "b" is a
+// point on b0b1.  If the two edges intersect, "a" and "b" are both equal to
+// the intersection point.  Handles a0 == a1 and b0 == b1 correctly.
+std::pair<S2Point, S2Point> GetEdgePairClosestPoints(
+    const S2Point& a0, const S2Point& a1,
+    const S2Point& b0, const S2Point& b1);
+
+// Returns true if every point on edge B=b0b1 is no further than "tolerance"
+// from some point on edge A=a0a1.  Equivalently, returns true if the directed
+// Hausdorff distance from B to A is no more than "tolerance".
+// Requires that tolerance is less than 90 degrees.
+bool IsEdgeBNearEdgeA(const S2Point& a0, const S2Point& a1,
+                      const S2Point& b0, const S2Point& b1,
+                      S1Angle tolerance);
+
+
+//////////////////   Implementation details follow   ////////////////////
+
+
+inline bool IsDistanceLess(const S2Point& x, const S2Point& a,
+                           const S2Point& b, S1ChordAngle limit) {
+  return UpdateMinDistance(x, a, b, &limit);
+}
+
+inline bool IsInteriorDistanceLess(const S2Point& x, const S2Point& a,
+                                   const S2Point& b, S1ChordAngle limit) {
+  return UpdateMinInteriorDistance(x, a, b, &limit);
+}
+
+}  // namespace S2
+
+#endif  // S2_S2EDGE_DISTANCES_H_
diff --git a/src/s2/s2edge_tessellator.cc b/src/s2/s2edge_tessellator.cc
new file mode 100644 (file)
index 0000000..bbdc8a5
--- /dev/null
@@ -0,0 +1,276 @@
+// Copyright 2017 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// Author: ericv@google.com (Eric Veach)
+
+#include "s2/s2edge_tessellator.h"
+
+#include <cmath>
+#include "s2/s2edge_distances.h"
+#include "s2/s2latlng.h"
+#include "s2/s2pointutil.h"
+
+using std::vector;
+// Tessellation is implemented by subdividing the edge until the estimated
+// maximum error is below the given tolerance.  Estimating error is a hard
+// problem, especially when the only methods available are point evaluation of
+// the projection and its inverse.  (These are the only methods that
+// S2::Projection provides, which makes it easier and less error-prone to
+// implement new projections.)
+//
+// One technique that significantly increases robustness is to treat the
+// geodesic and projected edges as parametric curves rather than geometric ones.
+// Given a spherical edge AB and a projection p:S2->R2, let f(t) be the
+// normalized arc length parametrization of AB and let g(t) be the normalized
+// arc length parameterization of the projected edge p(A)p(B).  (In other words,
+// f(0)=A, f(1)=B, g(0)=p(A), g(1)=p(B).)  We now define the geometric error as
+// the maximum distance from the point p^-1(g(t)) to the geodesic edge AB for
+// any t in [0,1], where p^-1 denotes the inverse projection.  In other words,
+// the geometric error is the maximum distance from any point on the projected
+// edge (mapped back onto the sphere) to the geodesic edge AB.  On the other
+// hand we define the parametric error as the maximum distance between the
+// points f(t) and p^-1(g(t)) for any t in [0,1], i.e. the maximum distance
+// (measured on the sphere) between the geodesic and projected points at the
+// same interpolation fraction t.
+//
+// The easiest way to estimate the parametric error is to simply evaluate both
+// edges at their midpoints and measure the distance between them (the "midpoint
+// method").  This is very fast and works quite well for most edges, however it
+// has one major drawback: it doesn't handle points of inflection (i.e., points
+// where the curvature changes sign).  For example, edges in the Mercator and
+// Plate Carree projections always curve towards the equator relative to the
+// corresponding geodesic edge, so in these projections there is a point of
+// inflection whenever the projected edge crosses the equator.  The worst case
+// occurs when the edge endpoints have different longitudes but the same
+// absolute latitude, since in that case the error is non-zero but the edges
+// have exactly the same midpoint (on the equator).
+//
+// One solution to this problem is to split the input edges at all inflection
+// points (i.e., along the equator in the case of the Mercator and Plate Carree
+// projections).  However for general projections these inflection points can
+// occur anywhere on the sphere (e.g., consider the Transverse Mercator
+// projection).  This could be addressed by adding methods to the S2Projection
+// interface to split edges at inflection points but this would make it harder
+// and more error-prone to implement new projections.
+//
+// Another problem with this approach is that the midpoint method sometimes
+// underestimates the true error even when edges do not cross the equator.  For
+// the Plate Carree and Mercator projections, the midpoint method can
+// underestimate the error by up to 3%.
+//
+// Both of these problems can be solved as follows.  We assume that the error
+// can be modeled as a convex combination of two worst-case functions, one
+// where the error is maximized at the edge midpoint and another where the
+// error is *minimized* (i.e., zero) at the edge midpoint.  For example, we
+// could choose these functions as:
+//
+//    E1(x) = 1 - x^2
+//    E2(x) = x * (1 - x^2)
+//
+// where for convenience we use an interpolation parameter "x" in the range
+// [-1, 1] rather than the original "t" in the range [0, 1].  Note that both
+// error functions must have roots at x = {-1, 1} since the error must be zero
+// at the edge endpoints.  E1 is simply a parabola whose maximum value is 1
+// attained at x = 0, while E2 is a cubic with an additional root at x = 0,
+// and whose maximum value is 2 * sqrt(3) / 9 attained at x = 1 / sqrt(3).
+//
+// Next, it is convenient to scale these functions so that the both have a
+// maximum value of 1.  E1 already satisfies this requirement, and we simply
+// redefine E2 as
+//
+//   E2(x) = x * (1 - x^2) / (2 * sqrt(3) / 9)
+//
+// Now define x0 to be the point where these two functions intersect, i.e. the
+// point in the range (-1, 1) where E1(x0) = E2(x0).  This value has the very
+// convenient property that if we evaluate the actual error E(x0), then the
+// maximum error on the entire interval [-1, 1] is bounded by
+//
+//   E(x) <= E(x0) / E1(x0)
+//
+// since whether the error is modeled using E1 or E2, the resulting function
+// has the same maximum value (namely E(x0) / E1(x0)).  If it is modeled as
+// some other convex combination of E1 and E2, the maximum value can only
+// decrease.
+//
+// Finally, since E2 is not symmetric about the y-axis, we must also allow for
+// the possibility that the error is a convex combination of E1 and -E2.  This
+// can be handled by evaluating the error at E(-x0) as well, and then
+// computing the final error bound as
+//
+//   E(x) <= max(E(x0), E(-x0)) / E1(x0) .
+//
+// Effectively, this method is simply evaluating the error at two points about
+// 1/3 and 2/3 of the way along the edges, and then scaling the maximum of
+// these two errors by a constant factor.  Intuitively, the reason this works
+// is that if the two edges cross somewhere in the interior, then at least one
+// of these points will be far from the crossing.
+//
+// The actual algorithm implemented below has some additional refinements.
+// First, edges longer than 90 degrees are always subdivided; this avoids
+// various unusual situations that can happen with very long edges, and there
+// is really no reason to avoid adding vertices to edges that are so long.
+//
+// Second, the error function E1 above needs to be modified to take into
+// account spherical distortions.  (It turns out that spherical distortions are
+// beneficial in the case of E2, i.e. they only make its error estimates
+// slightly more conservative.)  To do this, we model E1 as the maximum error
+// in a Plate Carree edge of length 90 degrees or less.  This turns out to be
+// an edge from 45:-90 to 45:90 (in lat:lng format).  The corresponding error
+// as a function of "x" in the range [-1, 1] can be computed as the distance
+// between the the the Plate Caree edge point (45, 90 * x) and the geodesic
+// edge point (90 - 45 * abs(x), 90 * sgn(x)).  Using the Haversine formula,
+// the corresponding function E1 (normalized to have a maximum value of 1) is:
+//
+//   E1(x) =
+//     asin(sqrt(sin(Pi / 8 * (1 - x)) ^ 2 +
+//               sin(Pi / 4 * (1 - x)) ^ 2 * cos(Pi / 4) * sin(Pi / 4 * x))) /
+//     asin(sqrt((1 - 1 / sqrt(2)) / 2))
+//
+// Note that this function does not need to be evaluated at runtime, it
+// simply affects the calculation of the value x0 where E1(x0) = E2(x0)
+// and the corresponding scaling factor C = 1 / E1(x0).
+//
+// ------------------------------------------------------------------
+//
+// In the case of the Mercator and Plate Carree projections this strategy
+// produces a conservative upper bound (verified using 10 million random
+// edges).  Furthermore the bound is nearly tight; the scaling constant is
+// C = 1.19289, whereas the maximum observed value was 1.19254.
+//
+// Compared to the simpler midpoint evaluation method, this strategy requires
+// more function evaluations (currently twice as many, but with a smarter
+// tessellation algorithm it will only be 50% more).  It also results in a
+// small amount of additional tessellation (about 1.5%) compared to the
+// midpoint method, but this is due almost entirely to the fact that the
+// midpoint method does not yield conservative error estimates.
+//
+// For random edges with a tolerance of 1 meter, the expected amount of
+// overtessellation is as follows:
+//
+//                   Midpoint Method    Cubic Method
+//   Plate Carree               1.8%            3.0%
+//   Mercator                  15.8%           17.4%
+
+// The interpolation fraction at which the two edges are evaluated in order to
+// measure the error between them.  (Edges are evaluated at two points measured
+// this fraction from either end.)  With respect to the algorithm description
+// above, this value is t0 = (1 - x0) / 2 in the range [0, 1] that corresponds
+// to x0 in the range [-1, 1] chosen such that E1(x0) == E2(x0).
+static constexpr double kInterpolationFraction = 0.31215691082248312;
+
+// The following is the value of E1(x0) == E2(x0).
+static constexpr double kScaleFactor = 0.83829992569888509;
+
+S1Angle S2EdgeTessellator::kMinTolerance() {
+  // This distance is less than 1 micrometer on the Earth's surface, but is
+  // still much larger than the expected projection and interpolation errors.
+  return S1Angle::Radians(1e-13);
+}
+
+S2EdgeTessellator::S2EdgeTessellator(const S2::Projection* projection,
+                                     S1Angle tolerance)
+    : proj_(*projection) {
+  if (tolerance < kMinTolerance()) S2_LOG(DFATAL) << "Tolerance too small";
+
+  // Rather than scaling the error estimate as described above, instead we scale
+  // the tolerance.  See algorithm description at the top of this file.
+  scaled_tolerance_ = S1ChordAngle(kScaleFactor *
+                                   std::max(tolerance, kMinTolerance()));
+}
+
+S1ChordAngle S2EdgeTessellator::EstimateMaxError(
+    const R2Point& pa, const S2Point& a, const R2Point& pb, const S2Point& b)
+    const {
+  // See the algorithm description at the top of this file.
+
+  // We always tessellate edges longer than 90 degrees on the sphere, since the
+  // approximation below is not robust enough to handle such edges.
+  if (a.DotProd(b) < -1e-14) return S1ChordAngle::Infinity();
+
+  constexpr double t1 = kInterpolationFraction;
+  constexpr double t2 = 1 - kInterpolationFraction;
+  S2Point mid1 = S2::Interpolate(t1, a, b);
+  S2Point mid2 = S2::Interpolate(t2, a, b);
+  S2Point pmid1 = proj_.Unproject(proj_.Interpolate(t1, pa, pb));
+  S2Point pmid2 = proj_.Unproject(proj_.Interpolate(t2, pa, pb));
+  return std::max(S1ChordAngle(mid1, pmid1), S1ChordAngle(mid2, pmid2));
+}
+
+void S2EdgeTessellator::AppendProjected(
+    const S2Point& a, const S2Point& b, vector<R2Point>* vertices) const {
+  R2Point pa = proj_.Project(a);
+  if (vertices->empty()) {
+    vertices->push_back(pa);
+  } else {
+    pa = proj_.WrapDestination(vertices->back(), pa);
+    S2_DCHECK_EQ(vertices->back(), pa) << "Appended edges must form a chain";
+  }
+  R2Point pb = proj_.Project(b);
+  AppendProjected(pa, a, pb, b, vertices);
+}
+
+// Given a geodesic edge AB, split the edge as necessary and append all
+// projected vertices except the first to "vertices".
+//
+// The maximum recursion depth is (M_PI / kMinTolerance()) < 45, and the
+// frame size is small so stack overflow should not be an issue.
+void S2EdgeTessellator::AppendProjected(const R2Point& pa, const S2Point& a,
+                                        const R2Point& pb_in, const S2Point& b,
+                                        vector<R2Point>* vertices) const {
+  R2Point pb = proj_.WrapDestination(pa, pb_in);
+  if (EstimateMaxError(pa, a, pb, b) <= scaled_tolerance_) {
+    vertices->push_back(pb);
+  } else {
+    S2Point mid = (a + b).Normalize();
+    R2Point pmid = proj_.WrapDestination(pa, proj_.Project(mid));
+    AppendProjected(pa, a, pmid, mid, vertices);
+    AppendProjected(pmid, mid, pb, b, vertices);
+  }
+}
+
+void S2EdgeTessellator::AppendUnprojected(
+    const R2Point& pa, const R2Point& pb, vector<S2Point>* vertices) const {
+  S2Point a = proj_.Unproject(pa);
+  S2Point b = proj_.Unproject(pb);
+  if (vertices->empty()) {
+    vertices->push_back(a);
+  } else {
+    // Note that coordinate wrapping can create a small amount of error.  For
+    // example in the edge chain "0:-175, 0:179, 0:-177", the first edge is
+    // transformed into "0:-175, 0:-181" while the second is transformed into
+    // "0:179, 0:183".  The two coordinate pairs for the middle vertex
+    // ("0:-181" and "0:179") may not yield exactly the same S2Point.
+    S2_DCHECK(S2::ApproxEquals(vertices->back(), a))
+        << "Appended edges must form a chain";
+  }
+  AppendUnprojected(pa, a, pb, b, vertices);
+}
+
+// Like AppendProjected, but interpolates a projected edge and appends the
+// corresponding points on the sphere.
+void S2EdgeTessellator::AppendUnprojected(
+    const R2Point& pa, const S2Point& a,
+    const R2Point& pb_in, const S2Point& b, vector<S2Point>* vertices) const {
+  // See notes above regarding measuring the interpolation error.
+  R2Point pb = proj_.WrapDestination(pa, pb_in);
+  if (EstimateMaxError(pa, a, pb, b) <= scaled_tolerance_) {
+    vertices->push_back(b);
+  } else {
+    R2Point pmid = proj_.Interpolate(0.5, pa, pb);
+    S2Point mid = proj_.Unproject(pmid);
+    AppendUnprojected(pa, a, pmid, mid, vertices);
+    AppendUnprojected(pmid, mid, pb, b, vertices);
+  }
+}
diff --git a/src/s2/s2edge_tessellator.h b/src/s2/s2edge_tessellator.h
new file mode 100644 (file)
index 0000000..bcc6ca3
--- /dev/null
@@ -0,0 +1,101 @@
+// Copyright 2017 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// Author: ericv@google.com (Eric Veach)
+
+#ifndef S2_S2EDGE_TESSELLATOR_H_
+#define S2_S2EDGE_TESSELLATOR_H_
+
+#include <vector>
+#include "s2/r2.h"
+#include "s2/s1chord_angle.h"
+#include "s2/s2point.h"
+#include "s2/s2projections.h"
+
+// Given an edge in some 2D projection (e.g., Mercator), S2EdgeTessellator
+// converts the edge into a chain of spherical geodesic edges such that the
+// maximum distance between the original edge and the geodesic edge chain is
+// at most "tolerance".  Similarly, it can convert a spherical geodesic edge
+// into a chain of edges in a given 2D projection such that the maximum
+// distance between the geodesic edge and the chain of projected edges is at
+// most "tolerance".
+class S2EdgeTessellator {
+ public:
+  // Constructs an S2EdgeTessellator using the given projection and error
+  // tolerance.  The projection object must be valid for the entire lifetime
+  // of this object.  (Projections are typically declared once and reused.)
+  //
+  // Method            | Input                  | Output
+  // ------------------|------------------------|-----------------------
+  // AppendProjected   | S2 geodesics           | Planar projected edges
+  // AppendUnprojected | Planar projected edges | S2 geodesics
+  S2EdgeTessellator(const S2::Projection* projection, S1Angle tolerance);
+
+  // Converts the spherical geodesic edge AB to a chain of planar edges in the
+  // given projection and appends the corresponding vertices to "vertices".
+  //
+  // This method can be called multiple times with the same output vector to
+  // convert an entire polyline or loop.  All vertices of the first edge are
+  // appended, but the first vertex of each subsequent edge is omitted (and
+  // must match the last vertex of the previous edge).
+  //
+  // If the given projection has one or more coordinate axes that "wrap", then
+  // every vertex's coordinates will be as close as possible to the previous
+  // vertex's coordinates.  Note that this may yield vertices whose
+  // coordinates are outside the usual range.  For example, tessellating the
+  // edge (0:170, 0:-170) (in lat:lng notation) yields (0:170, 0:190).
+  void AppendProjected(const S2Point& a, const S2Point& b,
+                       std::vector<R2Point>* vertices) const;
+
+  // Converts the planar edge AB in the given projection to a chain of
+  // spherical geodesic edges and appends the vertices to "vertices".
+  //
+  // This method can be called multiple times with the same output vector to
+  // convert an entire polyline or loop.  All vertices of the first edge are
+  // appended, but the first vertex of each subsequent edge is omitted (and is
+  // required to match that last vertex of the previous edge).
+  //
+  // Note that to construct an S2Loop, you must call vertices->pop_back() at
+  // the very end to eliminate the duplicate first and last vertex.  Note also
+  // that if the given projection involves coordinate "wrapping" (e.g. across
+  // the 180 degree meridian) then the first and last vertices may not be
+  // exactly the same.
+  void AppendUnprojected(const R2Point& a, const R2Point& b,
+                         std::vector<S2Point>* vertices) const;
+
+  // Returns the minimum supported tolerance (which corresponds to a distance
+  // less than one micrometer on the Earth's surface).
+  static S1Angle kMinTolerance();
+
+ private:
+  S1ChordAngle EstimateMaxError(const R2Point& pa, const S2Point& a,
+                                const R2Point& pb, const S2Point& b) const;
+
+  void AppendUnprojected(const R2Point& pa, const S2Point& a,
+                         const R2Point& pb, const S2Point& b,
+                         std::vector<S2Point>* vertices) const;
+
+  void AppendProjected(const R2Point& pa, const S2Point& a,
+                       const R2Point& pb, const S2Point& b,
+                       std::vector<R2Point>* vertices) const;
+
+  const S2::Projection& proj_;
+
+  // The given tolerance scaled by a constant fraction so that it can be
+  // compared against the result returned by EstimateMaxError().
+  S1ChordAngle scaled_tolerance_;
+};
+
+#endif  // S2_S2EDGE_TESSELLATOR_H_
diff --git a/src/s2/s2edge_vector_shape.h b/src/s2/s2edge_vector_shape.h
new file mode 100644 (file)
index 0000000..cd50a89
--- /dev/null
@@ -0,0 +1,85 @@
+// Copyright 2013 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// Author: ericv@google.com (Eric Veach)
+
+#ifndef S2_S2EDGE_VECTOR_SHAPE_H_
+#define S2_S2EDGE_VECTOR_SHAPE_H_
+
+#include <utility>
+#include <vector>
+#include "s2/s2shape.h"
+
+// S2EdgeVectorShape is an S2Shape representing an arbitrary set of edges.  It
+// is mainly used for testing, but it can also be useful if you have, say, a
+// collection of polylines and don't care about memory efficiency (since this
+// class would store most of the vertices twice).
+//
+// Note that if you already have data stored in an S2Loop, S2Polyline, or
+// S2Polygon, then you would be better off using the "Shape" class defined
+// within those classes (e.g., S2Loop::Shape).  Similarly, if the vertex data
+// is stored in your own data structures, you can easily write your own
+// subclass of S2Shape that points to the existing vertex data rather than
+// copying it.
+class S2EdgeVectorShape : public S2Shape {
+ public:
+  // Constructs an empty edge vector.
+  S2EdgeVectorShape() {}
+
+  // Constructs an S2EdgeVectorShape from a vector of edges.
+  explicit S2EdgeVectorShape(std::vector<std::pair<S2Point, S2Point>> edges) {
+    edges_ = std::move(edges);
+  }
+
+  // Creates an S2EdgeVectorShape containing a single edge.
+  S2EdgeVectorShape(const S2Point& a, const S2Point& b) {
+    edges_.push_back(std::make_pair(a, b));
+  }
+
+  ~S2EdgeVectorShape() override = default;
+
+  // Adds an edge to the vector.
+  //
+  // IMPORTANT: This method should only be called *before* adding the
+  // S2EdgeVectorShape to an S2ShapeIndex.  S2Shapes can only be modified by
+  // removing them from the index, making changes, and adding them back again.
+  void Add(const S2Point& a, const S2Point& b) {
+    edges_.push_back(std::make_pair(a, b));
+  }
+
+  // S2Shape interface:
+  int num_edges() const final { return static_cast<int>(edges_.size()); }
+  Edge edge(int e) const final {
+    return Edge(edges_[e].first, edges_[e].second);
+  }
+  int dimension() const final { return 1; }
+  ReferencePoint GetReferencePoint() const final {
+    return ReferencePoint::Contained(false);
+  }
+  int num_chains() const final { return static_cast<int>(edges_.size()); }
+  Chain chain(int i) const final { return Chain(i, 1); }
+  Edge chain_edge(int i, int j) const final {
+    S2_DCHECK_EQ(j, 0);
+    return Edge(edges_[i].first, edges_[i].second);
+  }
+  ChainPosition chain_position(int e) const final {
+    return ChainPosition(e, 0);
+  }
+
+ private:
+  std::vector<std::pair<S2Point, S2Point>> edges_;
+};
+
+#endif  // S2_S2EDGE_VECTOR_SHAPE_H_
diff --git a/src/s2/s2error.cc b/src/s2/s2error.cc
new file mode 100644 (file)
index 0000000..6c8beab
--- /dev/null
@@ -0,0 +1,29 @@
+// Copyright 2013 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// Author: ericv@google.com (Eric Veach)
+
+#include "s2/s2error.h"
+
+#include "s2/base/stringprintf.h"
+
+void S2Error::Init(Code code, const char* format, ...) {
+  code_ = code;
+  text_.clear();
+  va_list ap;
+  va_start(ap, format);
+  StringAppendV(&text_, format, ap);
+  va_end(ap);
+}
diff --git a/src/s2/s2error.h b/src/s2/s2error.h
new file mode 100644 (file)
index 0000000..4144963
--- /dev/null
@@ -0,0 +1,147 @@
+// Copyright 2013 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// Author: ericv@google.com (Eric Veach)
+//
+// S2Error is a simple class consisting of an error code and a human-readable
+// error message.
+
+#ifndef S2_S2ERROR_H_
+#define S2_S2ERROR_H_
+
+#include <cstdarg>
+#include <ostream>
+#include <string>
+
+#include "s2/base/port.h"
+
+// This class is intended to be copied by value as desired.  It uses
+// the default copy constructor and assignment operator.
+class S2Error {
+ public:
+  enum Code {
+    OK = 0,                  // No error.
+
+    ////////////////////////////////////////////////////////////////////
+    // Generic errors, not specific to geometric objects:
+
+    UNKNOWN = 1000,              // Unknown error.
+    UNIMPLEMENTED = 1001,        // Operation is not implemented.
+    OUT_OF_RANGE = 1002,         // Argument is out of range.
+    INVALID_ARGUMENT = 1003,     // Invalid argument (other than a range error).
+    FAILED_PRECONDITION = 1004,  // Object is not in the required state.
+    INTERNAL = 1005,             // An internal invariant has failed.
+    DATA_LOSS = 1006,            // Data loss or corruption.
+    RESOURCE_EXHAUSTED = 1007,   // A resource has been exhausted.
+
+    ////////////////////////////////////////////////////////////////////
+    // Error codes in the following range can be defined by clients:
+
+    USER_DEFINED_START = 1000000,
+    USER_DEFINED_END   = 9999999,
+
+    ////////////////////////////////////////////////////////////////////
+    // Errors that apply to more than one type of geometry:
+
+    NOT_UNIT_LENGTH = 1,     // Vertex is not unit length.
+    DUPLICATE_VERTICES = 2,  // There are two identical vertices.
+    ANTIPODAL_VERTICES = 3,  // There are two antipodal vertices.
+
+    ////////////////////////////////////////////////////////////////////
+    // S2Loop errors:
+
+    LOOP_NOT_ENOUGH_VERTICES = 100,  // Loop with fewer than 3 vertices.
+    LOOP_SELF_INTERSECTION = 101,    // Loop has a self-intersection.
+
+    ////////////////////////////////////////////////////////////////////
+    // S2Polygon errors:
+
+    POLYGON_LOOPS_SHARE_EDGE = 200,  // Two polygon loops share an edge.
+    POLYGON_LOOPS_CROSS = 201,       // Two polygon loops cross.
+    POLYGON_EMPTY_LOOP = 202,        // Polygon has an empty loop.
+    POLYGON_EXCESS_FULL_LOOP = 203,  // Non-full polygon has a full loop.
+
+    // InitOriented() was called and detected inconsistent loop orientations.
+    POLYGON_INCONSISTENT_LOOP_ORIENTATIONS = 204,
+
+    // Loop depths don't correspond to any valid nesting hierarchy.
+    POLYGON_INVALID_LOOP_DEPTH = 205,
+
+    // Actual polygon nesting does not correspond to the nesting hierarchy
+    // encoded by the loop depths.
+    POLYGON_INVALID_LOOP_NESTING = 206,
+
+    ////////////////////////////////////////////////////////////////////
+    // S2Builder errors:
+
+    // The S2Builder snap function moved a vertex by more than the specified
+    // snap radius.
+    BUILDER_SNAP_RADIUS_TOO_SMALL = 300,
+
+    // S2Builder expected all edges to have siblings (as specified by
+    // S2Builder::GraphOptions::SiblingPairs::REQUIRE), but some were missing.
+    BUILDER_MISSING_EXPECTED_SIBLING_EDGES = 301,
+
+    // S2Builder found an unexpected degenerate edge.  For example,
+    // Graph::GetLeftTurnMap() does not support degenerate edges.
+    BUILDER_UNEXPECTED_DEGENERATE_EDGE = 302,
+
+    // S2Builder found a vertex with (indegree != outdegree), which means
+    // that the given edges cannot be assembled into loops.
+    BUILDER_EDGES_DO_NOT_FORM_LOOPS = 303,
+
+    // The edges provided to S2Builder cannot be assembled into a polyline.
+    BUILDER_EDGES_DO_NOT_FORM_POLYLINE = 304,
+
+    // There was an attempt to assemble a polygon from degenerate geometry
+    // without having specified a predicate to decide whether the output is
+    // the empty polygon (containing no points) or the full polygon
+    // (containing all points).
+    BUILDER_IS_FULL_PREDICATE_NOT_SPECIFIED = 305,
+  };
+  S2Error() : code_(OK), text_() {}
+
+  // Set the error to the given code and printf-style message.  Note that you
+  // can prepend text to an existing error by calling Init() more than once:
+  //
+  //   error->Init(error->code(), "Loop %d: %s", j, error->text().c_str());
+  void Init(Code code, const char* format, ...) ABSL_PRINTF_ATTRIBUTE(3, 4);
+
+  bool ok() const { return code_ == OK; }
+  Code code() const { return code_; }
+  std::string text() const { return text_; }
+
+  // Clear the error to contain the OK code and no error message.
+  void Clear();
+
+ private:
+  Code code_;
+  std::string text_;
+};
+
+
+//////////////////   Implementation details follow   ////////////////////
+
+
+inline std::ostream& operator<<(std::ostream& os, const S2Error& error) {
+  return os << error.text();
+}
+
+inline void S2Error::Clear() {
+  code_ = OK;
+  text_.clear();
+}
+
+#endif  // S2_S2ERROR_H_
diff --git a/src/s2/s2furthest_edge_query.cc b/src/s2/s2furthest_edge_query.cc
new file mode 100644 (file)
index 0000000..5b7b3ec
--- /dev/null
@@ -0,0 +1,117 @@
+// Copyright Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#include "s2/s2furthest_edge_query.h"
+
+#include <vector>
+
+#include "s2/s2edge_distances.h"
+
+void S2FurthestEdgeQuery::Options::set_conservative_min_distance(
+    S1ChordAngle min_distance) {
+  set_max_distance(Distance(min_distance.PlusError(
+      -S2::GetUpdateMinDistanceMaxError(min_distance)).Predecessor()));
+}
+
+void S2FurthestEdgeQuery::Options::set_conservative_min_distance(
+    S1Angle min_distance) {
+  set_conservative_min_distance(S1ChordAngle(min_distance));
+}
+
+// See s2closest_edge_query.cc for justifications of
+// max_brute_force_index_size() for that query.
+int S2FurthestEdgeQuery::PointTarget::max_brute_force_index_size() const {
+  // Using BM_FindFurthest (which finds the single furthest edge), the
+  // break-even points are approximately 100, 400, and 600 edges for point
+  // cloud, fractal, and regular loop geometry respectively.
+  return 300;
+}
+
+int S2FurthestEdgeQuery::EdgeTarget::max_brute_force_index_size() const {
+  // Using BM_FindFurthestToEdge (which finds the single furthest edge), the
+  // break-even points are approximately 80, 100, and 230 edges for point
+  // cloud, fractal, and regular loop geometry respectively.
+  return 110;
+}
+
+int S2FurthestEdgeQuery::CellTarget::max_brute_force_index_size() const {
+  // Using BM_FindFurthestToCell (which finds the single furthest edge), the
+  // break-even points are approximately 70, 100, and 170 edges for point
+  // cloud, fractal, and regular loop geometry respectively.
+  return 100;
+}
+
+int S2FurthestEdgeQuery::ShapeIndexTarget::max_brute_force_index_size() const {
+  // For BM_FindFurthestToSameSizeAbuttingIndex (which uses two nearby indexes
+  // with similar edge counts), the break-even points are approximately 30,
+  // 100, and 130 edges for point cloud, fractal, and regular loop geometry
+  // respectively.
+  return 70;
+}
+
+S2FurthestEdgeQuery::S2FurthestEdgeQuery() {
+  // Prevent inline constructor bloat by defining here.
+}
+
+S2FurthestEdgeQuery::~S2FurthestEdgeQuery() {
+  // Prevent inline destructor bloat by defining here.
+}
+
+void S2FurthestEdgeQuery::FindFurthestEdges(
+    Target* target, std::vector<S2FurthestEdgeQuery::Result>* results) {
+  results->clear();
+  for (auto result : base_.FindClosestEdges(target, options_)) {
+    results->push_back(S2FurthestEdgeQuery::Result(result));
+  }
+}
+
+S2FurthestEdgeQuery::Result S2FurthestEdgeQuery::FindFurthestEdge(
+    Target* target) {
+  static_assert(sizeof(Options) <= 32, "Consider not copying Options here");
+  Options tmp_options = options_;
+  tmp_options.set_max_results(1);
+  Base::Result base_result = base_.FindClosestEdge(target, tmp_options);
+  return S2FurthestEdgeQuery::Result(base_result);
+}
+
+bool S2FurthestEdgeQuery::IsDistanceGreater(
+    Target* target, S1ChordAngle limit) {
+  static_assert(sizeof(Options) <= 32, "Consider not copying Options here");
+  Options tmp_options = options_;
+  tmp_options.set_max_results(1);
+  tmp_options.set_min_distance(limit);
+  tmp_options.set_max_error(S1ChordAngle::Straight());
+  return base_.FindClosestEdge(target, tmp_options).shape_id() >= 0;
+}
+
+bool S2FurthestEdgeQuery::IsDistanceGreaterOrEqual(
+    Target* target, S1ChordAngle limit) {
+  static_assert(sizeof(Options) <= 32, "Consider not copying Options here");
+  Options tmp_options = options_;
+  tmp_options.set_max_results(1);
+  tmp_options.set_inclusive_min_distance(limit);
+  tmp_options.set_max_error(S1ChordAngle::Straight());
+  return base_.FindClosestEdge(target, tmp_options).shape_id() >= 0;
+}
+
+bool S2FurthestEdgeQuery::IsConservativeDistanceGreaterOrEqual(
+    Target* target, S1ChordAngle limit) {
+  static_assert(sizeof(Options) <= 32, "Consider not copying Options here");
+  Options tmp_options = options_;
+  tmp_options.set_max_results(1);
+  tmp_options.set_conservative_min_distance(limit);
+  tmp_options.set_max_error(S1ChordAngle::Straight());
+  return base_.FindClosestEdge(target, tmp_options).shape_id() >= 0;
+}
diff --git a/src/s2/s2furthest_edge_query.h b/src/s2/s2furthest_edge_query.h
new file mode 100644 (file)
index 0000000..8a50024
--- /dev/null
@@ -0,0 +1,439 @@
+// Copyright Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#ifndef S2_S2FURTHEST_EDGE_QUERY_H_
+#define S2_S2FURTHEST_EDGE_QUERY_H_
+
+#include <memory>
+#include <queue>
+#include <type_traits>
+#include <vector>
+
+#include "s2/base/logging.h"
+#include "absl/base/macros.h"
+#include "absl/container/inlined_vector.h"
+#include "s2/_fp_contract_off.h"
+#include "s2/s1angle.h"
+#include "s2/s1chord_angle.h"
+#include "s2/s2cell.h"
+#include "s2/s2cell_id.h"
+#include "s2/s2closest_edge_query_base.h"
+#include "s2/s2edge_distances.h"
+#include "s2/s2max_distance_targets.h"
+#include "s2/s2shape_index.h"
+
+// S2FurthestEdgeQuery is a helper class for searching within an S2ShapeIndex
+// for the furthest edge(s) to a given query point, edge, S2Cell, or geometry
+// collection.  The furthest edge is defined as the one which maximizes the
+// distance from any point on that edge to any point on the target geometry.
+
+// As an example, given a set of polylines, the following code efficiently
+// finds the furthest 5 edges to a query point:
+//
+// void Test(const vector<S2Polyline*>& polylines, const S2Point& point) {
+//   MutableS2ShapeIndex index;
+//   for (S2Polyline* polyline : polylines) {
+//     index.Add(new S2Polyline::Shape(polyline));
+//   }
+//   S2FurthestEdgeQuery query(&index);
+//   query.mutable_options()->set_max_results(5);
+//   S2FurthestEdgeQuery::PointTarget target(point);
+//   for (const auto& result : query.FindFurthestEdges(&target)) {
+//     // The Result struct contains the following accessors:
+//     //   "distance()" is the distance to the edge.
+//     //   "shape_id()" identifies the S2Shape containing the edge.
+//     //   "edge_id()" identifies the edge with the given shape.
+//     // The following convenience methods may also be useful:
+//     //   query.GetEdge(result) returns the endpoints of the edge.
+//     int polyline_index = result.shape_id();
+//     int edge_index = result.edge_id();
+//     S1ChordAngle distance = result.distance();
+//     S2Shape::Edge edge = query.GetEdge(result);
+//   }
+// }
+//
+// You can find either the k furthest edges, or all edges no closer than a
+// given radius, or both (i.e., the k furthest edges no closer than a given
+// minimum radius).
+// E.g. to find all the edges further than 5 kilometers, call
+//
+//   query.mutable_options()->set_min_distance(
+//       S2Earth::ToAngle(util::units::Kilometers(5)));
+//
+// By default *all* edges are returned, so you should always specify either
+// max_results() or min_distance() or both.  Setting min distance may not be
+// very restrictive, so strongly consider using max_results().  There is also a
+// FindFurthestEdge() convenience method that returns only the single furthest
+// edge.
+//
+// Note that by default, distances are measured to the boundary and interior
+// of polygons.  To change this behavior, call set_include_interiors(false).
+//
+// If you only need to test whether the distance is above or below a given
+// threshold (e.g., 10 km), you can use the IsDistanceGreater() method.  This
+// is much faster than actually calculating the distance with
+// FindFurthestEdge(), since the implementation can stop as soon as it can
+// prove that the maximum distance is either above or below the threshold.
+//
+// To find the furthest edges to a query edge rather than a point, use:
+//
+//   S2FurthestEdgeQuery::EdgeTarget target(v0, v1);
+//   query.FindFurthestEdges(&target);
+//
+// Similarly you can find the furthest edges to an S2Cell by using an
+// S2FurthestEdgeQuery::CellTarget, and you can find the furthest edges to an
+// arbitrary collection of points, polylines, and polygons by using an
+// S2FurthestEdgeQuery::ShapeIndexTarget.
+//
+// The implementation is designed to be fast for both simple and complex
+// geometric objects.
+class S2FurthestEdgeQuery {
+ public:
+  // See S2FurthestEdgeQueryBase for full documentation.
+
+  // S2MaxDistance is a thin wrapper around S1ChordAngle that implements the
+  // Distance concept required by S2ClosestEdgeQueryBase.  It inverts the sense
+  // of some methods to enable the closest edge query to return furthest
+  // edges.
+  // Distance and Base are made private to prevent leakage outside of this
+  // class.  The private and public sections are interleaved since the public
+  // options class needs the private Base class.
+ private:
+  using Distance = S2MaxDistance;
+  using Base = S2ClosestEdgeQueryBase<Distance>;
+
+ public:
+  // Options that control the set of edges returned.  Note that by default
+  // *all* edges are returned, so you will always want to set either the
+  // max_results() option or the min_distance() option (or both).
+  class Options : public Base::Options {
+   public:
+    // See S2ClosestEdgeQueryBase::Options for the full set of options.
+    Options();
+
+    // The following methods are like the corresponding max_distance() methods
+    // in S2ClosestEdgeQuery, except that they specify the minimum distance to
+    // the target.
+    S1ChordAngle min_distance() const;
+    void set_min_distance(S1ChordAngle min_distance);
+    void set_inclusive_min_distance(S1ChordAngle min_distance);
+    void set_conservative_min_distance(S1ChordAngle min_distance);
+
+    void set_min_distance(S1Angle min_distance);
+    void set_inclusive_min_distance(S1Angle min_distance);
+    void set_conservative_min_distance(S1Angle min_distance);
+
+    // Versions of set_max_error() that accept S1ChordAngle / S1Angle.
+    // (See S2ClosestEdgeQueryBaseOptions for details.)
+    S1ChordAngle max_error() const;
+    void set_max_error(S1ChordAngle max_error);
+    void set_max_error(S1Angle max_error);
+
+    // Inherited options (see s2closestedgequerybase.h for details):
+    using Base::Options::set_max_results;
+    using Base::Options::set_include_interiors;
+    using Base::Options::set_use_brute_force;
+
+   private:
+    // The S2MaxDistance versions of these methods are not intended for
+    // public use.
+    using Base::Options::set_max_distance;
+    using Base::Options::set_max_error;
+    using Base::Options::max_distance;
+    using Base::Options::max_error;
+  };
+
+  // "Target" represents the geometry to which the distance is measured.
+  // There are subtypes for measuring the distance to a point, an edge, an
+  // S2Cell, or an S2ShapeIndex (an arbitrary collection of geometry).  Note
+  // that S2DistanceTarget<Distance> is equivalent to S2MaxDistanceTarget in
+  // s2max_distance_targets, which the following subtypes
+  // (e.g. S2MaxDistancePointTarget) extend.
+  using Target = S2DistanceTarget<Distance>;
+
+  // Target subtype that computes the furthest distance to a point.
+  class PointTarget final : public S2MaxDistancePointTarget {
+   public:
+    explicit PointTarget(const S2Point& point);
+    int max_brute_force_index_size() const override;
+  };
+
+  // Target subtype that computes the furthest distance to an edge.
+  class EdgeTarget final : public S2MaxDistanceEdgeTarget {
+   public:
+    explicit EdgeTarget(const S2Point& a, const S2Point& b);
+    int max_brute_force_index_size() const override;
+  };
+
+  // Target subtype that computes the furthest distance to an S2Cell
+  // (including the interior of the cell).
+  class CellTarget final : public S2MaxDistanceCellTarget {
+   public:
+    explicit CellTarget(const S2Cell& cell);
+    int max_brute_force_index_size() const override;
+  };
+
+  // Target subtype that computes the furthest distance to an S2ShapeIndex
+  // (an arbitrary collection of points, polylines, and/or polygons).
+  //
+  // By default, distances are measured to the boundary and interior of
+  // polygons in the S2ShapeIndex rather than to polygon boundaries only.
+  // If you wish to change this behavior, you may call
+  //
+  //   target.set_include_interiors(false);
+  //
+  // (see S2MaxDistanceShapeIndexTarget for details).
+  class ShapeIndexTarget final : public S2MaxDistanceShapeIndexTarget {
+   public:
+    explicit ShapeIndexTarget(const S2ShapeIndex* index);
+    int max_brute_force_index_size() const override;
+  };
+
+  // Result class to pass back to user.  We choose to pass back this result
+  // type, which has an S1ChordAngle as its distance, rather than the
+  // Base::Result returned from the query which uses S2MaxDistance.
+  class Result {
+   public:
+    // The default constructor, which yields an invalid result.
+    Result() : Result(S1ChordAngle::Negative(), -1, -1) {}
+
+    // Construct a Result from a Base::Result.
+    explicit Result(const Base::Result& base)
+        : Result(S1ChordAngle(base.distance()), base.shape_id(),
+                 base.edge_id()) {}
+
+    // Constructs a Result object for the given edge with the given distance.
+    Result(S1ChordAngle distance, int32 _shape_id, int32 _edge_id)
+        : distance_(distance), shape_id_(_shape_id), edge_id_(_edge_id) {}
+
+    // Returns true if this Result object does not refer to any edge.
+    // (The only case where an empty Result is returned is when the
+    // FindFurthestEdges() method does not find any edges that meet the
+    // specified criteria.)
+    bool is_empty() const { return edge_id_ < 0; }
+
+    // The distance from the target to this point.
+    S1ChordAngle distance() const { return distance_; }
+
+    // The edge identifiers.
+    int32 shape_id() const { return shape_id_; }
+    int32 edge_id() const { return edge_id_; }
+
+    // Returns true if two Result objects are identical.
+    friend bool operator==(const Result& x, const Result& y) {
+      return (x.distance_ == y.distance_ &&
+              x.shape_id_ == y.shape_id_ &&
+              x.edge_id_ == y.edge_id_);
+    }
+
+    // Compares edges first by distance, then by (shape_id, edge_id).
+    friend bool operator<(const Result& x, const Result& y) {
+      if (x.distance_ < y.distance_) return true;
+      if (y.distance_ < x.distance_) return false;
+      if (x.shape_id_ < y.shape_id_) return true;
+      if (y.shape_id_ < x.shape_id_) return false;
+      return x.edge_id_ < y.edge_id_;
+    }
+
+   private:
+    S1ChordAngle distance_;
+    int32 shape_id_;     // Identifies an indexed shape.
+    int32 edge_id_;      // Identifies an edge within the shape.
+  };
+
+  // Convenience constructor that calls Init().  Options may be specified here
+  // or changed at any time using the mutable_options() accessor method.
+  explicit S2FurthestEdgeQuery(const S2ShapeIndex* index,
+                               const Options& options = Options());
+
+  // Default constructor; requires Init() to be called.
+  S2FurthestEdgeQuery();
+  ~S2FurthestEdgeQuery();
+
+  S2FurthestEdgeQuery(const S2FurthestEdgeQuery&) = delete;
+  void operator=(const S2FurthestEdgeQuery&) = delete;
+
+  // Initializes the query.  Options may be specified here or changed at any
+  // time using the mutable_options() accessor method.
+  //
+  // REQUIRES: "index" must persist for the lifetime of this object.
+  // REQUIRES: ReInit() must be called if "index" is modified.
+  void Init(const S2ShapeIndex* index, const Options& options = Options());
+
+  // Reinitializes the query.  This method must be called whenever the
+  // underlying S2ShapeIndex is modified.
+  void ReInit();
+
+  // Returns a reference to the underlying S2ShapeIndex.
+  const S2ShapeIndex& index() const;
+
+  // Returns the query options.  Options can be modified between queries.
+  const Options& options() const;
+  Options* mutable_options();
+
+  // Returns the furthest edges to the given target that satisfy the given
+  // options.  This method may be called multiple times.
+  std::vector<Result> FindFurthestEdges(Target* target);
+
+  // This version can be more efficient when this method is called many times,
+  // since it does not require allocating a new vector on each call.
+  void FindFurthestEdges(Target* target, std::vector<Result>* results);
+
+  //////////////////////// Convenience Methods ////////////////////////
+
+  // Returns the furthest edge to the target.  If no edge satisfies the search
+  // criteria, then the Result object will have
+  // distance == S1ChordAngle::Negative() and shape_id == edge_id == -1.
+  Result FindFurthestEdge(Target* target);
+
+  // Returns the maximum distance to the target.  If the index or target is
+  // empty, returns S1ChordAngle::Negative().
+  //
+  // Use IsDistanceGreater() if you only want to compare the distance against a
+  // threshold value, since it is often much faster.
+  S1ChordAngle GetDistance(Target* target);
+
+  // Returns true if the distance to "target" is greater than "limit".
+  //
+  // This method is usually much faster than GetDistance(), since it is much
+  // less work to determine whether the maximum distance is above or below a
+  // threshold than it is to calculate the actual maximum distance.
+  bool IsDistanceGreater(Target* target, S1ChordAngle limit);
+
+  // Like IsDistanceGreater(), but also returns true if the distance to
+  // "target" is exactly equal to "limit".
+  bool IsDistanceGreaterOrEqual(Target* target, S1ChordAngle limit);
+
+  // Like IsDistanceGreaterOrEqual(), except that "limit" is decreased by the
+  // maximum error in the distance calculation.  This ensures that this
+  // function returns true whenever the true, exact distance is greater than
+  // or equal to "limit".
+  bool IsConservativeDistanceGreaterOrEqual(Target* target,
+                                            S1ChordAngle limit);
+
+  // Returns the endpoints of the given result edge.
+  // REQUIRES: result.edge_id >= 0
+  S2Shape::Edge GetEdge(const Result& result) const;
+
+ private:
+  Options options_;
+  Base base_;
+};
+
+
+//////////////////   Implementation details follow   ////////////////////
+
+inline S2FurthestEdgeQuery::Options::Options() {
+}
+
+inline S1ChordAngle S2FurthestEdgeQuery::Options::min_distance() const {
+  return S1ChordAngle(max_distance());
+}
+
+inline void S2FurthestEdgeQuery::Options::set_min_distance(
+    S1ChordAngle min_distance) {
+  Base::Options::set_max_distance(Distance(min_distance));
+}
+
+inline void S2FurthestEdgeQuery::Options::set_min_distance(
+    S1Angle min_distance) {
+  Base::Options::set_max_distance(Distance(S1ChordAngle(min_distance)));
+}
+
+inline void S2FurthestEdgeQuery::Options::set_inclusive_min_distance(
+    S1ChordAngle min_distance) {
+  set_min_distance(min_distance.Predecessor());
+}
+
+inline void S2FurthestEdgeQuery::Options::set_inclusive_min_distance(
+    S1Angle min_distance) {
+  set_inclusive_min_distance(S1ChordAngle(min_distance));
+}
+
+inline S1ChordAngle S2FurthestEdgeQuery::Options::max_error() const {
+  return S1ChordAngle(Base::Options::max_error());
+}
+
+inline void S2FurthestEdgeQuery::Options::set_max_error(
+    S1ChordAngle max_error) {
+  Base::Options::set_max_error(max_error);
+}
+
+inline void S2FurthestEdgeQuery::Options::set_max_error(S1Angle max_error) {
+  Base::Options::set_max_error(S1ChordAngle(max_error));
+}
+
+inline S2FurthestEdgeQuery::PointTarget::PointTarget(const S2Point& point)
+    : S2MaxDistancePointTarget(point) {
+}
+
+inline S2FurthestEdgeQuery::EdgeTarget::EdgeTarget(const S2Point& a,
+                                                  const S2Point& b)
+    : S2MaxDistanceEdgeTarget(a, b) {
+}
+
+inline S2FurthestEdgeQuery::CellTarget::CellTarget(const S2Cell& cell)
+    : S2MaxDistanceCellTarget(cell) {
+}
+
+inline S2FurthestEdgeQuery::ShapeIndexTarget::ShapeIndexTarget(
+    const S2ShapeIndex* index)
+    : S2MaxDistanceShapeIndexTarget(index) {
+}
+
+inline S2FurthestEdgeQuery::S2FurthestEdgeQuery(const S2ShapeIndex* index,
+                                                const Options& options) {
+  Init(index, options);
+}
+
+inline void S2FurthestEdgeQuery::Init(const S2ShapeIndex* index,
+                                      const Options& options) {
+  options_ = options;
+  base_.Init(index);
+}
+
+inline void S2FurthestEdgeQuery::ReInit() {
+  base_.ReInit();
+}
+
+inline const S2ShapeIndex& S2FurthestEdgeQuery::index() const {
+  return base_.index();
+}
+
+inline const S2FurthestEdgeQuery::Options&
+    S2FurthestEdgeQuery::options() const {
+  return options_;
+}
+
+inline S2FurthestEdgeQuery::Options* S2FurthestEdgeQuery::mutable_options() {
+  return &options_;
+}
+
+inline std::vector<S2FurthestEdgeQuery::Result>
+S2FurthestEdgeQuery::FindFurthestEdges(Target* target) {
+  std::vector<S2FurthestEdgeQuery::Result> results;
+  FindFurthestEdges(target, &results);
+  return results;
+}
+
+inline S1ChordAngle S2FurthestEdgeQuery::GetDistance(Target* target) {
+  return FindFurthestEdge(target).distance();
+}
+
+inline S2Shape::Edge S2FurthestEdgeQuery::GetEdge(const Result& result) const {
+  return index().shape(result.shape_id())->edge(result.edge_id());
+}
+
+#endif  // S2_S2FURTHEST_EDGE_QUERY_H_
diff --git a/src/s2/s2latlng.cc b/src/s2/s2latlng.cc
new file mode 100644 (file)
index 0000000..693079b
--- /dev/null
@@ -0,0 +1,90 @@
+// Copyright 2005 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// Author: ericv@google.com (Eric Veach)
+
+#include "s2/s2latlng.h"
+
+#include <algorithm>
+#include <ostream>
+
+#include "s2/base/logging.h"
+#include "s2/base/stringprintf.h"
+
+using std::max;
+using std::min;
+
+S2LatLng S2LatLng::Normalized() const {
+  // remainder(x, 2 * M_PI) reduces its argument to the range [-M_PI, M_PI]
+  // inclusive, which is what we want here.
+  return S2LatLng(max(-M_PI_2, min(M_PI_2, lat().radians())),
+                  remainder(lng().radians(), 2 * M_PI));
+}
+
+S2Point S2LatLng::ToPoint() const {
+  S2_DLOG_IF(ERROR, !is_valid())
+      << "Invalid S2LatLng in S2LatLng::ToPoint: " << *this;
+  double phi = lat().radians();
+  double theta = lng().radians();
+  double cosphi = cos(phi);
+  return S2Point(cos(theta) * cosphi, sin(theta) * cosphi, sin(phi));
+}
+
+S2LatLng::S2LatLng(const S2Point& p)
+  : coords_(Latitude(p).radians(), Longitude(p).radians()) {
+  // The latitude and longitude are already normalized.
+  S2_DLOG_IF(ERROR, !is_valid())
+      << "Invalid S2LatLng in constructor: " << *this;
+}
+
+S1Angle S2LatLng::GetDistance(const S2LatLng& o) const {
+  // This implements the Haversine formula, which is numerically stable for
+  // small distances but only gets about 8 digits of precision for very large
+  // distances (e.g. antipodal points).  Note that 8 digits is still accurate
+  // to within about 10cm for a sphere the size of the Earth.
+  //
+  // This could be fixed with another sin() and cos() below, but at that point
+  // you might as well just convert both arguments to S2Points and compute the
+  // distance that way (which gives about 15 digits of accuracy for all
+  // distances).
+
+  S2_DLOG_IF(ERROR, !is_valid())
+      << "Invalid S2LatLng in S2LatLng::GetDistance: " << *this;
+
+  S2_DLOG_IF(ERROR, !o.is_valid())
+      << "Invalid S2LatLng in S2LatLng::GetDistance: " << o;
+
+  double lat1 = lat().radians();
+  double lat2 = o.lat().radians();
+  double lng1 = lng().radians();
+  double lng2 = o.lng().radians();
+  double dlat = sin(0.5 * (lat2 - lat1));
+  double dlng = sin(0.5 * (lng2 - lng1));
+  double x = dlat * dlat + dlng * dlng * cos(lat1) * cos(lat2);
+  return S1Angle::Radians(2 * asin(sqrt(min(1.0, x))));
+}
+
+std::string S2LatLng::ToStringInDegrees() const {
+  S2LatLng pt = Normalized();
+  return StringPrintf("%f,%f", pt.lat().degrees(), pt.lng().degrees());
+}
+
+void S2LatLng::ToStringInDegrees(std::string* s) const {
+  *s = ToStringInDegrees();
+}
+
+std::ostream& operator<<(std::ostream& os, const S2LatLng& ll) {
+  return os << "[" << ll.lat() << ", " << ll.lng() << "]";
+}
diff --git a/src/s2/s2latlng.h b/src/s2/s2latlng.h
new file mode 100644 (file)
index 0000000..c449335
--- /dev/null
@@ -0,0 +1,234 @@
+// Copyright 2005 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// Author: ericv@google.com (Eric Veach)
+
+#ifndef S2_S2LATLNG_H_
+#define S2_S2LATLNG_H_
+
+#include <cmath>
+#include <iosfwd>
+#include <ostream>
+#include <string>
+
+#include "s2/base/integral_types.h"
+#include "s2/_fp_contract_off.h"
+#include "s2/r2.h"
+#include "s2/s1angle.h"
+#include "s2/util/math/vector.h"
+
+// This class represents a point on the unit sphere as a pair
+// of latitude-longitude coordinates.  Like the rest of the "geometry"
+// package, the intent is to represent spherical geometry as a mathematical
+// abstraction, so functions that are specifically related to the Earth's
+// geometry (e.g. easting/northing conversions) should be put elsewhere.
+//
+// This class is intended to be copied by value as desired.  It uses
+// the default copy constructor and assignment operator.
+class S2LatLng {
+ public:
+  // Constructor.  The latitude and longitude are allowed to be outside
+  // the is_valid() range.  However, note that most methods that accept
+  // S2LatLngs expect them to be normalized (see Normalized() below).
+  S2LatLng(S1Angle lat, S1Angle lng);
+
+  // The default constructor sets the latitude and longitude to zero.  This is
+  // mainly useful when declaring arrays, STL containers, etc.
+  S2LatLng();
+
+  // Convert a direction vector (not necessarily unit length) to an S2LatLng.
+  explicit S2LatLng(const S2Point& p);
+
+  // Returns an S2LatLng for which is_valid() will return false.
+  static S2LatLng Invalid();
+
+  // Convenience functions -- shorter than calling S1Angle::Radians(), etc.
+  static S2LatLng FromRadians(double lat_radians, double lng_radians);
+  static S2LatLng FromDegrees(double lat_degrees, double lng_degrees);
+  static S2LatLng FromE5(int32 lat_e5, int32 lng_e5);
+  static S2LatLng FromE6(int32 lat_e6, int32 lng_e6);
+  static S2LatLng FromE7(int32 lat_e7, int32 lng_e7);
+
+  // Convenience functions -- to use when args have been fixed32s in protos.
+  //
+  // The arguments are static_cast into int32, so very large unsigned values
+  // are treated as negative numbers.
+  static S2LatLng FromUnsignedE6(uint32 lat_e6, uint32 lng_e6);
+  static S2LatLng FromUnsignedE7(uint32 lat_e7, uint32 lng_e7);
+
+  // Methods to compute the latitude and longitude of a point separately.
+  static S1Angle Latitude(const S2Point& p);
+  static S1Angle Longitude(const S2Point& p);
+
+  // Accessor methods.
+  S1Angle lat() const { return S1Angle::Radians(coords_[0]); }
+  S1Angle lng() const { return S1Angle::Radians(coords_[1]); }
+  const R2Point& coords() const { return coords_; }
+
+  // Return true if the latitude is between -90 and 90 degrees inclusive
+  // and the longitude is between -180 and 180 degrees inclusive.
+  bool is_valid() const;
+
+  // Clamps the latitude to the range [-90, 90] degrees, and adds or subtracts
+  // a multiple of 360 degrees to the longitude if necessary to reduce it to
+  // the range [-180, 180].
+  S2LatLng Normalized() const;
+
+  // Converts a normalized S2LatLng to the equivalent unit-length vector.
+  // The maximum error in the result is 1.5 * DBL_EPSILON.  (This does not
+  // include the error of converting degrees, E5, E6, or E7 to radians.)
+  //
+  // Can be used just like an S2Point constructor.  For example:
+  //   S2Cap cap;
+  //   cap.AddPoint(S2Point(latlng));
+  explicit operator S2Point() const;
+
+  // Converts to an S2Point (equivalent to the operator above).
+  S2Point ToPoint() const;
+
+  // Returns the distance (measured along the surface of the sphere) to the
+  // given S2LatLng, implemented using the Haversine formula.  This is
+  // equivalent to
+  //
+  //   S1Angle(ToPoint(), o.ToPoint())
+  //
+  // except that this function is slightly faster, and is also somewhat less
+  // accurate for distances approaching 180 degrees (see s1angle.h for
+  // details).  Both S2LatLngs must be normalized.
+  S1Angle GetDistance(const S2LatLng& o) const;
+
+  // Simple arithmetic operations for manipulating latitude-longitude pairs.
+  // The results are not normalized (see Normalized()).
+  friend S2LatLng operator+(const S2LatLng& a, const S2LatLng& b);
+  friend S2LatLng operator-(const S2LatLng& a, const S2LatLng& b);
+  friend S2LatLng operator*(double m, const S2LatLng& a);
+  friend S2LatLng operator*(const S2LatLng& a, double m);
+
+  bool operator==(const S2LatLng& o) const { return coords_ == o.coords_; }
+  bool operator!=(const S2LatLng& o) const { return coords_ != o.coords_; }
+  bool operator<(const S2LatLng& o) const { return coords_ < o.coords_; }
+  bool operator>(const S2LatLng& o) const { return coords_ > o.coords_; }
+  bool operator<=(const S2LatLng& o) const { return coords_ <= o.coords_; }
+  bool operator>=(const S2LatLng& o) const { return coords_ >= o.coords_; }
+
+  bool ApproxEquals(const S2LatLng& o,
+                    S1Angle max_error = S1Angle::Radians(1e-15)) const {
+    return coords_.aequal(o.coords_, max_error.radians());
+  }
+
+  // Exports the latitude and longitude in degrees, separated by a comma.
+  // e.g. "94.518000,150.300000"
+  std::string ToStringInDegrees() const;
+  void ToStringInDegrees(std::string* s) const;
+
+ private:
+  // Internal constructor.
+  explicit S2LatLng(const R2Point& coords) : coords_(coords) {}
+
+  // This is internal to avoid ambiguity about which units are expected.
+  S2LatLng(double lat_radians, double lng_radians)
+    : coords_(lat_radians, lng_radians) {}
+
+  R2Point coords_;
+};
+
+// Hasher for S2LatLng.
+// Example use: std::unordered_map<S2LatLng, int, S2LatLngHash>.
+struct S2LatLngHash {
+  size_t operator()(const S2LatLng& lat_lng) const {
+    return GoodFastHash<R2Point>()(lat_lng.coords());
+  }
+};
+
+//////////////////   Implementation details follow   ////////////////////
+
+
+inline S2LatLng::S2LatLng(S1Angle lat, S1Angle lng)
+    : coords_(lat.radians(), lng.radians()) {}
+
+inline S2LatLng::S2LatLng() : coords_(0, 0) {}
+
+inline S2LatLng S2LatLng::FromRadians(double lat_radians, double lng_radians) {
+  return S2LatLng(lat_radians, lng_radians);
+}
+
+inline S2LatLng S2LatLng::FromDegrees(double lat_degrees, double lng_degrees) {
+  return S2LatLng(S1Angle::Degrees(lat_degrees), S1Angle::Degrees(lng_degrees));
+}
+
+inline S2LatLng S2LatLng::FromE5(int32 lat_e5, int32 lng_e5) {
+  return S2LatLng(S1Angle::E5(lat_e5), S1Angle::E5(lng_e5));
+}
+
+inline S2LatLng S2LatLng::FromE6(int32 lat_e6, int32 lng_e6) {
+  return S2LatLng(S1Angle::E6(lat_e6), S1Angle::E6(lng_e6));
+}
+
+inline S2LatLng S2LatLng::FromE7(int32 lat_e7, int32 lng_e7) {
+  return S2LatLng(S1Angle::E7(lat_e7), S1Angle::E7(lng_e7));
+}
+
+inline S2LatLng S2LatLng::FromUnsignedE6(uint32 lat_e6, uint32 lng_e6) {
+  return S2LatLng(S1Angle::UnsignedE6(lat_e6), S1Angle::UnsignedE6(lng_e6));
+}
+
+inline S2LatLng S2LatLng::FromUnsignedE7(uint32 lat_e7, uint32 lng_e7) {
+  return S2LatLng(S1Angle::UnsignedE7(lat_e7), S1Angle::UnsignedE7(lng_e7));
+}
+
+inline S2LatLng S2LatLng::Invalid() {
+  // These coordinates are outside the bounds allowed by is_valid().
+  return S2LatLng(M_PI, 2 * M_PI);
+}
+
+inline S1Angle S2LatLng::Latitude(const S2Point& p) {
+  // We use atan2 rather than asin because the input vector is not necessarily
+  // unit length, and atan2 is much more accurate than asin near the poles.
+  return S1Angle::Radians(atan2(p[2], sqrt(p[0]*p[0] + p[1]*p[1])));
+}
+
+inline S1Angle S2LatLng::Longitude(const S2Point& p) {
+  // Note that atan2(0, 0) is defined to be zero.
+  return S1Angle::Radians(atan2(p[1], p[0]));
+}
+
+inline bool S2LatLng::is_valid() const {
+  return (std::fabs(lat().radians()) <= M_PI_2 &&
+          std::fabs(lng().radians()) <= M_PI);
+}
+
+inline S2LatLng::operator S2Point() const {
+  return ToPoint();
+}
+
+inline S2LatLng operator+(const S2LatLng& a, const S2LatLng& b) {
+  return S2LatLng(a.coords_ + b.coords_);
+}
+
+inline S2LatLng operator-(const S2LatLng& a, const S2LatLng& b) {
+  return S2LatLng(a.coords_ - b.coords_);
+}
+
+inline S2LatLng operator*(double m, const S2LatLng& a) {
+  return S2LatLng(m * a.coords_);
+}
+
+inline S2LatLng operator*(const S2LatLng& a, double m) {
+  return S2LatLng(m * a.coords_);
+}
+
+std::ostream& operator<<(std::ostream& os, const S2LatLng& ll);
+
+#endif  // S2_S2LATLNG_H_
diff --git a/src/s2/s2latlng_rect.cc b/src/s2/s2latlng_rect.cc
new file mode 100644 (file)
index 0000000..d107b5b
--- /dev/null
@@ -0,0 +1,727 @@
+// Copyright 2005 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// Author: ericv@google.com (Eric Veach)
+
+#include "s2/s2latlng_rect.h"
+
+#include <algorithm>
+#include <cmath>
+#include <iosfwd>
+#include <iostream>
+
+#include "s2/base/logging.h"
+#include "s2/util/coding/coder.h"
+#include "s2/s2cap.h"
+#include "s2/s2cell.h"
+#include "s2/s2debug.h"
+#include "s2/s2edge_crossings.h"
+#include "s2/s2edge_distances.h"
+#include "s2/s2pointutil.h"
+
+using std::fabs;
+using std::max;
+using std::min;
+
+static const unsigned char kCurrentLosslessEncodingVersionNumber = 1;
+
+S2LatLngRect S2LatLngRect::FromCenterSize(const S2LatLng& center,
+                                          const S2LatLng& size) {
+  return FromPoint(center).Expanded(0.5 * size);
+}
+
+S2LatLngRect S2LatLngRect::FromPoint(const S2LatLng& p) {
+  S2_DLOG_IF(ERROR, !p.is_valid())
+      << "Invalid S2LatLng in S2LatLngRect::GetDistance: " << p;
+
+  return S2LatLngRect(p, p);
+}
+
+S2LatLngRect S2LatLngRect::FromPointPair(const S2LatLng& p1,
+                                         const S2LatLng& p2) {
+  S2_DLOG_IF(ERROR, !p1.is_valid())
+      << "Invalid S2LatLng in S2LatLngRect::FromPointPair: " << p1;
+
+  S2_DLOG_IF(ERROR, !p2.is_valid())
+      << "Invalid S2LatLng in S2LatLngRect::FromPointPair: " << p2;
+
+  return S2LatLngRect(R1Interval::FromPointPair(p1.lat().radians(),
+                                                p2.lat().radians()),
+                      S1Interval::FromPointPair(p1.lng().radians(),
+                                                p2.lng().radians()));
+}
+
+S2LatLngRect* S2LatLngRect::Clone() const {
+  return new S2LatLngRect(*this);
+}
+
+S2LatLng S2LatLngRect::GetVertex(int k) const {
+  // Twiddle bits to return the points in CCW order (lower left, lower right,
+  // upper right, upper left).
+  int i = (k >> 1) & 1;
+  return S2LatLng::FromRadians(lat_[i], lng_[i ^ (k & 1)]);
+}
+
+S2LatLng S2LatLngRect::GetCenter() const {
+  return S2LatLng::FromRadians(lat_.GetCenter(), lng_.GetCenter());
+}
+
+S2LatLng S2LatLngRect::GetSize() const {
+  return S2LatLng::FromRadians(lat_.GetLength(), lng_.GetLength());
+}
+
+double S2LatLngRect::Area() const {
+  if (is_empty()) return 0.0;
+  // This is the size difference of the two spherical caps, multiplied by
+  // the longitude ratio.
+  return lng().GetLength() * (sin(lat_hi()) - sin(lat_lo()));
+}
+
+S2Point S2LatLngRect::GetCentroid() const {
+  // When a sphere is divided into slices of constant thickness by a set of
+  // parallel planes, all slices have the same surface area.  This implies
+  // that the z-component of the centroid is simply the midpoint of the
+  // z-interval spanned by the S2LatLngRect.
+  //
+  // Similarly, it is easy to see that the (x,y) of the centroid lies in the
+  // plane through the midpoint of the rectangle's longitude interval.  We
+  // only need to determine the distance "d" of this point from the z-axis.
+  //
+  // Let's restrict our attention to a particular z-value.  In this z-plane,
+  // the S2LatLngRect is a circular arc.  The centroid of this arc lies on a
+  // radial line through the midpoint of the arc, and at a distance from the
+  // z-axis of
+  //
+  //     r * (sin(alpha) / alpha)
+  //
+  // where r = sqrt(1-z^2) is the radius of the arc, and "alpha" is half of
+  // the arc length (i.e., the arc covers longitudes [-alpha, alpha]).
+  //
+  // To find the centroid distance from the z-axis for the entire rectangle,
+  // we just need to integrate over the z-interval.  This gives
+  //
+  //    d = Integrate[sqrt(1-z^2)*sin(alpha)/alpha, z1..z2] / (z2 - z1)
+  //
+  // where [z1, z2] is the range of z-values covered by the rectangle.  This
+  // simplifies to
+  //
+  //    d = sin(alpha)/(2*alpha*(z2-z1))*(z2*r2 - z1*r1 + theta2 - theta1)
+  //
+  // where [theta1, theta2] is the latitude interval, z1=sin(theta1),
+  // z2=sin(theta2), r1=cos(theta1), and r2=cos(theta2).
+  //
+  // Finally, we want to return not the centroid itself, but the centroid
+  // scaled by the area of the rectangle.  The area of the rectangle is
+  //
+  //    A = 2 * alpha * (z2 - z1)
+  //
+  // which fortunately appears in the denominator of "d".
+
+  if (is_empty()) return S2Point();
+  double z1 = sin(lat_lo()), z2 = sin(lat_hi());
+  double r1 = cos(lat_lo()), r2 = cos(lat_hi());
+  double alpha = 0.5 * lng_.GetLength();
+  double r = sin(alpha) * (r2 * z2 - r1 * z1 + lat_.GetLength());
+  double lng = lng_.GetCenter();
+  double z = alpha * (z2 + z1) * (z2 - z1);  // scaled by the area
+  return S2Point(r * cos(lng), r * sin(lng), z);
+}
+
+bool S2LatLngRect::Contains(const S2LatLng& ll) const {
+  S2_DLOG_IF(ERROR, !ll.is_valid())
+      << "Invalid S2LatLng in S2LatLngRect::Contains: " << ll;
+
+  return (lat_.Contains(ll.lat().radians()) &&
+          lng_.Contains(ll.lng().radians()));
+}
+
+bool S2LatLngRect::InteriorContains(const S2Point& p) const {
+  return InteriorContains(S2LatLng(p));
+}
+
+bool S2LatLngRect::InteriorContains(const S2LatLng& ll) const {
+  S2_DLOG_IF(ERROR, !ll.is_valid())
+      << "Invalid S2LatLng in S2LatLngRect::InteriorContains: " << ll;
+
+  return (lat_.InteriorContains(ll.lat().radians()) &&
+          lng_.InteriorContains(ll.lng().radians()));
+}
+
+bool S2LatLngRect::Contains(const S2LatLngRect& other) const {
+  return lat_.Contains(other.lat_) && lng_.Contains(other.lng_);
+}
+
+bool S2LatLngRect::InteriorContains(const S2LatLngRect& other) const {
+  return (lat_.InteriorContains(other.lat_) &&
+          lng_.InteriorContains(other.lng_));
+}
+
+bool S2LatLngRect::Intersects(const S2LatLngRect& other) const {
+  return lat_.Intersects(other.lat_) && lng_.Intersects(other.lng_);
+}
+
+bool S2LatLngRect::InteriorIntersects(const S2LatLngRect& other) const {
+  return (lat_.InteriorIntersects(other.lat_) &&
+          lng_.InteriorIntersects(other.lng_));
+}
+
+bool S2LatLngRect::BoundaryIntersects(const S2Point& v0,
+                                      const S2Point& v1) const {
+  if (is_empty()) return false;
+  if (!lng_.is_full()) {
+    if (IntersectsLngEdge(v0, v1, lat_, lng_.lo())) return true;
+    if (IntersectsLngEdge(v0, v1, lat_, lng_.hi())) return true;
+  }
+  if (lat_.lo() != -M_PI_2 && IntersectsLatEdge(v0, v1, lat_.lo(), lng_)) {
+    return true;
+  }
+  if (lat_.hi() != M_PI_2 && IntersectsLatEdge(v0, v1, lat_.hi(), lng_)) {
+    return true;
+  }
+  return false;
+}
+
+void S2LatLngRect::AddPoint(const S2Point& p) {
+  AddPoint(S2LatLng(p));
+}
+
+void S2LatLngRect::AddPoint(const S2LatLng& ll) {
+  S2_DLOG_IF(ERROR, !ll.is_valid())
+      << "Invalid S2LatLng in S2LatLngRect::AddPoint: " << ll;
+
+  lat_.AddPoint(ll.lat().radians());
+  lng_.AddPoint(ll.lng().radians());
+}
+
+S2LatLngRect S2LatLngRect::Expanded(const S2LatLng& margin) const {
+  R1Interval lat = lat_.Expanded(margin.lat().radians());
+  S1Interval lng = lng_.Expanded(margin.lng().radians());
+  if (lat.is_empty() || lng.is_empty()) return Empty();
+  return S2LatLngRect(lat.Intersection(FullLat()), lng);
+}
+
+S2LatLngRect S2LatLngRect::PolarClosure() const {
+  if (lat_.lo() == -M_PI_2 || lat_.hi() == M_PI_2) {
+    return S2LatLngRect(lat_, S1Interval::Full());
+  }
+  return *this;
+}
+
+S2LatLngRect S2LatLngRect::Union(const S2LatLngRect& other) const {
+  return S2LatLngRect(lat_.Union(other.lat_),
+                      lng_.Union(other.lng_));
+}
+
+S2LatLngRect S2LatLngRect::Intersection(const S2LatLngRect& other) const {
+  R1Interval lat = lat_.Intersection(other.lat_);
+  S1Interval lng = lng_.Intersection(other.lng_);
+  if (lat.is_empty() || lng.is_empty()) {
+    // The lat/lng ranges must either be both empty or both non-empty.
+    return Empty();
+  }
+  return S2LatLngRect(lat, lng);
+}
+
+S2LatLngRect S2LatLngRect::ExpandedByDistance(S1Angle distance) const {
+  if (distance >= S1Angle::Zero()) {
+    // The most straightforward approach is to build a cap centered on each
+    // vertex and take the union of all the bounding rectangles (including the
+    // original rectangle; this is necessary for very large rectangles).
+
+    // TODO(ericv): Update this code to use an algorithm like the one below.
+    S1ChordAngle radius(distance);
+    S2LatLngRect r = *this;
+    for (int k = 0; k < 4; ++k) {
+      r = r.Union(S2Cap(GetVertex(k).ToPoint(), radius).GetRectBound());
+    }
+    return r;
+  } else {
+    // Shrink the latitude interval unless the latitude interval contains a pole
+    // and the longitude interval is full, in which case the rectangle has no
+    // boundary at that pole.
+    R1Interval lat_result(
+        lat().lo() <= FullLat().lo() && lng().is_full() ?
+            FullLat().lo() : lat().lo() - distance.radians(),
+        lat().hi() >= FullLat().hi() && lng().is_full() ?
+            FullLat().hi() : lat().hi() + distance.radians());
+    if (lat_result.is_empty()) {
+      return S2LatLngRect::Empty();
+    }
+
+    // Maximum absolute value of a latitude in lat_result. At this latitude,
+    // the cap occupies the largest longitude interval.
+    double max_abs_lat = max(-lat_result.lo(), lat_result.hi());
+
+    // Compute the largest longitude interval that the cap occupies. We use the
+    // law of sines for spherical triangles. For the details, see the comment in
+    // S2Cap::GetRectBound().
+    //
+    // When sin_a >= sin_c, the cap covers all the latitude.
+    double sin_a = sin(-distance.radians());
+    double sin_c = cos(max_abs_lat);
+    double max_lng_margin = sin_a < sin_c ? asin(sin_a / sin_c) : M_PI_2;
+
+    S1Interval lng_result = lng().Expanded(-max_lng_margin);
+    if (lng_result.is_empty()) {
+      return S2LatLngRect::Empty();
+    }
+    return S2LatLngRect(lat_result, lng_result);
+  }
+}
+
+S2Cap S2LatLngRect::GetCapBound() const {
+  // We consider two possible bounding caps, one whose axis passes
+  // through the center of the lat-long rectangle and one whose axis
+  // is the north or south pole.  We return the smaller of the two caps.
+
+  if (is_empty()) return S2Cap::Empty();
+
+  double pole_z, pole_angle;
+  if (lat_.lo() + lat_.hi() < 0) {
+    // South pole axis yields smaller cap.
+    pole_z = -1;
+    pole_angle = M_PI_2 + lat_.hi();
+  } else {
+    pole_z = 1;
+    pole_angle = M_PI_2 - lat_.lo();
+  }
+  S2Cap pole_cap(S2Point(0, 0, pole_z), S1Angle::Radians(pole_angle));
+
+  // For bounding rectangles that span 180 degrees or less in longitude, the
+  // maximum cap size is achieved at one of the rectangle vertices.  For
+  // rectangles that are larger than 180 degrees, we punt and always return a
+  // bounding cap centered at one of the two poles.
+  double lng_span = lng_.hi() - lng_.lo();
+  if (remainder(lng_span, 2 * M_PI) >= 0 && lng_span < 2 * M_PI) {
+    S2Cap mid_cap(GetCenter().ToPoint(), S1Angle::Radians(0));
+    for (int k = 0; k < 4; ++k) {
+      mid_cap.AddPoint(GetVertex(k).ToPoint());
+    }
+    if (mid_cap.height() < pole_cap.height())
+      return mid_cap;
+  }
+  return pole_cap;
+}
+
+S2LatLngRect S2LatLngRect::GetRectBound() const {
+  return *this;
+}
+
+bool S2LatLngRect::Contains(const S2Cell& cell) const {
+  // A latitude-longitude rectangle contains a cell if and only if it contains
+  // the cell's bounding rectangle.  This test is exact from a mathematical
+  // point of view, assuming that the bounds returned by S2Cell::GetRectBound()
+  // are tight.  However, note that there can be a loss of precision when
+  // converting between representations -- for example, if an S2Cell is
+  // converted to a polygon, the polygon's bounding rectangle may not contain
+  // the cell's bounding rectangle.  This has some slightly unexpected side
+  // effects; for instance, if one creates an S2Polygon from an S2Cell, the
+  // polygon will contain the cell, but the polygon's bounding box will not.
+  return Contains(cell.GetRectBound());
+}
+
+bool S2LatLngRect::MayIntersect(const S2Cell& cell) const {
+  // This test is cheap but is NOT exact (see s2latlng_rect.h).
+  return Intersects(cell.GetRectBound());
+}
+
+void S2LatLngRect::Encode(Encoder* encoder) const {
+  encoder->Ensure(40);  // sufficient
+
+  encoder->put8(kCurrentLosslessEncodingVersionNumber);
+  encoder->putdouble(lat_.lo());
+  encoder->putdouble(lat_.hi());
+  encoder->putdouble(lng_.lo());
+  encoder->putdouble(lng_.hi());
+
+  S2_DCHECK_GE(encoder->avail(), 0);
+}
+
+bool S2LatLngRect::Decode(Decoder* decoder) {
+  if (decoder->avail() < sizeof(unsigned char) + 4 * sizeof(double))
+    return false;
+  unsigned char version = decoder->get8();
+  if (version > kCurrentLosslessEncodingVersionNumber) return false;
+
+  double lat_lo = decoder->getdouble();
+  double lat_hi = decoder->getdouble();
+  lat_ = R1Interval(lat_lo, lat_hi);
+  double lng_lo = decoder->getdouble();
+  double lng_hi = decoder->getdouble();
+  lng_ = S1Interval(lng_lo, lng_hi);
+
+  if (!is_valid()) {
+    S2_DLOG_IF(ERROR, FLAGS_s2debug)
+        << "Invalid result in S2LatLngRect::Decode: " << *this;
+    return false;
+  }
+
+  return true;
+}
+
+bool S2LatLngRect::IntersectsLngEdge(const S2Point& a, const S2Point& b,
+                                     const R1Interval& lat, double lng) {
+  // Return true if the segment AB intersects the given edge of constant
+  // longitude.  The nice thing about edges of constant longitude is that
+  // they are straight lines on the sphere (geodesics).
+
+  return S2::CrossingSign(
+      a, b, S2LatLng::FromRadians(lat.lo(), lng).ToPoint(),
+      S2LatLng::FromRadians(lat.hi(), lng).ToPoint()) > 0;
+}
+
+bool S2LatLngRect::IntersectsLatEdge(const S2Point& a, const S2Point& b,
+                                     double lat, const S1Interval& lng) {
+  // Return true if the segment AB intersects the given edge of constant
+  // latitude.  Unfortunately, lines of constant latitude are curves on
+  // the sphere.  They can intersect a straight edge in 0, 1, or 2 points.
+  S2_DCHECK(S2::IsUnitLength(a));
+  S2_DCHECK(S2::IsUnitLength(b));
+
+  // First, compute the normal to the plane AB that points vaguely north.
+  Vector3_d z = S2::RobustCrossProd(a, b).Normalize();
+  if (z[2] < 0) z = -z;
+
+  // Extend this to an orthonormal frame (x,y,z) where x is the direction
+  // where the great circle through AB achieves its maximium latitude.
+  Vector3_d y = S2::RobustCrossProd(z, S2Point(0, 0, 1)).Normalize();
+  Vector3_d x = y.CrossProd(z);
+  S2_DCHECK(S2::IsUnitLength(x));
+  S2_DCHECK_GE(x[2], 0);
+
+  // Compute the angle "theta" from the x-axis (in the x-y plane defined
+  // above) where the great circle intersects the given line of latitude.
+  double sin_lat = sin(lat);
+  if (fabs(sin_lat) >= x[2]) {
+    return false;  // The great circle does not reach the given latitude.
+  }
+  S2_DCHECK_GT(x[2], 0);
+  double cos_theta = sin_lat / x[2];
+  double sin_theta = sqrt(1 - cos_theta * cos_theta);
+  double theta = atan2(sin_theta, cos_theta);
+
+  // The candidate intersection points are located +/- theta in the x-y
+  // plane.  For an intersection to be valid, we need to check that the
+  // intersection point is contained in the interior of the edge AB and
+  // also that it is contained within the given longitude interval "lng".
+
+  // Compute the range of theta values spanned by the edge AB.
+  S1Interval ab_theta = S1Interval::FromPointPair(
+      atan2(a.DotProd(y), a.DotProd(x)),
+      atan2(b.DotProd(y), b.DotProd(x)));
+
+  if (ab_theta.Contains(theta)) {
+    // Check if the intersection point is also in the given "lng" interval.
+    S2Point isect = x * cos_theta + y * sin_theta;
+    if (lng.Contains(atan2(isect[1], isect[0]))) return true;
+  }
+  if (ab_theta.Contains(-theta)) {
+    // Check if the intersection point is also in the given "lng" interval.
+    S2Point isect = x * cos_theta - y * sin_theta;
+    if (lng.Contains(atan2(isect[1], isect[0]))) return true;
+  }
+  return false;
+}
+
+bool S2LatLngRect::Intersects(const S2Cell& cell) const {
+  // First we eliminate the cases where one region completely contains the
+  // other.  Once these are disposed of, then the regions will intersect
+  // if and only if their boundaries intersect.
+
+  if (is_empty()) return false;
+  if (Contains(cell.GetCenterRaw())) return true;
+  if (cell.Contains(GetCenter().ToPoint())) return true;
+
+  // Quick rejection test (not required for correctness).
+  if (!Intersects(cell.GetRectBound())) return false;
+
+  // Precompute the cell vertices as points and latitude-longitudes.  We also
+  // check whether the S2Cell contains any corner of the rectangle, or
+  // vice-versa, since the edge-crossing tests only check the edge interiors.
+
+  S2Point cell_v[4];
+  S2LatLng cell_ll[4];
+  for (int i = 0; i < 4; ++i) {
+    cell_v[i] = cell.GetVertex(i);  // Must be normalized.
+    cell_ll[i] = S2LatLng(cell_v[i]);
+    if (Contains(cell_ll[i])) return true;
+    if (cell.Contains(GetVertex(i).ToPoint())) return true;
+  }
+
+  // Now check whether the boundaries intersect.  Unfortunately, a
+  // latitude-longitude rectangle does not have straight edges -- two edges
+  // are curved, and at least one of them is concave.
+
+  for (int i = 0; i < 4; ++i) {
+    S1Interval edge_lng = S1Interval::FromPointPair(
+        cell_ll[i].lng().radians(), cell_ll[(i+1)&3].lng().radians());
+    if (!lng_.Intersects(edge_lng)) continue;
+
+    const S2Point& a = cell_v[i];
+    const S2Point& b = cell_v[(i+1)&3];
+    if (edge_lng.Contains(lng_.lo())) {
+      if (IntersectsLngEdge(a, b, lat_, lng_.lo())) return true;
+    }
+    if (edge_lng.Contains(lng_.hi())) {
+      if (IntersectsLngEdge(a, b, lat_, lng_.hi())) return true;
+    }
+    if (IntersectsLatEdge(a, b, lat_.lo(), lng_)) return true;
+    if (IntersectsLatEdge(a, b, lat_.hi(), lng_)) return true;
+  }
+  return false;
+}
+
+S1Angle S2LatLngRect::GetDistance(const S2LatLngRect& other) const {
+  const S2LatLngRect& a = *this;
+  const S2LatLngRect& b = other;
+  S2_DCHECK(!a.is_empty());
+  S2_DCHECK(!b.is_empty());
+
+  // First, handle the trivial cases where the longitude intervals overlap.
+  if (a.lng().Intersects(b.lng())) {
+    if (a.lat().Intersects(b.lat()))
+      return S1Angle::Radians(0);  // Intersection between a and b.
+
+    // We found an overlap in the longitude interval, but not in the latitude
+    // interval. This means the shortest path travels along some line of
+    // longitude connecting the high-latitude of the lower rect with the
+    // low-latitude of the higher rect.
+    S1Angle lo, hi;
+    if (a.lat().lo() > b.lat().hi()) {
+      lo = b.lat_hi();
+      hi = a.lat_lo();
+    } else {
+      lo = a.lat_hi();
+      hi = b.lat_lo();
+    }
+    return hi - lo;
+  }
+
+  // The longitude intervals don't overlap. In this case, the closest points
+  // occur somewhere on the pair of longitudinal edges which are nearest in
+  // longitude-space.
+  S1Angle a_lng, b_lng;
+  S1Interval lo_hi = S1Interval::FromPointPair(a.lng().lo(), b.lng().hi());
+  S1Interval hi_lo = S1Interval::FromPointPair(a.lng().hi(), b.lng().lo());
+  if (lo_hi.GetLength() < hi_lo.GetLength()) {
+    a_lng = a.lng_lo();
+    b_lng = b.lng_hi();
+  } else {
+    a_lng = a.lng_hi();
+    b_lng = b.lng_lo();
+  }
+
+  // The shortest distance between the two longitudinal segments will include at
+  // least one segment endpoint. We could probably narrow this down further to a
+  // single point-edge distance by comparing the relative latitudes of the
+  // endpoints, but for the sake of clarity, we'll do all four point-edge
+  // distance tests.
+  S2Point a_lo = S2LatLng(a.lat_lo(), a_lng).ToPoint();
+  S2Point a_hi = S2LatLng(a.lat_hi(), a_lng).ToPoint();
+  S2Point b_lo = S2LatLng(b.lat_lo(), b_lng).ToPoint();
+  S2Point b_hi = S2LatLng(b.lat_hi(), b_lng).ToPoint();
+  return min(S2::GetDistance(a_lo, b_lo, b_hi),
+         min(S2::GetDistance(a_hi, b_lo, b_hi),
+         min(S2::GetDistance(b_lo, a_lo, a_hi),
+             S2::GetDistance(b_hi, a_lo, a_hi))));
+}
+
+S1Angle S2LatLngRect::GetDistance(const S2LatLng& p) const {
+  // The algorithm here is the same as in GetDistance(S2LatLngRect), only
+  // with simplified calculations.
+  const S2LatLngRect& a = *this;
+  S2_DLOG_IF(ERROR, a.is_empty())
+      << "Empty S2LatLngRect in S2LatLngRect::GetDistance: " << a;
+
+  S2_DLOG_IF(ERROR, !p.is_valid())
+      << "Invalid S2LatLng in S2LatLngRect::GetDistance: " << p;
+
+  if (a.lng().Contains(p.lng().radians())) {
+    return S1Angle::Radians(max(0.0, max(p.lat().radians() - a.lat().hi(),
+                                         a.lat().lo() - p.lat().radians())));
+  }
+
+  S1Interval interval(a.lng().hi(), a.lng().GetComplementCenter());
+  double a_lng;
+  if (interval.Contains(p.lng().radians())) {
+    a_lng = a.lng().hi();
+  } else {
+    a_lng = a.lng().lo();
+  }
+  S2Point lo = S2LatLng::FromRadians(a.lat().lo(), a_lng).ToPoint();
+  S2Point hi = S2LatLng::FromRadians(a.lat().hi(), a_lng).ToPoint();
+  return S2::GetDistance(p.ToPoint(), lo, hi);
+}
+
+S1Angle S2LatLngRect::GetHausdorffDistance(const S2LatLngRect& other) const {
+  return max(GetDirectedHausdorffDistance(other),
+             other.GetDirectedHausdorffDistance(*this));
+}
+
+S1Angle S2LatLngRect::GetDirectedHausdorffDistance(
+    const S2LatLngRect& other) const {
+  if (is_empty()) {
+    return S1Angle::Radians(0);
+  }
+  if (other.is_empty()) {
+    return S1Angle::Radians(M_PI);  // maximum possible distance on S2
+  }
+
+  double lng_distance = lng().GetDirectedHausdorffDistance(other.lng());
+  S2_DCHECK_GE(lng_distance, 0);
+  return GetDirectedHausdorffDistance(lng_distance, lat(), other.lat());
+}
+
+// Return the directed Hausdorff distance from one longitudinal edge spanning
+// latitude range 'a_lat' to the other longitudinal edge spanning latitude
+// range 'b_lat', with their longitudinal difference given by 'lng_diff'.
+S1Angle S2LatLngRect::GetDirectedHausdorffDistance(
+    double lng_diff, const R1Interval& a, const R1Interval& b) {
+  // By symmetry, we can assume a's longtitude is 0 and b's longtitude is
+  // lng_diff. Call b's two endpoints b_lo and b_hi. Let H be the hemisphere
+  // containing a and delimited by the longitude line of b. The Voronoi diagram
+  // of b on H has three edges (portions of great circles) all orthogonal to b
+  // and meeting at b_lo cross b_hi.
+  // E1: (b_lo, b_lo cross b_hi)
+  // E2: (b_hi, b_lo cross b_hi)
+  // E3: (-b_mid, b_lo cross b_hi), where b_mid is the midpoint of b
+  //
+  // They subdivide H into three Voronoi regions. Depending on how longitude 0
+  // (which contains edge a) intersects these regions, we distinguish two cases:
+  // Case 1: it intersects three regions. This occurs when lng_diff <= M_PI_2.
+  // Case 2: it intersects only two regions. This occurs when lng_diff > M_PI_2.
+  //
+  // In the first case, the directed Hausdorff distance to edge b can only be
+  // realized by the following points on a:
+  // A1: two endpoints of a.
+  // A2: intersection of a with the equator, if b also intersects the equator.
+  //
+  // In the second case, the directed Hausdorff distance to edge b can only be
+  // realized by the following points on a:
+  // B1: two endpoints of a.
+  // B2: intersection of a with E3
+  // B3: farthest point from b_lo to the interior of D, and farthest point from
+  //     b_hi to the interior of U, if any, where D (resp. U) is the portion
+  //     of edge a below (resp. above) the intersection point from B2.
+
+  S2_DCHECK_GE(lng_diff, 0);
+  S2_DCHECK_LE(lng_diff, M_PI);
+
+  if (lng_diff == 0) {
+    return S1Angle::Radians(a.GetDirectedHausdorffDistance(b));
+  }
+
+  // Assumed longtitude of b.
+  double b_lng = lng_diff;
+  // Two endpoints of b.
+  S2Point b_lo = S2LatLng::FromRadians(b.lo(), b_lng).ToPoint();
+  S2Point b_hi = S2LatLng::FromRadians(b.hi(), b_lng).ToPoint();
+
+  // Handling of each case outlined at the top of the function starts here.
+  // This is initialized a few lines below.
+  S1Angle max_distance;
+
+  // Cases A1 and B1.
+  S2Point a_lo = S2LatLng::FromRadians(a.lo(), 0).ToPoint();
+  S2Point a_hi = S2LatLng::FromRadians(a.hi(), 0).ToPoint();
+  max_distance = S2::GetDistance(a_lo, b_lo, b_hi);
+  max_distance = max(
+      max_distance, S2::GetDistance(a_hi, b_lo, b_hi));
+
+  if (lng_diff <= M_PI_2) {
+    // Case A2.
+    if (a.Contains(0) && b.Contains(0)) {
+      max_distance = max(max_distance, S1Angle::Radians(lng_diff));
+    }
+  } else {
+    // Case B2.
+    const S2Point& p = GetBisectorIntersection(b, b_lng);
+    double p_lat = S2LatLng::Latitude(p).radians();
+    if (a.Contains(p_lat)) {
+      max_distance = max(max_distance, S1Angle(p, b_lo));
+    }
+
+    // Case B3.
+    if (p_lat > a.lo()) {
+      max_distance = max(max_distance, GetInteriorMaxDistance(
+          R1Interval(a.lo(), min(p_lat, a.hi())), b_lo));
+    }
+    if (p_lat < a.hi()) {
+      max_distance = max(max_distance, GetInteriorMaxDistance(
+          R1Interval(max(p_lat, a.lo()), a.hi()), b_hi));
+    }
+  }
+
+  return max_distance;
+}
+
+// Return the intersection of longitude 0 with the bisector of an edge
+// on longitude 'lng' and spanning latitude range 'lat'.
+S2Point S2LatLngRect::GetBisectorIntersection(const R1Interval& lat,
+                                              double lng) {
+  lng = fabs(lng);
+  double lat_center = lat.GetCenter();
+  // A vector orthogonal to the bisector of the given longitudinal edge.
+  S2LatLng ortho_bisector;
+  if (lat_center >= 0) {
+    ortho_bisector = S2LatLng::FromRadians(lat_center - M_PI_2, lng);
+  } else {
+    ortho_bisector = S2LatLng::FromRadians(-lat_center - M_PI_2, lng - M_PI);
+  }
+  // A vector orthogonal to longitude 0.
+  static const S2Point ortho_lng = S2Point(0, -1, 0);
+  return S2::RobustCrossProd(ortho_lng, ortho_bisector.ToPoint());
+}
+
+// Return max distance from a point b to the segment spanning latitude range
+// a_lat on longitude 0, if the max occurs in the interior of a_lat. Otherwise
+// return -1.
+S1Angle S2LatLngRect::GetInteriorMaxDistance(const R1Interval& a_lat,
+                                             const S2Point& b) {
+  // Longitude 0 is in the y=0 plane. b.x() >= 0 implies that the maximum
+  // does not occur in the interior of a_lat.
+  if (a_lat.is_empty() || b.x() >= 0) return S1Angle::Radians(-1);
+
+  // Project b to the y=0 plane. The antipodal of the normalized projection is
+  // the point at which the maxium distance from b occurs, if it is contained
+  // in a_lat.
+  S2Point intersection_point = S2Point(-b.x(), 0, -b.z()).Normalize();
+  if (a_lat.InteriorContains(
+      S2LatLng::Latitude(intersection_point).radians())) {
+    return S1Angle(b, intersection_point);
+  } else {
+    return S1Angle::Radians(-1);
+  }
+}
+
+bool S2LatLngRect::Contains(const S2Point& p) const {
+  return Contains(S2LatLng(p));
+}
+
+bool S2LatLngRect::ApproxEquals(const S2LatLngRect& other,
+                                S1Angle max_error) const {
+  return (lat_.ApproxEquals(other.lat_, max_error.radians()) &&
+          lng_.ApproxEquals(other.lng_, max_error.radians()));
+}
+
+bool S2LatLngRect::ApproxEquals(const S2LatLngRect& other,
+                                const S2LatLng& max_error) const {
+  return (lat_.ApproxEquals(other.lat_, max_error.lat().radians()) &&
+          lng_.ApproxEquals(other.lng_, max_error.lng().radians()));
+}
+
+std::ostream& operator<<(std::ostream& os, const S2LatLngRect& r) {
+  return os << "[Lo" << r.lo() << ", Hi" << r.hi() << "]";
+}
diff --git a/src/s2/s2latlng_rect.h b/src/s2/s2latlng_rect.h
new file mode 100644 (file)
index 0000000..c529d33
--- /dev/null
@@ -0,0 +1,434 @@
+// Copyright 2005 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// Author: ericv@google.com (Eric Veach)
+
+#ifndef S2_S2LATLNG_RECT_H_
+#define S2_S2LATLNG_RECT_H_
+
+#include <cmath>
+#include <iosfwd>
+#include <iostream>
+
+#include "s2/base/logging.h"
+#include "s2/_fp_contract_off.h"
+#include "s2/r1interval.h"
+#include "s2/s1angle.h"
+#include "s2/s1interval.h"
+#include "s2/s2latlng.h"
+#include "s2/s2region.h"
+
+class Decoder;
+class Encoder;
+class S2Cap;
+class S2Cell;
+
+// An S2LatLngRect represents a closed latitude-longitude rectangle.  It is
+// capable of representing the empty and full rectangles as well as single
+// points.  Note that the latitude-longitude space is considered to have a
+// *cylindrical* topology rather than a spherical one, i.e. the poles have
+// multiple lat/lng representations.  An S2LatLngRect may be defined so that
+// includes some representations of a pole but not others.  Use the
+// PolarClosure() method if you want to expand a rectangle so that it contains
+// all possible representations of any contained poles.
+//
+// Because S2LatLngRect uses S1Interval to store the longitude range,
+// longitudes of -180 degrees are treated specially.  Except for empty
+// and full longitude spans, -180 degree longitudes will turn into +180
+// degrees.  This sign flip causes lng_lo() to be greater than lng_hi(),
+// indicating that the rectangle will wrap around through -180 instead of
+// through +179. Thus the math is consistent within the library, but the sign
+// flip can be surprising, especially when working with map projections where
+// -180 and +180 are at opposite ends of the flattened map.  See the comments
+// on S1Interval for more details.
+//
+// This class is intended to be copied by value as desired.  It uses
+// the default copy constructor and assignment operator, however it is
+// not a "plain old datatype" (POD) because it has virtual functions.
+class S2LatLngRect final : public S2Region {
+ public:
+  // Construct a rectangle from minimum and maximum latitudes and longitudes.
+  // If lo.lng() > hi.lng(), the rectangle spans the 180 degree longitude
+  // line. Both points must be normalized, with lo.lat() <= hi.lat().
+  // The rectangle contains all the points p such that 'lo' <= p <= 'hi',
+  // where '<=' is defined in the obvious way.
+  S2LatLngRect(const S2LatLng& lo, const S2LatLng& hi);
+
+  // Construct a rectangle from latitude and longitude intervals.  The two
+  // intervals must either be both empty or both non-empty, and the latitude
+  // interval must not extend outside [-90, +90] degrees.
+  // Note that both intervals (and hence the rectangle) are closed.
+  S2LatLngRect(const R1Interval& lat, const S1Interval& lng);
+
+  // The default constructor creates an empty S2LatLngRect.
+  S2LatLngRect();
+
+  // Construct a rectangle of the given size centered around the given point.
+  // "center" needs to be normalized, but "size" does not.  The latitude
+  // interval of the result is clamped to [-90,90] degrees, and the longitude
+  // interval of the result is Full() if and only if the longitude size is
+  // 360 degrees or more.  Examples of clamping (in degrees):
+  //
+  //   center=(80,170),  size=(40,60)   -> lat=[60,90],   lng=[140,-160]
+  //   center=(10,40),   size=(210,400) -> lat=[-90,90],  lng=[-180,180]
+  //   center=(-90,180), size=(20,50)   -> lat=[-90,-80], lng=[155,-155]
+  static S2LatLngRect FromCenterSize(const S2LatLng& center,
+                                     const S2LatLng& size);
+
+  // Construct a rectangle containing a single (normalized) point.
+  static S2LatLngRect FromPoint(const S2LatLng& p);
+
+  // Construct the minimal bounding rectangle containing the two given
+  // normalized points.  This is equivalent to starting with an empty
+  // rectangle and calling AddPoint() twice.  Note that it is different than
+  // the S2LatLngRect(lo, hi) constructor, where the first point is always
+  // used as the lower-left corner of the resulting rectangle.
+  static S2LatLngRect FromPointPair(const S2LatLng& p1, const S2LatLng& p2);
+
+  // Accessor methods.
+  S1Angle lat_lo() const { return S1Angle::Radians(lat_.lo()); }
+  S1Angle lat_hi() const { return S1Angle::Radians(lat_.hi()); }
+  S1Angle lng_lo() const { return S1Angle::Radians(lng_.lo()); }
+  S1Angle lng_hi() const { return S1Angle::Radians(lng_.hi()); }
+  const R1Interval& lat() const { return lat_; }
+  const S1Interval& lng() const { return lng_; }
+  R1Interval *mutable_lat() { return &lat_; }
+  S1Interval *mutable_lng() { return &lng_; }
+  S2LatLng lo() const { return S2LatLng(lat_lo(), lng_lo()); }
+  S2LatLng hi() const { return S2LatLng(lat_hi(), lng_hi()); }
+
+  // The canonical empty and full rectangles, as derived from the Empty
+  // and Full R1 and S1 Intervals.
+  // Empty: lat_lo=1, lat_hi=0, lng_lo=Pi, lng_hi=-Pi (radians)
+  static S2LatLngRect Empty();
+  // Full: lat_lo=-Pi/2, lat_hi=Pi/2, lng_lo=-Pi, lng_hi=Pi (radians)
+  static S2LatLngRect Full();
+
+  // The full allowable range of latitudes and longitudes.
+  static R1Interval FullLat() { return R1Interval(-M_PI_2, M_PI_2); }
+  static S1Interval FullLng() { return S1Interval::Full(); }
+
+  // Returns true if the rectangle is valid, which essentially just means
+  // that the latitude bounds do not exceed Pi/2 in absolute value and
+  // the longitude bounds do not exceed Pi in absolute value.  Also, if
+  // either the latitude or longitude bound is empty then both must be.
+  bool is_valid() const;
+
+  // Returns true if the rectangle is empty, i.e. it contains no points at all.
+  bool is_empty() const;
+
+  // Returns true if the rectangle is full, i.e. it contains all points.
+  bool is_full() const;
+
+  // Returns true if the rectangle is a point, i.e. lo() == hi()
+  bool is_point() const;
+
+  // Returns true if lng_.lo() > lng_.hi(), i.e. the rectangle crosses
+  // the 180 degree longitude line.
+  bool is_inverted() const { return lng_.is_inverted(); }
+
+  // Returns the k-th vertex of the rectangle (k = 0,1,2,3) in CCW order
+  // (lower left, lower right, upper right, upper left).  For convenience, the
+  // argument is reduced modulo 4 to the range [0..3].
+  S2LatLng GetVertex(int k) const;
+
+  // Returns the center of the rectangle in latitude-longitude space
+  // (in general this is not the center of the region on the sphere).
+  S2LatLng GetCenter() const;
+
+  // Returns the width and height of this rectangle in latitude-longitude
+  // space.  Empty rectangles have a negative width and height.
+  S2LatLng GetSize() const;
+
+  // Returns the surface area of this rectangle on the unit sphere.
+  double Area() const;
+
+  // Returns the true centroid of the rectangle multiplied by its surface area
+  // (see s2centroids.h for details on centroids).  The result is not unit
+  // length, so you may want to normalize it.  Note that in general the
+  // centroid is *not* at the center of the rectangle, and in fact it may not
+  // even be contained by the rectangle.  (It is the "center of mass" of the
+  // rectangle viewed as subset of the unit sphere, i.e. it is the point in
+  // space about which this curved shape would rotate.)
+  //
+  // The reason for multiplying the result by the rectangle area is to make it
+  // easier to compute the centroid of more complicated shapes.  The centroid
+  // of a union of disjoint regions can be computed simply by adding their
+  // GetCentroid() results.
+  S2Point GetCentroid() const;
+
+  // More efficient version of Contains() that accepts a S2LatLng rather than
+  // an S2Point.  The argument must be normalized.
+  bool Contains(const S2LatLng& ll) const;
+
+  // Returns true if and only if the given point is contained in the interior
+  // of the region (i.e. the region excluding its boundary).  The point 'p'
+  // does not need to be normalized.
+  bool InteriorContains(const S2Point& p) const;
+
+  // More efficient version of InteriorContains() that accepts a S2LatLng
+  // rather than an S2Point.  The argument must be normalized.
+  bool InteriorContains(const S2LatLng& ll) const;
+
+  // Returns true if and only if the rectangle contains the given other
+  // rectangle.
+  bool Contains(const S2LatLngRect& other) const;
+
+  // Returns true if and only if the interior of this rectangle contains all
+  // points of the given other rectangle (including its boundary).
+  bool InteriorContains(const S2LatLngRect& other) const;
+
+  // Returns true if this rectangle and the given other rectangle have any
+  // points in common.
+  bool Intersects(const S2LatLngRect& other) const;
+
+  // Returns true if this rectangle intersects the given cell.  (This is an
+  // exact test and may be fairly expensive, see also MayIntersect below.)
+  bool Intersects(const S2Cell& cell) const;
+
+  // Returns true if and only if the interior of this rectangle intersects
+  // any point (including the boundary) of the given other rectangle.
+  bool InteriorIntersects(const S2LatLngRect& other) const;
+
+  // Returns true if the boundary of this rectangle intersects the given
+  // geodesic edge (v0, v1).
+  bool BoundaryIntersects(const S2Point& v0, const S2Point& v1) const;
+
+  // Increase the size of the bounding rectangle to include the given point.
+  // The rectangle is expanded by the minimum amount possible.  The S2LatLng
+  // argument must be normalized.
+  void AddPoint(const S2Point& p);
+  void AddPoint(const S2LatLng& ll);
+
+  // Returns a rectangle that has been expanded by margin.lat() on each side in
+  // the latitude direction, and by margin.lng() on each side in the longitude
+  // direction.  If either margin is negative, then shrinks the rectangle on
+  // the corresponding sides instead.  The resulting rectangle may be empty.
+  //
+  // As noted above, the latitude-longitude space has the topology of a
+  // cylinder.  Longitudes "wrap around" at +/-180 degrees, while latitudes
+  // are clamped to range [-90, 90].  This means that any expansion (positive
+  // or negative) of the full longitude range remains full (since the
+  // "rectangle" is actually a continuous band around the cylinder), while
+  // expansion of the full latitude range remains full only if the margin is
+  // positive.
+  //
+  // If either the latitude or longitude interval becomes empty after
+  // expansion by a negative margin, the result is empty.
+  //
+  // Note that if an expanded rectangle contains a pole, it may not contain
+  // all possible lat/lng representations of that pole (see header above).
+  // Use the PolarClosure() method if you do not want this behavior.
+  //
+  // If you are trying to grow a rectangle by a certain *distance* on the
+  // sphere (e.g. 5km), use the ExpandedByDistance() method instead.
+  S2LatLngRect Expanded(const S2LatLng& margin) const;
+
+  // If the rectangle does not include either pole, returns it unmodified.
+  // Otherwise expands the longitude range to Full() so that the rectangle
+  // contains all possible representations of the contained pole(s).
+  S2LatLngRect PolarClosure() const;
+
+  // Returns the smallest rectangle containing the union of this rectangle and
+  // the given rectangle.
+  S2LatLngRect Union(const S2LatLngRect& other) const;
+
+  // Returns the smallest rectangle containing the intersection of this
+  // rectangle and the given rectangle.  Note that the region of intersection
+  // may consist of two disjoint rectangles, in which case a single rectangle
+  // spanning both of them is returned.
+  S2LatLngRect Intersection(const S2LatLngRect& other) const;
+
+  // Expands this rectangle so that it contains all points within the given
+  // distance of the boundary, and return the smallest such rectangle.  If the
+  // distance is negative, then instead shrinks this rectangle so that it
+  // excludes all points within the given absolute distance of the boundary,
+  // and returns the largest such rectangle.
+  //
+  // Unlike Expanded(), this method treats the rectangle as a set of points on
+  // the sphere, and measures distances on the sphere.  For example, you can
+  // use this method to find a rectangle that contains all points within 5km
+  // of a given rectangle.  Because this method uses the topology of the
+  // sphere, note the following:
+  //
+  //  - The full and empty rectangles have no boundary on the sphere.  Any
+  //    expansion (positive or negative) of these rectangles leaves them
+  //    unchanged.
+  //
+  //  - Any rectangle that covers the full longitude range does not have an
+  //    east or west boundary, therefore no expansion (positive or negative)
+  //    will occur in that direction.
+  //
+  //  - Any rectangle that covers the full longitude range and also includes
+  //    a pole will not be expanded or contracted at that pole, because it
+  //    does not have a boundary there.
+  //
+  //  - If a rectangle is within the given distance of a pole, the result will
+  //    include the full longitude range (because all longitudes are present
+  //    at the poles).
+  //
+  // Expansion and contraction are defined such that they are inverses whenver
+  // possible, i.e.
+  //
+  //   rect.ExpandedByDistance(x).ExpandedByDistance(-x) == rect
+  //
+  // (approximately), so long as the first operation does not cause a
+  // rectangle boundary to disappear (i.e., the longitude range newly becomes
+  // full or empty, or the latitude range expands to include a pole).
+  S2LatLngRect ExpandedByDistance(S1Angle distance) const;
+
+  // Returns the minimum distance (measured along the surface of the sphere) to
+  // the given S2LatLngRect. Both S2LatLngRects must be non-empty.
+  S1Angle GetDistance(const S2LatLngRect& other) const;
+
+  // Returns the minimum distance (measured along the surface of the sphere)
+  // from a given point to the rectangle (both its boundary and its interior).
+  // The latlng must be valid.
+  S1Angle GetDistance(const S2LatLng& p) const;
+
+  // Returns the (directed or undirected) Hausdorff distance (measured along the
+  // surface of the sphere) to the given S2LatLngRect. The directed Hausdorff
+  // distance from rectangle A to rectangle B is given by
+  //     h(A, B) = max_{p in A} min_{q in B} d(p, q).
+  // The Hausdorff distance between rectangle A and rectangle B is given by
+  //     H(A, B) = max{h(A, B), h(B, A)}.
+  S1Angle GetDirectedHausdorffDistance(const S2LatLngRect& other) const;
+  S1Angle GetHausdorffDistance(const S2LatLngRect& other) const;
+
+  // Returns true if two rectangles contains the same set of points.
+  bool operator==(const S2LatLngRect& other) const;
+
+  // Returns the opposite of what operator == returns.
+  bool operator!=(const S2LatLngRect& other) const;
+
+  // Returns true if the latitude and longitude intervals of the two rectangles
+  // are the same up to the given tolerance (see r1interval.h and s1interval.h
+  // for details).
+  bool ApproxEquals(const S2LatLngRect& other,
+                    S1Angle max_error = S1Angle::Radians(1e-15)) const;
+
+  // ApproxEquals() with separate tolerances for latitude and longitude.
+  bool ApproxEquals(const S2LatLngRect& other, const S2LatLng& max_error) const;
+
+  ////////////////////////////////////////////////////////////////////////
+  // S2Region interface (see s2region.h for details):
+
+  S2LatLngRect* Clone() const override;
+  S2Cap GetCapBound() const override;
+  S2LatLngRect GetRectBound() const override;
+  bool Contains(const S2Cell& cell) const override;
+
+  // This test is cheap but is NOT exact.  Use Intersects() if you want a more
+  // accurate and more expensive test.  Note that when this method is used by
+  // an S2RegionCoverer, the accuracy isn't all that important since if a cell
+  // may intersect the region then it is subdivided, and the accuracy of this
+  // method goes up as the cells get smaller.
+  bool MayIntersect(const S2Cell& cell) const override;
+
+  // The point 'p' does not need to be normalized.
+  bool Contains(const S2Point& p) const override;
+
+  // Appends a serialized representation of the S2LatLngRect to "encoder".
+  //
+  // REQUIRES: "encoder" uses the default constructor, so that its buffer
+  //           can be enlarged as necessary by calling Ensure(int).
+  void Encode(Encoder* const encoder) const;
+
+  // Decodes an S2LatLngRect encoded with Encode().  Returns true on success.
+  bool Decode(Decoder* const decoder);
+
+  // Returns true if the edge AB intersects the given edge of constant
+  // longitude.
+  static bool IntersectsLngEdge(const S2Point& a, const S2Point& b,
+                                const R1Interval& lat, double lng);
+
+  // Returns true if the edge AB intersects the given edge of constant
+  // latitude.  Requires the vectors to have unit length.
+  static bool IntersectsLatEdge(const S2Point& a, const S2Point& b,
+                                double lat, const S1Interval& lng);
+
+ private:
+  // Helper function. See .cc for description.
+  static S1Angle GetDirectedHausdorffDistance(double lng_diff,
+                                              const R1Interval& a_lat,
+                                              const R1Interval& b_lat);
+
+  // Helper function. See .cc for description.
+  static S1Angle GetInteriorMaxDistance(const R1Interval& a_lat,
+                                        const S2Point& b);
+
+  // Helper function. See .cc for description.
+  static S2Point GetBisectorIntersection(const R1Interval& lat, double lng);
+
+  R1Interval lat_;
+  S1Interval lng_;
+};
+
+inline S2LatLngRect::S2LatLngRect(const S2LatLng& lo, const S2LatLng& hi)
+  : lat_(lo.lat().radians(), hi.lat().radians()),
+    lng_(lo.lng().radians(), hi.lng().radians()) {
+  S2_DLOG_IF(ERROR, !is_valid())
+      << "Invalid rect: " << lo << ", " << hi;
+}
+
+inline S2LatLngRect::S2LatLngRect(const R1Interval& lat, const S1Interval& lng)
+  : lat_(lat), lng_(lng) {
+  S2_DLOG_IF(ERROR, !is_valid())
+      << "Invalid rect: " << lat << ", " << lng;
+}
+
+inline S2LatLngRect::S2LatLngRect()
+    : lat_(R1Interval::Empty()), lng_(S1Interval::Empty()) {
+}
+
+inline S2LatLngRect S2LatLngRect::Empty() {
+  return S2LatLngRect();
+}
+
+inline S2LatLngRect S2LatLngRect::Full() {
+  return S2LatLngRect(FullLat(), FullLng());
+}
+
+inline bool S2LatLngRect::is_valid() const {
+  // The lat/lng ranges must either be both empty or both non-empty.
+  return (std::fabs(lat_.lo()) <= M_PI_2 &&
+          std::fabs(lat_.hi()) <= M_PI_2 &&
+          lng_.is_valid() &&
+          lat_.is_empty() == lng_.is_empty());
+}
+
+inline bool S2LatLngRect::is_empty() const {
+  return lat_.is_empty();
+}
+
+inline bool S2LatLngRect::is_full() const {
+  return lat_ == FullLat() && lng_.is_full();
+}
+
+inline bool S2LatLngRect::is_point() const {
+  return lat_.lo() == lat_.hi() && lng_.lo() == lng_.hi();
+}
+
+inline bool S2LatLngRect::operator==(const S2LatLngRect& other) const {
+  return lat() == other.lat() && lng() == other.lng();
+}
+
+inline bool S2LatLngRect::operator!=(const S2LatLngRect& other) const {
+  return !operator==(other);
+}
+
+std::ostream& operator<<(std::ostream& os, const S2LatLngRect& r);
+
+#endif  // S2_S2LATLNG_RECT_H_
diff --git a/src/s2/s2latlng_rect_bounder.cc b/src/s2/s2latlng_rect_bounder.cc
new file mode 100644 (file)
index 0000000..b2943b4
--- /dev/null
@@ -0,0 +1,344 @@
+// Copyright 2005 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// Author: ericv@google.com (Eric Veach)
+
+#include "s2/s2latlng_rect_bounder.h"
+
+#include <cfloat>
+#include <cmath>
+
+#include "s2/base/logging.h"
+#include "s2/r1interval.h"
+#include "s2/s1chord_angle.h"
+#include "s2/s1interval.h"
+#include "s2/s2pointutil.h"
+
+using std::fabs;
+using std::max;
+using std::min;
+
+void S2LatLngRectBounder::AddPoint(const S2Point& b) {
+  S2_DCHECK(S2::IsUnitLength(b));
+  AddInternal(b, S2LatLng(b));
+}
+
+void S2LatLngRectBounder::AddLatLng(const S2LatLng& b_latlng) {
+  AddInternal(b_latlng.ToPoint(), b_latlng);
+}
+
+void S2LatLngRectBounder::AddInternal(const S2Point& b,
+                                      const S2LatLng& b_latlng) {
+  // Simple consistency check to verify that b and b_latlng are alternate
+  // representations of the same vertex.
+  S2_DCHECK(S2::ApproxEquals(b, b_latlng.ToPoint()));
+
+  if (bound_.is_empty()) {
+    bound_.AddPoint(b_latlng);
+  } else {
+    // First compute the cross product N = A x B robustly.  This is the normal
+    // to the great circle through A and B.  We don't use S2::RobustCrossProd()
+    // since that method returns an arbitrary vector orthogonal to A if the two
+    // vectors are proportional, and we want the zero vector in that case.
+    Vector3_d n = (a_ - b).CrossProd(a_ + b);  // N = 2 * (A x B)
+
+    // The relative error in N gets large as its norm gets very small (i.e.,
+    // when the two points are nearly identical or antipodal).  We handle this
+    // by choosing a maximum allowable error, and if the error is greater than
+    // this we fall back to a different technique.  Since it turns out that
+    // the other sources of error in converting the normal to a maximum
+    // latitude add up to at most 1.16 * DBL_EPSILON (see below), and it is
+    // desirable to have the total error be a multiple of DBL_EPSILON, we have
+    // chosen to limit the maximum error in the normal to 3.84 * DBL_EPSILON.
+    // It is possible to show that the error is less than this when
+    //
+    //   n.Norm() >= 8 * sqrt(3) / (3.84 - 0.5 - sqrt(3)) * DBL_EPSILON
+    //            = 1.91346e-15 (about 8.618 * DBL_EPSILON)
+    double n_norm = n.Norm();
+    if (n_norm < 1.91346e-15) {
+      // A and B are either nearly identical or nearly antipodal (to within
+      // 4.309 * DBL_EPSILON, or about 6 nanometers on the earth's surface).
+      if (a_.DotProd(b) < 0) {
+        // The two points are nearly antipodal.  The easiest solution is to
+        // assume that the edge between A and B could go in any direction
+        // around the sphere.
+        bound_ = S2LatLngRect::Full();
+      } else {
+        // The two points are nearly identical (to within 4.309 * DBL_EPSILON).
+        // In this case we can just use the bounding rectangle of the points,
+        // since after the expansion done by GetBound() this rectangle is
+        // guaranteed to include the (lat,lng) values of all points along AB.
+        bound_ = bound_.Union(S2LatLngRect::FromPointPair(a_latlng_, b_latlng));
+      }
+    } else {
+      // Compute the longitude range spanned by AB.
+      S1Interval lng_ab = S1Interval::FromPointPair(a_latlng_.lng().radians(),
+                                                    b_latlng.lng().radians());
+      if (lng_ab.GetLength() >= M_PI - 2 * DBL_EPSILON) {
+        // The points lie on nearly opposite lines of longitude to within the
+        // maximum error of the calculation.  (Note that this test relies on
+        // the fact that M_PI is slightly less than the true value of Pi, and
+        // that representable values near M_PI are 2 * DBL_EPSILON apart.)
+        // The easiest solution is to assume that AB could go on either side
+        // of the pole.
+        lng_ab = S1Interval::Full();
+      }
+
+      // Next we compute the latitude range spanned by the edge AB.  We start
+      // with the range spanning the two endpoints of the edge:
+      R1Interval lat_ab = R1Interval::FromPointPair(a_latlng_.lat().radians(),
+                                                    b_latlng.lat().radians());
+
+      // This is the desired range unless the edge AB crosses the plane
+      // through N and the Z-axis (which is where the great circle through A
+      // and B attains its minimum and maximum latitudes).  To test whether AB
+      // crosses this plane, we compute a vector M perpendicular to this
+      // plane and then project A and B onto it.
+      Vector3_d m = n.CrossProd(S2Point(0, 0, 1));
+      double m_a = m.DotProd(a_);
+      double m_b = m.DotProd(b);
+
+      // We want to test the signs of "m_a" and "m_b", so we need to bound
+      // the error in these calculations.  It is possible to show that the
+      // total error is bounded by
+      //
+      //  (1 + sqrt(3)) * DBL_EPSILON * n_norm + 8 * sqrt(3) * (DBL_EPSILON**2)
+      //    = 6.06638e-16 * n_norm + 6.83174e-31
+
+      double m_error = 6.06638e-16 * n_norm + 6.83174e-31;
+      if (m_a * m_b < 0 || fabs(m_a) <= m_error || fabs(m_b) <= m_error) {
+        // Minimum/maximum latitude *may* occur in the edge interior.
+        //
+        // The maximum latitude is 90 degrees minus the latitude of N.  We
+        // compute this directly using atan2 in order to get maximum accuracy
+        // near the poles.
+        //
+        // Our goal is compute a bound that contains the computed latitudes of
+        // all S2Points P that pass the point-in-polygon containment test.
+        // There are three sources of error we need to consider:
+        //  - the directional error in N (at most 3.84 * DBL_EPSILON)
+        //  - converting N to a maximum latitude
+        //  - computing the latitude of the test point P
+        // The latter two sources of error are at most 0.955 * DBL_EPSILON
+        // individually, but it is possible to show by a more complex analysis
+        // that together they can add up to at most 1.16 * DBL_EPSILON, for a
+        // total error of 5 * DBL_EPSILON.
+        //
+        // We add 3 * DBL_EPSILON to the bound here, and GetBound() will pad
+        // the bound by another 2 * DBL_EPSILON.
+        double max_lat = min(
+            atan2(sqrt(n[0]*n[0] + n[1]*n[1]), fabs(n[2])) + 3 * DBL_EPSILON,
+            M_PI_2);
+
+        // In order to get tight bounds when the two points are close together,
+        // we also bound the min/max latitude relative to the latitudes of the
+        // endpoints A and B.  First we compute the distance between A and B,
+        // and then we compute the maximum change in latitude between any two
+        // points along the great circle that are separated by this distance.
+        // This gives us a latitude change "budget".  Some of this budget must
+        // be spent getting from A to B; the remainder bounds the round-trip
+        // distance (in latitude) from A or B to the min or max latitude
+        // attained along the edge AB.
+        double lat_budget = 2 * asin(0.5 * (a_ - b).Norm() * sin(max_lat));
+        double max_delta = 0.5*(lat_budget - lat_ab.GetLength()) + DBL_EPSILON;
+
+        // Test whether AB passes through the point of maximum latitude or
+        // minimum latitude.  If the dot product(s) are small enough then the
+        // result may be ambiguous.
+        if (m_a <= m_error && m_b >= -m_error) {
+          lat_ab.set_hi(min(max_lat, lat_ab.hi() + max_delta));
+        }
+        if (m_b <= m_error && m_a >= -m_error) {
+          lat_ab.set_lo(max(-max_lat, lat_ab.lo() - max_delta));
+        }
+      }
+      bound_ = bound_.Union(S2LatLngRect(lat_ab, lng_ab));
+    }
+  }
+  a_ = b;
+  a_latlng_ = b_latlng;
+}
+
+S2LatLngRect S2LatLngRectBounder::GetBound() const {
+  // To save time, we ignore numerical errors in the computed S2LatLngs while
+  // accumulating the bounds and then account for them here.
+  //
+  // S2LatLng(S2Point) has a maximum error of 0.955 * DBL_EPSILON in latitude.
+  // In the worst case, we might have rounded "inwards" when computing the
+  // bound and "outwards" when computing the latitude of a contained point P,
+  // therefore we expand the latitude bounds by 2 * DBL_EPSILON in each
+  // direction.  (A more complex analysis shows that 1.5 * DBL_EPSILON is
+  // enough, but the expansion amount should be a multiple of DBL_EPSILON in
+  // order to avoid rounding errors during the expansion itself.)
+  //
+  // S2LatLng(S2Point) has a maximum error of DBL_EPSILON in longitude, which
+  // is simply the maximum rounding error for results in the range [-Pi, Pi].
+  // This is true because the Gnu implementation of atan2() comes from the IBM
+  // Accurate Mathematical Library, which implements correct rounding for this
+  // instrinsic (i.e., it returns the infinite precision result rounded to the
+  // nearest representable value, with ties rounded to even values).  This
+  // implies that we don't need to expand the longitude bounds at all, since
+  // we only guarantee that the bound contains the *rounded* latitudes of
+  // contained points.  The *true* latitudes of contained points may lie up to
+  // DBL_EPSILON outside of the returned bound.
+
+  const S2LatLng kExpansion = S2LatLng::FromRadians(2 * DBL_EPSILON, 0);
+  return bound_.Expanded(kExpansion).PolarClosure();
+}
+
+S2LatLngRect S2LatLngRectBounder::ExpandForSubregions(
+    const S2LatLngRect& bound) {
+  // Empty bounds don't need expansion.
+  if (bound.is_empty()) return bound;
+
+  // First we need to check whether the bound B contains any nearly-antipodal
+  // points (to within 4.309 * DBL_EPSILON).  If so then we need to return
+  // S2LatLngRect::Full(), since the subregion might have an edge between two
+  // such points, and AddPoint() returns Full() for such edges.  Note that
+  // this can happen even if B is not Full(); for example, consider a loop
+  // that defines a 10km strip straddling the equator extending from
+  // longitudes -100 to +100 degrees.
+  //
+  // It is easy to check whether B contains any antipodal points, but checking
+  // for nearly-antipodal points is trickier.  Essentially we consider the
+  // original bound B and its reflection through the origin B', and then test
+  // whether the minimum distance between B and B' is less than 4.309 *
+  // DBL_EPSILON.
+
+  // "lng_gap" is a lower bound on the longitudinal distance between B and its
+  // reflection B'.  (2.5 * DBL_EPSILON is the maximum combined error of the
+  // endpoint longitude calculations and the GetLength() call.)
+  double lng_gap = max(0.0, M_PI - bound.lng().GetLength() - 2.5 * DBL_EPSILON);
+
+  // "min_abs_lat" is the minimum distance from B to the equator (if zero or
+  // negative, then B straddles the equator).
+  double min_abs_lat = max(bound.lat().lo(), -bound.lat().hi());
+
+  // "lat_gap1" and "lat_gap2" measure the minimum distance from B to the
+  // south and north poles respectively.
+  double lat_gap1 = M_PI_2 + bound.lat().lo();
+  double lat_gap2 = M_PI_2 - bound.lat().hi();
+
+  if (min_abs_lat >= 0) {
+    // The bound B does not straddle the equator.  In this case the minimum
+    // distance is between one endpoint of the latitude edge in B closest to
+    // the equator and the other endpoint of that edge in B'.  The latitude
+    // distance between these two points is 2*min_abs_lat, and the longitude
+    // distance is lng_gap.  We could compute the distance exactly using the
+    // Haversine formula, but then we would need to bound the errors in that
+    // calculation.  Since we only need accuracy when the distance is very
+    // small (close to 4.309 * DBL_EPSILON), we substitute the Euclidean
+    // distance instead.  This gives us a right triangle XYZ with two edges of
+    // length x = 2*min_abs_lat and y ~= lng_gap.  The desired distance is the
+    // length of the third edge "z", and we have
+    //
+    //         z  ~=  sqrt(x^2 + y^2)  >=  (x + y) / sqrt(2)
+    //
+    // Therefore the region may contain nearly antipodal points only if
+    //
+    //  2*min_abs_lat + lng_gap  <  sqrt(2) * 4.309 * DBL_EPSILON
+    //                           ~= 1.354e-15
+    //
+    // Note that because the given bound B is conservative, "min_abs_lat" and
+    // "lng_gap" are both lower bounds on their true values so we do not need
+    // to make any adjustments for their errors.
+    if (2 * min_abs_lat + lng_gap < 1.354e-15) {
+      return S2LatLngRect::Full();
+    }
+  } else if (lng_gap >= M_PI_2) {
+    // B spans at most Pi/2 in longitude.  The minimum distance is always
+    // between one corner of B and the diagonally opposite corner of B'.  We
+    // use the same distance approximation that we used above; in this case
+    // we have an obtuse triangle XYZ with two edges of length x = lat_gap1
+    // and y = lat_gap2, and angle Z >= Pi/2 between them.  We then have
+    //
+    //         z  >=  sqrt(x^2 + y^2)  >=  (x + y) / sqrt(2)
+    //
+    // Unlike the case above, "lat_gap1" and "lat_gap2" are not lower bounds
+    // (because of the extra addition operation, and because M_PI_2 is not
+    // exactly equal to Pi/2); they can exceed their true values by up to
+    // 0.75 * DBL_EPSILON.  Putting this all together, the region may
+    // contain nearly antipodal points only if
+    //
+    //   lat_gap1 + lat_gap2  <  (sqrt(2) * 4.309 + 1.5) * DBL_EPSILON
+    //                        ~= 1.687e-15
+    if (lat_gap1 + lat_gap2 < 1.687e-15) {
+      return S2LatLngRect::Full();
+    }
+  } else {
+    // Otherwise we know that (1) the bound straddles the equator and (2) its
+    // width in longitude is at least Pi/2.  In this case the minimum
+    // distance can occur either between a corner of B and the diagonally
+    // opposite corner of B' (as in the case above), or between a corner of B
+    // and the opposite longitudinal edge reflected in B'.  It is sufficient
+    // to only consider the corner-edge case, since this distance is also a
+    // lower bound on the corner-corner distance when that case applies.
+
+    // Consider the spherical triangle XYZ where X is a corner of B with
+    // minimum absolute latitude, Y is the closest pole to X, and Z is the
+    // point closest to X on the opposite longitudinal edge of B'.  This is a
+    // right triangle (Z = Pi/2), and from the spherical law of sines we have
+    //
+    //     sin(z) / sin(Z)  =  sin(y) / sin(Y)
+    //     sin(max_lat_gap) / 1  =  sin(d_min) / sin(lng_gap)
+    //     sin(d_min)  =  sin(max_lat_gap) * sin(lng_gap)
+    //
+    // where "max_lat_gap" = max(lat_gap1, lat_gap2) and "d_min" is the
+    // desired minimum distance.  Now using the facts that sin(t) >= (2/Pi)*t
+    // for 0 <= t <= Pi/2, that we only need an accurate approximation when
+    // at least one of "max_lat_gap" or "lng_gap" is extremely small (in
+    // which case sin(t) ~= t), and recalling that "max_lat_gap" has an error
+    // of up to 0.75 * DBL_EPSILON, we want to test whether
+    //
+    //   max_lat_gap * lng_gap  <  (4.309 + 0.75) * (Pi/2) * DBL_EPSILON
+    //                          ~= 1.765e-15
+    if (max(lat_gap1, lat_gap2) * lng_gap < 1.765e-15) {
+      return S2LatLngRect::Full();
+    }
+  }
+  // Next we need to check whether the subregion might contain any edges that
+  // span (M_PI - 2 * DBL_EPSILON) radians or more in longitude, since AddPoint
+  // sets the longitude bound to Full() in that case.  This corresponds to
+  // testing whether (lng_gap <= 0) in "lng_expansion" below.
+
+  // Otherwise, the maximum latitude error in AddPoint is 4.8 * DBL_EPSILON.
+  // In the worst case, the errors when computing the latitude bound for a
+  // subregion could go in the opposite direction as the errors when computing
+  // the bound for the original region, so we need to double this value.
+  // (More analysis shows that it's okay to round down to a multiple of
+  // DBL_EPSILON.)
+  //
+  // For longitude, we rely on the fact that atan2 is correctly rounded and
+  // therefore no additional bounds expansion is necessary.
+
+  double lat_expansion = 9 * DBL_EPSILON;
+  double lng_expansion = (lng_gap <= 0) ? M_PI : 0;
+  return bound.Expanded(S2LatLng::FromRadians(lat_expansion,
+                                              lng_expansion)).PolarClosure();
+}
+
+S2LatLng S2LatLngRectBounder::MaxErrorForTests() {
+  // The maximum error in the latitude calculation is
+  //    3.84 * DBL_EPSILON   for the RobustCrossProd calculation
+  //    0.96 * DBL_EPSILON   for the Latitude() calculation
+  //    5    * DBL_EPSILON   added by AddPoint/GetBound to compensate for error
+  //    ------------------
+  //    9.80 * DBL_EPSILON   maximum error in result
+  //
+  // The maximum error in the longitude calculation is DBL_EPSILON.  GetBound
+  // does not do any expansion because this isn't necessary in order to
+  // bound the *rounded* longitudes of contained points.
+  return S2LatLng::FromRadians(10 * DBL_EPSILON, 1 * DBL_EPSILON);
+}
diff --git a/src/s2/s2latlng_rect_bounder.h b/src/s2/s2latlng_rect_bounder.h
new file mode 100644 (file)
index 0000000..540bbb0
--- /dev/null
@@ -0,0 +1,89 @@
+// Copyright 2005 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// Author: ericv@google.com (Eric Veach)
+
+#ifndef S2_S2LATLNG_RECT_BOUNDER_H_
+#define S2_S2LATLNG_RECT_BOUNDER_H_
+
+#include "s2/s2latlng.h"
+#include "s2/s2latlng_rect.h"
+#include "s2/s2point.h"
+
+// This class computes a bounding rectangle that contains all edges defined
+// by a vertex chain v0, v1, v2, ...  All vertices must be unit length.
+// Note that the bounding rectangle of an edge can be larger than the
+// bounding rectangle of its endpoints, e.g. consider an edge that passes
+// through the north pole.
+//
+// The bounds are calculated conservatively to account for numerical errors
+// when S2Points are converted to S2LatLngs.  More precisely, this class
+// guarantees the following.  Let L be a closed edge chain (loop) such that
+// the interior of the loop does not contain either pole.  Now if P is any
+// point such that L.Contains(P), then RectBound(L).Contains(S2LatLng(P)).
+class S2LatLngRectBounder {
+ public:
+  S2LatLngRectBounder() : bound_(S2LatLngRect::Empty()) {}
+
+  // This method is called to add a vertex to the chain when the vertex is
+  // represented as an S2Point.  Requires that 'b' has unit length.  Repeated
+  // vertices are ignored.
+  void AddPoint(const S2Point& b);
+
+  // This method is called to add a vertex to the chain when the vertex is
+  // represented as an S2LatLng.  Repeated vertices are ignored.
+  void AddLatLng(const S2LatLng& b_latlng);
+
+  // Returns the bounding rectangle of the edge chain that connects the
+  // vertices defined so far.  This bound satisfies the guarantee made
+  // above, i.e. if the edge chain defines a loop, then the bound contains
+  // the S2LatLng coordinates of all S2Points contained by the loop.
+  S2LatLngRect GetBound() const;
+
+  // Expands a bound returned by GetBound() so that it is guaranteed to
+  // contain the bounds of any subregion whose bounds are computed using
+  // this class.  For example, consider a loop L that defines a square.
+  // GetBound() ensures that if a point P is contained by this square, then
+  // S2LatLng(P) is contained by the bound.  But now consider a diamond
+  // shaped loop S contained by L.  It is possible that GetBound() returns a
+  // *larger* bound for S than it does for L, due to rounding errors.  This
+  // method expands the bound for L so that it is guaranteed to contain the
+  // bounds of any subregion S.
+  //
+  // More precisely, if L is a loop that does not contain either pole, and S
+  // is a loop such that L.Contains(S), then
+  //
+  //   ExpandForSubregions(RectBound(L)).Contains(RectBound(S)).
+  static S2LatLngRect ExpandForSubregions(const S2LatLngRect& bound);
+
+  // Returns the maximum error in GetBound() provided that the result does
+  // not include either pole.  It is only to be used for testing purposes
+  // (e.g., by passing it to S2LatLngRect::ApproxEquals).
+  static S2LatLng MaxErrorForTests();
+
+ private:
+  // Common back end for AddPoint() and AddLatLng().  b and b_latlng
+  // must refer to the same vertex.
+  void AddInternal(const S2Point& b, const S2LatLng& b_latlng);
+
+  S2Point a_;             // The previous vertex in the chain.
+  S2LatLng a_latlng_;     // The corresponding latitude-longitude.
+  S2LatLngRect bound_;    // The current bounding rectangle.
+
+  S2LatLngRectBounder(const S2LatLngRectBounder&) = delete;
+  void operator=(const S2LatLngRectBounder&) = delete;
+};
+
+#endif  // S2_S2LATLNG_RECT_BOUNDER_H_
diff --git a/src/s2/s2lax_loop_shape.cc b/src/s2/s2lax_loop_shape.cc
new file mode 100644 (file)
index 0000000..f1ba0a6
--- /dev/null
@@ -0,0 +1,104 @@
+// Copyright 2013 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// Author: ericv@google.com (Eric Veach)
+
+#include "s2/s2lax_loop_shape.h"
+
+#include <vector>
+
+#include "s2/s2loop.h"
+#include "s2/s2shapeutil_get_reference_point.h"
+
+using std::vector;
+using ReferencePoint = S2Shape::ReferencePoint;
+
+S2LaxLoopShape::S2LaxLoopShape(const vector<S2Point>& vertices) {
+  Init(vertices);
+}
+
+S2LaxLoopShape::S2LaxLoopShape(const S2Loop& loop) {
+  Init(loop);
+}
+
+void S2LaxLoopShape::Init(const vector<S2Point>& vertices) {
+  num_vertices_ = vertices.size();
+  vertices_.reset(new S2Point[num_vertices_]);
+  std::copy(vertices.begin(), vertices.end(), vertices_.get());
+}
+
+void S2LaxLoopShape::Init(const S2Loop& loop) {
+  S2_DCHECK(!loop.is_full()) << "Full loops not supported; use S2LaxPolygonShape";
+  if (loop.is_empty()) {
+    num_vertices_ = 0;
+    vertices_ = nullptr;
+  } else {
+    num_vertices_ = loop.num_vertices();
+    vertices_.reset(new S2Point[num_vertices_]);
+    std::copy(&loop.vertex(0), &loop.vertex(0) + num_vertices_,
+              vertices_.get());
+  }
+}
+
+S2Shape::Edge S2LaxLoopShape::edge(int e0) const {
+  S2_DCHECK_LT(e0, num_edges());
+  int e1 = e0 + 1;
+  if (e1 == num_vertices()) e1 = 0;
+  return Edge(vertices_[e0], vertices_[e1]);
+}
+
+S2Shape::Edge S2LaxLoopShape::chain_edge(int i, int j) const {
+  S2_DCHECK_EQ(i, 0);
+  S2_DCHECK_LT(j, num_edges());
+  int k = (j + 1 == num_vertices()) ? 0 : j + 1;
+  return Edge(vertices_[j], vertices_[k]);
+}
+
+S2Shape::ReferencePoint S2LaxLoopShape::GetReferencePoint() const {
+  return s2shapeutil::GetReferencePoint(*this);
+}
+
+S2VertexIdLaxLoopShape::S2VertexIdLaxLoopShape(
+    const std::vector<int32>& vertex_ids, const S2Point* vertex_array) {
+  Init(vertex_ids, vertex_array);
+}
+
+void S2VertexIdLaxLoopShape::Init(const std::vector<int32>& vertex_ids,
+                           const S2Point* vertex_array) {
+  num_vertices_ = vertex_ids.size();
+  vertex_ids_.reset(new int32[num_vertices_]);
+  std::copy(vertex_ids.begin(), vertex_ids.end(), vertex_ids_.get());
+  vertex_array_ = vertex_array;
+}
+
+S2Shape::Edge S2VertexIdLaxLoopShape::edge(int e0) const {
+  S2_DCHECK_LT(e0, num_edges());
+  int e1 = e0 + 1;
+  if (e1 == num_vertices()) e1 = 0;
+  return Edge(vertex(e0), vertex(e1));
+}
+
+S2Shape::Edge S2VertexIdLaxLoopShape::chain_edge(int i, int j) const {
+  S2_DCHECK_EQ(i, 0);
+  S2_DCHECK_LT(j, num_edges());
+  int k = (j + 1 == num_vertices()) ? 0 : j + 1;
+  return Edge(vertex(j), vertex(k));
+}
+
+S2Shape::ReferencePoint S2VertexIdLaxLoopShape::GetReferencePoint() const {
+  // GetReferencePoint interprets a loop with no vertices as "full".
+  if (num_vertices() == 0) return ReferencePoint::Contained(false);
+  return s2shapeutil::GetReferencePoint(*this);
+}
diff --git a/src/s2/s2lax_loop_shape.h b/src/s2/s2lax_loop_shape.h
new file mode 100644 (file)
index 0000000..7740e80
--- /dev/null
@@ -0,0 +1,153 @@
+// Copyright 2013 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// Author: ericv@google.com (Eric Veach)
+//
+// This file defines various S2Shape types representing loops:
+//
+// S2LaxLoopShape
+//   - like S2Loop::Shape but allows duplicate vertices & edges, more compact
+//     representation, and faster to initialize.
+//
+// S2LaxClosedPolylineShape
+//   - like S2LaxLoopShape, but defines a loop that does not have an interior
+//     (a closed polyline).
+//
+// S2VertexIdLaxLoopShape
+//   - like S2LaxLoopShape, but vertices are specified as indices into an
+//     existing vertex array.
+
+#ifndef S2_S2LAX_LOOP_SHAPE_H_
+#define S2_S2LAX_LOOP_SHAPE_H_
+
+#include <algorithm>
+#include <memory>
+#include <vector>
+
+#include "s2/s2loop.h"
+#include "s2/s2shape.h"
+
+// S2LaxLoopShape represents a closed loop of edges surrounding an interior
+// region.  It is similar to S2Loop::Shape except that this class allows
+// duplicate vertices and edges.  Loops may have any number of vertices,
+// including 0, 1, or 2.  (A one-vertex loop defines a degenerate edge
+// consisting of a single point.)
+//
+// Note that S2LaxLoopShape is faster to initialize and more compact than
+// S2Loop::Shape, but does not support the same operations as S2Loop.
+class S2LaxLoopShape : public S2Shape {
+ public:
+  // Constructs an empty loop.
+  S2LaxLoopShape() : num_vertices_(0) {}
+
+  // Constructs an S2LaxLoopShape with the given vertices.
+  explicit S2LaxLoopShape(const std::vector<S2Point>& vertices);
+
+  // Constructs an S2LaxLoopShape from the given S2Loop, by copying its data.
+  explicit S2LaxLoopShape(const S2Loop& loop);
+
+  // Initializes an S2LaxLoopShape with the given vertices.
+  void Init(const std::vector<S2Point>& vertices);
+
+  // Initializes an S2LaxLoopShape from the given S2Loop, by copying its data.
+  //
+  // REQUIRES: !loop->is_full()
+  //           [Use S2LaxPolygonShape if you need to represent a full loop.]
+  void Init(const S2Loop& loop);
+
+  int num_vertices() const { return num_vertices_; }
+  const S2Point& vertex(int i) const { return vertices_[i]; }
+
+  // S2Shape interface:
+  int num_edges() const final { return num_vertices(); }
+  Edge edge(int e) const final;
+  // Not final; overridden by S2LaxClosedPolylineShape.
+  int dimension() const override { return 2; }
+  // Not final; overridden by S2LaxClosedPolylineShape.
+  ReferencePoint GetReferencePoint() const override;
+  int num_chains() const final { return std::min(1, num_vertices_); }
+  Chain chain(int i) const final { return Chain(0, num_vertices_); }
+  Edge chain_edge(int i, int j) const final;
+  ChainPosition chain_position(int e) const final {
+    return ChainPosition(0, e);
+  }
+
+ private:
+  // For clients that have many small loops, we save some memory by
+  // representing the vertices as an array rather than using std::vector.
+  int32 num_vertices_;
+  std::unique_ptr<S2Point[]> vertices_;
+};
+
+// S2LaxClosedPolylineShape is like S2LaxPolylineShape except that the last
+// vertex is implicitly joined to the first.  It is also like S2LaxLoopShape
+// except that it does not have an interior (which makes it more efficient to
+// index).
+class S2LaxClosedPolylineShape : public S2LaxLoopShape {
+ public:
+  // See S2LaxLoopShape for constructors.
+  using S2LaxLoopShape::S2LaxLoopShape;
+
+  int dimension() const final { return 1; }
+  ReferencePoint GetReferencePoint() const final {
+    return ReferencePoint::Contained(false);
+  }
+};
+
+// S2VertexIdLaxLoopShape is just like S2LaxLoopShape, except that vertices are
+// specified as indices into a vertex array.  This representation can be more
+// compact when many loops are arranged in a mesh structure.
+class S2VertexIdLaxLoopShape : public S2Shape {
+ public:
+  // Constructs an empty loop.
+  S2VertexIdLaxLoopShape() : num_vertices_(0) {}
+
+  // Constructs the shape from the given vertex array and indices.
+  // "vertex_ids" is a vector of indices into "vertex_array".
+  //
+  // ENSURES:  loop->vertex(i) == (*vertex_array)[vertex_ids[i]]
+  // REQUIRES: "vertex_array" persists for the lifetime of this object.
+  explicit S2VertexIdLaxLoopShape(const std::vector<int32>& vertex_ids,
+                                  const S2Point* vertex_array);
+
+  // Initializes the shape from the given vertex array and indices.
+  // "vertex_ids" is a vector of indices into "vertex_array".
+  void Init(const std::vector<int32>& vertex_ids,
+            const S2Point* vertex_array);
+
+  // Returns the number of vertices in the loop.
+  int num_vertices() const { return num_vertices_; }
+  int32 vertex_id(int i) const { return vertex_ids_[i]; }
+  const S2Point& vertex(int i) const { return vertex_array_[vertex_id(i)]; }
+
+  // S2Shape interface:
+  int num_edges() const final { return num_vertices(); }
+  Edge edge(int e) const final;
+  int dimension() const final { return 2; }
+  ReferencePoint GetReferencePoint() const final;
+  int num_chains() const final { return std::min(1, num_vertices_); }
+  Chain chain(int i) const final { return Chain(0, num_vertices_); }
+  Edge chain_edge(int i, int j) const final;
+  ChainPosition chain_position(int e) const final {
+    return ChainPosition(0, e);
+  }
+
+ private:
+  int32 num_vertices_;
+  std::unique_ptr<int32[]> vertex_ids_;
+  const S2Point* vertex_array_;
+};
+
+#endif  // S2_S2LAX_LOOP_SHAPE_H_
diff --git a/src/s2/s2lax_polygon_shape.cc b/src/s2/s2lax_polygon_shape.cc
new file mode 100644 (file)
index 0000000..43c3d94
--- /dev/null
@@ -0,0 +1,348 @@
+// Copyright 2013 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// Author: ericv@google.com (Eric Veach)
+
+#include "s2/s2lax_polygon_shape.h"
+
+#include "s2/s2shapeutil_get_reference_point.h"
+
+using absl::make_unique;
+using absl::MakeSpan;
+using absl::Span;
+using std::vector;
+using ChainPosition = S2Shape::ChainPosition;
+
+// When adding a new encoding, be aware that old binaries will not be able
+// to decode it.
+static const unsigned char kCurrentEncodingVersionNumber = 1;
+
+S2LaxPolygonShape::S2LaxPolygonShape(
+    const vector<S2LaxPolygonShape::Loop>& loops) {
+  Init(loops);
+}
+
+S2LaxPolygonShape::S2LaxPolygonShape(const S2Polygon& polygon) {
+  Init(polygon);
+}
+
+void S2LaxPolygonShape::Init(const vector<S2LaxPolygonShape::Loop>& loops) {
+  vector<Span<const S2Point>> spans;
+  spans.reserve(loops.size());
+  for (const S2LaxPolygonShape::Loop& loop : loops) {
+    spans.emplace_back(loop);
+  }
+  Init(spans);
+}
+
+void S2LaxPolygonShape::Init(const S2Polygon& polygon) {
+  vector<Span<const S2Point>> spans;
+  for (int i = 0; i < polygon.num_loops(); ++i) {
+    const S2Loop* loop = polygon.loop(i);
+    if (loop->is_full()) {
+      spans.emplace_back();  // Empty span.
+    } else {
+      spans.emplace_back(&loop->vertex(0), loop->num_vertices());
+    }
+  }
+  Init(spans);
+
+  // S2Polygon and S2LaxPolygonShape holes are oriented oppositely, so we need
+  // to reverse the orientation of any loops representing holes.
+  for (int i = 0; i < polygon.num_loops(); ++i) {
+    if (polygon.loop(i)->is_hole()) {
+      S2Point* v0 = &vertices_[cumulative_vertices_[i]];
+      std::reverse(v0, v0 + num_loop_vertices(i));
+    }
+  }
+}
+
+void S2LaxPolygonShape::Init(const vector<Span<const S2Point>>& loops) {
+  num_loops_ = loops.size();
+  if (num_loops_ == 0) {
+    num_vertices_ = 0;
+    vertices_ = nullptr;
+  } else if (num_loops_ == 1) {
+    num_vertices_ = loops[0].size();
+    vertices_.reset(new S2Point[num_vertices_]);
+    std::copy(loops[0].begin(), loops[0].end(), vertices_.get());
+  } else {
+    cumulative_vertices_ = new uint32[num_loops_ + 1];
+    int32 num_vertices = 0;
+    for (int i = 0; i < num_loops_; ++i) {
+      cumulative_vertices_[i] = num_vertices;
+      num_vertices += loops[i].size();
+    }
+    cumulative_vertices_[num_loops_] = num_vertices;
+    vertices_.reset(new S2Point[num_vertices]);
+    for (int i = 0; i < num_loops_; ++i) {
+      std::copy(loops[i].begin(), loops[i].end(),
+                vertices_.get() + cumulative_vertices_[i]);
+    }
+  }
+}
+
+S2LaxPolygonShape::~S2LaxPolygonShape() {
+  if (num_loops() > 1) {
+    delete[] cumulative_vertices_;
+  }
+}
+
+int S2LaxPolygonShape::num_vertices() const {
+  if (num_loops() <= 1) {
+    return num_vertices_;
+  } else {
+    return cumulative_vertices_[num_loops()];
+  }
+}
+
+int S2LaxPolygonShape::num_loop_vertices(int i) const {
+  S2_DCHECK_LT(i, num_loops());
+  if (num_loops() == 1) {
+    return num_vertices_;
+  } else {
+    return cumulative_vertices_[i + 1] - cumulative_vertices_[i];
+  }
+}
+
+const S2Point& S2LaxPolygonShape::loop_vertex(int i, int j) const {
+  S2_DCHECK_LT(i, num_loops());
+  S2_DCHECK_LT(j, num_loop_vertices(i));
+  if (num_loops() == 1) {
+    return vertices_[j];
+  } else {
+    return vertices_[cumulative_vertices_[i] + j];
+  }
+}
+
+void S2LaxPolygonShape::Encode(Encoder* encoder,
+                               s2coding::CodingHint hint) const {
+  encoder->Ensure(1 + Varint::kMax32);
+  encoder->put8(kCurrentEncodingVersionNumber);
+  encoder->put_varint32(num_loops_);
+  s2coding::EncodeS2PointVector(MakeSpan(vertices_.get(), num_vertices()),
+                                hint, encoder);
+  if (num_loops() > 1) {
+    s2coding::EncodeUintVector<uint32>(MakeSpan(cumulative_vertices_,
+                                                num_loops() + 1), encoder);
+  }
+}
+
+bool S2LaxPolygonShape::Init(Decoder* decoder) {
+  if (decoder->avail() < 1) return false;
+  uint8 version = decoder->get8();
+  if (version != kCurrentEncodingVersionNumber) return false;
+
+  uint32 num_loops;
+  if (!decoder->get_varint32(&num_loops)) return false;
+  num_loops_ = num_loops;
+  s2coding::EncodedS2PointVector vertices;
+  if (!vertices.Init(decoder)) return false;
+
+  if (num_loops_ == 0) {
+    num_vertices_ = 0;
+    vertices_ = nullptr;
+  } else {
+    vertices_ = make_unique<S2Point[]>(vertices.size());
+    for (int i = 0; i < vertices.size(); ++i) {
+      vertices_[i] = vertices[i];
+    }
+    if (num_loops_ == 1) {
+      num_vertices_ = vertices.size();
+    } else {
+      s2coding::EncodedUintVector<uint32> cumulative_vertices;
+      if (!cumulative_vertices.Init(decoder)) return false;
+      cumulative_vertices_ = new uint32[cumulative_vertices.size()];
+      for (int i = 0; i < cumulative_vertices.size(); ++i) {
+        cumulative_vertices_[i] = cumulative_vertices[i];
+      }
+    }
+  }
+  return true;
+}
+
+S2Shape::Edge S2LaxPolygonShape::edge(int e0) const {
+  S2_DCHECK_LT(e0, num_edges());
+  int e1 = e0 + 1;
+  if (num_loops() == 1) {
+    if (e1 == num_vertices_) { e1 = 0; }
+  } else {
+    // Find the index of the first vertex of the loop following this one.
+    const int kMaxLinearSearchLoops = 12;  // From benchmarks.
+    uint32* next = cumulative_vertices_ + 1;
+    if (num_loops() <= kMaxLinearSearchLoops) {
+      while (*next <= e0) ++next;
+    } else {
+      next = std::lower_bound(next, next + num_loops(), e1);
+    }
+    // Wrap around to the first vertex of the loop if necessary.
+    if (e1 == *next) { e1 = next[-1]; }
+  }
+  return Edge(vertices_[e0], vertices_[e1]);
+}
+
+S2Shape::ReferencePoint S2LaxPolygonShape::GetReferencePoint() const {
+  return s2shapeutil::GetReferencePoint(*this);
+}
+
+S2Shape::Chain S2LaxPolygonShape::chain(int i) const {
+  S2_DCHECK_LT(i, num_loops());
+  if (num_loops() == 1) {
+    return Chain(0, num_vertices_);
+  } else {
+    int start = cumulative_vertices_[i];
+    return Chain(start, cumulative_vertices_[i + 1] - start);
+  }
+}
+
+S2Shape::Edge S2LaxPolygonShape::chain_edge(int i, int j) const {
+  S2_DCHECK_LT(i, num_loops());
+  S2_DCHECK_LT(j, num_loop_vertices(i));
+  int n = num_loop_vertices(i);
+  int k = (j + 1 == n) ? 0 : j + 1;
+  if (num_loops() == 1) {
+    return Edge(vertices_[j], vertices_[k]);
+  } else {
+    int base = cumulative_vertices_[i];
+    return Edge(vertices_[base + j], vertices_[base + k]);
+  }
+}
+
+S2Shape::ChainPosition S2LaxPolygonShape::chain_position(int e) const {
+  S2_DCHECK_LT(e, num_edges());
+  const int kMaxLinearSearchLoops = 12;  // From benchmarks.
+  if (num_loops() == 1) {
+    return ChainPosition(0, e);
+  } else {
+    // Find the index of the first vertex of the loop following this one.
+    uint32* next = cumulative_vertices_ + 1;
+    if (num_loops() <= kMaxLinearSearchLoops) {
+      while (*next <= e) ++next;
+    } else {
+      next = std::lower_bound(next, next + num_loops(), e + 1);
+    }
+    return ChainPosition(next - (cumulative_vertices_ + 1), e - next[-1]);
+  }
+}
+
+bool EncodedS2LaxPolygonShape::Init(Decoder* decoder) {
+  if (decoder->avail() < 1) return false;
+  uint8 version = decoder->get8();
+  if (version != kCurrentEncodingVersionNumber) return false;
+
+  uint32 num_loops;
+  if (!decoder->get_varint32(&num_loops)) return false;
+  num_loops_ = num_loops;
+
+  if (!vertices_.Init(decoder)) return false;
+
+  if (num_loops_ > 1) {
+    if (!cumulative_vertices_.Init(decoder)) return false;
+  }
+  return true;
+}
+
+int EncodedS2LaxPolygonShape::num_vertices() const {
+  if (num_loops() <= 1) {
+    return vertices_.size();
+  } else {
+    return cumulative_vertices_[num_loops()];
+  }
+}
+
+int EncodedS2LaxPolygonShape::num_loop_vertices(int i) const {
+  S2_DCHECK_LT(i, num_loops());
+  if (num_loops() == 1) {
+    return vertices_.size();
+  } else {
+    return cumulative_vertices_[i + 1] - cumulative_vertices_[i];
+  }
+}
+
+S2Point EncodedS2LaxPolygonShape::loop_vertex(int i, int j) const {
+  S2_DCHECK_LT(i, num_loops());
+  S2_DCHECK_LT(j, num_loop_vertices(i));
+  if (num_loops() == 1) {
+    return vertices_[j];
+  } else {
+    return vertices_[cumulative_vertices_[i] + j];
+  }
+}
+
+S2Shape::Edge EncodedS2LaxPolygonShape::edge(int e) const {
+  S2_DCHECK_LT(e, num_edges());
+  int e1 = e + 1;
+  if (num_loops() == 1) {
+    if (e1 == vertices_.size()) { e1 = 0; }
+  } else {
+    // Find the index of the first vertex of the loop following this one.
+    const int kMaxLinearSearchLoops = 12;  // From benchmarks.
+    int next = 1;
+    if (num_loops() <= kMaxLinearSearchLoops) {
+      while (cumulative_vertices_[next] <= e) ++next;
+    } else {
+      next = cumulative_vertices_.lower_bound(e1);
+    }
+    // Wrap around to the first vertex of the loop if necessary.
+    if (e1 == cumulative_vertices_[next]) {
+      e1 = cumulative_vertices_[next - 1];
+    }
+  }
+  return Edge(vertices_[e], vertices_[e1]);
+}
+
+S2Shape::ReferencePoint EncodedS2LaxPolygonShape::GetReferencePoint() const {
+  return s2shapeutil::GetReferencePoint(*this);
+}
+
+S2Shape::Chain EncodedS2LaxPolygonShape::chain(int i) const {
+  S2_DCHECK_LT(i, num_loops());
+  if (num_loops() == 1) {
+    return Chain(0, vertices_.size());
+  } else {
+    int start = cumulative_vertices_[i];
+    return Chain(start, cumulative_vertices_[i + 1] - start);
+  }
+}
+
+S2Shape::Edge EncodedS2LaxPolygonShape::chain_edge(int i, int j) const {
+  S2_DCHECK_LT(i, num_loops());
+  S2_DCHECK_LT(j, num_loop_vertices(i));
+  int n = num_loop_vertices(i);
+  int k = (j + 1 == n) ? 0 : j + 1;
+  if (num_loops() == 1) {
+    return Edge(vertices_[j], vertices_[k]);
+  } else {
+    int base = cumulative_vertices_[i];
+    return Edge(vertices_[base + j], vertices_[base + k]);
+  }
+}
+
+S2Shape::ChainPosition EncodedS2LaxPolygonShape::chain_position(int e) const {
+  S2_DCHECK_LT(e, num_edges());
+  const int kMaxLinearSearchLoops = 12;  // From benchmarks.
+  if (num_loops() == 1) {
+    return ChainPosition(0, e);
+  } else {
+    // Find the index of the first vertex of the loop following this one.
+    int next = 1;
+    if (num_loops() <= kMaxLinearSearchLoops) {
+      while (cumulative_vertices_[next] <= e) ++next;
+    } else {
+      next = cumulative_vertices_.lower_bound(e + 1);
+    }
+    return ChainPosition(next - 1, e - cumulative_vertices_[next - 1]);
+  }
+}
diff --git a/src/s2/s2lax_polygon_shape.h b/src/s2/s2lax_polygon_shape.h
new file mode 100644 (file)
index 0000000..f261382
--- /dev/null
@@ -0,0 +1,183 @@
+// Copyright 2013 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// Author: ericv@google.com (Eric Veach)
+
+#ifndef S2_S2LAX_POLYGON_SHAPE_H_
+#define S2_S2LAX_POLYGON_SHAPE_H_
+
+#include <memory>
+#include <vector>
+
+#include "absl/types/span.h"
+#include "s2/encoded_s2point_vector.h"
+#include "s2/encoded_uint_vector.h"
+#include "s2/s2polygon.h"
+#include "s2/s2shape.h"
+
+// S2LaxPolygonShape represents a region defined by a collection of zero or
+// more closed loops.  The interior is the region to the left of all loops.
+// This is similar to S2Polygon::Shape except that this class supports
+// polygons with degeneracies.  Degeneracies are of two types: degenerate
+// edges (from a vertex to itself) and sibling edge pairs (consisting of two
+// oppositely oriented edges).  Degeneracies can represent either "shells" or
+// "holes" depending on the loop they are contained by.  For example, a
+// degenerate edge or sibling pair contained by a "shell" would be interpreted
+// as a degenerate hole.  Such edges form part of the boundary of the polygon.
+//
+// Loops with fewer than three vertices are interpreted as follows:
+//  - A loop with two vertices defines two edges (in opposite directions).
+//  - A loop with one vertex defines a single degenerate edge.
+//  - A loop with no vertices is interpreted as the "full loop" containing
+//    all points on the sphere.  If this loop is present, then all other loops
+//    must form degeneracies (i.e., degenerate edges or sibling pairs).  For
+//    example, two loops {} and {X} would be interpreted as the full polygon
+//    with a degenerate single-point hole at X.
+//
+// S2LaxPolygonShape does not have any error checking, and it is perfectly
+// fine to create S2LaxPolygonShape objects that do not meet the requirements
+// below (e.g., in order to analyze or fix those problems).  However,
+// S2LaxPolygonShapes must satisfy some additional conditions in order to
+// perform certain operations:
+//
+//  - In order to be valid for point containment tests, the polygon must
+//    satisfy the "interior is on the left" rule.  This means that there must
+//    not be any crossing edges, and if there are duplicate edges then all but
+//    at most one of thm must belong to a sibling pair (i.e., the number of
+//    edges in opposite directions must differ by at most one).
+//
+//  - To be valid for boolean operations (S2BooleanOperation), degenerate
+//    edges and sibling pairs cannot coincide with any other edges.  For
+//    example, the following situations are not allowed:
+//
+//      {AA, AA}      // degenerate edge coincides with another edge
+//      {AA, AB}      // degenerate edge coincides with another edge
+//      {AB, BA, AB}  // sibling pair coincides with another edge
+//
+// Note that S2LaxPolygonShape is must faster to initialize and is more
+// compact than S2Polygon, but unlike S2Polygon it does not have any built-in
+// operations.  Instead you should use S2ShapeIndex operations
+// (S2BooleanOperation, S2ClosestEdgeQuery, etc).
+class S2LaxPolygonShape : public S2Shape {
+ public:
+  static constexpr TypeTag kTypeTag = 5;
+
+  // Constructs an empty polygon.
+  S2LaxPolygonShape() : num_loops_(0), num_vertices_(0) {}
+
+  // Constructs an S2LaxPolygonShape from the given vertex loops.
+  using Loop = std::vector<S2Point>;
+  explicit S2LaxPolygonShape(const std::vector<Loop>& loops);
+
+  // Constructs an S2LaxPolygonShape from an S2Polygon, by copying its data.
+  // Full and empty S2Polygons are supported.
+  explicit S2LaxPolygonShape(const S2Polygon& polygon);
+
+  ~S2LaxPolygonShape() override;
+
+  // Initializes an S2LaxPolygonShape from the given vertex loops.
+  void Init(const std::vector<Loop>& loops);
+
+  // Initializes an S2LaxPolygonShape from an S2Polygon, by copying its data.
+  // Full and empty S2Polygons are supported.
+  void Init(const S2Polygon& polygon);
+
+  // Returns the number of loops.
+  int num_loops() const { return num_loops_; }
+
+  // Returns the total number of vertices in all loops.
+  int num_vertices() const;
+
+  // Returns the number of vertices in the given loop.
+  int num_loop_vertices(int i) const;
+
+  // Returns the vertex from loop "i" at index "j".
+  // REQUIRES: 0 <= i < num_loops()
+  // REQUIRES: 0 <= j < num_loop_vertices(i)
+  const S2Point& loop_vertex(int i, int j) const;
+
+  // Appends an encoded representation of the S2LaxPolygonShape to "encoder".
+  //
+  // REQUIRES: "encoder" uses the default constructor, so that its buffer
+  //           can be enlarged as necessary by calling Ensure(int).
+  void Encode(Encoder* encoder,
+              s2coding::CodingHint hint = s2coding::CodingHint::COMPACT) const;
+
+  // Decodes an S2LaxPolygonShape, returning true on success.  (The method
+  // name is chosen for compatibility with EncodedS2LaxPolygonShape below.)
+  bool Init(Decoder* decoder);
+
+  // S2Shape interface:
+  int num_edges() const final { return num_vertices(); }
+  Edge edge(int e) const final;
+  int dimension() const final { return 2; }
+  ReferencePoint GetReferencePoint() const final;
+  int num_chains() const final { return num_loops(); }
+  Chain chain(int i) const final;
+  Edge chain_edge(int i, int j) const final;
+  ChainPosition chain_position(int e) const final;
+  TypeTag type_tag() const override { return kTypeTag; }
+
+ private:
+  void Init(const std::vector<absl::Span<const S2Point>>& loops);
+
+  int32 num_loops_;
+  std::unique_ptr<S2Point[]> vertices_;
+  // If num_loops_ <= 1, this union stores the number of vertices.
+  // Otherwise it points to an array of size (num_loops + 1) where element "i"
+  // is the total number of vertices in loops 0..i-1.
+  union {
+    int32 num_vertices_;
+    uint32* cumulative_vertices_;  // Don't use unique_ptr in unions.
+  };
+};
+
+// Exactly like S2LaxPolygonShape, except that the vertices are kept in an
+// encoded form and are decoded only as they are accessed.  This allows for
+// very fast initialization and no additional memory use beyond the encoded
+// data.  The encoded data is not owned by this class; typically it points
+// into a large contiguous buffer that contains other encoded data as well.
+class EncodedS2LaxPolygonShape : public S2Shape {
+ public:
+  // Constructs an uninitialized object; requires Init() to be called.
+  EncodedS2LaxPolygonShape() {}
+
+  // Initializes an EncodedS2LaxPolygonShape.
+  //
+  // REQUIRES: The Decoder data buffer must outlive this object.
+  bool Init(Decoder* decoder);
+
+  int num_loops() const { return num_loops_; }
+  int num_vertices() const;
+  int num_loop_vertices(int i) const;
+  S2Point loop_vertex(int i, int j) const;
+
+  // S2Shape interface:
+  int num_edges() const final { return num_vertices(); }
+  Edge edge(int e) const final;
+  int dimension() const final { return 2; }
+  ReferencePoint GetReferencePoint() const final;
+  int num_chains() const final { return num_loops(); }
+  Chain chain(int i) const final;
+  Edge chain_edge(int i, int j) const final;
+  ChainPosition chain_position(int e) const final;
+
+ private:
+  int32 num_loops_;
+  s2coding::EncodedS2PointVector vertices_;
+  s2coding::EncodedUintVector<uint32> cumulative_vertices_;
+};
+
+#endif  // S2_S2LAX_POLYGON_SHAPE_H_
diff --git a/src/s2/s2lax_polyline_shape.cc b/src/s2/s2lax_polyline_shape.cc
new file mode 100644 (file)
index 0000000..af14344
--- /dev/null
@@ -0,0 +1,118 @@
+// Copyright 2013 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// Author: ericv@google.com (Eric Veach)
+
+#include "s2/s2lax_polyline_shape.h"
+
+#include <algorithm>
+#include "s2/base/logging.h"
+#include "s2/s2polyline.h"
+
+using absl::make_unique;
+using absl::MakeSpan;
+using std::vector;
+
+S2LaxPolylineShape::S2LaxPolylineShape(const vector<S2Point>& vertices) {
+  Init(vertices);
+}
+
+S2LaxPolylineShape::S2LaxPolylineShape(const S2Polyline& polyline) {
+  Init(polyline);
+}
+
+void S2LaxPolylineShape::Init(const vector<S2Point>& vertices) {
+  num_vertices_ = vertices.size();
+  S2_LOG_IF(WARNING, num_vertices_ == 1)
+      << "s2shapeutil::S2LaxPolylineShape with one vertex has no edges";
+  vertices_.reset(new S2Point[num_vertices_]);
+  std::copy(vertices.begin(), vertices.end(), vertices_.get());
+}
+
+void S2LaxPolylineShape::Init(const S2Polyline& polyline) {
+  num_vertices_ = polyline.num_vertices();
+  S2_LOG_IF(WARNING, num_vertices_ == 1)
+      << "s2shapeutil::S2LaxPolylineShape with one vertex has no edges";
+  vertices_.reset(new S2Point[num_vertices_]);
+  std::copy(&polyline.vertex(0), &polyline.vertex(0) + num_vertices_,
+            vertices_.get());
+}
+
+void S2LaxPolylineShape::Encode(Encoder* encoder,
+                                s2coding::CodingHint hint) const {
+  s2coding::EncodeS2PointVector(MakeSpan(vertices_.get(), num_vertices_),
+                                hint, encoder);
+}
+
+bool S2LaxPolylineShape::Init(Decoder* decoder) {
+  s2coding::EncodedS2PointVector vertices;
+  if (!vertices.Init(decoder)) return false;
+  num_vertices_ = vertices.size();
+  vertices_ = make_unique<S2Point[]>(vertices.size());
+  for (int i = 0; i < num_vertices_; ++i) {
+    vertices_[i] = vertices[i];
+  }
+  return true;
+}
+
+S2Shape::Edge S2LaxPolylineShape::edge(int e) const {
+  S2_DCHECK_LT(e, num_edges());
+  return Edge(vertex(e), vertex(e + 1));
+}
+
+int S2LaxPolylineShape::num_chains() const {
+  return std::min(1, S2LaxPolylineShape::num_edges());  // Avoid virtual call.
+}
+
+S2Shape::Chain S2LaxPolylineShape::chain(int i) const {
+  return Chain(0, S2LaxPolylineShape::num_edges());  // Avoid virtual call.
+}
+
+S2Shape::Edge S2LaxPolylineShape::chain_edge(int i, int j) const {
+  S2_DCHECK_EQ(i, 0);
+  S2_DCHECK_LT(j, num_edges());
+  return Edge(vertex(j), vertex(j + 1));
+}
+
+S2Shape::ChainPosition S2LaxPolylineShape::chain_position(int e) const {
+  return S2Shape::ChainPosition(0, e);
+}
+
+bool EncodedS2LaxPolylineShape::Init(Decoder* decoder) {
+  return vertices_.Init(decoder);
+}
+
+S2Shape::Edge EncodedS2LaxPolylineShape::edge(int e) const {
+  S2_DCHECK_LT(e, num_edges());
+  return Edge(vertex(e), vertex(e + 1));
+}
+
+int EncodedS2LaxPolylineShape::num_chains() const {
+  return std::min(1, EncodedS2LaxPolylineShape::num_edges());
+}
+
+S2Shape::Chain EncodedS2LaxPolylineShape::chain(int i) const {
+  return Chain(0, EncodedS2LaxPolylineShape::num_edges());
+}
+
+S2Shape::Edge EncodedS2LaxPolylineShape::chain_edge(int i, int j) const {
+  S2_DCHECK_EQ(i, 0);
+  S2_DCHECK_LT(j, num_edges());
+  return Edge(vertex(j), vertex(j + 1));
+}
+
+S2Shape::ChainPosition EncodedS2LaxPolylineShape::chain_position(int e) const {
+  return S2Shape::ChainPosition(0, e);
+}
diff --git a/src/s2/s2lax_polyline_shape.h b/src/s2/s2lax_polyline_shape.h
new file mode 100644 (file)
index 0000000..d0f384f
--- /dev/null
@@ -0,0 +1,124 @@
+// Copyright 2013 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// Author: ericv@google.com (Eric Veach)
+
+#ifndef S2_S2LAX_POLYLINE_SHAPE_H_
+#define S2_S2LAX_POLYLINE_SHAPE_H_
+
+#include <memory>
+#include <vector>
+#include "s2/encoded_s2point_vector.h"
+#include "s2/s2polyline.h"
+#include "s2/s2shape.h"
+
+// S2LaxPolylineShape represents a polyline.  It is similar to
+// S2Polyline::Shape except that duplicate vertices are allowed, and the
+// representation is slightly more compact.
+//
+// Polylines may have any number of vertices, but note that polylines with
+// fewer than 2 vertices do not define any edges.  (To create a polyline
+// consisting of a single degenerate edge, either repeat the same vertex twice
+// or use S2LaxClosedPolylineShape defined in s2_lax_loop_shape.h.)
+class S2LaxPolylineShape : public S2Shape {
+ public:
+  static constexpr TypeTag kTypeTag = 4;
+
+  // Constructs an empty polyline.
+  S2LaxPolylineShape() : num_vertices_(0) {}
+
+  // Constructs an S2LaxPolylineShape with the given vertices.
+  explicit S2LaxPolylineShape(const std::vector<S2Point>& vertices);
+
+  // Constructs an S2LaxPolylineShape from the given S2Polyline, by copying
+  // its data.
+  explicit S2LaxPolylineShape(const S2Polyline& polyline);
+
+  // Initializes an S2LaxPolylineShape with the given vertices.
+  void Init(const std::vector<S2Point>& vertices);
+
+  // Initializes an S2LaxPolylineShape from the given S2Polyline, by copying
+  // its data.
+  void Init(const S2Polyline& polyline);
+
+  int num_vertices() const { return num_vertices_; }
+  const S2Point& vertex(int i) const { return vertices_[i]; }
+
+  // Appends an encoded representation of the S2LaxPolylineShape to "encoder".
+  //
+  // REQUIRES: "encoder" uses the default constructor, so that its buffer
+  //           can be enlarged as necessary by calling Ensure(int).
+  void Encode(Encoder* encoder,
+              s2coding::CodingHint hint = s2coding::CodingHint::COMPACT) const;
+
+  // Decodes an S2LaxPolylineShape, returning true on success.  (The method
+  // name is chosen for compatibility with EncodedS2LaxPolylineShape below.)
+  bool Init(Decoder* decoder);
+
+  // S2Shape interface:
+  int num_edges() const final { return std::max(0, num_vertices() - 1); }
+  Edge edge(int e) const final;
+  int dimension() const final { return 1; }
+  ReferencePoint GetReferencePoint() const final {
+    return ReferencePoint::Contained(false);
+  }
+  int num_chains() const final;
+  Chain chain(int i) const final;
+  Edge chain_edge(int i, int j) const final;
+  ChainPosition chain_position(int e) const final;
+  TypeTag type_tag() const override { return kTypeTag; }
+
+ private:
+  // For clients that have many small polylines, we save some memory by
+  // representing the vertices as an array rather than using std::vector.
+  int32 num_vertices_;
+  std::unique_ptr<S2Point[]> vertices_;
+};
+
+// Exactly like S2LaxPolylineShape, except that the vertices are kept in an
+// encoded form and are decoded only as they are accessed.  This allows for
+// very fast initialization and no additional memory use beyond the encoded
+// data.  The encoded data is not owned by this class; typically it points
+// into a large contiguous buffer that contains other encoded data as well.
+class EncodedS2LaxPolylineShape : public S2Shape {
+ public:
+  // Constructs an uninitialized object; requires Init() to be called.
+  EncodedS2LaxPolylineShape() {}
+
+  // Initializes an EncodedS2LaxPolylineShape.
+  //
+  // REQUIRES: The Decoder data buffer must outlive this object.
+  bool Init(Decoder* decoder);
+
+  int num_vertices() const { return vertices_.size(); }
+  S2Point vertex(int i) const { return vertices_[i]; }
+
+  // S2Shape interface:
+  int num_edges() const final { return std::max(0, num_vertices() - 1); }
+  Edge edge(int e) const final;
+  int dimension() const final { return 1; }
+  ReferencePoint GetReferencePoint() const final {
+    return ReferencePoint::Contained(false);
+  }
+  int num_chains() const final;
+  Chain chain(int i) const final;
+  Edge chain_edge(int i, int j) const final;
+  ChainPosition chain_position(int e) const final;
+
+ private:
+  s2coding::EncodedS2PointVector vertices_;
+};
+
+#endif  // S2_S2LAX_POLYLINE_SHAPE_H_
diff --git a/src/s2/s2loop.cc b/src/s2/s2loop.cc
new file mode 100644 (file)
index 0000000..4df96c8
--- /dev/null
@@ -0,0 +1,1509 @@
+// Copyright 2005 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// Author: ericv@google.com (Eric Veach)
+
+#include "s2/s2loop.h"
+
+#include <algorithm>
+#include <atomic>
+#include <bitset>
+#include <cfloat>
+#include <cmath>
+#include <set>
+#include <utility>
+#include <vector>
+
+#include "s2/base/commandlineflags.h"
+#include "s2/base/integral_types.h"
+#include "s2/base/logging.h"
+#include "s2/mutable_s2shape_index.h"
+#include "s2/r1interval.h"
+#include "s2/s1angle.h"
+#include "s2/s1interval.h"
+#include "s2/s2cap.h"
+#include "s2/s2cell.h"
+#include "s2/s2centroids.h"
+#include "s2/s2closest_edge_query.h"
+#include "s2/s2coords.h"
+#include "s2/s2crossing_edge_query.h"
+#include "s2/s2debug.h"
+#include "s2/s2edge_clipping.h"
+#include "s2/s2edge_crosser.h"
+#include "s2/s2edge_distances.h"
+#include "s2/s2error.h"
+#include "s2/s2latlng_rect_bounder.h"
+#include "s2/s2measures.h"
+#include "s2/s2padded_cell.h"
+#include "s2/s2point_compression.h"
+#include "s2/s2pointutil.h"
+#include "s2/s2predicates.h"
+#include "s2/s2shape_index.h"
+#include "s2/s2shapeutil_visit_crossing_edge_pairs.h"
+#include "s2/s2wedge_relations.h"
+#include "absl/memory/memory.h"
+#include "absl/types/span.h"
+#include "s2/util/coding/coder.h"
+#include "s2/util/coding/coder.h"
+#include "s2/util/math/matrix3x3.h"
+
+using absl::make_unique;
+using absl::MakeSpan;
+using std::pair;
+using std::set;
+using std::vector;
+
+DEFINE_bool(
+    s2loop_lazy_indexing, true,
+    "Build the S2ShapeIndex only when it is first needed.  This can save "
+    "significant amounts of memory and time when geometry is constructed but "
+    "never queried, for example when loops are passed directly to S2Polygon, "
+    "or when geometry is being converted from one format to another.");
+
+// The maximum number of vertices we'll allow when decoding a loop.
+// The default value of 50 million is about 30x bigger than the number of
+DEFINE_int32(
+    s2polygon_decode_max_num_vertices, 50000000,
+    "The upper limit on the number of loops that are allowed by the "
+    "S2Polygon::Decode method.");
+
+static const unsigned char kCurrentLosslessEncodingVersionNumber = 1;
+
+// Boolean properties for compressed loops.
+// See GetCompressedEncodingProperties.
+enum CompressedLoopProperty {
+  kOriginInside,
+  kBoundEncoded,
+  kNumProperties
+};
+
+S2Loop::S2Loop() {
+  // The loop is not valid until Init() is called.
+}
+
+S2Loop::S2Loop(const vector<S2Point>& vertices)
+  : S2Loop(vertices, S2Debug::ALLOW) {}
+
+S2Loop::S2Loop(const vector<S2Point>& vertices,
+               S2Debug override)
+  : s2debug_override_(override) {
+  Init(vertices);
+}
+
+void S2Loop::set_s2debug_override(S2Debug override) {
+  s2debug_override_ = override;
+}
+
+S2Debug S2Loop::s2debug_override() const {
+  return s2debug_override_;
+}
+
+void S2Loop::ClearIndex() {
+  unindexed_contains_calls_.store(0, std::memory_order_relaxed);
+  index_.Clear();
+}
+
+void S2Loop::Init(const vector<S2Point>& vertices) {
+  ClearIndex();
+  if (owns_vertices_) delete[] vertices_;
+  num_vertices_ = vertices.size();
+  vertices_ = new S2Point[num_vertices_];
+  std::copy(vertices.begin(), vertices.end(), &vertices_[0]);
+  owns_vertices_ = true;
+  InitOriginAndBound();
+}
+
+bool S2Loop::IsValid() const {
+  S2Error error;
+  if (FindValidationError(&error)) {
+    S2_LOG_IF(ERROR, FLAGS_s2debug) << error;
+    return false;
+  }
+  return true;
+}
+
+bool S2Loop::FindValidationError(S2Error* error) const {
+  return (FindValidationErrorNoIndex(error) ||
+          s2shapeutil::FindSelfIntersection(index_, error));
+}
+
+bool S2Loop::FindValidationErrorNoIndex(S2Error* error) const {
+  // subregion_bound_ must be at least as large as bound_.  (This is an
+  // internal consistency check rather than a test of client data.)
+  S2_DCHECK(subregion_bound_.Contains(bound_));
+
+  // All vertices must be unit length.  (Unfortunately this check happens too
+  // late in debug mode, because S2Loop construction calls s2pred::Sign which
+  // expects vertices to be unit length.  But it is still a useful check in
+  // optimized builds.)
+  for (int i = 0; i < num_vertices(); ++i) {
+    if (!S2::IsUnitLength(vertex(i))) {
+      error->Init(S2Error::NOT_UNIT_LENGTH,
+                  "Vertex %d is not unit length", i);
+      return true;
+    }
+  }
+  // Loops must have at least 3 vertices (except for the empty and full loops).
+  if (num_vertices() < 3) {
+    if (is_empty_or_full()) {
+      return false;  // Skip remaining tests.
+    }
+    error->Init(S2Error::LOOP_NOT_ENOUGH_VERTICES,
+                "Non-empty, non-full loops must have at least 3 vertices");
+    return true;
+  }
+  // Loops are not allowed to have any duplicate vertices or edge crossings.
+  // We split this check into two parts.  First we check that no edge is
+  // degenerate (identical endpoints).  Then we check that there are no
+  // intersections between non-adjacent edges (including at vertices).  The
+  // second part needs the S2ShapeIndex, so it does not fall within the scope
+  // of this method.
+  for (int i = 0; i < num_vertices(); ++i) {
+    if (vertex(i) == vertex(i+1)) {
+      error->Init(S2Error::DUPLICATE_VERTICES,
+                  "Edge %d is degenerate (duplicate vertex)", i);
+      return true;
+    }
+    if (vertex(i) == -vertex(i + 1)) {
+      error->Init(S2Error::ANTIPODAL_VERTICES,
+                  "Vertices %d and %d are antipodal", i,
+                  (i + 1) % num_vertices());
+      return true;
+    }
+  }
+  return false;
+}
+
+void S2Loop::InitOriginAndBound() {
+  if (num_vertices() < 3) {
+    // Check for the special empty and full loops (which have one vertex).
+    if (!is_empty_or_full()) {
+      origin_inside_ = false;
+      return;  // Bail out without trying to access non-existent vertices.
+    }
+    // If the vertex is in the southern hemisphere then the loop is full,
+    // otherwise it is empty.
+    origin_inside_ = (vertex(0).z() < 0);
+  } else {
+    // Point containment testing is done by counting edge crossings starting
+    // at a fixed point on the sphere (S2::Origin()).  Historically this was
+    // important, but it is now no longer necessary, and it may be worthwhile
+    // experimenting with using a loop vertex as the reference point.  In any
+    // case, we need to know whether the reference point (S2::Origin) is
+    // inside or outside the loop before we can construct the S2ShapeIndex.
+    // We do this by first guessing that it is outside, and then seeing
+    // whether we get the correct containment result for vertex 1.  If the
+    // result is incorrect, the origin must be inside the loop.
+    //
+    // A loop with consecutive vertices A,B,C contains vertex B if and only if
+    // the fixed vector R = S2::Ortho(B) is contained by the wedge ABC.  The
+    // wedge is closed at A and open at C, i.e. the point B is inside the loop
+    // if A=R but not if C=R.  This convention is required for compatibility
+    // with S2::VertexCrossing.  (Note that we can't use S2::Origin()
+    // as the fixed vector because of the possibility that B == S2::Origin().)
+    //
+    // TODO(ericv): Investigate using vertex(0) as the reference point.
+
+    origin_inside_ = false;  // Initialize before calling Contains().
+    bool v1_inside = s2pred::OrderedCCW(S2::Ortho(vertex(1)), vertex(0),
+                                        vertex(2), vertex(1));
+    // Note that Contains(S2Point) only does a bounds check once InitIndex()
+    // has been called, so it doesn't matter that bound_ is undefined here.
+    if (v1_inside != Contains(vertex(1))) {
+      origin_inside_ = true;
+    }
+  }
+  // We *must* call InitBound() before InitIndex(), because InitBound() calls
+  // Contains(S2Point), and Contains(S2Point) does a bounds check whenever the
+  // index is not fresh (i.e., the loop has been added to the index but the
+  // index has not been updated yet).
+  //
+  // TODO(ericv): When fewer S2Loop methods depend on internal bounds checks,
+  // consider computing the bound on demand as well.
+  InitBound();
+  InitIndex();
+}
+
+void S2Loop::InitBound() {
+  // Check for the special empty and full loops.
+  if (is_empty_or_full()) {
+    if (is_empty()) {
+      subregion_bound_ = bound_ = S2LatLngRect::Empty();
+    } else {
+      subregion_bound_ = bound_ = S2LatLngRect::Full();
+    }
+    return;
+  }
+
+  // The bounding rectangle of a loop is not necessarily the same as the
+  // bounding rectangle of its vertices.  First, the maximal latitude may be
+  // attained along the interior of an edge.  Second, the loop may wrap
+  // entirely around the sphere (e.g. a loop that defines two revolutions of a
+  // candy-cane stripe).  Third, the loop may include one or both poles.
+  // Note that a small clockwise loop near the equator contains both poles.
+
+  S2LatLngRectBounder bounder;
+  for (int i = 0; i <= num_vertices(); ++i) {
+    bounder.AddPoint(vertex(i));
+  }
+  S2LatLngRect b = bounder.GetBound();
+  if (Contains(S2Point(0, 0, 1))) {
+    b = S2LatLngRect(R1Interval(b.lat().lo(), M_PI_2), S1Interval::Full());
+  }
+  // If a loop contains the south pole, then either it wraps entirely
+  // around the sphere (full longitude range), or it also contains the
+  // north pole in which case b.lng().is_full() due to the test above.
+  // Either way, we only need to do the south pole containment test if
+  // b.lng().is_full().
+  if (b.lng().is_full() && Contains(S2Point(0, 0, -1))) {
+    b.mutable_lat()->set_lo(-M_PI_2);
+  }
+  bound_ = b;
+  subregion_bound_ = S2LatLngRectBounder::ExpandForSubregions(bound_);
+}
+
+void S2Loop::InitIndex() {
+  index_.Add(make_unique<Shape>(this));
+  if (!FLAGS_s2loop_lazy_indexing) {
+    index_.ForceBuild();
+  }
+  if (FLAGS_s2debug && s2debug_override_ == S2Debug::ALLOW) {
+    // Note that FLAGS_s2debug is false in optimized builds (by default).
+    S2_CHECK(IsValid());
+  }
+}
+
+S2Loop::S2Loop(const S2Cell& cell)
+    : depth_(0),
+      num_vertices_(4),
+      vertices_(new S2Point[num_vertices_]),
+      owns_vertices_(true),
+      s2debug_override_(S2Debug::ALLOW),
+      unindexed_contains_calls_(0) {
+  for (int i = 0; i < 4; ++i) {
+    vertices_[i] = cell.GetVertex(i);
+  }
+  // We recompute the bounding rectangle ourselves, since S2Cell uses a
+  // different method and we need all the bounds to be consistent.
+  InitOriginAndBound();
+}
+
+S2Loop::~S2Loop() {
+  if (owns_vertices_) delete[] vertices_;
+}
+
+S2Loop::S2Loop(const S2Loop& src)
+    : depth_(src.depth_),
+      num_vertices_(src.num_vertices_),
+      vertices_(new S2Point[num_vertices_]),
+      owns_vertices_(true),
+      s2debug_override_(src.s2debug_override_),
+      origin_inside_(src.origin_inside_),
+      unindexed_contains_calls_(0),
+      bound_(src.bound_),
+      subregion_bound_(src.subregion_bound_) {
+  std::copy(&src.vertices_[0], &src.vertices_[num_vertices_], &vertices_[0]);
+  InitIndex();
+}
+
+S2Loop* S2Loop::Clone() const {
+  return new S2Loop(*this);
+}
+
+int S2Loop::FindVertex(const S2Point& p) const {
+  if (num_vertices() < 10) {
+    // Exhaustive search.  Return value must be in the range [1..N].
+    for (int i = 1; i <= num_vertices(); ++i) {
+      if (vertex(i) == p) return i;
+    }
+    return -1;
+  }
+  MutableS2ShapeIndex::Iterator it(&index_);
+  if (!it.Locate(p)) return -1;
+
+  const S2ClippedShape& a_clipped = it.cell().clipped(0);
+  for (int i = a_clipped.num_edges() - 1; i >= 0; --i) {
+    int ai = a_clipped.edge(i);
+    // Return value must be in the range [1..N].
+    if (vertex(ai) == p) return (ai == 0) ? num_vertices() : ai;
+    if (vertex(ai+1) == p) return ai+1;
+  }
+  return -1;
+}
+
+bool S2Loop::IsNormalized() const {
+  // Optimization: if the longitude span is less than 180 degrees, then the
+  // loop covers less than half the sphere and is therefore normalized.
+  if (bound_.lng().GetLength() < M_PI) return true;
+
+  return S2::IsNormalized(vertices_span());
+}
+
+void S2Loop::Normalize() {
+  S2_CHECK(owns_vertices_);
+  if (!IsNormalized()) Invert();
+  S2_DCHECK(IsNormalized());
+}
+
+void S2Loop::Invert() {
+  S2_CHECK(owns_vertices_);
+  ClearIndex();
+  if (is_empty_or_full()) {
+    vertices_[0] = is_full() ? kEmptyVertex() : kFullVertex();
+  } else {
+    std::reverse(vertices_, vertices_ + num_vertices());
+  }
+  // origin_inside_ must be set correctly before building the S2ShapeIndex.
+  origin_inside_ ^= true;
+  if (bound_.lat().lo() > -M_PI_2 && bound_.lat().hi() < M_PI_2) {
+    // The complement of this loop contains both poles.
+    subregion_bound_ = bound_ = S2LatLngRect::Full();
+  } else {
+    InitBound();
+  }
+  InitIndex();
+}
+
+double S2Loop::GetArea() const {
+  // S2Loop has its own convention for empty and full loops.
+  if (is_empty_or_full()) {
+    return contains_origin() ? (4 * M_PI) : 0;
+  }
+  return S2::GetArea(vertices_span());
+}
+
+S2Point S2Loop::GetCentroid() const {
+  // Empty and full loops are handled correctly.
+  return S2::GetCentroid(vertices_span());
+}
+
+S2::LoopOrder S2Loop::GetCanonicalLoopOrder() const {
+  return S2::GetCanonicalLoopOrder(vertices_span());
+}
+
+S1Angle S2Loop::GetDistance(const S2Point& x) const {
+  // Note that S2Loop::Contains(S2Point) is slightly more efficient than the
+  // generic version used by S2ClosestEdgeQuery.
+  if (Contains(x)) return S1Angle::Zero();
+  return GetDistanceToBoundary(x);
+}
+
+S1Angle S2Loop::GetDistanceToBoundary(const S2Point& x) const {
+  S2ClosestEdgeQuery::Options options;
+  options.set_include_interiors(false);
+  S2ClosestEdgeQuery::PointTarget t(x);
+  return S2ClosestEdgeQuery(&index_, options).GetDistance(&t).ToAngle();
+}
+
+S2Point S2Loop::Project(const S2Point& x) const {
+  if (Contains(x)) return x;
+  return ProjectToBoundary(x);
+}
+
+S2Point S2Loop::ProjectToBoundary(const S2Point& x) const {
+  S2ClosestEdgeQuery::Options options;
+  options.set_include_interiors(false);
+  S2ClosestEdgeQuery q(&index_, options);
+  S2ClosestEdgeQuery::PointTarget target(x);
+  S2ClosestEdgeQuery::Result edge = q.FindClosestEdge(&target);
+  return q.Project(x, edge);
+}
+
+double S2Loop::GetCurvature() const {
+  // S2Loop has its own convention for empty and full loops.  For such loops,
+  // we return the limit value as the area approaches 0 or 4*Pi respectively.
+  if (is_empty_or_full()) {
+    return contains_origin() ? (-2 * M_PI) : (2 * M_PI);
+  }
+  return S2::GetCurvature(vertices_span());
+}
+
+double S2Loop::GetCurvatureMaxError() const {
+  return S2::GetCurvatureMaxError(vertices_span());
+}
+
+S2Cap S2Loop::GetCapBound() const {
+  return bound_.GetCapBound();
+}
+
+bool S2Loop::Contains(const S2Cell& target) const {
+  MutableS2ShapeIndex::Iterator it(&index_);
+  S2ShapeIndex::CellRelation relation = it.Locate(target.id());
+
+  // If "target" is disjoint from all index cells, it is not contained.
+  // Similarly, if "target" is subdivided into one or more index cells then it
+  // is not contained, since index cells are subdivided only if they (nearly)
+  // intersect a sufficient number of edges.  (But note that if "target" itself
+  // is an index cell then it may be contained, since it could be a cell with
+  // no edges in the loop interior.)
+  if (relation != S2ShapeIndex::INDEXED) return false;
+
+  // Otherwise check if any edges intersect "target".
+  if (BoundaryApproxIntersects(it, target)) return false;
+
+  // Otherwise check if the loop contains the center of "target".
+  return Contains(it, target.GetCenter());
+}
+
+bool S2Loop::MayIntersect(const S2Cell& target) const {
+  MutableS2ShapeIndex::Iterator it(&index_);
+  S2ShapeIndex::CellRelation relation = it.Locate(target.id());
+
+  // If "target" does not overlap any index cell, there is no intersection.
+  if (relation == S2ShapeIndex::DISJOINT) return false;
+
+  // If "target" is subdivided into one or more index cells, there is an
+  // intersection to within the S2ShapeIndex error bound (see Contains).
+  if (relation == S2ShapeIndex::SUBDIVIDED) return true;
+
+  // If "target" is an index cell, there is an intersection because index cells
+  // are created only if they have at least one edge or they are entirely
+  // contained by the loop.
+  if (it.id() == target.id()) return true;
+
+  // Otherwise check if any edges intersect "target".
+  if (BoundaryApproxIntersects(it, target)) return true;
+
+  // Otherwise check if the loop contains the center of "target".
+  return Contains(it, target.GetCenter());
+}
+
+bool S2Loop::BoundaryApproxIntersects(const MutableS2ShapeIndex::Iterator& it,
+                                      const S2Cell& target) const {
+  S2_DCHECK(it.id().contains(target.id()));
+  const S2ClippedShape& a_clipped = it.cell().clipped(0);
+  int a_num_edges = a_clipped.num_edges();
+
+  // If there are no edges, there is no intersection.
+  if (a_num_edges == 0) return false;
+
+  // We can save some work if "target" is the index cell itself.
+  if (it.id() == target.id()) return true;
+
+  // Otherwise check whether any of the edges intersect "target".
+  static const double kMaxError = (S2::kFaceClipErrorUVCoord +
+                                   S2::kIntersectsRectErrorUVDist);
+  R2Rect bound = target.GetBoundUV().Expanded(kMaxError);
+  for (int i = 0; i < a_num_edges; ++i) {
+    int ai = a_clipped.edge(i);
+    R2Point v0, v1;
+    if (S2::ClipToPaddedFace(vertex(ai), vertex(ai+1), target.face(),
+                             kMaxError, &v0, &v1) &&
+        S2::IntersectsRect(v0, v1, bound)) {
+      return true;
+    }
+  }
+  return false;
+}
+
+bool S2Loop::Contains(const S2Point& p) const {
+  // NOTE(ericv): A bounds check slows down this function by about 50%.  It is
+  // worthwhile only when it might allow us to delay building the index.
+  if (!index_.is_fresh() && !bound_.Contains(p)) return false;
+
+  // For small loops it is faster to just check all the crossings.  We also
+  // use this method during loop initialization because InitOriginAndBound()
+  // calls Contains() before InitIndex().  Otherwise, we keep track of the
+  // number of calls to Contains() and only build the index when enough calls
+  // have been made so that we think it is worth the effort.  Note that the
+  // code below is structured so that if many calls are made in parallel only
+  // one thread builds the index, while the rest continue using brute force
+  // until the index is actually available.
+  //
+  // The constants below were tuned using the benchmarks.  It turns out that
+  // building the index costs roughly 50x as much as Contains().  (The ratio
+  // increases slowly from 46x with 64 points to 61x with 256k points.)  The
+  // textbook approach to this problem would be to wait until the cumulative
+  // time we would have saved with an index approximately equals the cost of
+  // building the index, and then build it.  (This gives the optimal
+  // competitive ratio of 2; look up "competitive algorithms" for details.)
+  // We set the limit somewhat lower than this (20 rather than 50) because
+  // building the index may be forced anyway by other API calls, and so we
+  // want to err on the side of building it too early.
+
+  static const int kMaxBruteForceVertices = 32;
+  static const int kMaxUnindexedContainsCalls = 20;  // See notes above.
+  if (index_.num_shape_ids() == 0 ||  // InitIndex() not called yet
+      num_vertices() <= kMaxBruteForceVertices ||
+      (!index_.is_fresh() &&
+       ++unindexed_contains_calls_ != kMaxUnindexedContainsCalls)) {
+    return BruteForceContains(p);
+  }
+  // Otherwise we look up the S2ShapeIndex cell containing this point.  Note
+  // the index is built automatically the first time an iterator is created.
+  MutableS2ShapeIndex::Iterator it(&index_);
+  if (!it.Locate(p)) return false;
+  return Contains(it, p);
+}
+
+bool S2Loop::BruteForceContains(const S2Point& p) const {
+  // Empty and full loops don't need a special case, but invalid loops with
+  // zero vertices do, so we might as well handle them all at once.
+  if (num_vertices() < 3) return origin_inside_;
+
+  S2Point origin = S2::Origin();
+  S2EdgeCrosser crosser(&origin, &p, &vertex(0));
+  bool inside = origin_inside_;
+  for (int i = 1; i <= num_vertices(); ++i) {
+    inside ^= crosser.EdgeOrVertexCrossing(&vertex(i));
+  }
+  return inside;
+}
+
+bool S2Loop::Contains(const MutableS2ShapeIndex::Iterator& it,
+                      const S2Point& p) const {
+  // Test containment by drawing a line segment from the cell center to the
+  // given point and counting edge crossings.
+  const S2ClippedShape& a_clipped = it.cell().clipped(0);
+  bool inside = a_clipped.contains_center();
+  int a_num_edges = a_clipped.num_edges();
+  if (a_num_edges > 0) {
+    S2Point center = it.center();
+    S2EdgeCrosser crosser(&center, &p);
+    int ai_prev = -2;
+    for (int i = 0; i < a_num_edges; ++i) {
+      int ai = a_clipped.edge(i);
+      if (ai != ai_prev + 1) crosser.RestartAt(&vertex(ai));
+      ai_prev = ai;
+      inside ^= crosser.EdgeOrVertexCrossing(&vertex(ai+1));
+    }
+  }
+  return inside;
+}
+
+void S2Loop::Encode(Encoder* const encoder) const {
+  encoder->Ensure(num_vertices_ * sizeof(*vertices_) + 20);  // sufficient
+
+  encoder->put8(kCurrentLosslessEncodingVersionNumber);
+  encoder->put32(num_vertices_);
+  encoder->putn(vertices_, sizeof(*vertices_) * num_vertices_);
+  encoder->put8(origin_inside_);
+  encoder->put32(depth_);
+  S2_DCHECK_GE(encoder->avail(), 0);
+
+  bound_.Encode(encoder);
+}
+
+bool S2Loop::Decode(Decoder* const decoder) {
+  if (decoder->avail() < sizeof(unsigned char)) return false;
+  unsigned char version = decoder->get8();
+  switch (version) {
+    case kCurrentLosslessEncodingVersionNumber:
+      return DecodeInternal(decoder, false);
+  }
+  return false;
+}
+
+bool S2Loop::DecodeWithinScope(Decoder* const decoder) {
+  if (decoder->avail() < sizeof(unsigned char)) return false;
+  unsigned char version = decoder->get8();
+  switch (version) {
+    case kCurrentLosslessEncodingVersionNumber:
+      return DecodeInternal(decoder, true);
+  }
+  return false;
+}
+
+bool S2Loop::DecodeInternal(Decoder* const decoder,
+                            bool within_scope) {
+  // Perform all checks before modifying vertex state. Empty loops are
+  // explicitly allowed here: a newly created loop has zero vertices
+  // and such loops encode and decode properly.
+  if (decoder->avail() < sizeof(uint32)) return false;
+  const uint32 num_vertices = decoder->get32();
+  if (num_vertices > FLAGS_s2polygon_decode_max_num_vertices) {
+    return false;
+  }
+  if (decoder->avail() < (num_vertices * sizeof(*vertices_) +
+                          sizeof(uint8) + sizeof(uint32))) {
+    return false;
+  }
+  ClearIndex();
+  if (owns_vertices_) delete[] vertices_;
+  num_vertices_ = num_vertices;
+
+  // x86 can do unaligned floating-point reads; however, many other
+  // platforms cannot. Do not use the zero-copy version if we are on
+  // an architecture that does not support unaligned reads, and the
+  // pointer is not correctly aligned.
+#if defined(__x86_64__) || defined(_M_X64) || defined(__i386) || \
+    defined(_M_IX86)
+  bool is_misaligned = false;
+#else
+  bool is_misaligned =
+      reinterpret_cast<intptr_t>(decoder->ptr()) % sizeof(double) != 0;
+#endif
+  if (within_scope && !is_misaligned) {
+    vertices_ = const_cast<S2Point *>(reinterpret_cast<const S2Point*>(
+                    decoder->ptr()));
+    decoder->skip(num_vertices_ * sizeof(*vertices_));
+    owns_vertices_ = false;
+  } else {
+    vertices_ = new S2Point[num_vertices_];
+    decoder->getn(vertices_, num_vertices_ * sizeof(*vertices_));
+    owns_vertices_ = true;
+  }
+  origin_inside_ = decoder->get8();
+  depth_ = decoder->get32();
+  if (!bound_.Decode(decoder)) return false;
+  subregion_bound_ = S2LatLngRectBounder::ExpandForSubregions(bound_);
+
+  // An initialized loop will have some non-zero count of vertices. A default
+  // (uninitialized) has zero vertices. This code supports encoding and
+  // decoding of uninitialized loops, but we only want to call InitIndex for
+  // initialized loops. Otherwise we defer InitIndex until the call to Init().
+  if (num_vertices > 0) {
+    InitIndex();
+  }
+
+  return true;
+}
+
+// LoopRelation is an abstract class that defines a relationship between two
+// loops (Contains, Intersects, or CompareBoundary).
+class LoopRelation {
+ public:
+  LoopRelation() {}
+  virtual ~LoopRelation() {}
+
+  // Optionally, a_target() and b_target() can specify an early-exit condition
+  // for the loop relation.  If any point P is found such that
+  //
+  //   A.Contains(P) == a_crossing_target() &&
+  //   B.Contains(P) == b_crossing_target()
+  //
+  // then the loop relation is assumed to be the same as if a pair of crossing
+  // edges were found.  For example, the Contains() relation has
+  //
+  //   a_crossing_target() == 0
+  //   b_crossing_target() == 1
+  //
+  // because if A.Contains(P) == 0 (false) and B.Contains(P) == 1 (true) for
+  // any point P, then it is equivalent to finding an edge crossing (i.e.,
+  // since Contains() returns false in both cases).
+  //
+  // Loop relations that do not have an early-exit condition of this form
+  // should return -1 for both crossing targets.
+  virtual int a_crossing_target() const = 0;
+  virtual int b_crossing_target() const = 0;
+
+  // Given a vertex "ab1" that is shared between the two loops, return true if
+  // the two associated wedges (a0, ab1, b2) and (b0, ab1, b2) are equivalent
+  // to an edge crossing.  The loop relation is also allowed to maintain its
+  // own internal state, and can return true if it observes any sequence of
+  // wedges that are equivalent to an edge crossing.
+  virtual bool WedgesCross(const S2Point& a0, const S2Point& ab1,
+                           const S2Point& a2, const S2Point& b0,
+                           const S2Point& b2) = 0;
+};
+
+// RangeIterator is a wrapper over MutableS2ShapeIndex::Iterator with extra
+// methods that are useful for merging the contents of two or more
+// S2ShapeIndexes.
+class RangeIterator {
+ public:
+  // Construct a new RangeIterator positioned at the first cell of the index.
+  explicit RangeIterator(const MutableS2ShapeIndex* index)
+      : it_(index, S2ShapeIndex::BEGIN) {
+    Refresh();
+  }
+
+  // The current S2CellId and cell contents.
+  S2CellId id() const { return it_.id(); }
+  const S2ShapeIndexCell& cell() const { return it_.cell(); }
+
+  // The min and max leaf cell ids covered by the current cell.  If Done() is
+  // true, these methods return a value larger than any valid cell id.
+  S2CellId range_min() const { return range_min_; }
+  S2CellId range_max() const { return range_max_; }
+
+  // Various other convenience methods for the current cell.
+  const S2ClippedShape& clipped() const { return cell().clipped(0); }
+
+  int num_edges() const { return clipped().num_edges(); }
+  bool contains_center() const { return clipped().contains_center(); }
+
+  void Next() { it_.Next(); Refresh(); }
+  bool Done() { return it_.done(); }
+
+  // Position the iterator at the first cell that overlaps or follows
+  // "target", i.e. such that range_max() >= target.range_min().
+  void SeekTo(const RangeIterator& target) {
+    it_.Seek(target.range_min());
+    // If the current cell does not overlap "target", it is possible that the
+    // previous cell is the one we are looking for.  This can only happen when
+    // the previous cell contains "target" but has a smaller S2CellId.
+    if (it_.done() || it_.id().range_min() > target.range_max()) {
+      if (it_.Prev() && it_.id().range_max() < target.id()) it_.Next();
+    }
+    Refresh();
+  }
+
+  // Position the iterator at the first cell that follows "target", i.e. the
+  // first cell such that range_min() > target.range_max().
+  void SeekBeyond(const RangeIterator& target) {
+    it_.Seek(target.range_max().next());
+    if (!it_.done() && it_.id().range_min() <= target.range_max()) {
+      it_.Next();
+    }
+    Refresh();
+  }
+
+ private:
+  // Updates internal state after the iterator has been repositioned.
+  void Refresh() {
+    range_min_ = id().range_min();
+    range_max_ = id().range_max();
+  }
+
+  MutableS2ShapeIndex::Iterator it_;
+  S2CellId range_min_, range_max_;
+};
+
+// LoopCrosser is a helper class for determining whether two loops cross.
+// It is instantiated twice for each pair of loops to be tested, once for the
+// pair (A,B) and once for the pair (B,A), in order to be able to process
+// edges in either loop nesting order.
+class LoopCrosser {
+ public:
+  // If "swapped" is true, the loops A and B have been swapped.  This affects
+  // how arguments are passed to the given loop relation, since for example
+  // A.Contains(B) is not the same as B.Contains(A).
+  LoopCrosser(const S2Loop& a, const S2Loop& b,
+              LoopRelation* relation, bool swapped)
+      : a_(a), b_(b), relation_(relation), swapped_(swapped),
+        a_crossing_target_(relation->a_crossing_target()),
+        b_crossing_target_(relation->b_crossing_target()),
+        b_query_(&b.index_) {
+    using std::swap;
+    if (swapped) swap(a_crossing_target_, b_crossing_target_);
+  }
+
+  // Return the crossing targets for the loop relation, taking into account
+  // whether the loops have been swapped.
+  int a_crossing_target() const { return a_crossing_target_; }
+  int b_crossing_target() const { return b_crossing_target_; }
+
+  // Given two iterators positioned such that ai->id().Contains(bi->id()),
+  // return true if there is a crossing relationship anywhere within ai->id().
+  // Specifically, this method returns true if there is an edge crossing, a
+  // wedge crossing, or a point P that matches both "crossing targets".
+  // Advances both iterators past ai->id().
+  bool HasCrossingRelation(RangeIterator* ai, RangeIterator* bi);
+
+  // Given two index cells, return true if there are any edge crossings or
+  // wedge crossings within those cells.
+  bool CellCrossesCell(const S2ClippedShape& a_clipped,
+                       const S2ClippedShape& b_clipped);
+
+ private:
+  // Given two iterators positioned such that ai->id().Contains(bi->id()),
+  // return true if there is an edge crossing or wedge crosssing anywhere
+  // within ai->id().  Advances "bi" (only) past ai->id().
+  bool HasCrossing(RangeIterator* ai, RangeIterator* bi);
+
+  // Given an index cell of A, return true if there are any edge or wedge
+  // crossings with any index cell of B contained within "b_id".
+  bool CellCrossesAnySubcell(const S2ClippedShape& a_clipped, S2CellId b_id);
+
+  // Prepare to check the given edge of loop A for crossings.
+  void StartEdge(int aj);
+
+  // Check the current edge of loop A for crossings with all edges of the
+  // given index cell of loop B.
+  bool EdgeCrossesCell(const S2ClippedShape& b_clipped);
+
+  const S2Loop& a_;
+  const S2Loop& b_;
+  LoopRelation* const relation_;
+  const bool swapped_;
+  int a_crossing_target_, b_crossing_target_;
+
+  // State maintained by StartEdge() and EdgeCrossesCell().
+  S2EdgeCrosser crosser_;
+  int aj_, bj_prev_;
+
+  // Temporary data declared here to avoid repeated memory allocations.
+  S2CrossingEdgeQuery b_query_;
+  vector<const S2ShapeIndexCell*> b_cells_;
+};
+
+inline void LoopCrosser::StartEdge(int aj) {
+  // Start testing the given edge of A for crossings.
+  crosser_.Init(&a_.vertex(aj), &a_.vertex(aj+1));
+  aj_ = aj;
+  bj_prev_ = -2;
+}
+
+inline bool LoopCrosser::EdgeCrossesCell(const S2ClippedShape& b_clipped) {
+  // Test the current edge of A against all edges of "b_clipped".
+  int b_num_edges = b_clipped.num_edges();
+  for (int j = 0; j < b_num_edges; ++j) {
+    int bj = b_clipped.edge(j);
+    if (bj != bj_prev_ + 1) crosser_.RestartAt(&b_.vertex(bj));
+    bj_prev_ = bj;
+    int crossing = crosser_.CrossingSign(&b_.vertex(bj + 1));
+    if (crossing < 0) continue;
+    if (crossing > 0) return true;
+    // We only need to check each shared vertex once, so we only
+    // consider the case where a_vertex(aj_+1) == b_.vertex(bj+1).
+    if (a_.vertex(aj_+1) == b_.vertex(bj+1)) {
+      if (swapped_ ?
+          relation_->WedgesCross(
+              b_.vertex(bj), b_.vertex(bj+1), b_.vertex(bj+2),
+              a_.vertex(aj_), a_.vertex(aj_+2)) :
+          relation_->WedgesCross(
+              a_.vertex(aj_), a_.vertex(aj_+1), a_.vertex(aj_+2),
+              b_.vertex(bj), b_.vertex(bj+2))) {
+        return true;
+      }
+    }
+  }
+  return false;
+}
+
+bool LoopCrosser::CellCrossesCell(const S2ClippedShape& a_clipped,
+                                  const S2ClippedShape& b_clipped) {
+  // Test all edges of "a_clipped" against all edges of "b_clipped".
+  int a_num_edges = a_clipped.num_edges();
+  for (int i = 0; i < a_num_edges; ++i) {
+    StartEdge(a_clipped.edge(i));
+    if (EdgeCrossesCell(b_clipped)) return true;
+  }
+  return false;
+}
+
+bool LoopCrosser::CellCrossesAnySubcell(const S2ClippedShape& a_clipped,
+                                        S2CellId b_id) {
+  // Test all edges of "a_clipped" against all edges of B.  The relevant B
+  // edges are guaranteed to be children of "b_id", which lets us find the
+  // correct index cells more efficiently.
+  S2PaddedCell b_root(b_id, 0);
+  int a_num_edges = a_clipped.num_edges();
+  for (int i = 0; i < a_num_edges; ++i) {
+    int aj = a_clipped.edge(i);
+    // Use an S2CrossingEdgeQuery starting at "b_root" to find the index cells
+    // of B that might contain crossing edges.
+    b_query_.GetCells(a_.vertex(aj), a_.vertex(aj+1), b_root, &b_cells_);
+    if (b_cells_.empty()) continue;
+    StartEdge(aj);
+    for (const S2ShapeIndexCell* b_cell : b_cells_) {
+      if (EdgeCrossesCell(b_cell->clipped(0))) return true;
+    }
+  }
+  return false;
+}
+
+bool LoopCrosser::HasCrossing(RangeIterator* ai, RangeIterator* bi) {
+  S2_DCHECK(ai->id().contains(bi->id()));
+  // If ai->id() intersects many edges of B, then it is faster to use
+  // S2CrossingEdgeQuery to narrow down the candidates.  But if it intersects
+  // only a few edges, it is faster to check all the crossings directly.
+  // We handle this by advancing "bi" and keeping track of how many edges we
+  // would need to test.
+
+  static const int kEdgeQueryMinEdges = 20;  // Tuned using benchmarks.
+  int total_edges = 0;
+  b_cells_.clear();
+  do {
+    if (bi->num_edges() > 0) {
+      total_edges += bi->num_edges();
+      if (total_edges >= kEdgeQueryMinEdges) {
+        // There are too many edges to test them directly, so use
+        // S2CrossingEdgeQuery.
+        if (CellCrossesAnySubcell(ai->clipped(), ai->id())) return true;
+        bi->SeekBeyond(*ai);
+        return false;
+      }
+      b_cells_.push_back(&bi->cell());
+    }
+    bi->Next();
+  } while (bi->id() <= ai->range_max());
+
+  // Test all the edge crossings directly.
+  for (const S2ShapeIndexCell* b_cell : b_cells_) {
+    if (CellCrossesCell(ai->clipped(), b_cell->clipped(0))) {
+      return true;
+    }
+  }
+  return false;
+}
+
+bool LoopCrosser::HasCrossingRelation(RangeIterator* ai, RangeIterator* bi) {
+  S2_DCHECK(ai->id().contains(bi->id()));
+  if (ai->num_edges() == 0) {
+    if (ai->contains_center() == a_crossing_target_) {
+      // All points within ai->id() satisfy the crossing target for A, so it's
+      // worth iterating through the cells of B to see whether any cell
+      // centers also satisfy the crossing target for B.
+      do {
+        if (bi->contains_center() == b_crossing_target_) return true;
+        bi->Next();
+      } while (bi->id() <= ai->range_max());
+    } else {
+      // The crossing target for A is not satisfied, so we skip over the cells
+      // of B using binary search.
+      bi->SeekBeyond(*ai);
+    }
+  } else {
+    // The current cell of A has at least one edge, so check for crossings.
+    if (HasCrossing(ai, bi)) return true;
+  }
+  ai->Next();
+  return false;
+}
+
+/*static*/ bool S2Loop::HasCrossingRelation(const S2Loop& a, const S2Loop& b,
+                                            LoopRelation* relation) {
+  // We look for S2CellId ranges where the indexes of A and B overlap, and
+  // then test those edges for crossings.
+  RangeIterator ai(&a.index_), bi(&b.index_);
+  LoopCrosser ab(a, b, relation, false);  // Tests edges of A against B
+  LoopCrosser ba(b, a, relation, true);   // Tests edges of B against A
+  while (!ai.Done() || !bi.Done()) {
+    if (ai.range_max() < bi.range_min()) {
+      // The A and B cells don't overlap, and A precedes B.
+      ai.SeekTo(bi);
+    } else if (bi.range_max() < ai.range_min()) {
+      // The A and B cells don't overlap, and B precedes A.
+      bi.SeekTo(ai);
+    } else {
+      // One cell contains the other.  Determine which cell is larger.
+      int64 ab_relation = ai.id().lsb() - bi.id().lsb();
+      if (ab_relation > 0) {
+        // A's index cell is larger.
+        if (ab.HasCrossingRelation(&ai, &bi)) return true;
+      } else if (ab_relation < 0) {
+        // B's index cell is larger.
+        if (ba.HasCrossingRelation(&bi, &ai)) return true;
+      } else {
+        // The A and B cells are the same.  Since the two cells have the same
+        // center point P, check whether P satisfies the crossing targets.
+        if (ai.contains_center() == ab.a_crossing_target() &&
+            bi.contains_center() == ab.b_crossing_target()) {
+          return true;
+        }
+        // Otherwise test all the edge crossings directly.
+        if (ai.num_edges() > 0 && bi.num_edges() > 0 &&
+            ab.CellCrossesCell(ai.clipped(), bi.clipped())) {
+          return true;
+        }
+        ai.Next();
+        bi.Next();
+      }
+    }
+  }
+  return false;
+}
+
+// Loop relation for Contains().
+class ContainsRelation : public LoopRelation {
+ public:
+  ContainsRelation() : found_shared_vertex_(false) {}
+  bool found_shared_vertex() const { return found_shared_vertex_; }
+
+  // If A.Contains(P) == false && B.Contains(P) == true, it is equivalent to
+  // having an edge crossing (i.e., Contains returns false).
+  int a_crossing_target() const override { return false; }
+  int b_crossing_target() const override { return true; }
+
+  bool WedgesCross(const S2Point& a0, const S2Point& ab1, const S2Point& a2,
+                   const S2Point& b0, const S2Point& b2) override {
+    found_shared_vertex_ = true;
+    return !S2::WedgeContains(a0, ab1, a2, b0, b2);
+  }
+
+ private:
+  bool found_shared_vertex_;
+};
+
+bool S2Loop::Contains(const S2Loop* b) const {
+  // For this loop A to contains the given loop B, all of the following must
+  // be true:
+  //
+  //  (1) There are no edge crossings between A and B except at vertices.
+  //
+  //  (2) At every vertex that is shared between A and B, the local edge
+  //      ordering implies that A contains B.
+  //
+  //  (3) If there are no shared vertices, then A must contain a vertex of B
+  //      and B must not contain a vertex of A.  (An arbitrary vertex may be
+  //      chosen in each case.)
+  //
+  // The second part of (3) is necessary to detect the case of two loops whose
+  // union is the entire sphere, i.e. two loops that contains each other's
+  // boundaries but not each other's interiors.
+  if (!subregion_bound_.Contains(b->bound_)) return false;
+
+  // Special cases to handle either loop being empty or full.
+  if (is_empty_or_full() || b->is_empty_or_full()) {
+    return is_full() || b->is_empty();
+  }
+
+  // Check whether there are any edge crossings, and also check the loop
+  // relationship at any shared vertices.
+  ContainsRelation relation;
+  if (HasCrossingRelation(*this, *b, &relation)) return false;
+
+  // There are no crossings, and if there are any shared vertices then A
+  // contains B locally at each shared vertex.
+  if (relation.found_shared_vertex()) return true;
+
+  // Since there are no edge intersections or shared vertices, we just need to
+  // test condition (3) above.  We can skip this test if we discovered that A
+  // contains at least one point of B while checking for edge crossings.
+  if (!Contains(b->vertex(0))) return false;
+
+  // We still need to check whether (A union B) is the entire sphere.
+  // Normally this check is very cheap due to the bounding box precondition.
+  if ((b->subregion_bound_.Contains(bound_) ||
+       b->bound_.Union(bound_).is_full()) && b->Contains(vertex(0))) {
+    return false;
+  }
+  return true;
+}
+
+
+// Loop relation for Intersects().
+class IntersectsRelation : public LoopRelation {
+ public:
+  IntersectsRelation() : found_shared_vertex_(false) {}
+  bool found_shared_vertex() const { return found_shared_vertex_; }
+
+  // If A.Contains(P) == true && B.Contains(P) == true, it is equivalent to
+  // having an edge crossing (i.e., Intersects returns true).
+  int a_crossing_target() const override { return true; }
+  int b_crossing_target() const override { return true; }
+
+  bool WedgesCross(const S2Point& a0, const S2Point& ab1, const S2Point& a2,
+                   const S2Point& b0, const S2Point& b2) override {
+    found_shared_vertex_ = true;
+    return S2::WedgeIntersects(a0, ab1, a2, b0, b2);
+  }
+
+ private:
+  bool found_shared_vertex_;
+};
+
+bool S2Loop::Intersects(const S2Loop* b) const {
+  // a->Intersects(b) if and only if !a->Complement()->Contains(b).
+  // This code is similar to Contains(), but is optimized for the case
+  // where both loops enclose less than half of the sphere.
+  if (!bound_.Intersects(b->bound_)) return false;
+
+  // Check whether there are any edge crossings, and also check the loop
+  // relationship at any shared vertices.
+  IntersectsRelation relation;
+  if (HasCrossingRelation(*this, *b, &relation)) return true;
+  if (relation.found_shared_vertex()) return false;
+
+  // Since there are no edge intersections or shared vertices, the loops
+  // intersect only if A contains B, B contains A, or the two loops contain
+  // each other's boundaries.  These checks are usually cheap because of the
+  // bounding box preconditions.  Note that neither loop is empty (because of
+  // the bounding box check above), so it is safe to access vertex(0).
+
+  // Check whether A contains B, or A and B contain each other's boundaries.
+  // (Note that A contains all the vertices of B in either case.)
+  if (subregion_bound_.Contains(b->bound_) ||
+      bound_.Union(b->bound_).is_full()) {
+    if (Contains(b->vertex(0))) return true;
+  }
+  // Check whether B contains A.
+  if (b->subregion_bound_.Contains(bound_)) {
+    if (b->Contains(vertex(0))) return true;
+  }
+  return false;
+}
+
+// Returns true if the wedge (a0, ab1, a2) contains the "semiwedge" defined as
+// any non-empty open set of rays immediately CCW from the edge (ab1, b2).  If
+// "reverse_b" is true, then substitute "clockwise" for "CCW"; this simulates
+// what would happen if the direction of loop B was reversed.
+inline static bool WedgeContainsSemiwedge(const S2Point& a0, const S2Point& ab1,
+                                          const S2Point& a2, const S2Point& b2,
+                                          bool reverse_b) {
+  if (b2 == a0 || b2 == a2) {
+    // We have a shared or reversed edge.
+    return (b2 == a0) == reverse_b;
+  } else {
+    return s2pred::OrderedCCW(a0, a2, b2, ab1);
+  }
+}
+
+// Loop relation for CompareBoundary().
+class CompareBoundaryRelation : public LoopRelation {
+ public:
+  explicit CompareBoundaryRelation(bool reverse_b):
+      reverse_b_(reverse_b), found_shared_vertex_(false),
+      contains_edge_(false), excludes_edge_(false) {
+  }
+  bool found_shared_vertex() const { return found_shared_vertex_; }
+  bool contains_edge() const { return contains_edge_; }
+
+  // The CompareBoundary relation does not have a useful early-exit condition,
+  // so we return -1 for both crossing targets.
+  //
+  // Aside: A possible early exit condition could be based on the following.
+  //   If A contains a point of both B and ~B, then A intersects Boundary(B).
+  //   If ~A contains a point of both B and ~B, then ~A intersects Boundary(B).
+  //   So if the intersections of {A, ~A} with {B, ~B} are all non-empty,
+  //   the return value is 0, i.e., Boundary(A) intersects Boundary(B).
+  // Unfortunately it isn't worth detecting this situation because by the
+  // time we have seen a point in all four intersection regions, we are also
+  // guaranteed to have seen at least one pair of crossing edges.
+  int a_crossing_target() const override { return -1; }
+  int b_crossing_target() const override { return -1; }
+
+  bool WedgesCross(const S2Point& a0, const S2Point& ab1, const S2Point& a2,
+                   const S2Point& b0, const S2Point& b2) override {
+    // Because we don't care about the interior of B, only its boundary, it is
+    // sufficient to check whether A contains the semiwedge (ab1, b2).
+    found_shared_vertex_ = true;
+    if (WedgeContainsSemiwedge(a0, ab1, a2, b2, reverse_b_)) {
+      contains_edge_ = true;
+    } else {
+      excludes_edge_ = true;
+    }
+    return contains_edge_ & excludes_edge_;
+  }
+
+ protected:
+  const bool reverse_b_;      // True if loop B should be reversed.
+  bool found_shared_vertex_;  // True if any wedge was processed.
+  bool contains_edge_;        // True if any edge of B is contained by A.
+  bool excludes_edge_;        // True if any edge of B is excluded by A.
+};
+
+int S2Loop::CompareBoundary(const S2Loop* b) const {
+  S2_DCHECK(!is_empty() && !b->is_empty());
+  S2_DCHECK(!b->is_full() || !b->is_hole());
+
+  // The bounds must intersect for containment or crossing.
+  if (!bound_.Intersects(b->bound_)) return -1;
+
+  // Full loops are handled as though the loop surrounded the entire sphere.
+  if (is_full()) return 1;
+  if (b->is_full()) return -1;
+
+  // Check whether there are any edge crossings, and also check the loop
+  // relationship at any shared vertices.
+  CompareBoundaryRelation relation(b->is_hole());
+  if (HasCrossingRelation(*this, *b, &relation)) return 0;
+  if (relation.found_shared_vertex()) {
+    return relation.contains_edge() ? 1 : -1;
+  }
+
+  // There are no edge intersections or shared vertices, so we can check
+  // whether A contains an arbitrary vertex of B.
+  return Contains(b->vertex(0)) ? 1 : -1;
+}
+
+bool S2Loop::ContainsNonCrossingBoundary(const S2Loop* b, bool reverse_b)
+    const {
+  S2_DCHECK(!is_empty() && !b->is_empty());
+  S2_DCHECK(!b->is_full() || !reverse_b);
+
+  // The bounds must intersect for containment.
+  if (!bound_.Intersects(b->bound_)) return false;
+
+  // Full loops are handled as though the loop surrounded the entire sphere.
+  if (is_full()) return true;
+  if (b->is_full()) return false;
+
+  int m = FindVertex(b->vertex(0));
+  if (m < 0) {
+    // Since vertex b0 is not shared, we can check whether A contains it.
+    return Contains(b->vertex(0));
+  }
+  // Otherwise check whether the edge (b0, b1) is contained by A.
+  return WedgeContainsSemiwedge(vertex(m-1), vertex(m), vertex(m+1),
+                                b->vertex(1), reverse_b);
+}
+
+bool S2Loop::ContainsNested(const S2Loop* b) const {
+  if (!subregion_bound_.Contains(b->bound_)) return false;
+
+  // Special cases to handle either loop being empty or full.  Also bail out
+  // when B has no vertices to avoid heap overflow on the vertex(1) call
+  // below.  (This method is called during polygon initialization before the
+  // client has an opportunity to call IsValid().)
+  if (is_empty_or_full() || b->num_vertices() < 2) {
+    return is_full() || b->is_empty();
+  }
+
+  // We are given that A and B do not share any edges, and that either one
+  // loop contains the other or they do not intersect.
+  int m = FindVertex(b->vertex(1));
+  if (m < 0) {
+    // Since b->vertex(1) is not shared, we can check whether A contains it.
+    return Contains(b->vertex(1));
+  }
+  // Check whether the edge order around b->vertex(1) is compatible with
+  // A containing B.
+  return S2::WedgeContains(vertex(m-1), vertex(m), vertex(m+1),
+                                   b->vertex(0), b->vertex(2));
+}
+
+bool S2Loop::Equals(const S2Loop* b) const {
+  if (num_vertices() != b->num_vertices()) return false;
+  for (int i = 0; i < num_vertices(); ++i) {
+    if (vertex(i) != b->vertex(i)) return false;
+  }
+  return true;
+}
+
+bool S2Loop::BoundaryEquals(const S2Loop* b) const {
+  if (num_vertices() != b->num_vertices()) return false;
+
+  // Special case to handle empty or full loops.  Since they have the same
+  // number of vertices, if one loop is empty/full then so is the other.
+  if (is_empty_or_full()) return is_empty() == b->is_empty();
+
+  for (int offset = 0; offset < num_vertices(); ++offset) {
+    if (vertex(offset) == b->vertex(0)) {
+      // There is at most one starting offset since loop vertices are unique.
+      for (int i = 0; i < num_vertices(); ++i) {
+        if (vertex(i + offset) != b->vertex(i)) return false;
+      }
+      return true;
+    }
+  }
+  return false;
+}
+
+bool S2Loop::BoundaryApproxEquals(const S2Loop& b, S1Angle max_error) const {
+  if (num_vertices() != b.num_vertices()) return false;
+
+  // Special case to handle empty or full loops.  Since they have the same
+  // number of vertices, if one loop is empty/full then so is the other.
+  if (is_empty_or_full()) return is_empty() == b.is_empty();
+
+  for (int offset = 0; offset < num_vertices(); ++offset) {
+    if (S2::ApproxEquals(vertex(offset), b.vertex(0), max_error)) {
+      bool success = true;
+      for (int i = 0; i < num_vertices(); ++i) {
+        if (!S2::ApproxEquals(vertex(i + offset), b.vertex(i), max_error)) {
+          success = false;
+          break;
+        }
+      }
+      if (success) return true;
+      // Otherwise continue looping.  There may be more than one candidate
+      // starting offset since vertices are only matched approximately.
+    }
+  }
+  return false;
+}
+
+static bool MatchBoundaries(const S2Loop& a, const S2Loop& b, int a_offset,
+                            S1Angle max_error) {
+  // The state consists of a pair (i,j).  A state transition consists of
+  // incrementing either "i" or "j".  "i" can be incremented only if
+  // a(i+1+a_offset) is near the edge from b(j) to b(j+1), and a similar rule
+  // applies to "j".  The function returns true iff we can proceed all the way
+  // around both loops in this way.
+  //
+  // Note that when "i" and "j" can both be incremented, sometimes only one
+  // choice leads to a solution.  We handle this using a stack and
+  // backtracking.  We also keep track of which states have already been
+  // explored to avoid duplicating work.
+
+  vector<pair<int, int>> pending;
+  set<pair<int, int>> done;
+  pending.push_back(std::make_pair(0, 0));
+  while (!pending.empty()) {
+    int i = pending.back().first;
+    int j = pending.back().second;
+    pending.pop_back();
+    if (i == a.num_vertices() && j == b.num_vertices()) {
+      return true;
+    }
+    done.insert(std::make_pair(i, j));
+
+    // If (i == na && offset == na-1) where na == a->num_vertices(), then
+    // then (i+1+offset) overflows the [0, 2*na-1] range allowed by vertex().
+    // So we reduce the range if necessary.
+    int io = i + a_offset;
+    if (io >= a.num_vertices()) io -= a.num_vertices();
+
+    if (i < a.num_vertices() && done.count(std::make_pair(i + 1, j)) == 0 &&
+        S2::GetDistance(a.vertex(io + 1), b.vertex(j),
+                                b.vertex(j + 1)) <= max_error) {
+      pending.push_back(std::make_pair(i + 1, j));
+    }
+    if (j < b.num_vertices() && done.count(std::make_pair(i, j + 1)) == 0 &&
+        S2::GetDistance(b.vertex(j + 1), a.vertex(io),
+                                a.vertex(io + 1)) <= max_error) {
+      pending.push_back(std::make_pair(i, j + 1));
+    }
+  }
+  return false;
+}
+
+bool S2Loop::BoundaryNear(const S2Loop& b, S1Angle max_error) const {
+  // Special case to handle empty or full loops.
+  if (is_empty_or_full() || b.is_empty_or_full()) {
+    return (is_empty() && b.is_empty()) || (is_full() && b.is_full());
+  }
+
+  for (int a_offset = 0; a_offset < num_vertices(); ++a_offset) {
+    if (MatchBoundaries(*this, b, a_offset, max_error)) return true;
+  }
+  return false;
+}
+
+void S2Loop::GetXYZFaceSiTiVertices(S2XYZFaceSiTi* vertices) const {
+  for (int i = 0; i < num_vertices(); ++i) {
+    vertices[i].xyz = vertex(i);
+    vertices[i].cell_level = S2::XYZtoFaceSiTi(vertices[i].xyz,
+        &vertices[i].face, &vertices[i].si, &vertices[i].ti);
+  }
+}
+
+void S2Loop::EncodeCompressed(Encoder* encoder, const S2XYZFaceSiTi* vertices,
+                              int snap_level) const {
+  // Ensure enough for the data we write before S2EncodePointsCompressed.
+  // S2EncodePointsCompressed ensures its space.
+  encoder->Ensure(Encoder::kVarintMax32);
+  encoder->put_varint32(num_vertices_);
+
+  S2EncodePointsCompressed(MakeSpan(vertices, num_vertices_),
+                           snap_level, encoder);
+
+  std::bitset<kNumProperties> properties = GetCompressedEncodingProperties();
+
+  // Ensure enough only for what we write.  Let the bound ensure its own
+  // space.
+  encoder->Ensure(2 * Encoder::kVarintMax32);
+  encoder->put_varint32(properties.to_ulong());
+  encoder->put_varint32(depth_);
+  if (properties.test(kBoundEncoded)) {
+    bound_.Encode(encoder);
+  }
+  S2_DCHECK_GE(encoder->avail(), 0);
+}
+
+bool S2Loop::DecodeCompressed(Decoder* decoder, int snap_level) {
+  // get_varint32 takes a uint32*, but num_vertices_ is signed.
+  // Decode to a temporary variable to avoid reinterpret_cast.
+  uint32 unsigned_num_vertices;
+  if (!decoder->get_varint32(&unsigned_num_vertices)) {
+    return false;
+  }
+  if (unsigned_num_vertices == 0 ||
+      unsigned_num_vertices > FLAGS_s2polygon_decode_max_num_vertices) {
+    return false;
+  }
+  ClearIndex();
+  if (owns_vertices_) delete[] vertices_;
+  num_vertices_ = unsigned_num_vertices;
+  vertices_ = new S2Point[num_vertices_];
+  owns_vertices_ = true;
+
+  if (!S2DecodePointsCompressed(decoder, snap_level,
+                                MakeSpan(vertices_, num_vertices_))) {
+    return false;
+  }
+  uint32 properties_uint32;
+  if (!decoder->get_varint32(&properties_uint32)) {
+    return false;
+  }
+  const std::bitset<kNumProperties> properties(properties_uint32);
+  origin_inside_ = properties.test(kOriginInside);
+
+  uint32 unsigned_depth;
+  if (!decoder->get_varint32(&unsigned_depth)) {
+    return false;
+  }
+  depth_ = unsigned_depth;
+
+  if (properties.test(kBoundEncoded)) {
+    if (!bound_.Decode(decoder)) {
+      return false;
+    }
+    subregion_bound_ = S2LatLngRectBounder::ExpandForSubregions(bound_);
+  } else {
+    InitBound();
+  }
+  InitIndex();
+  return true;
+}
+
+std::bitset<kNumProperties> S2Loop::GetCompressedEncodingProperties() const {
+  std::bitset<kNumProperties> properties;
+  if (origin_inside_) {
+    properties.set(kOriginInside);
+  }
+
+  // Write whether there is a bound so we can change the threshold later.
+  // Recomputing the bound multiplies the decode time taken per vertex
+  // by a factor of about 3.5.  Without recomputing the bound, decode
+  // takes approximately 125 ns / vertex.  A loop with 63 vertices
+  // encoded without the bound will take ~30us to decode, which is
+  // acceptable.  At ~3.5 bytes / vertex without the bound, adding
+  // the bound will increase the size by <15%, which is also acceptable.
+  static const int kMinVerticesForBound = 64;
+  if (num_vertices_ >= kMinVerticesForBound) {
+    properties.set(kBoundEncoded);
+  }
+  return properties;
+}
+
+/* static */
+std::unique_ptr<S2Loop> S2Loop::MakeRegularLoop(const S2Point& center,
+                                                S1Angle radius,
+                                                int num_vertices) {
+  Matrix3x3_d m;
+  S2::GetFrame(center, &m);  // TODO(ericv): Return by value
+  return MakeRegularLoop(m, radius, num_vertices);
+}
+
+/* static */
+std::unique_ptr<S2Loop> S2Loop::MakeRegularLoop(const Matrix3x3_d& frame,
+                                                S1Angle radius,
+                                                int num_vertices) {
+  // We construct the loop in the given frame coordinates, with the center at
+  // (0, 0, 1).  For a loop of radius "r", the loop vertices have the form
+  // (x, y, z) where x^2 + y^2 = sin(r) and z = cos(r).  The distance on the
+  // sphere (arc length) from each vertex to the center is acos(cos(r)) = r.
+  double z = cos(radius.radians());
+  double r = sin(radius.radians());
+  double radian_step = 2 * M_PI / num_vertices;
+  vector<S2Point> vertices;
+  for (int i = 0; i < num_vertices; ++i) {
+    double angle = i * radian_step;
+    S2Point p(r * cos(angle), r * sin(angle), z);
+    vertices.push_back(S2::FromFrame(frame, p).Normalize());
+  }
+  return make_unique<S2Loop>(vertices);
+}
+
+size_t S2Loop::SpaceUsed() const {
+  size_t size = sizeof(*this);
+  size += num_vertices() * sizeof(S2Point);
+  // index_ itself is already included in sizeof(*this).
+  size += index_.SpaceUsed() - sizeof(index_);
+  return size;
+}
+
+int S2Loop::Shape::num_chains() const {
+  return loop_->is_empty() ? 0 : 1;
+}
+
+S2Shape::Chain S2Loop::Shape::chain(int i) const {
+  S2_DCHECK_EQ(i, 0);
+  return Chain(0, Shape::num_edges());  // Avoid virtual call.
+}
diff --git a/src/s2/s2loop.h b/src/s2/s2loop.h
new file mode 100644 (file)
index 0000000..4bc95ca
--- /dev/null
@@ -0,0 +1,711 @@
+// Copyright 2005 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// Author: ericv@google.com (Eric Veach)
+
+#ifndef S2_S2LOOP_H_
+#define S2_S2LOOP_H_
+
+#include <atomic>
+#include <bitset>
+#include <cmath>
+#include <cstddef>
+#include <map>
+#include <vector>
+
+#include "s2/base/integral_types.h"
+#include "s2/base/logging.h"
+#include "s2/_fp_contract_off.h"
+#include "s2/mutable_s2shape_index.h"
+#include "s2/s1angle.h"
+#include "s2/s1chord_angle.h"
+#include "s2/s2debug.h"
+#include "s2/s2latlng_rect.h"
+#include "s2/s2loop_measures.h"
+#include "s2/s2pointutil.h"
+#include "s2/s2region.h"
+#include "s2/s2shape_index.h"
+#include "absl/base/macros.h"
+#include "s2/util/math/matrix3x3.h"
+#include "s2/util/math/vector.h"
+
+class Decoder;
+class Encoder;
+class LoopCrosser;
+class LoopRelation;
+class MergingIterator;
+class S2Cap;
+class S2Cell;
+class S2CrossingEdgeQuery;
+class S2Error;
+class S2Loop;
+struct S2XYZFaceSiTi;
+namespace s2builderutil { class S2PolygonLayer; }
+
+// An S2Loop represents a simple spherical polygon.  It consists of a single
+// chain of vertices where the first vertex is implicitly connected to the
+// last. All loops are defined to have a CCW orientation, i.e. the interior of
+// the loop is on the left side of the edges.  This implies that a clockwise
+// loop enclosing a small area is interpreted to be a CCW loop enclosing a
+// very large area.
+//
+// Loops are not allowed to have any duplicate vertices (whether adjacent or
+// not).  Non-adjacent edges are not allowed to intersect, and furthermore edges
+// of length 180 degrees are not allowed (i.e., adjacent vertices cannot be
+// antipodal).  Loops must have at least 3 vertices (except for the empty and
+// full loops discussed below).  Although these restrictions are not enforced
+// in optimized code, you may get unexpected results if they are violated.
+//
+// There are two special loops: the "empty loop" contains no points, while the
+// "full loop" contains all points.  These loops do not have any edges, but to
+// preserve the invariant that every loop can be represented as a vertex
+// chain, they are defined as having exactly one vertex each (see kEmpty and
+// kFull).
+//
+// Point containment of loops is defined such that if the sphere is subdivided
+// into faces (loops), every point is contained by exactly one face.  This
+// implies that loops do not necessarily contain their vertices.
+//
+// Note: The reason that duplicate vertices and intersecting edges are not
+// allowed is that they make it harder to define and implement loop
+// relationships, e.g. whether one loop contains another.  If your data does
+// not satisfy these restrictions, you can use S2Builder to normalize it.
+class S2Loop final : public S2Region {
+ public:
+  // Default constructor.  The loop must be initialized by calling Init() or
+  // Decode() before it is used.
+  S2Loop();
+
+  // Convenience constructor that calls Init() with the given vertices.
+  explicit S2Loop(const std::vector<S2Point>& vertices);
+
+  // Convenience constructor to disable the automatic validity checking
+  // controlled by the --s2debug flag.  Example:
+  //
+  //   S2Loop* loop = new S2Loop(vertices, S2Debug::DISABLE);
+  //
+  // This is equivalent to:
+  //
+  //   S2Loop* loop = new S2Loop;
+  //   loop->set_s2debug_override(S2Debug::DISABLE);
+  //   loop->Init(vertices);
+  //
+  // The main reason to use this constructor is if you intend to call
+  // IsValid() explicitly.  See set_s2debug_override() for details.
+  S2Loop(const std::vector<S2Point>& vertices, S2Debug override);
+
+  // Initialize a loop with given vertices.  The last vertex is implicitly
+  // connected to the first.  All points should be unit length.  Loops must
+  // have at least 3 vertices (except for the empty and full loops, see
+  // kEmpty and kFull).  This method may be called multiple times.
+  void Init(const std::vector<S2Point>& vertices);
+
+  // A special vertex chain of length 1 that creates an empty loop (i.e., a
+  // loop with no edges that contains no points).  Example usage:
+  //
+  //    S2Loop empty(S2Loop::kEmpty());
+  //
+  // The loop may be safely encoded lossily (e.g. by snapping it to an S2Cell
+  // center) as long as its position does not move by 90 degrees or more.
+  static std::vector<S2Point> kEmpty();
+
+  // A special vertex chain of length 1 that creates a full loop (i.e., a loop
+  // with no edges that contains all points).  See kEmpty() for details.
+  static std::vector<S2Point> kFull();
+
+  // Construct a loop corresponding to the given cell.
+  //
+  // Note that the loop and cell *do not* contain exactly the same set of
+  // points, because S2Loop and S2Cell have slightly different definitions of
+  // point containment.  For example, an S2Cell vertex is contained by all
+  // four neighboring S2Cells, but it is contained by exactly one of four
+  // S2Loops constructed from those cells.  As another example, the S2Cell
+  // coverings of "cell" and "S2Loop(cell)" will be different, because the
+  // loop contains points on its boundary that actually belong to other cells
+  // (i.e., the covering will include a layer of neighboring cells).
+  explicit S2Loop(const S2Cell& cell);
+
+  ~S2Loop() override;
+
+  // Allows overriding the automatic validity checks controlled by the
+  // --s2debug flag.  If this flag is true, then loops are automatically
+  // checked for validity as they are initialized.  The main reason to disable
+  // this flag is if you intend to call IsValid() explicitly, like this:
+  //
+  //   S2Loop loop;
+  //   loop.set_s2debug_override(S2Debug::DISABLE);
+  //   loop.Init(...);
+  //   if (!loop.IsValid()) { ... }
+  //
+  // Without the call to set_s2debug_override(), invalid data would cause a
+  // fatal error in Init() whenever the --s2debug flag is enabled.
+  //
+  // This setting is preserved across calls to Init() and Decode().
+  void set_s2debug_override(S2Debug override);
+  S2Debug s2debug_override() const;
+
+  // Returns true if this is a valid loop.  Note that validity is checked
+  // automatically during initialization when --s2debug is enabled (true by
+  // default in debug binaries).
+  bool IsValid() const;
+
+  // Returns true if this is *not* a valid loop and sets "error"
+  // appropriately.  Otherwise returns false and leaves "error" unchanged.
+  //
+  // REQUIRES: error != nullptr
+  bool FindValidationError(S2Error* error) const;
+
+  int num_vertices() const { return num_vertices_; }
+
+  // For convenience, we make two entire copies of the vertex list available:
+  // vertex(n..2*n-1) is mapped to vertex(0..n-1), where n == num_vertices().
+  //
+  // REQUIRES: 0 <= i < 2 * num_vertices()
+  const S2Point& vertex(int i) const {
+    S2_DCHECK_GE(i, 0);
+    S2_DCHECK_LT(i, 2 * num_vertices());
+    int j = i - num_vertices();
+    return vertices_[j < 0 ? i : j];
+  }
+
+  // Like vertex(), but this method returns vertices in reverse order if the
+  // loop represents a polygon hole.  For example, arguments 0, 1, 2 are
+  // mapped to vertices n-1, n-2, n-3, where n == num_vertices().  This
+  // ensures that the interior of the polygon is always to the left of the
+  // vertex chain.
+  //
+  // REQUIRES: 0 <= i < 2 * num_vertices()
+  const S2Point& oriented_vertex(int i) const {
+    S2_DCHECK_GE(i, 0);
+    S2_DCHECK_LT(i, 2 * num_vertices());
+    int j = i - num_vertices();
+    if (j < 0) j = i;
+    if (is_hole()) j = num_vertices() - 1 - j;
+    return vertices_[j];
+  }
+
+  // Returns true if this is the special empty loop that contains no points.
+  bool is_empty() const;
+
+  // Returns true if this is the special full loop that contains all points.
+  bool is_full() const;
+
+  // Returns true if this loop is either empty or full.
+  bool is_empty_or_full() const;
+
+  // The depth of a loop is defined as its nesting level within its containing
+  // polygon.  "Outer shell" loops have depth 0, holes within those loops have
+  // depth 1, shells within those holes have depth 2, etc.  This field is only
+  // used by the S2Polygon implementation.
+  int depth() const { return depth_; }
+  void set_depth(int depth) { depth_ = depth; }
+
+  // Returns true if this loop represents a hole in its containing polygon.
+  bool is_hole() const { return (depth_ & 1) != 0; }
+
+  // The sign of a loop is -1 if the loop represents a hole in its containing
+  // polygon, and +1 otherwise.
+  int sign() const { return is_hole() ? -1 : 1; }
+
+  // Returns true if the loop area is at most 2*Pi.  Degenerate loops are
+  // handled consistently with s2pred::Sign(), i.e., if a loop can be
+  // expressed as the union of degenerate or nearly-degenerate CCW triangles,
+  // then it will always be considered normalized.
+  bool IsNormalized() const;
+
+  // Invert the loop if necessary so that the area enclosed by the loop is at
+  // most 2*Pi.
+  void Normalize();
+
+  // Reverse the order of the loop vertices, effectively complementing the
+  // region represented by the loop.  For example, the loop ABCD (with edges
+  // AB, BC, CD, DA) becomes the loop DCBA (with edges DC, CB, BA, AD).
+  // Notice that the last edge is the same in both cases except that its
+  // direction has been reversed.
+  void Invert();
+
+  // Returns the area of the loop interior, i.e. the region on the left side of
+  // the loop.  The return value is between 0 and 4*Pi.  (Note that the return
+  // value is not affected by whether this loop is a "hole" or a "shell".)
+  double GetArea() const;
+
+  // Returns the true centroid of the loop multiplied by the area of the loop
+  // (see s2centroids.h for details on centroids).  The result is not unit
+  // length, so you may want to normalize it.  Also note that in general, the
+  // centroid may not be contained by the loop.
+  //
+  // We prescale by the loop area for two reasons: (1) it is cheaper to
+  // compute this way, and (2) it makes it easier to compute the centroid of
+  // more complicated shapes (by splitting them into disjoint regions and
+  // adding their centroids).
+  //
+  // Note that the return value is not affected by whether this loop is a
+  // "hole" or a "shell".
+  S2Point GetCentroid() const;
+
+  // Returns the geodesic curvature of the loop, defined as the sum of the turn
+  // angles at each vertex (see S2::TurnAngle).  The result is positive if the
+  // loop is counter-clockwise, negative if the loop is clockwise, and zero if
+  // the loop is a great circle.  The geodesic curvature is equal to 2*Pi minus
+  // the area of the loop.
+  //
+  // Degenerate and nearly-degenerate loops are handled consistently with
+  // s2pred::Sign().  So for example, if a loop has zero area (i.e., it is a
+  // very small CCW loop) then its geodesic curvature will always be positive.
+  double GetCurvature() const;
+
+  // Returns the maximum error in GetCurvature().  The return value is not
+  // constant; it depends on the loop.
+  double GetCurvatureMaxError() const;
+
+  // Returns the distance from the given point to the loop interior.  If the
+  // loop is empty, return S1Angle::Infinity().  "x" should be unit length.
+  S1Angle GetDistance(const S2Point& x) const;
+
+  // Returns the distance from the given point to the loop boundary.  If the
+  // loop is empty or full, return S1Angle::Infinity() (since the loop has no
+  // boundary).  "x" should be unit length.
+  S1Angle GetDistanceToBoundary(const S2Point& x) const;
+
+  // If the given point is contained by the loop, return it.  Otherwise return
+  // the closest point on the loop boundary.  If the loop is empty, return the
+  // input argument.  Note that the result may or may not be contained by the
+  // loop.  "x" should be unit length.
+  S2Point Project(const S2Point& x) const;
+
+  // Returns the closest point on the loop boundary to the given point.  If the
+  // loop is empty or full, return the input argument (since the loop has no
+  // boundary).  "x" should be unit length.
+  S2Point ProjectToBoundary(const S2Point& x) const;
+
+  // Returns true if the region contained by this loop is a superset of the
+  // region contained by the given other loop.
+  bool Contains(const S2Loop* b) const;
+
+  // Returns true if the region contained by this loop intersects the region
+  // contained by the given other loop.
+  bool Intersects(const S2Loop* b) const;
+
+  // Returns true if two loops have the same vertices in the same linear order
+  // (i.e., cyclic rotations are not allowed).
+  bool Equals(const S2Loop* b) const;
+
+  // Returns true if two loops have the same boundary.  This is true if and
+  // only if the loops have the same vertices in the same cyclic order (i.e.,
+  // the vertices may be cyclically rotated).  The empty and full loops are
+  // considered to have different boundaries.
+  bool BoundaryEquals(const S2Loop* b) const;
+
+  // Returns true if two loops have the same boundary except for vertex
+  // perturbations.  More precisely, the vertices in the two loops must be in
+  // the same cyclic order, and corresponding vertex pairs must be separated
+  // by no more than "max_error".
+  bool BoundaryApproxEquals(const S2Loop& b,
+                            S1Angle max_error = S1Angle::Radians(1e-15)) const;
+
+  // Returns true if the two loop boundaries are within "max_error" of each
+  // other along their entire lengths.  The two loops may have different
+  // numbers of vertices.  More precisely, this method returns true if the two
+  // loops have parameterizations a:[0,1] -> S^2, b:[0,1] -> S^2 such that
+  // distance(a(t), b(t)) <= max_error for all t.  You can think of this as
+  // testing whether it is possible to drive two cars all the way around the
+  // two loops such that no car ever goes backward and the cars are always
+  // within "max_error" of each other.
+  bool BoundaryNear(const S2Loop& b,
+                    S1Angle max_error = S1Angle::Radians(1e-15)) const;
+
+  // This method computes the oriented surface integral of some quantity f(x)
+  // over the loop interior, given a function f_tri(A,B,C) that returns the
+  // corresponding integral over the spherical triangle ABC.  Here "oriented
+  // surface integral" means:
+  //
+  // (1) f_tri(A,B,C) must be the integral of f if ABC is counterclockwise,
+  //     and the integral of -f if ABC is clockwise.
+  //
+  // (2) The result of this function is *either* the integral of f over the
+  //     loop interior, or the integral of (-f) over the loop exterior.
+  //
+  // Note that there are at least two common situations where it easy to work
+  // around property (2) above:
+  //
+  //  - If the integral of f over the entire sphere is zero, then it doesn't
+  //    matter which case is returned because they are always equal.
+  //
+  //  - If f is non-negative, then it is easy to detect when the integral over
+  //    the loop exterior has been returned, and the integral over the loop
+  //    interior can be obtained by adding the integral of f over the entire
+  //    unit sphere (a constant) to the result.
+  //
+  // Also requires that the default constructor for T must initialize the
+  // value to zero.  (This is true for built-in types such as "double".)
+  template <class T>
+  T GetSurfaceIntegral(T f_tri(const S2Point&, const S2Point&, const S2Point&))
+      const;
+
+  // Constructs a regular polygon with the given number of vertices, all
+  // located on a circle of the specified radius around "center".  The radius
+  // is the actual distance from "center" to each vertex.
+  static std::unique_ptr<S2Loop> MakeRegularLoop(const S2Point& center,
+                                                 S1Angle radius,
+                                                 int num_vertices);
+
+  // Like the function above, but this version constructs a loop centered
+  // around the z-axis of the given coordinate frame, with the first vertex in
+  // the direction of the positive x-axis.  (This allows the loop to be
+  // rotated for testing purposes.)
+  static std::unique_ptr<S2Loop> MakeRegularLoop(const Matrix3x3_d& frame,
+                                                 S1Angle radius,
+                                                 int num_vertices);
+
+  // Returnss the total number of bytes used by the loop.
+  size_t SpaceUsed() const;
+
+  ////////////////////////////////////////////////////////////////////////
+  // S2Region interface (see s2region.h for details):
+
+  S2Loop* Clone() const override;
+
+  // GetRectBound() returns essentially tight results, while GetCapBound()
+  // might have a lot of extra padding.  Both bounds are conservative in that
+  // if the loop contains a point P, then the bound contains P also.
+  S2Cap GetCapBound() const override;
+  S2LatLngRect GetRectBound() const override { return bound_; }
+
+  bool Contains(const S2Cell& cell) const override;
+  bool MayIntersect(const S2Cell& cell) const override;
+
+  // The point 'p' does not need to be normalized.
+  bool Contains(const S2Point& p) const override;
+
+  // Appends a serialized representation of the S2Loop to "encoder".
+  //
+  // Generally clients should not use S2Loop::Encode().  Instead they should
+  // encode an S2Polygon, which unlike this method supports (lossless)
+  // compression.
+  //
+  // REQUIRES: "encoder" uses the default constructor, so that its buffer
+  //           can be enlarged as necessary by calling Ensure(int).
+  void Encode(Encoder* const encoder) const;
+
+  // Decodes a loop encoded with Encode() or the private method
+  // EncodeCompressed() (used by the S2Polygon encoder).  Returns true on
+  // success.
+  //
+  // This method may be called with loops that have already been initialized.
+  bool Decode(Decoder* const decoder);
+
+  // Provides the same functionality as Decode, except that decoded regions
+  // are allowed to point directly into the Decoder's memory buffer rather
+  // than copying the data.  This can be much faster, but the decoded loop is
+  // only valid within the scope (lifetime) of the Decoder's memory buffer.
+  bool DecodeWithinScope(Decoder* const decoder);
+
+  ////////////////////////////////////////////////////////////////////////
+  // Methods intended primarily for use by the S2Polygon implementation:
+
+  // Given two loops of a polygon, return true if A contains B.  This version
+  // of Contains() is cheap because it does not test for edge intersections.
+  // The loops must meet all the S2Polygon requirements; for example this
+  // implies that their boundaries may not cross or have any shared edges
+  // (although they may have shared vertices).
+  bool ContainsNested(const S2Loop* b) const;
+
+  // Returns +1 if A contains the boundary of B, -1 if A excludes the boundary
+  // of B, and 0 if the boundaries of A and B cross.  Shared edges are handled
+  // as follows: If XY is a shared edge, define Reversed(XY) to be true if XY
+  // appears in opposite directions in A and B.  Then A contains XY if and
+  // only if Reversed(XY) == B->is_hole().  (Intuitively, this checks whether
+  // A contains a vanishingly small region extending from the boundary of B
+  // toward the interior of the polygon to which loop B belongs.)
+  //
+  // This method is used for testing containment and intersection of
+  // multi-loop polygons.  Note that this method is not symmetric, since the
+  // result depends on the direction of loop A but not on the direction of
+  // loop B (in the absence of shared edges).
+  //
+  // REQUIRES: neither loop is empty.
+  // REQUIRES: if b->is_full(), then !b->is_hole().
+  int CompareBoundary(const S2Loop* b) const;
+
+  // Given two loops whose boundaries do not cross (see CompareBoundary),
+  // return true if A contains the boundary of B.  If "reverse_b" is true, the
+  // boundary of B is reversed first (which only affects the result when there
+  // are shared edges).  This method is cheaper than CompareBoundary() because
+  // it does not test for edge intersections.
+  //
+  // REQUIRES: neither loop is empty.
+  // REQUIRES: if b->is_full(), then reverse_b == false.
+  bool ContainsNonCrossingBoundary(const S2Loop* b, bool reverse_b) const;
+
+  // Wrapper class for indexing a loop (see S2ShapeIndex).  Once this object
+  // is inserted into an S2ShapeIndex it is owned by that index, and will be
+  // automatically deleted when no longer needed by the index.  Note that this
+  // class does not take ownership of the loop itself (see OwningShape below).
+  // You can also subtype this class to store additional data (see S2Shape for
+  // details).
+#ifndef SWIG
+  class Shape : public S2Shape {
+   public:
+    Shape() : loop_(nullptr) {}  // Must call Init().
+
+    // Initialize the shape.  Does not take ownership of "loop".
+    explicit Shape(const S2Loop* loop) { Init(loop); }
+    void Init(const S2Loop* loop) { loop_ = loop; }
+
+    const S2Loop* loop() const { return loop_; }
+
+    // S2Shape interface:
+    int num_edges() const final {
+      return loop_->is_empty_or_full() ? 0 : loop_->num_vertices();
+    }
+    Edge edge(int e) const final {
+      return Edge(loop_->vertex(e), loop_->vertex(e + 1));
+    }
+    int dimension() const final { return 2; }
+    ReferencePoint GetReferencePoint() const final {
+      return ReferencePoint(S2::Origin(), loop_->contains_origin());
+    }
+    int num_chains() const final;
+    Chain chain(int i) const final;
+    Edge chain_edge(int i, int j) const final {
+      S2_DCHECK_EQ(i, 0);
+      return Edge(loop_->vertex(j), loop_->vertex(j + 1));
+    }
+    ChainPosition chain_position(int e) const final {
+      return ChainPosition(0, e);
+    }
+
+   private:
+    const S2Loop* loop_;
+  };
+
+  // Like Shape, except that the S2Loop is automatically deleted when this
+  // object is deleted by the S2ShapeIndex.  This is useful when an S2Loop
+  // is constructed solely for the purpose of indexing it.
+  class OwningShape : public Shape {
+   public:
+    OwningShape() {}  // Must call Init().
+    explicit OwningShape(std::unique_ptr<const S2Loop> loop)
+        : Shape(loop.release()) {
+    }
+    void Init(std::unique_ptr<const S2Loop> loop) {
+      Shape::Init(loop.release());
+    }
+    ~OwningShape() override { delete loop(); }
+  };
+#endif  // SWIG
+
+ private:
+  // All of the following need access to contains_origin().  Possibly this
+  // method should be public.
+  friend class Shape;
+  friend class S2Polygon;
+  friend class S2Stats;
+  friend class S2LoopTestBase;
+  friend class LoopCrosser;
+  friend class s2builderutil::S2PolygonLayer;
+
+  // Internal copy constructor used only by Clone() that makes a deep copy of
+  // its argument.
+  S2Loop(const S2Loop& src);
+
+  // Returns an S2PointLoopSpan containing the loop vertices, for use with the
+  // functions defined in s2loop_measures.h.
+  S2PointLoopSpan vertices_span() const {
+    return S2PointLoopSpan(vertices_, num_vertices());
+  }
+
+  // Returns true if this loop contains S2::Origin().
+  bool contains_origin() const { return origin_inside_; }
+
+  // The single vertex in the "empty loop" vertex chain.
+  static S2Point kEmptyVertex();
+
+  // The single vertex in the "full loop" vertex chain.
+  static S2Point kFullVertex();
+
+  void InitOriginAndBound();
+  void InitBound();
+  void InitIndex();
+
+  // A version of Contains(S2Point) that does not use the S2ShapeIndex.
+  // Used by the S2Polygon implementation.
+  bool BruteForceContains(const S2Point& p) const;
+
+  // Like FindValidationError(), but skips any checks that would require
+  // building the S2ShapeIndex (i.e., self-intersection tests).  This is used
+  // by the S2Polygon implementation, which uses its own index to check for
+  // loop self-intersections.
+  bool FindValidationErrorNoIndex(S2Error* error) const;
+
+  // Internal implementation of the Decode and DecodeWithinScope methods above.
+  // If within_scope is true, memory is allocated for vertices_ and data
+  // is copied from the decoder using std::copy. If it is false, vertices_
+  // will point to the memory area inside the decoder, and the field
+  // owns_vertices_ is set to false.
+  bool DecodeInternal(Decoder* const decoder, bool within_scope);
+
+  // Converts the loop vertices to the S2XYZFaceSiTi format and store the result
+  // in the given array, which must be large enough to store all the vertices.
+  void GetXYZFaceSiTiVertices(S2XYZFaceSiTi* vertices) const;
+
+  // Encode the loop's vertices using S2EncodePointsCompressed.  Uses
+  // approximately 8 bytes for the first vertex, going down to less than 4 bytes
+  // per vertex on Google's geographic repository, plus 24 bytes per vertex that
+  // does not correspond to the center of a cell at level 'snap_level'. The loop
+  // vertices must first be converted to the S2XYZFaceSiTi format with
+  // GetXYZFaceSiTiVertices.
+  //
+  // REQUIRES: the loop is initialized and valid.
+  void EncodeCompressed(Encoder* encoder, const S2XYZFaceSiTi* vertices,
+                        int snap_level) const;
+
+  // Decode a loop encoded with EncodeCompressed. The parameters must be the
+  // same as the one used when EncodeCompressed was called.
+  bool DecodeCompressed(Decoder* decoder, int snap_level);
+
+  // Returns a bitset of properties used by EncodeCompressed
+  // to efficiently encode boolean values.  Properties are
+  // origin_inside and whether the bound was encoded.
+  std::bitset<2> GetCompressedEncodingProperties() const;
+
+  // Given an iterator that is already positioned at the S2ShapeIndexCell
+  // containing "p", returns Contains(p).
+  bool Contains(const MutableS2ShapeIndex::Iterator& it,
+                const S2Point& p) const;
+
+  // Returns true if the loop boundary intersects "target".  It may also
+  // return true when the loop boundary does not intersect "target" but
+  // some edge comes within the worst-case error tolerance.
+  //
+  // REQUIRES: it.id().contains(target.id())
+  // [This condition is true whenever it.Locate(target) returns INDEXED.]
+  bool BoundaryApproxIntersects(const MutableS2ShapeIndex::Iterator& it,
+                                const S2Cell& target) const;
+
+  // Returns an index "first" and a direction "dir" such that the vertex
+  // sequence (first, first + dir, ..., first + (n - 1) * dir) does not change
+  // when the loop vertex order is rotated or reversed.  This allows the loop
+  // vertices to be traversed in a canonical order.
+  S2::LoopOrder GetCanonicalLoopOrder() const;
+
+  // Returns the index of a vertex at point "p", or -1 if not found.
+  // The return value is in the range 1..num_vertices_ if found.
+  int FindVertex(const S2Point& p) const;
+
+  // This method checks all edges of loop A for intersection against all edges
+  // of loop B.  If there is any shared vertex, the wedges centered at this
+  // vertex are sent to "relation".
+  //
+  // If the two loop boundaries cross, this method is guaranteed to return
+  // true.  It also returns true in certain cases if the loop relationship is
+  // equivalent to crossing.  For example, if the relation is Contains() and a
+  // point P is found such that B contains P but A does not contain P, this
+  // method will return true to indicate that the result is the same as though
+  // a pair of crossing edges were found (since Contains() returns false in
+  // both cases).
+  //
+  // See Contains(), Intersects() and CompareBoundary() for the three uses of
+  // this function.
+  static bool HasCrossingRelation(const S2Loop& a, const S2Loop& b,
+                                  LoopRelation* relation);
+
+  // When the loop is modified (Invert(), or Init() called again) then the
+  // indexing structures need to be cleared since they become invalid.
+  void ClearIndex();
+
+  // The nesting depth, if this field belongs to an S2Polygon.  We define it
+  // here to optimize field packing.
+  int depth_ = 0;
+
+  // We store the vertices in an array rather than a vector because we don't
+  // need any STL methods, and computing the number of vertices using size()
+  // would be relatively expensive (due to division by sizeof(S2Point) == 24).
+  // When DecodeWithinScope is used to initialize the loop, we do not
+  // take ownership of the memory for vertices_, and the owns_vertices_ field
+  // is used to prevent deallocation and overwriting.
+  int num_vertices_ = 0;
+  S2Point* vertices_ = nullptr;
+  bool owns_vertices_ = false;
+
+  S2Debug s2debug_override_ = S2Debug::ALLOW;
+  bool origin_inside_ = false;  // Does the loop contain S2::Origin()?
+
+  // In general we build the index the first time it is needed, but we make an
+  // exception for Contains(S2Point) because this method has a simple brute
+  // force implementation that is also relatively cheap.  For this one method
+  // we keep track of the number of calls made and only build the index once
+  // enough calls have been made that we think an index would be worthwhile.
+  mutable std::atomic<int32> unindexed_contains_calls_;
+
+  // "bound_" is a conservative bound on all points contained by this loop:
+  // if A.Contains(P), then A.bound_.Contains(S2LatLng(P)).
+  S2LatLngRect bound_;
+
+  // Since "bound_" is not exact, it is possible that a loop A contains
+  // another loop B whose bounds are slightly larger.  "subregion_bound_"
+  // has been expanded sufficiently to account for this error, i.e.
+  // if A.Contains(B), then A.subregion_bound_.Contains(B.bound_).
+  S2LatLngRect subregion_bound_;
+
+  // Spatial index for this loop.
+  MutableS2ShapeIndex index_;
+
+  // SWIG doesn't understand "= delete".
+#ifndef SWIG
+  void operator=(const S2Loop&) = delete;
+#endif  // SWIG
+};
+
+
+//////////////////// Implementation Details Follow ////////////////////////
+
+
+// Any single-vertex loop is interpreted as being either the empty loop or the
+// full loop, depending on whether the vertex is in the northern or southern
+// hemisphere respectively.
+inline S2Point S2Loop::kEmptyVertex() { return S2Point(0, 0, 1); }
+inline S2Point S2Loop::kFullVertex() { return S2Point(0, 0, -1); }
+
+inline std::vector<S2Point> S2Loop::kEmpty() {
+  return std::vector<S2Point>(1, kEmptyVertex());
+}
+
+inline std::vector<S2Point> S2Loop::kFull() {
+  return std::vector<S2Point>(1, kFullVertex());
+}
+
+inline bool S2Loop::is_empty() const {
+  return is_empty_or_full() && !contains_origin();
+}
+
+inline bool S2Loop::is_full() const {
+  return is_empty_or_full() && contains_origin();
+}
+
+inline bool S2Loop::is_empty_or_full() const {
+  return num_vertices() == 1;
+}
+
+// Since this method is templatized and public, the implementation needs to be
+// in the .h file.
+
+template <class T>
+T S2Loop::GetSurfaceIntegral(T f_tri(const S2Point&, const S2Point&,
+                                     const S2Point&)) const {
+  return S2::GetSurfaceIntegral(vertices_span(), f_tri);
+}
+
+#endif  // S2_S2LOOP_H_
diff --git a/src/s2/s2loop_measures.cc b/src/s2/s2loop_measures.cc
new file mode 100644 (file)
index 0000000..e53df6e
--- /dev/null
@@ -0,0 +1,313 @@
+// Copyright 2018 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// Author: ericv@google.com (Eric Veach)
+
+#include "s2/s2loop_measures.h"
+
+#include <cfloat>
+#include <cmath>
+#include <vector>
+#include "s2/base/logging.h"
+#include "absl/container/inlined_vector.h"
+#include "s2/s1angle.h"
+#include "s2/s2centroids.h"
+#include "s2/s2edge_distances.h"
+#include "s2/s2measures.h"
+#include "s2/s2pointutil.h"
+
+using std::fabs;
+using std::max;
+using std::min;
+using std::vector;
+
+namespace S2 {
+
+S1Angle GetPerimeter(S2PointLoopSpan loop) {
+  S1Angle perimeter = S1Angle::Zero();
+  if (loop.size() <= 1) return perimeter;
+  for (int i = 0; i < loop.size(); ++i) {
+    perimeter += S1Angle(loop[i], loop[i + 1]);
+  }
+  return perimeter;
+}
+
+double GetArea(S2PointLoopSpan loop) {
+  double area = GetSignedArea(loop);
+  S2_DCHECK_LE(fabs(area), 2 * M_PI);
+  if (area < 0.0) area += 4 * M_PI;
+  return area;
+}
+
+double GetSignedArea(S2PointLoopSpan loop) {
+  // It is suprisingly difficult to compute the area of a loop robustly.  The
+  // main issues are (1) whether degenerate loops are considered to be CCW or
+  // not (i.e., whether their area is close to 0 or 4*Pi), and (2) computing
+  // the areas of small loops with good relative accuracy.
+  //
+  // With respect to degeneracies, we would like GetArea() to be consistent
+  // with S2Loop::Contains(S2Point) in that loops that contain many points
+  // should have large areas, and loops that contain few points should have
+  // small areas.  For example, if a degenerate triangle is considered CCW
+  // according to s2pred::Sign(), then it will contain very few points and
+  // its area should be approximately zero.  On the other hand if it is
+  // considered clockwise, then it will contain virtually all points and so
+  // its area should be approximately 4*Pi.
+  //
+  // More precisely, let U be the set of S2Points for which S2::IsUnitLength()
+  // is true, let P(U) be the projection of those points onto the mathematical
+  // unit sphere, and let V(P(U)) be the Voronoi diagram of the projected
+  // points.  Then for every loop x, we would like GetArea() to approximately
+  // equal the sum of the areas of the Voronoi regions of the points p for
+  // which x.Contains(p) is true.
+  //
+  // The second issue is that we want to compute the area of small loops
+  // accurately.  This requires having good relative precision rather than
+  // good absolute precision.  For example, if the area of a loop is 1e-12 and
+  // the error is 1e-15, then the area only has 3 digits of accuracy.  (For
+  // reference, 1e-12 is about 40 square meters on the surface of the earth.)
+  // We would like to have good relative accuracy even for small loops.
+  //
+  // To achieve these goals, we combine two different methods of computing the
+  // area.  This first method is based on the Gauss-Bonnet theorem, which says
+  // that the area enclosed by the loop equals 2*Pi minus the total geodesic
+  // curvature of the loop (i.e., the sum of the "turning angles" at all the
+  // loop vertices).  The big advantage of this method is that as long as we
+  // use s2pred::Sign() to compute the turning angle at each vertex, then
+  // degeneracies are always handled correctly.  In other words, if a
+  // degenerate loop is CCW according to the symbolic perturbations used by
+  // s2pred::Sign(), then its turning angle will be approximately 2*Pi.
+  //
+  // The disadvantage of the Gauss-Bonnet method is that its absolute error is
+  // about 2e-15 times the number of vertices (see GetCurvatureMaxError).
+  // So, it cannot compute the area of small loops accurately.
+  //
+  // The second method is based on splitting the loop into triangles and
+  // summing the area of each triangle.  To avoid the difficulty and expense
+  // of decomposing the loop into a union of non-overlapping triangles,
+  // instead we compute a signed sum over triangles that may overlap (see the
+  // comments for S2Loop::GetSurfaceIntegral).  The advantage of this method
+  // is that the area of each triangle can be computed with much better
+  // relative accuracy (using l'Huilier's theorem).  The disadvantage is that
+  // the result is a signed area: CCW loops may yield a small positive value,
+  // while CW loops may yield a small negative value (which is converted to a
+  // positive area by adding 4*Pi).  This means that small errors in computing
+  // the signed area may translate into a very large error in the result (if
+  // the sign of the sum is incorrect).
+  //
+  // So, our strategy is to combine these two methods as follows.  First we
+  // compute the area using the "signed sum over triangles" approach (since it
+  // is generally more accurate).  We also estimate the maximum error in this
+  // result.  If the signed area is too close to zero (i.e., zero is within
+  // the error bounds), then we double-check the sign of the result using the
+  // Gauss-Bonnet method.  If the two methods disagree, we return the smallest
+  // possible positive or negative area based on the result of GetCurvature().
+  // Otherwise we return the area that we computed originally.
+
+  // The signed area should be between approximately -4*Pi and 4*Pi.
+  // Normalize it to be in the range [-2*Pi, 2*Pi].
+  double area = GetSurfaceIntegral(loop, S2::SignedArea);
+  double max_error = GetCurvatureMaxError(loop);
+  S2_DCHECK_LE(fabs(area), 4 * M_PI + max_error);
+  area = remainder(area, 4 * M_PI);
+
+  // If the area is a small negative or positive number, verify that the sign
+  // of the result is consistent with the loop orientation.
+  if (fabs(area) <= max_error) {
+    double curvature = GetCurvature(loop);
+    // Zero-area loops should have a curvature of approximately +/- 2*Pi.
+    S2_DCHECK(!(area == 0 && curvature == 0));
+    if (curvature == 2 * M_PI) return 0.0;  // Degenerate
+    if (area <= 0 && curvature > 0) {
+      return std::numeric_limits<double>::min();
+    }
+    // Full loops are handled by the case below.
+    if (area >= 0 && curvature < 0) {
+      return -std::numeric_limits<double>::min();
+    }
+  }
+  return area;
+}
+
+double GetApproxArea(S2PointLoopSpan loop) {
+  return 2 * M_PI - GetCurvature(loop);
+}
+
+S2PointLoopSpan PruneDegeneracies(S2PointLoopSpan loop,
+                                  vector<S2Point>* new_vertices) {
+  vector<S2Point>& vertices = *new_vertices;
+  vertices.clear();
+  vertices.reserve(loop.size());
+  for (const S2Point& v : loop) {
+    // Remove duplicate vertices.
+    if (vertices.empty() || v != vertices.back()) {
+      // Remove edge pairs of the form ABA.
+      if (vertices.size() >= 2 && v == vertices.end()[-2]) {
+        vertices.pop_back();
+      } else {
+        vertices.push_back(v);
+      }
+    }
+  }
+  // Check whether the loop was completely degenerate.
+  if (vertices.size() < 3) return S2PointLoopSpan();
+
+  // Otherwise some portion of the loop is guaranteed to be non-degenerate.
+  // However there may still be some degenerate portions to remove.
+  if (vertices[0] == vertices.back()) vertices.pop_back();
+
+  // If the loop begins with BA and ends with A, then there is an edge pair of
+  // the form ABA at the end/start of the loop.  Remove all such pairs.  As
+  // noted above, this is guaranteed to leave a non-degenerate loop.
+  int k = 0;
+  while (vertices[k + 1] == vertices.end()[-(k + 1)]) ++k;
+  return S2PointLoopSpan(vertices.data() + k, vertices.size() - 2 * k);
+}
+
+double GetCurvature(S2PointLoopSpan loop) {
+  // By convention, a loop with no vertices contains all points on the sphere.
+  if (loop.empty()) return -2 * M_PI;
+
+  // Remove any degeneracies from the loop.
+  vector<S2Point> vertices;
+  loop = PruneDegeneracies(loop, &vertices);
+
+  // If the entire loop was degenerate, it's turning angle is defined as 2*Pi.
+  if (loop.empty()) return 2 * M_PI;
+
+  // To ensure that we get the same result when the vertex order is rotated,
+  // and that the result is negated when the vertex order is reversed, we need
+  // to add up the individual turn angles in a consistent order.  (In general,
+  // adding up a set of numbers in a different order can change the sum due to
+  // rounding errors.)
+  //
+  // Furthermore, if we just accumulate an ordinary sum then the worst-case
+  // error is quadratic in the number of vertices.  (This can happen with
+  // spiral shapes, where the partial sum of the turning angles can be linear
+  // in the number of vertices.)  To avoid this we use the Kahan summation
+  // algorithm (http://en.wikipedia.org/wiki/Kahan_summation_algorithm).
+  LoopOrder order = GetCanonicalLoopOrder(loop);
+  int i = order.first, dir = order.dir, n = loop.size();
+  double sum = S2::TurnAngle(loop[(i + n - dir) % n], loop[i],
+                             loop[(i + dir) % n]);
+  double compensation = 0;  // Kahan summation algorithm
+  while (--n > 0) {
+    i += dir;
+    double angle = S2::TurnAngle(loop[i - dir], loop[i], loop[i + dir]);
+    double old_sum = sum;
+    angle += compensation;
+    sum += angle;
+    compensation = (old_sum - sum) + angle;
+  }
+  constexpr double kMaxCurvature = 2 * M_PI - 4 * DBL_EPSILON;
+  sum += compensation;
+  return max(-kMaxCurvature, min(kMaxCurvature, dir * sum));
+}
+
+double GetCurvatureMaxError(S2PointLoopSpan loop) {
+  // The maximum error can be bounded as follows:
+  //   2.24 * DBL_EPSILON    for RobustCrossProd(b, a)
+  //   2.24 * DBL_EPSILON    for RobustCrossProd(c, b)
+  //   3.25 * DBL_EPSILON    for Angle()
+  //   2.00 * DBL_EPSILON    for each addition in the Kahan summation
+  //   ------------------
+  //   9.73 * DBL_EPSILON
+  //
+  // TODO(ericv): This error estimate is approximate.  There are two issues:
+  // (1) SignedArea needs some improvements to ensure that its error is
+  // actually never higher than GirardArea, and (2) although the number of
+  // triangles in the sum is typically N-2, in theory it could be as high as
+  // 2*N for pathological inputs.  But in other respects this error bound is
+  // very conservative since it assumes that the maximum error is achieved on
+  // every triangle.
+  const double kMaxErrorPerVertex = 9.73 * DBL_EPSILON;
+  return kMaxErrorPerVertex * loop.size();
+}
+
+S2Point GetCentroid(S2PointLoopSpan loop) {
+  // GetSurfaceIntegral() returns either the integral of position over loop
+  // interior, or the negative of the integral of position over the loop
+  // exterior.  But these two values are the same (!), because the integral of
+  // position over the entire sphere is (0, 0, 0).
+  return GetSurfaceIntegral(loop, S2::TrueCentroid);
+}
+
+static inline bool IsOrderLess(LoopOrder order1, LoopOrder order2,
+                               S2PointLoopSpan loop) {
+  if (order1 == order2) return false;
+
+  int i1 = order1.first, i2 = order2.first;
+  int dir1 = order1.dir, dir2 = order2.dir;
+  S2_DCHECK_EQ(loop[i1], loop[i2]);
+  for (int n = loop.size(); --n > 0; ) {
+    i1 += dir1;
+    i2 += dir2;
+    if (loop[i1] < loop[i2]) return true;
+    if (loop[i1] > loop[i2]) return false;
+  }
+  return false;
+}
+
+LoopOrder GetCanonicalLoopOrder(S2PointLoopSpan loop) {
+  // In order to handle loops with duplicate vertices and/or degeneracies, we
+  // return the LoopOrder that minimizes the entire corresponding vertex
+  // *sequence*.  For example, suppose that vertices are sorted
+  // alphabetically, and consider the loop CADBAB.  The canonical loop order
+  // would be (4, 1), corresponding to the vertex sequence ABCADB.  (For
+  // comparison, loop order (4, -1) yields the sequence ABDACB.)
+  //
+  // If two or more loop orders yield identical minimal vertex sequences, then
+  // it doesn't matter which one we return (since they yield the same result).
+
+  // For efficiency, we divide the process into two steps.  First we find the
+  // smallest vertex, and the set of vertex indices where that vertex occurs
+  // (noting that the loop may contain duplicate vertices).  Then we consider
+  // both possible directions starting from each such vertex index, and return
+  // the LoopOrder corresponding to the smallest vertex sequence.
+  int n = loop.size();
+  if (n == 0) return LoopOrder(0, 1);
+
+  absl::InlinedVector<int, 4> min_indices;
+  min_indices.push_back(0);
+  for (int i = 1; i < n; ++i) {
+    if (loop[i] <= loop[min_indices[0]]) {
+      if (loop[i] < loop[min_indices[0]]) min_indices.clear();
+      min_indices.push_back(i);
+    }
+  }
+  LoopOrder min_order(min_indices[0], 1);
+  for (int min_index : min_indices) {
+    LoopOrder order1(min_index, 1);
+    LoopOrder order2(min_index + n, -1);
+    if (IsOrderLess(order1, min_order, loop)) min_order = order1;
+    if (IsOrderLess(order2, min_order, loop)) min_order = order2;
+  }
+  return min_order;
+}
+
+bool IsNormalized(S2PointLoopSpan loop) {
+  // We allow some error so that hemispheres are always considered normalized.
+  //
+  // TODO(ericv): This is no longer required by the S2Polygon implementation,
+  // so alternatively we could create the invariant that a loop is normalized
+  // if and only if its complement is not normalized.
+  return GetCurvature(loop) >= -GetCurvatureMaxError(loop);
+}
+
+std::ostream& operator<<(std::ostream& os, LoopOrder order) {
+  return os << "(" << order.first << ", " << order.dir << ")";
+}
+
+}  // namespace S2
diff --git a/src/s2/s2loop_measures.h b/src/s2/s2loop_measures.h
new file mode 100644 (file)
index 0000000..98b17c4
--- /dev/null
@@ -0,0 +1,280 @@
+// Copyright 2018 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// Author: ericv@google.com (Eric Veach)
+//
+// Defines various angle and area measures for loops on the sphere.  These are
+// low-level methods that work directly with arrays of S2Points.  They are
+// used to implement the methods in s2shapeindex_measures.h,
+// s2shape_measures.h, s2loop.h, and s2polygon.h.
+//
+// See s2polyline_measures.h, s2edge_distances.h, and s2measures.h for
+// additional low-level methods.
+
+#ifndef S2_S2LOOP_MEASURES_H_
+#define S2_S2LOOP_MEASURES_H_
+
+#include <cmath>
+#include <ostream>
+#include <vector>
+
+#include "s2/s1angle.h"
+#include "s2/s2point.h"
+#include "s2/s2point_span.h"
+#include "s2/s2pointutil.h"
+
+namespace S2 {
+
+// Returns the perimeter of the loop.
+S1Angle GetPerimeter(S2PointLoopSpan loop);
+
+// Returns the area of the loop interior, i.e. the region on the left side of
+// the loop.  The result is between 0 and 4*Pi steradians.  The implementation
+// ensures that nearly-degenerate clockwise loops have areas close to zero,
+// while nearly-degenerate counter-clockwise loops have areas close to 4*Pi.
+double GetArea(S2PointLoopSpan loop);
+
+// Like GetArea(), except that this method is faster and has more error.  The
+// result is between 0 and 4*Pi steradians.  The maximum error is 2.22e-15
+// steradians per loop vertex, which works out to about 0.09 square meters per
+// vertex on the Earth's surface.  For example, a loop with 100 vertices has a
+// maximum error of about 9 square meters.  (The actual error is typically
+// much smaller than this.)  The error bound can be computed using
+// GetCurvatureMaxError(), which returns the maximum error in steradians.
+double GetApproxArea(S2PointLoopSpan loop);
+
+// Returns either the positive area of the region on the left side of the
+// loop, or the negative area of the region on the right side of the loop,
+// whichever is smaller in magnitude.  The result is between -2*Pi and 2*Pi
+// steradians.  This method is used to accurately compute the area of polygons
+// consisting of multiple loops.
+//
+// The following cases are handled specially:
+//
+//  - Counter-clockwise loops are guaranteed to have positive area, and
+//    clockwise loops are guaranteed to have negative area.
+//
+//  - Degenerate loops (consisting of an isolated vertex or composed entirely
+//    of sibling edge pairs) have an area of exactly zero.
+//
+//  - The full loop (containing all points, and represented as a loop with no
+//    vertices) has a negative area with the minimum possible magnitude.
+//    (This is the "signed equivalent" of having an area of 4*Pi.)
+double GetSignedArea(S2PointLoopSpan loop);
+
+// Returns the geodesic curvature of the loop, defined as the sum of the turn
+// angles at each vertex (see S2::TurnAngle).  The result is positive if the
+// loop is counter-clockwise, negative if the loop is clockwise, and zero if
+// the loop is a great circle.  The geodesic curvature is equal to 2*Pi minus
+// the area of the loop.
+//
+// The following cases are handled specially:
+//
+//  - Degenerate loops (consisting of an isolated vertex or composed entirely
+//    of sibling edge pairs) have a curvature of 2*Pi exactly.
+//
+//  - The full loop (containing all points, and represented as a loop with no
+//    vertices) has a curvature of -2*Pi exactly.
+//
+//  - All other loops have a non-zero curvature in the range (-2*Pi, 2*Pi).
+//    For any such loop, reversing the order of the vertices is guaranteed to
+//    negate the curvature.  This property can be used to define a unique
+//    normalized orientation for every loop.
+double GetCurvature(S2PointLoopSpan loop);
+
+// Returns the maximum error in GetCurvature() for the given loop.  This value
+// is also an upper bound on the error in GetArea(), GetSignedArea(), and
+// GetApproxArea().
+double GetCurvatureMaxError(S2PointLoopSpan loop);
+
+// Returns the true centroid of the loop multiplied by the area of the loop
+// (see s2centroids.h for details on centroids).  The result is not unit
+// length, so you may want to normalize it.  Also note that in general, the
+// centroid may not be contained by the loop.
+//
+// The result is scaled by the loop area for two reasons: (1) it is cheaper to
+// compute this way, and (2) it makes it easier to compute the centroid of
+// more complicated shapes (by splitting them into disjoint regions and adding
+// their centroids).
+S2Point GetCentroid(S2PointLoopSpan loop);
+
+// Returns true if the loop area is at most 2*Pi.  (A small amount of error is
+// allowed in order to ensure that loops representing an entire hemisphere are
+// always considered normalized.)
+//
+// Degenerate loops are handled consistently with s2pred::Sign(), i.e., if a
+// loop can be expressed as the union of degenerate or nearly-degenerate
+// counter-clockwise triangles then this method will return true.
+bool IsNormalized(S2PointLoopSpan loop);
+
+// LoopOrder represents a cyclic ordering of the loop vertices, starting at
+// the index "first" and proceeding in direction "dir" (either +1 or -1).
+// "first" and "dir" must be chosen such that (first, ..., first + n * dir)
+// are all in the range [0, 2*n-1] as required by S2PointLoopSpan::operator[].
+struct LoopOrder {
+  LoopOrder(int _first, int _dir) : first(_first), dir(_dir) {}
+  int first;
+  int dir;
+};
+bool operator==(LoopOrder x, LoopOrder y);
+std::ostream& operator<<(std::ostream& os, LoopOrder order);
+
+// Returns an index "first" and a direction "dir" such that the vertex
+// sequence (first, first + dir, ..., first + (n - 1) * dir) does not change
+// when the loop vertex order is rotated or reversed.  This allows the loop
+// vertices to be traversed in a canonical order.
+LoopOrder GetCanonicalLoopOrder(S2PointLoopSpan loop);
+
+// Returns the oriented surface integral of some quantity f(x) over the loop
+// interior, given a function f_tri(A,B,C) that returns the corresponding
+// integral over the spherical triangle ABC.  Here "oriented surface integral"
+// means:
+//
+// (1) f_tri(A,B,C) must be the integral of f if ABC is counterclockwise,
+//     and the integral of -f if ABC is clockwise.
+//
+// (2) The result of this function is *either* the integral of f over the
+//     loop interior, or the integral of (-f) over the loop exterior.
+//
+// Note that there are at least two common situations where property (2) above
+// is not a limitation:
+//
+//  - If the integral of f over the entire sphere is zero, then it doesn't
+//    matter which case is returned because they are always equal.
+//
+//  - If f is non-negative, then it is easy to detect when the integral over
+//    the loop exterior has been returned, and the integral over the loop
+//    interior can be obtained by adding the integral of f over the entire
+//    unit sphere (a constant) to the result.
+//
+// REQUIRES: The default constructor for T must initialize the value to zero.
+//           (This is true for built-in types such as "double".)
+template <class T>
+T GetSurfaceIntegral(S2PointLoopSpan loop,
+                     T f_tri(const S2Point&, const S2Point&, const S2Point&));
+
+// Returns a new loop obtained by removing all degeneracies from "loop".  In
+// particular, the result will not contain any adjacent duplicate vertices or
+// sibling edge pairs, i.e. vertex sequences of the form (A, A) or (A, B, A).
+//
+// "new_vertices" represents storage where new loop vertices may be written.
+// Note that the S2PointLoopSpan result may be a subsequence of either "loop"
+// or "new_vertices", and therefore "new_vertices" must persist until the
+// result of this method is no longer needed.
+S2PointLoopSpan PruneDegeneracies(S2PointLoopSpan loop,
+                                  std::vector<S2Point>* new_vertices);
+
+
+//////////////////// Implementation details follow ////////////////////////
+
+
+inline bool operator==(LoopOrder x, LoopOrder y) {
+  return x.first == y.first && x.dir == y.dir;
+}
+
+template <class T>
+T GetSurfaceIntegral(S2PointLoopSpan loop,
+                     T f_tri(const S2Point&, const S2Point&, const S2Point&)) {
+  // We sum "f_tri" over a collection T of oriented triangles, possibly
+  // overlapping.  Let the sign of a triangle be +1 if it is CCW and -1
+  // otherwise, and let the sign of a point "x" be the sum of the signs of the
+  // triangles containing "x".  Then the collection of triangles T is chosen
+  // such that either:
+  //
+  //  (1) Each point in the loop interior has sign +1, and sign 0 otherwise; or
+  //  (2) Each point in the loop exterior has sign -1, and sign 0 otherwise.
+  //
+  // The triangles basically consist of a "fan" from vertex 0 to every loop
+  // edge that does not include vertex 0.  These triangles will always satisfy
+  // either (1) or (2).  However, what makes this a bit tricky is that
+  // spherical edges become numerically unstable as their length approaches
+  // 180 degrees.  Of course there is not much we can do if the loop itself
+  // contains such edges, but we would like to make sure that all the triangle
+  // edges under our control (i.e., the non-loop edges) are stable.  For
+  // example, consider a loop around the equator consisting of four equally
+  // spaced points.  This is a well-defined loop, but we cannot just split it
+  // into two triangles by connecting vertex 0 to vertex 2.
+  //
+  // We handle this type of situation by moving the origin of the triangle fan
+  // whenever we are about to create an unstable edge.  We choose a new
+  // location for the origin such that all relevant edges are stable.  We also
+  // create extra triangles with the appropriate orientation so that the sum
+  // of the triangle signs is still correct at every point.
+
+  // The maximum length of an edge for it to be considered numerically stable.
+  // The exact value is fairly arbitrary since it depends on the stability of
+  // the "f_tri" function.  The value below is quite conservative but could be
+  // reduced further if desired.
+  static const double kMaxLength = M_PI - 1e-5;
+
+  // The default constructor for T must initialize the value to zero.
+  // (This is true for built-in types such as "double".)
+  T sum = T();
+  if (loop.size() < 3) return sum;
+
+  S2Point origin = loop[0];
+  for (int i = 1; i + 1 < loop.size(); ++i) {
+    // Let V_i be loop[i], let O be the current origin, and let length(A,B)
+    // be the length of edge (A,B).  At the start of each loop iteration, the
+    // "leading edge" of the triangle fan is (O,V_i), and we want to extend
+    // the triangle fan so that the leading edge is (O,V_i+1).
+    //
+    // Invariants:
+    //  1. length(O,V_i) < kMaxLength for all (i > 1).
+    //  2. Either O == V_0, or O is approximately perpendicular to V_0.
+    //  3. "sum" is the oriented integral of f over the area defined by
+    //     (O, V_0, V_1, ..., V_i).
+    S2_DCHECK(i == 1 || origin.Angle(loop[i]) < kMaxLength);
+    S2_DCHECK(origin == loop[0] || std::fabs(origin.DotProd(loop[0])) < 1e-15);
+
+    if (loop[i + 1].Angle(origin) > kMaxLength) {
+      // We are about to create an unstable edge, so choose a new origin O'
+      // for the triangle fan.
+      S2Point old_origin = origin;
+      if (origin == loop[0]) {
+        // The following point is well-separated from V_i and V_0 (and
+        // therefore V_i+1 as well).
+        origin = S2::RobustCrossProd(loop[0], loop[i]).Normalize();
+      } else if (loop[i].Angle(loop[0]) < kMaxLength) {
+        // All edges of the triangle (O, V_0, V_i) are stable, so we can
+        // revert to using V_0 as the origin.
+        origin = loop[0];
+      } else {
+        // (O, V_i+1) and (V_0, V_i) are antipodal pairs, and O and V_0 are
+        // perpendicular.  Therefore V_0.CrossProd(O) is approximately
+        // perpendicular to all of {O, V_0, V_i, V_i+1}, and we can choose
+        // this point O' as the new origin.
+        origin = loop[0].CrossProd(old_origin);
+
+        // Advance the edge (V_0,O) to (V_0,O').
+        sum += f_tri(loop[0], old_origin, origin);
+      }
+      // Advance the edge (O,V_i) to (O',V_i).
+      sum += f_tri(old_origin, loop[i], origin);
+    }
+    // Advance the edge (O,V_i) to (O,V_i+1).
+    sum += f_tri(origin, loop[i], loop[i+1]);
+  }
+  // If the origin is not V_0, we need to sum one more triangle.
+  if (origin != loop[0]) {
+    // Advance the edge (O,V_n-1) to (O,V_0).
+    sum += f_tri(origin, loop[loop.size() - 1], loop[0]);
+  }
+  return sum;
+}
+
+}  // namespace S2
+
+#endif  // S2_S2LOOP_MEASURES_H_
diff --git a/src/s2/s2max_distance_targets.cc b/src/s2/s2max_distance_targets.cc
new file mode 100644 (file)
index 0000000..6fc951b
--- /dev/null
@@ -0,0 +1,265 @@
+// Copyright Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#include "s2/s2max_distance_targets.h"
+
+#include <memory>
+#include "absl/memory/memory.h"
+#include "s2/s1angle.h"
+#include "s2/s2cap.h"
+#include "s2/s2cell.h"
+#include "s2/s2edge_distances.h"
+#include "s2/s2furthest_edge_query.h"
+#include "s2/s2shape_index_region.h"
+#include "s2/s2text_format.h"
+
+//////////////////   Point Target   ////////////////////
+
+// This method returns an S2Cap that bounds the antipode of the target.  (This
+// is the set of points whose S2MaxDistance to the target is
+// S2MaxDistance::Zero().)
+S2Cap S2MaxDistancePointTarget::GetCapBound() {
+  return S2Cap(-point_, S1ChordAngle::Zero());
+}
+
+bool S2MaxDistancePointTarget::UpdateMinDistance(
+    const S2Point& p, S2MaxDistance* min_dist) {
+  return min_dist->UpdateMin(S2MaxDistance(S1ChordAngle(p, point_)));
+}
+
+bool S2MaxDistancePointTarget::UpdateMinDistance(
+    const S2Point& v0, const S2Point& v1, S2MaxDistance* min_dist) {
+  S1ChordAngle dist(*min_dist);
+  if (S2::UpdateMaxDistance(point_, v0, v1, &dist)) {
+    min_dist->UpdateMin(S2MaxDistance(dist));
+    return true;
+  }
+  return false;
+}
+
+bool S2MaxDistancePointTarget::UpdateMinDistance(
+    const S2Cell& cell, S2MaxDistance* min_dist) {
+  return min_dist->UpdateMin(S2MaxDistance(cell.GetMaxDistance(point_)));
+}
+
+bool S2MaxDistancePointTarget::VisitContainingShapes(
+    const S2ShapeIndex& index, const ShapeVisitor& visitor) {
+  // For furthest points, we visit the polygons whose interior contains the
+  // antipode of the target point.  (These are the polygons whose
+  // S2MaxDistance to the target is S2MaxDistance::Zero().)
+  return MakeS2ContainsPointQuery(&index).VisitContainingShapes(
+      -point_, [this, &visitor](S2Shape* shape) {
+        return visitor(shape, point_);
+      });
+}
+
+//////////////////   Edge Target   ////////////////////
+
+// This method returns an S2Cap that bounds the antipode of the target.  (This
+// is the set of points whose S2MaxDistance to the target is
+// S2MaxDistance::Zero().)
+S2Cap S2MaxDistanceEdgeTarget::GetCapBound() {
+  // The following computes a radius equal to half the edge length in an
+  // efficient and numerically stable way.
+  double d2 = S1ChordAngle(a_, b_).length2();
+  double r2 = (0.5 * d2) / (1 + sqrt(1 - 0.25 * d2));
+  return S2Cap(-(a_ + b_).Normalize(), S1ChordAngle::FromLength2(r2));
+}
+
+bool S2MaxDistanceEdgeTarget::UpdateMinDistance(
+    const S2Point& p, S2MaxDistance* min_dist) {
+  S1ChordAngle dist(*min_dist);
+  if (S2::UpdateMaxDistance(p, a_, b_, &dist)) {
+    min_dist->UpdateMin(S2MaxDistance(dist));
+    return true;
+  }
+  return false;
+}
+
+bool S2MaxDistanceEdgeTarget::UpdateMinDistance(
+    const S2Point& v0, const S2Point& v1, S2MaxDistance* min_dist) {
+  S1ChordAngle dist(*min_dist);
+  if (S2::UpdateEdgePairMaxDistance(a_, b_, v0, v1, &dist)) {
+    min_dist->UpdateMin(S2MaxDistance(dist));
+    return true;
+  }
+  return false;
+}
+
+bool S2MaxDistanceEdgeTarget::UpdateMinDistance(
+    const S2Cell& cell, S2MaxDistance* min_dist) {
+  return min_dist->UpdateMin(S2MaxDistance(cell.GetMaxDistance(a_, b_)));
+}
+
+bool S2MaxDistanceEdgeTarget::VisitContainingShapes(
+    const S2ShapeIndex& index, const ShapeVisitor& visitor) {
+  // We only need to test one edge point.  That is because the method *must*
+  // visit a polygon if it fully contains the target, and *is allowed* to
+  // visit a polygon if it intersects the target.  If the tested vertex is not
+  // contained, we know the full edge is not contained; if the tested vertex is
+  // contained, then the edge either is fully contained (must be visited) or it
+  // intersects (is allowed to be visited).  We visit the center of the edge so
+  // that edge AB gives identical results to BA.
+  S2MaxDistancePointTarget target((a_ + b_).Normalize());
+  return target.VisitContainingShapes(index, visitor);
+}
+
+//////////////////   Cell Target   ////////////////////
+
+// This method returns an S2Cap that bounds the antipode of the target.  (This
+// is the set of points whose S2MaxDistance to the target is
+// S2MaxDistance::Zero().)
+S2Cap S2MaxDistanceCellTarget::GetCapBound() {
+  S2Cap cap = cell_.GetCapBound();
+  return S2Cap(-cap.center(), cap.radius());
+}
+
+bool S2MaxDistanceCellTarget::UpdateMinDistance(
+    const S2Point& p, S2MaxDistance* min_dist) {
+  return min_dist->UpdateMin(S2MaxDistance(cell_.GetMaxDistance(p)));
+}
+
+bool S2MaxDistanceCellTarget::UpdateMinDistance(
+    const S2Point& v0, const S2Point& v1, S2MaxDistance* min_dist) {
+  return min_dist->UpdateMin(S2MaxDistance(cell_.GetMaxDistance(v0, v1)));
+}
+
+bool S2MaxDistanceCellTarget::UpdateMinDistance(
+    const S2Cell& cell, S2MaxDistance* min_dist) {
+  return min_dist->UpdateMin(S2MaxDistance(cell_.GetMaxDistance(cell)));
+}
+
+bool S2MaxDistanceCellTarget::VisitContainingShapes(
+    const S2ShapeIndex& index, const ShapeVisitor& visitor) {
+  // We only need to check one point here - cell center is simplest.
+  // See comment at S2MaxDistanceEdgeTarget::VisitContainingShapes.
+  S2MaxDistancePointTarget target(cell_.GetCenter());
+  return target.VisitContainingShapes(index, visitor);
+}
+
+//////////////////   Index Target   ////////////////////
+
+S2MaxDistanceShapeIndexTarget::S2MaxDistanceShapeIndexTarget(
+    const S2ShapeIndex* index)
+    : index_(index), query_(absl::make_unique<S2FurthestEdgeQuery>(index)) {
+}
+
+S2MaxDistanceShapeIndexTarget::~S2MaxDistanceShapeIndexTarget() {
+}
+
+bool S2MaxDistanceShapeIndexTarget::include_interiors() const {
+  return query_->options().include_interiors();
+}
+
+void S2MaxDistanceShapeIndexTarget::set_include_interiors(
+    bool include_interiors) {
+  query_->mutable_options()->set_include_interiors(include_interiors);
+}
+
+bool S2MaxDistanceShapeIndexTarget::use_brute_force() const {
+  return query_->options().use_brute_force();
+}
+
+void S2MaxDistanceShapeIndexTarget::set_use_brute_force(
+    bool use_brute_force) {
+  query_->mutable_options()->set_use_brute_force(use_brute_force);
+}
+
+bool S2MaxDistanceShapeIndexTarget::set_max_error(
+    const S1ChordAngle& max_error) {
+  query_->mutable_options()->set_max_error(max_error);
+  return true;  // Indicates that we may return suboptimal results.
+}
+
+// This method returns an S2Cap that bounds the antipode of the target.  (This
+// is the set of points whose S2MaxDistance to the target is
+// S2MaxDistance::Zero().)
+S2Cap S2MaxDistanceShapeIndexTarget::GetCapBound() {
+  S2Cap cap = MakeS2ShapeIndexRegion(index_).GetCapBound();
+  return S2Cap(-cap.center(), cap.radius());
+}
+
+bool S2MaxDistanceShapeIndexTarget::UpdateMinDistance(
+    const S2Point& p, S2MaxDistance* min_dist) {
+  query_->mutable_options()->set_min_distance(S1ChordAngle(*min_dist));
+  S2FurthestEdgeQuery::PointTarget target(p);
+  S2FurthestEdgeQuery::Result r = query_->FindFurthestEdge(&target);
+  if (r.shape_id() < 0) {
+    return false;
+  }
+  *min_dist = S2MaxDistance(r.distance());
+  return true;
+}
+
+bool S2MaxDistanceShapeIndexTarget::UpdateMinDistance(
+    const S2Point& v0, const S2Point& v1, S2MaxDistance* min_dist) {
+  query_->mutable_options()->set_min_distance(S1ChordAngle(*min_dist));
+  S2FurthestEdgeQuery::EdgeTarget target(v0, v1);
+  S2FurthestEdgeQuery::Result r = query_->FindFurthestEdge(&target);
+  if (r.shape_id() < 0) return false;
+  *min_dist = S2MaxDistance(r.distance());
+  return true;
+}
+
+bool S2MaxDistanceShapeIndexTarget::UpdateMinDistance(
+    const S2Cell& cell, S2MaxDistance* min_dist) {
+  query_->mutable_options()->set_min_distance(S1ChordAngle(*min_dist));
+  S2FurthestEdgeQuery::CellTarget target(cell);
+  S2FurthestEdgeQuery::Result r = query_->FindFurthestEdge(&target);
+  if (r.shape_id() < 0) return false;
+  *min_dist = S2MaxDistance(r.distance());
+  return true;
+}
+
+// For target types consisting of multiple connected components (such as
+// S2MaxDistanceShapeIndexTarget), this method should return the
+// polygons containing the antipodal reflection of *any* connected
+// component.  (It is sufficient to test containment of one vertex per
+// connected component, since the API allows us to also return any polygon
+// whose boundary has S2MaxDistance::Zero() to the target.)
+bool S2MaxDistanceShapeIndexTarget::VisitContainingShapes(
+    const S2ShapeIndex& query_index, const ShapeVisitor& visitor) {
+  // It is sufficient to find the set of chain starts in the target index
+  // (i.e., one vertex per connected component of edges) that are contained by
+  // the query index, except for one special case to handle full polygons.
+  //
+  // TODO(ericv): Do this by merge-joining the two S2ShapeIndexes, and share
+  // the code with S2BooleanOperation.
+  for (S2Shape* shape : *index_) {
+    if (shape == nullptr) continue;
+    int num_chains = shape->num_chains();
+    // Shapes that don't have any edges require a special case (below).
+    bool tested_point = false;
+    for (int c = 0; c < num_chains; ++c) {
+      S2Shape::Chain chain = shape->chain(c);
+      if (chain.length == 0) continue;
+      tested_point = true;
+      S2MaxDistancePointTarget target(shape->chain_edge(c, 0).v0);
+      if (!target.VisitContainingShapes(query_index, visitor)) {
+        return false;
+      }
+    }
+    if (!tested_point) {
+      // Special case to handle full polygons.
+      S2Shape::ReferencePoint ref = shape->GetReferencePoint();
+      if (!ref.contained) continue;
+      S2MaxDistancePointTarget target(ref.point);
+      if (!target.VisitContainingShapes(query_index, visitor)) {
+        return false;
+      }
+    }
+  }
+  return true;
+}
diff --git a/src/s2/s2max_distance_targets.h b/src/s2/s2max_distance_targets.h
new file mode 100644 (file)
index 0000000..83b926b
--- /dev/null
@@ -0,0 +1,241 @@
+// Copyright Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// This file defines a collection of classes that are useful for computing
+// maximum distances on the sphere.  Their purpose is to allow code to be
+// shared among the various query classes that find remote geometry, such as
+// S2FurthestPointQuery and S2FurthestEdgeQuery.
+
+#ifndef S2_S2MAX_DISTANCE_TARGETS_H_
+#define S2_S2MAX_DISTANCE_TARGETS_H_
+
+#include <memory>
+
+#include "s2/_fp_contract_off.h"
+#include "s2/s1angle.h"
+#include "s2/s1chord_angle.h"
+#include "s2/s2cell.h"
+#include "s2/s2distance_target.h"
+#include "s2/s2edge_distances.h"
+#include "s2/s2shape_index.h"
+
+class S2FurthestEdgeQuery;
+
+// S2MaxDistance is a class that allows maximum distances to be computed using
+// a minimum distance algorithm.  Specifically, S2MaxDistance(x) represents the
+// supplementary distance (Pi - x).  This has the effect of inverting the sort
+// order, i.e.
+//
+//  (S2MaxDistance(x) < S2MaxDistance(y))  <=>  (Pi - x < Pi - y)  <=>  (x > y)
+//
+// All other operations are implemented similarly (using the supplementary
+// distance Pi - x).  For example, S2MaxDistance(x) - S2MaxDistance(y) ==
+// S2MaxDistance(x + y).
+class S2MaxDistance {
+ public:
+  using Delta = S1ChordAngle;
+
+  S2MaxDistance() : distance_() {}
+  explicit S2MaxDistance(S1ChordAngle x) : distance_(x) {}
+  explicit operator S1ChordAngle() const { return distance_; }
+  static S2MaxDistance Zero();
+  static S2MaxDistance Infinity();
+  static S2MaxDistance Negative();
+
+  friend bool operator==(S2MaxDistance x, S2MaxDistance y);
+  friend bool operator<(S2MaxDistance x, S2MaxDistance y);
+
+  friend S2MaxDistance operator-(S2MaxDistance x, S1ChordAngle delta);
+  S1ChordAngle GetChordAngleBound() const;
+
+  // If (dist < *this), updates *this and returns true (used internally).
+  bool UpdateMin(const S2MaxDistance& dist);
+
+ private:
+  S1ChordAngle distance_;
+};
+
+// S2MaxDistanceTarget represents a geometric object to which maximum distances
+// on the sphere are measured.
+//
+// Subtypes are defined below for measuring the distance to a point, an edge,
+// an S2Cell, or an S2ShapeIndex (an arbitrary collection of geometry).
+using S2MaxDistanceTarget = S2DistanceTarget<S2MaxDistance>;
+
+// An S2DistanceTarget subtype for computing the maximum distance to a point.
+class S2MaxDistancePointTarget : public S2MaxDistanceTarget {
+ public:
+  explicit S2MaxDistancePointTarget(const S2Point& point);
+
+  S2Cap GetCapBound() final;
+  bool UpdateMinDistance(const S2Point& p, S2MaxDistance* min_dist) final;
+  bool UpdateMinDistance(const S2Point& v0, const S2Point& v1,
+                         S2MaxDistance* min_dist) final;
+  bool UpdateMinDistance(const S2Cell& cell,
+                         S2MaxDistance* min_dist) final;
+  bool VisitContainingShapes(const S2ShapeIndex& index,
+                             const ShapeVisitor& visitor) final;
+
+ private:
+  S2Point point_;
+};
+
+// An S2DistanceTarget subtype for computing the maximum distance to an edge.
+class S2MaxDistanceEdgeTarget : public S2MaxDistanceTarget {
+ public:
+  explicit S2MaxDistanceEdgeTarget(const S2Point& a, const S2Point& b);
+
+  S2Cap GetCapBound() final;
+  bool UpdateMinDistance(const S2Point& p, S2MaxDistance* min_dist) final;
+  bool UpdateMinDistance(const S2Point& v0, const S2Point& v1,
+                         S2MaxDistance* min_dist) final;
+  bool UpdateMinDistance(const S2Cell& cell,
+                         S2MaxDistance* min_dist) final;
+  bool VisitContainingShapes(const S2ShapeIndex& index,
+                             const ShapeVisitor& visitor) final;
+
+ private:
+  S2Point a_, b_;
+};
+
+// An S2DistanceTarget subtype for computing the maximum distance to an S2Cell
+// (including the interior of the cell).
+class S2MaxDistanceCellTarget : public S2MaxDistanceTarget {
+ public:
+  explicit S2MaxDistanceCellTarget(const S2Cell& cell);
+  S2Cap GetCapBound() final;
+  bool UpdateMinDistance(const S2Point& p, S2MaxDistance* min_dist) final;
+  bool UpdateMinDistance(const S2Point& v0, const S2Point& v1,
+                         S2MaxDistance* min_dist) final;
+  bool UpdateMinDistance(const S2Cell& cell,
+                         S2MaxDistance* min_dist) final;
+  bool VisitContainingShapes(const S2ShapeIndex& index,
+                             const ShapeVisitor& visitor) final;
+
+ private:
+  S2Cell cell_;
+};
+
+// An S2DistanceTarget subtype for computing the maximum distance to an
+// S2ShapeIndex (a collection of points, polylines, and/or polygons).
+//
+// Note that ShapeIndexTarget has its own options:
+//
+//   include_interiors()
+//     - specifies that distances are measured to the boundary and interior
+//       of polygons in the S2ShapeIndex.  (If set to false, distance is
+//       measured to the polygon boundary only.)
+//       DEFAULT: true.
+//
+//   brute_force()
+//     - specifies that the distances should be computed by examining every
+//       edge in the S2ShapeIndex (for testing and debugging purposes).
+//       DEFAULT: false.
+//
+// These options are specified independently of the corresponding
+// S2FurthestEdgeQuery options.  For example, if include_interiors is true for
+// a ShapeIndexTarget but false for the S2FurthestEdgeQuery where the target
+// is used, then distances will be measured from the boundary of one
+// S2ShapeIndex to the boundary and interior of the other.
+//
+class S2MaxDistanceShapeIndexTarget : public S2MaxDistanceTarget {
+ public:
+  explicit S2MaxDistanceShapeIndexTarget(const S2ShapeIndex* index);
+  ~S2MaxDistanceShapeIndexTarget() override;
+
+  // Specifies that distance will be measured to the boundary and interior
+  // of polygons in the S2ShapeIndex rather than to polygon boundaries only.
+  //
+  // DEFAULT: true
+  bool include_interiors() const;
+  void set_include_interiors(bool include_interiors);
+
+  // Specifies that the distances should be computed by examining every edge
+  // in the S2ShapeIndex (for testing and debugging purposes).
+  //
+  // DEFAULT: false
+  bool use_brute_force() const;
+  void set_use_brute_force(bool use_brute_force);
+
+  bool set_max_error(const S1ChordAngle& max_error) override;
+  S2Cap GetCapBound() final;
+  bool UpdateMinDistance(const S2Point& p, S2MaxDistance* min_dist) final;
+  bool UpdateMinDistance(const S2Point& v0, const S2Point& v1,
+                         S2MaxDistance* min_dist) final;
+  bool UpdateMinDistance(const S2Cell& cell,
+                         S2MaxDistance* min_dist) final;
+  bool VisitContainingShapes(const S2ShapeIndex& query_index,
+                             const ShapeVisitor& visitor) final;
+
+ private:
+  const S2ShapeIndex* index_;
+  std::unique_ptr<S2FurthestEdgeQuery> query_;
+};
+
+
+//////////////////   Implementation details follow   ////////////////////
+
+inline S2MaxDistance S2MaxDistance::Zero() {
+  return S2MaxDistance(S1ChordAngle::Straight());
+}
+
+inline S2MaxDistance S2MaxDistance::Infinity() {
+  return S2MaxDistance(S1ChordAngle::Negative());
+}
+
+inline S2MaxDistance S2MaxDistance::Negative() {
+  return S2MaxDistance(S1ChordAngle::Infinity());
+}
+
+inline bool operator==(S2MaxDistance x, S2MaxDistance y) {
+  return x.distance_ == y.distance_;
+}
+
+inline bool operator<(S2MaxDistance x, S2MaxDistance y) {
+  return x.distance_ > y.distance_;
+}
+
+inline S2MaxDistance operator-(S2MaxDistance x, S1ChordAngle delta) {
+  return S2MaxDistance(x.distance_ + delta);
+}
+
+inline S1ChordAngle S2MaxDistance::GetChordAngleBound() const {
+  return S1ChordAngle::Straight() - distance_;
+}
+
+inline bool S2MaxDistance::UpdateMin(const S2MaxDistance& dist) {
+  if (dist < *this) {
+    *this = dist;
+    return true;
+  }
+  return false;
+}
+
+inline S2MaxDistancePointTarget::S2MaxDistancePointTarget(const S2Point& point)
+    : point_(point) {
+}
+
+inline S2MaxDistanceEdgeTarget::S2MaxDistanceEdgeTarget(const S2Point& a,
+                                                        const S2Point& b)
+    : a_(a), b_(b) {
+  a_.Normalize();
+  b_.Normalize();
+}
+
+inline S2MaxDistanceCellTarget::S2MaxDistanceCellTarget(const S2Cell& cell)
+    : cell_(cell) {
+}
+
+#endif  // S2_S2MAX_DISTANCE_TARGETS_H_
diff --git a/src/s2/s2measures.cc b/src/s2/s2measures.cc
new file mode 100644 (file)
index 0000000..0f9d3ff
--- /dev/null
@@ -0,0 +1,128 @@
+// Copyright 2005 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// Author: ericv@google.com (Eric Veach)
+
+#include "s2/s2measures.h"
+
+#include <algorithm>
+#include <cmath>
+
+#include "s2/s2pointutil.h"
+#include "s2/s2predicates.h"
+
+// TODO(ericv): Convert to using s2pred::Sign().
+//#include "util/geometry/s2predicates.h"
+
+using std::atan;
+using std::max;
+using std::sqrt;
+using std::tan;
+
+namespace S2 {
+
+double Angle(const S2Point& a, const S2Point& b, const S2Point& c) {
+  // RobustCrossProd() is necessary to get good accuracy when two of the input
+  // points are very close together.
+  return RobustCrossProd(a, b).Angle(RobustCrossProd(c, b));
+}
+
+double TurnAngle(const S2Point& a, const S2Point& b, const S2Point& c) {
+  // We use RobustCrossProd() to get good accuracy when two points are very
+  // close together, and Sign() to ensure that the sign is correct for
+  // turns that are close to 180 degrees.
+  //
+  // Unfortunately we can't save RobustCrossProd(a, b) and pass it as the
+  // optional 4th argument to Sign(), because Sign() requires a.CrossProd(b)
+  // exactly (the robust version differs in magnitude).
+  double angle = RobustCrossProd(a, b).Angle(RobustCrossProd(b, c));
+
+  // Don't return Sign() * angle because it is legal to have (a == c).
+  return (s2pred::Sign(a, b, c) > 0) ? angle : -angle;
+}
+
+double Area(const S2Point& a, const S2Point& b, const S2Point& c) {
+  S2_DCHECK(IsUnitLength(a));
+  S2_DCHECK(IsUnitLength(b));
+  S2_DCHECK(IsUnitLength(c));
+  // This method is based on l'Huilier's theorem,
+  //
+  //   tan(E/4) = sqrt(tan(s/2) tan((s-a)/2) tan((s-b)/2) tan((s-c)/2))
+  //
+  // where E is the spherical excess of the triangle (i.e. its area),
+  //       a, b, c, are the side lengths, and
+  //       s is the semiperimeter (a + b + c) / 2 .
+  //
+  // The only significant source of error using l'Huilier's method is the
+  // cancellation error of the terms (s-a), (s-b), (s-c).  This leads to a
+  // *relative* error of about 1e-16 * s / min(s-a, s-b, s-c).  This compares
+  // to a relative error of about 1e-15 / E using Girard's formula, where E is
+  // the true area of the triangle.  Girard's formula can be even worse than
+  // this for very small triangles, e.g. a triangle with a true area of 1e-30
+  // might evaluate to 1e-5.
+  //
+  // So, we prefer l'Huilier's formula unless dmin < s * (0.1 * E), where
+  // dmin = min(s-a, s-b, s-c).  This basically includes all triangles
+  // except for extremely long and skinny ones.
+  //
+  // Since we don't know E, we would like a conservative upper bound on
+  // the triangle area in terms of s and dmin.  It's possible to show that
+  // E <= k1 * s * sqrt(s * dmin), where k1 = 2*sqrt(3)/Pi (about 1).
+  // Using this, it's easy to show that we should always use l'Huilier's
+  // method if dmin >= k2 * s^5, where k2 is about 1e-2.  Furthermore,
+  // if dmin < k2 * s^5, the triangle area is at most k3 * s^4, where
+  // k3 is about 0.1.  Since the best case error using Girard's formula
+  // is about 1e-15, this means that we shouldn't even consider it unless
+  // s >= 3e-4 or so.
+  //
+  // TODO(ericv): Implement rigorous error bounds (analysis already done).
+  double sa = b.Angle(c);
+  double sb = c.Angle(a);
+  double sc = a.Angle(b);
+  double s = 0.5 * (sa + sb + sc);
+  if (s >= 3e-4) {
+    // Consider whether Girard's formula might be more accurate.
+    double s2 = s * s;
+    double dmin = s - max(sa, max(sb, sc));
+    if (dmin < 1e-2 * s * s2 * s2) {
+      // This triangle is skinny enough to consider using Girard's formula.
+      // We increase the area by the approximate maximum error in the Girard
+      // calculation in order to ensure that this test is conservative.
+      double area = GirardArea(a, b, c);
+      if (dmin < s * (0.1 * (area + 5e-15))) return area;
+    }
+  }
+  // Use l'Huilier's formula.
+  return 4 * atan(sqrt(max(0.0, tan(0.5 * s) * tan(0.5 * (s - sa)) *
+                           tan(0.5 * (s - sb)) * tan(0.5 * (s - sc)))));
+}
+
+double GirardArea(const S2Point& a, const S2Point& b, const S2Point& c) {
+  // This is equivalent to the usual Girard's formula but is slightly more
+  // accurate, faster to compute, and handles a == b == c without a special
+  // case.  RobustCrossProd() is necessary to get good accuracy when two of
+  // the input points are very close together.
+
+  Vector3_d ab = RobustCrossProd(a, b);
+  Vector3_d bc = RobustCrossProd(b, c);
+  Vector3_d ac = RobustCrossProd(a, c);
+  return max(0.0, ab.Angle(ac) - ab.Angle(bc) + bc.Angle(ac));
+}
+
+double SignedArea(const S2Point& a, const S2Point& b, const S2Point& c) {
+  return s2pred::Sign(a, b, c) * Area(a, b, c);
+}
+
+}  // namespace S2
diff --git a/src/s2/s2measures.h b/src/s2/s2measures.h
new file mode 100644 (file)
index 0000000..3b889a4
--- /dev/null
@@ -0,0 +1,78 @@
+// Copyright 2005 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// Author: ericv@google.com (Eric Veach)
+//
+// Defines various angle and area measures on the sphere.  Also see
+// s2edge_distances.h, s2loop_measures.h, and s2polyline_measures.h.
+
+#ifndef S2_S2MEASURES_H_
+#define S2_S2MEASURES_H_
+
+#include "s2/s2point.h"
+
+namespace S2 {
+
+// Return the interior angle at the vertex B in the triangle ABC.  The
+// return value is always in the range [0, Pi].  All points should be
+// normalized.  Ensures that Angle(a,b,c) == Angle(c,b,a) for all a,b,c.
+//
+// The angle is undefined if A or C is diametrically opposite from B, and
+// becomes numerically unstable as the length of edge AB or BC approaches
+// 180 degrees.
+double Angle(const S2Point& a, const S2Point& b, const S2Point& c);
+
+// Return the exterior angle at vertex B in the triangle ABC.  The return
+// value is positive if ABC is counterclockwise and negative otherwise.  If
+// you imagine an ant walking from A to B to C, this is the angle that the
+// ant turns at vertex B (positive = left = CCW, negative = right = CW).
+// This quantity is also known as the "geodesic curvature" at B.
+//
+// Ensures that TurnAngle(a,b,c) == -TurnAngle(c,b,a) for all distinct
+// a,b,c. The result is undefined if (a == b || b == c), but is either
+// -Pi or Pi if (a == c).  All points should be normalized.
+double TurnAngle(const S2Point& a, const S2Point& b, const S2Point& c);
+
+// Return the area of triangle ABC.  This method combines two different
+// algorithms to get accurate results for both large and small triangles.
+// The maximum error is about 5e-15 (about 0.25 square meters on the Earth's
+// surface), the same as GirardArea() below, but unlike that method it is
+// also accurate for small triangles.  Example: when the true area is 100
+// square meters, Area() yields an error about 1 trillion times smaller than
+// GirardArea().
+//
+// All points should be unit length, and no two points should be antipodal.
+// The area is always positive.
+double Area(const S2Point& a, const S2Point& b, const S2Point& c);
+
+// Return the area of the triangle computed using Girard's formula.  All
+// points should be unit length, and no two points should be antipodal.
+//
+// This method is about twice as fast as Area() but has poor relative
+// accuracy for small triangles.  The maximum error is about 5e-15 (about
+// 0.25 square meters on the Earth's surface) and the average error is about
+// 1e-15.  These bounds apply to triangles of any size, even as the maximum
+// edge length of the triangle approaches 180 degrees.  But note that for
+// such triangles, tiny perturbations of the input points can change the
+// true mathematical area dramatically.
+double GirardArea(const S2Point& a, const S2Point& b, const S2Point& c);
+
+// Like Area(), but returns a positive value for counterclockwise triangles
+// and a negative value otherwise.
+double SignedArea(const S2Point& a, const S2Point& b, const S2Point& c);
+
+}  // namespace S2
+
+#endif  // S2_S2MEASURES_H_
diff --git a/src/s2/s2metrics.cc b/src/s2/s2metrics.cc
new file mode 100644 (file)
index 0000000..e9cb1cb
--- /dev/null
@@ -0,0 +1,122 @@
+// Copyright 2005 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// Author: ericv@google.com (Eric Veach)
+//
+// All of the values below were obtained by a combination of hand analysis and
+// Mathematica.  In general, S2_TAN_PROJECTION produces the most uniform
+// shapes and sizes of cells, S2_LINEAR_PROJECTION is considerably worse, and
+// S2_QUADRATIC_PROJECTION is somewhere in between (but generally closer to
+// the tangent projection than the linear one).
+//
+// Note that S2_LINEAR_PROJECTION can be useful for analysis even when another
+// projection is being used, since it allows many cell metrics to be bounded
+// in terms of (u,v) coordinates rather than (s,t) coordinates.  (With the
+// linear projection, u = 2 * s - 1 and similarly for v.)  Similarly,
+// S2_TAN_PROJECTION allows cell metrics to be bounded in terms of (u,v)
+// coordinate changes when they are measured as distances on the unit sphere.
+
+#include "s2/s2metrics.h"
+
+namespace S2 {
+
+const LengthMetric kMinAngleSpan(
+    S2_PROJECTION == S2_LINEAR_PROJECTION ? 1.0 :                      // 1.000
+    S2_PROJECTION == S2_TAN_PROJECTION ? M_PI / 2 :                    // 1.571
+    S2_PROJECTION == S2_QUADRATIC_PROJECTION ? 4. / 3 :                // 1.333
+    0);
+
+const LengthMetric kMaxAngleSpan(
+    S2_PROJECTION == S2_LINEAR_PROJECTION ? 2 :                        // 2.000
+    S2_PROJECTION == S2_TAN_PROJECTION ? M_PI / 2 :                    // 1.571
+    S2_PROJECTION == S2_QUADRATIC_PROJECTION ? 1.704897179199218452 :  // 1.705
+    0);
+
+const LengthMetric kAvgAngleSpan(M_PI / 2);                    // 1.571
+// This is true for all projections.
+
+const LengthMetric kMinWidth(
+    S2_PROJECTION == S2_LINEAR_PROJECTION ? sqrt(2.0 / 3.0) :             // 0.816
+    S2_PROJECTION == S2_TAN_PROJECTION ? M_PI / (2 * sqrt(2.0)) :        // 1.111
+    S2_PROJECTION == S2_QUADRATIC_PROJECTION ? 2 * sqrt(2.0) / 3 :       // 0.943
+    0);
+
+const LengthMetric kMaxWidth(kMaxAngleSpan.deriv());
+// This is true for all projections.
+
+const LengthMetric kAvgWidth(
+    S2_PROJECTION == S2_LINEAR_PROJECTION ? 1.411459345844456965 :     // 1.411
+    S2_PROJECTION == S2_TAN_PROJECTION ? 1.437318638925160885 :        // 1.437
+    S2_PROJECTION == S2_QUADRATIC_PROJECTION ? 1.434523672886099389 :  // 1.435
+    0);
+
+const LengthMetric kMinEdge(
+    S2_PROJECTION == S2_LINEAR_PROJECTION ? 2 * sqrt(2.0) / 3 :          // 0.943
+    S2_PROJECTION == S2_TAN_PROJECTION ? M_PI / (2 * sqrt(2.0)) :        // 1.111
+    S2_PROJECTION == S2_QUADRATIC_PROJECTION ? 2 * sqrt(2.0) / 3 :       // 0.943
+    0);
+
+const LengthMetric kMaxEdge(kMaxAngleSpan.deriv());
+// This is true for all projections.
+
+const LengthMetric kAvgEdge(
+    S2_PROJECTION == S2_LINEAR_PROJECTION ? 1.440034192955603643 :     // 1.440
+    S2_PROJECTION == S2_TAN_PROJECTION ? 1.461667032546739266 :        // 1.462
+    S2_PROJECTION == S2_QUADRATIC_PROJECTION ? 1.459213746386106062 :  // 1.459
+    0);
+
+const LengthMetric kMinDiag(
+    S2_PROJECTION == S2_LINEAR_PROJECTION ? 2 * sqrt(2.0) / 3 :          // 0.943
+    S2_PROJECTION == S2_TAN_PROJECTION ? M_PI * sqrt(2.0) / 3 :          // 1.481
+    S2_PROJECTION == S2_QUADRATIC_PROJECTION ? 8 * sqrt(2.0) / 9 :       // 1.257
+    0);
+
+const LengthMetric kMaxDiag(
+    S2_PROJECTION == S2_LINEAR_PROJECTION ? 2 * sqrt(2.0) :              // 2.828
+    S2_PROJECTION == S2_TAN_PROJECTION ? M_PI * sqrt(2.0 / 3.0) :         // 2.565
+    S2_PROJECTION == S2_QUADRATIC_PROJECTION ? 2.438654594434021032 :  // 2.439
+    0);
+
+const LengthMetric kAvgDiag(
+    S2_PROJECTION == S2_LINEAR_PROJECTION ? 2.031817866418812674 :     // 2.032
+    S2_PROJECTION == S2_TAN_PROJECTION ? 2.063623197195635753 :        // 2.064
+    S2_PROJECTION == S2_QUADRATIC_PROJECTION ? 2.060422738998471683 :  // 2.060
+    0);
+
+const AreaMetric kMinArea(
+    S2_PROJECTION == S2_LINEAR_PROJECTION ? 4 / (3 * sqrt(3.0)) :        // 0.770
+    S2_PROJECTION == S2_TAN_PROJECTION ? (M_PI*M_PI) / (4*sqrt(2.0)) :   // 1.745
+    S2_PROJECTION == S2_QUADRATIC_PROJECTION ? 8 * sqrt(2.0) / 9 :       // 1.257
+    0);
+
+const AreaMetric kMaxArea(
+    S2_PROJECTION == S2_LINEAR_PROJECTION ? 4 :                        // 4.000
+    S2_PROJECTION == S2_TAN_PROJECTION ? M_PI * M_PI / 4 :             // 2.467
+    S2_PROJECTION == S2_QUADRATIC_PROJECTION ? 2.635799256963161491 :  // 2.636
+    0);
+
+const AreaMetric kAvgArea(4 * M_PI / 6);                       // 2.094
+// This is true for all projections.
+
+const double kMaxEdgeAspect = (
+    S2_PROJECTION == S2_LINEAR_PROJECTION ? sqrt(2.0) :                  // 1.414
+    S2_PROJECTION == S2_TAN_PROJECTION ?  sqrt(2.0) :                    // 1.414
+    S2_PROJECTION == S2_QUADRATIC_PROJECTION ? 1.442615274452682920 :  // 1.443
+    0);
+
+const double kMaxDiagAspect = sqrt(3.0);                             // 1.732
+// This is true for all projections.
+
+}  // namespace S2
diff --git a/src/s2/s2metrics.h b/src/s2/s2metrics.h
new file mode 100644 (file)
index 0000000..a9441f8
--- /dev/null
@@ -0,0 +1,199 @@
+// Copyright 2005 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// Author: ericv@google.com (Eric Veach)
+//
+// The following are various constants that describe the shapes and sizes of
+// S2Cells (see s2coords.h and s2cell_id.h).  They are useful for deciding
+// which cell level to use in order to satisfy a given condition (e.g. that
+// cell vertices must be no further than "x" apart).  All of the raw constants
+// are differential quantities; you can use the GetValue(level) method to
+// compute the corresponding length or area on the unit sphere for cells at a
+// given level.  The minimum and maximum bounds are valid for cells at all
+// levels, but they may be somewhat conservative for very large cells
+// (e.g. face cells).
+
+#ifndef S2_S2METRICS_H_
+#define S2_S2METRICS_H_
+
+#include <algorithm>
+#include <cmath>
+
+#include "s2/s2coords.h"
+#include "s2/util/math/mathutil.h"
+
+namespace S2 {
+
+// Defines a cell metric of the given dimension (1 == length, 2 == area).
+template <int dim> class Metric {
+ public:
+  explicit constexpr Metric(double deriv) : deriv_(deriv) {}
+
+  // The "deriv" value of a metric is a derivative, and must be multiplied by
+  // a length or area in (s,t)-space to get a useful value.
+  double deriv() const { return deriv_; }
+
+  // Return the value of a metric for cells at the given level. The value is
+  // either a length or an area on the unit sphere, depending on the
+  // particular metric.
+  double GetValue(int level) const { return ldexp(deriv_, - dim * level); }
+
+  // Return the level at which the metric has approximately the given
+  // value.  For example, S2::kAvgEdge.GetClosestLevel(0.1) returns the
+  // level at which the average cell edge length is approximately 0.1.
+  // The return value is always a valid level.
+  int GetClosestLevel(double value) const;
+
+  // Return the minimum level such that the metric is at most the given
+  // value, or S2CellId::kMaxLevel if there is no such level.  For example,
+  // S2::kMaxDiag.GetLevelForMaxValue(0.1) returns the minimum level such
+  // that all cell diagonal lengths are 0.1 or smaller.  The return value
+  // is always a valid level.
+  int GetLevelForMaxValue(double value) const;
+
+  // Return the maximum level such that the metric is at least the given
+  // value, or zero if there is no such level.  For example,
+  // S2::kMinWidth.GetLevelForMinValue(0.1) returns the maximum level such
+  // that all cells have a minimum width of 0.1 or larger.  The return value
+  // is always a valid level.
+  int GetLevelForMinValue(double value) const;
+
+ private:
+  const double deriv_;
+
+  Metric(const Metric&) = delete;
+  void operator=(const Metric&) = delete;
+};
+using LengthMetric = Metric<1>;
+using AreaMetric = Metric<2>;
+
+// Each cell is bounded by four planes passing through its four edges and
+// the center of the sphere.  These metrics relate to the angle between each
+// pair of opposite bounding planes, or equivalently, between the planes
+// corresponding to two different s-values or two different t-values.  For
+// example, the maximum angle between opposite bounding planes for a cell at
+// level k is kMaxAngleSpan.GetValue(k), and the average angle span for all
+// cells at level k is approximately kAvgAngleSpan.GetValue(k).
+extern const LengthMetric kMinAngleSpan;
+extern const LengthMetric kMaxAngleSpan;
+extern const LengthMetric kAvgAngleSpan;
+
+// The width of geometric figure is defined as the distance between two
+// parallel bounding lines in a given direction.  For cells, the minimum
+// width is always attained between two opposite edges, and the maximum
+// width is attained between two opposite vertices.  However, for our
+// purposes we redefine the width of a cell as the perpendicular distance
+// between a pair of opposite edges.  A cell therefore has two widths, one
+// in each direction.  The minimum width according to this definition agrees
+// with the classic geometric one, but the maximum width is different.  (The
+// maximum geometric width corresponds to kMaxDiag defined below.)
+//
+// For a cell at level k, the distance between opposite edges is at least
+// kMinWidth.GetValue(k) and at most kMaxWidth.GetValue(k).  The average
+// width in both directions for all cells at level k is approximately
+// kAvgWidth.GetValue(k).
+//
+// The width is useful for bounding the minimum or maximum distance from a
+// point on one edge of a cell to the closest point on the opposite edge.
+// For example, this is useful when "growing" regions by a fixed distance.
+//
+// Note that because S2Cells are not usually rectangles, the minimum width of
+// a cell is generally smaller than its minimum edge length.  (The interior
+// angles of an S2Cell range from 60 to 120 degrees.)
+extern const LengthMetric kMinWidth;
+extern const LengthMetric kMaxWidth;
+extern const LengthMetric kAvgWidth;
+
+// The minimum edge length of any cell at level k is at least
+// kMinEdge.GetValue(k), and the maximum is at most kMaxEdge.GetValue(k).
+// The average edge length is approximately kAvgEdge.GetValue(k).
+//
+// The edge length metrics can also be used to bound the minimum, maximum,
+// or average distance from the center of one cell to the center of one of
+// its edge neighbors.  In particular, it can be used to bound the distance
+// between adjacent cell centers along the space-filling Hilbert curve for
+// cells at any given level.
+extern const LengthMetric kMinEdge;
+extern const LengthMetric kMaxEdge;
+extern const LengthMetric kAvgEdge;
+
+// The minimum diagonal length of any cell at level k is at least
+// kMinDiag.GetValue(k), and the maximum is at most kMaxDiag.GetValue(k).
+// The average diagonal length is approximately kAvgDiag.GetValue(k).
+//
+// The maximum diagonal also happens to be the maximum diameter of any cell,
+// and also the maximum geometric width (see the discussion above).  So for
+// example, the distance from an arbitrary point to the closest cell center
+// at a given level is at most half the maximum diagonal length.
+extern const LengthMetric kMinDiag;
+extern const LengthMetric kMaxDiag;
+extern const LengthMetric kAvgDiag;
+
+// The minimum area of any cell at level k is at least kMinArea.GetValue(k),
+// and the maximum is at most kMaxArea.GetValue(k).  The average area of all
+// cells at level k is exactly kAvgArea.GetValue(k).
+extern const AreaMetric kMinArea;
+extern const AreaMetric kMaxArea;
+extern const AreaMetric kAvgArea;
+
+// This is the maximum edge aspect ratio over all cells at any level, where
+// the edge aspect ratio of a cell is defined as the ratio of its longest
+// edge length to its shortest edge length.
+extern const double kMaxEdgeAspect;
+
+// This is the maximum diagonal aspect ratio over all cells at any level,
+// where the diagonal aspect ratio of a cell is defined as the ratio of its
+// longest diagonal length to its shortest diagonal length.
+extern const double kMaxDiagAspect;
+
+
+//////////////////   Implementation details follow   ////////////////////
+
+
+template <int dim>
+int S2::Metric<dim>::GetLevelForMaxValue(double value) const {
+  if (value <= 0) return S2::kMaxCellLevel;
+
+  // This code is equivalent to computing a floating-point "level"
+  // value and rounding up.  ilogb() returns the exponent corresponding to a
+  // fraction in the range [1,2).
+  int level = ilogb(value / deriv_);
+  level = std::max(0, std::min(S2::kMaxCellLevel, -(level >> (dim - 1))));
+  S2_DCHECK(level == S2::kMaxCellLevel || GetValue(level) <= value);
+  S2_DCHECK(level == 0 || GetValue(level - 1) > value);
+  return level;
+}
+
+template <int dim>
+int S2::Metric<dim>::GetLevelForMinValue(double value) const {
+  if (value <= 0) return S2::kMaxCellLevel;
+
+  // This code is equivalent to computing a floating-point "level"
+  // value and rounding down.
+  int level = ilogb(deriv_ / value);
+  level = std::max(0, std::min(S2::kMaxCellLevel, level >> (dim - 1)));
+  S2_DCHECK(level == 0 || GetValue(level) >= value);
+  S2_DCHECK(level == kMaxCellLevel || GetValue(level + 1) < value);
+  return level;
+}
+
+template <int dim>
+int Metric<dim>::GetClosestLevel(double value) const {
+  return GetLevelForMaxValue((dim == 1 ? M_SQRT2 : 2) * value);
+}
+
+}  // namespace S2
+
+#endif  // S2_S2METRICS_H_
diff --git a/src/s2/s2min_distance_targets.cc b/src/s2/s2min_distance_targets.cc
new file mode 100644 (file)
index 0000000..344a681
--- /dev/null
@@ -0,0 +1,295 @@
+// Copyright 2013 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// Author: ericv@google.com (Eric Veach)
+
+#include "s2/s2min_distance_targets.h"
+
+#include <memory>
+#include "absl/memory/memory.h"
+#include "s2/s1angle.h"
+#include "s2/s2cap.h"
+#include "s2/s2cell.h"
+#include "s2/s2closest_cell_query.h"
+#include "s2/s2closest_edge_query.h"
+#include "s2/s2edge_distances.h"
+#include "s2/s2shape_index_region.h"
+
+S2Cap S2MinDistancePointTarget::GetCapBound() {
+  return S2Cap(point_, S1ChordAngle::Zero());
+}
+
+bool S2MinDistancePointTarget::UpdateMinDistance(
+    const S2Point& p, S2MinDistance* min_dist) {
+  return min_dist->UpdateMin(S2MinDistance(S1ChordAngle(p, point_)));
+}
+
+bool S2MinDistancePointTarget::UpdateMinDistance(
+    const S2Point& v0, const S2Point& v1, S2MinDistance* min_dist) {
+  return S2::UpdateMinDistance(point_, v0, v1, min_dist);
+}
+
+bool S2MinDistancePointTarget::UpdateMinDistance(
+    const S2Cell& cell, S2MinDistance* min_dist) {
+  return min_dist->UpdateMin(S2MinDistance(cell.GetDistance(point_)));
+}
+
+bool S2MinDistancePointTarget::VisitContainingShapes(
+    const S2ShapeIndex& index, const ShapeVisitor& visitor) {
+  return MakeS2ContainsPointQuery(&index).VisitContainingShapes(
+      point_, [this, &visitor](S2Shape* shape) {
+        return visitor(shape, point_);
+      });
+}
+
+S2Cap S2MinDistanceEdgeTarget::GetCapBound() {
+  // The following computes a radius equal to half the edge length in an
+  // efficient and numerically stable way.
+  double d2 = S1ChordAngle(a_, b_).length2();
+  double r2 = (0.5 * d2) / (1 + sqrt(1 - 0.25 * d2));
+  return S2Cap((a_ + b_).Normalize(), S1ChordAngle::FromLength2(r2));
+}
+
+bool S2MinDistanceEdgeTarget::UpdateMinDistance(
+    const S2Point& p, S2MinDistance* min_dist) {
+  return S2::UpdateMinDistance(p, a_, b_, min_dist);
+}
+
+bool S2MinDistanceEdgeTarget::UpdateMinDistance(
+    const S2Point& v0, const S2Point& v1, S2MinDistance* min_dist) {
+  return S2::UpdateEdgePairMinDistance(a_, b_, v0, v1, min_dist);
+}
+
+bool S2MinDistanceEdgeTarget::UpdateMinDistance(
+    const S2Cell& cell, S2MinDistance* min_dist) {
+  return min_dist->UpdateMin(S2MinDistance(cell.GetDistance(a_, b_)));
+}
+
+bool S2MinDistanceEdgeTarget::VisitContainingShapes(
+    const S2ShapeIndex& index, const ShapeVisitor& visitor) {
+  // We test the center of the edge in order to ensure that edge targets AB
+  // and BA yield identical results (which is not guaranteed by the API but
+  // users might expect).  Other options would be to test both endpoints, or
+  // return different results for AB and BA in some cases.
+  S2MinDistancePointTarget target((a_ + b_).Normalize());
+  return target.VisitContainingShapes(index, visitor);
+}
+
+S2MinDistanceCellTarget::S2MinDistanceCellTarget(const S2Cell& cell)
+    : cell_(cell) {
+}
+
+S2Cap S2MinDistanceCellTarget::GetCapBound() {
+  return cell_.GetCapBound();
+}
+
+bool S2MinDistanceCellTarget::UpdateMinDistance(const S2Point& p,
+                                                S2MinDistance* min_dist) {
+  return min_dist->UpdateMin(S2MinDistance(cell_.GetDistance(p)));
+}
+
+bool S2MinDistanceCellTarget::UpdateMinDistance(
+    const S2Point& v0, const S2Point& v1, S2MinDistance* min_dist) {
+  return min_dist->UpdateMin(S2MinDistance(cell_.GetDistance(v0, v1)));
+}
+
+bool S2MinDistanceCellTarget::UpdateMinDistance(
+    const S2Cell& cell, S2MinDistance* min_dist) {
+  return min_dist->UpdateMin(S2MinDistance(cell_.GetDistance(cell)));
+}
+
+bool S2MinDistanceCellTarget::VisitContainingShapes(
+    const S2ShapeIndex& index, const ShapeVisitor& visitor) {
+  // The simplest approach is simply to return the polygons that contain the
+  // cell center.  Alternatively, if the index cell is smaller than the target
+  // cell then we could return all polygons that are present in the
+  // S2ShapeIndexCell, but since the index is built conservatively this may
+  // include some polygons that don't quite intersect the cell.  So we would
+  // either need to recheck for intersection more accurately, or weaken the
+  // VisitContainingShapes contract so that it only guarantees approximate
+  // intersection, neither of which seems like a good tradeoff.
+  S2MinDistancePointTarget target(cell_.GetCenter());
+  return target.VisitContainingShapes(index, visitor);
+}
+
+S2MinDistanceCellUnionTarget::S2MinDistanceCellUnionTarget(
+    S2CellUnion cell_union)
+    : cell_union_(std::move(cell_union)),
+      query_(absl::make_unique<S2ClosestCellQuery>(&index_)) {
+  for (S2CellId cell_id : cell_union_) {
+    index_.Add(cell_id, 0);
+  }
+  index_.Build();
+}
+
+S2MinDistanceCellUnionTarget::~S2MinDistanceCellUnionTarget() {
+}
+
+bool S2MinDistanceCellUnionTarget::use_brute_force() const {
+  return query_->options().use_brute_force();
+}
+
+void S2MinDistanceCellUnionTarget::set_use_brute_force(
+    bool use_brute_force) {
+  query_->mutable_options()->set_use_brute_force(use_brute_force);
+}
+
+bool S2MinDistanceCellUnionTarget::set_max_error(
+    const S1ChordAngle& max_error) {
+  query_->mutable_options()->set_max_error(max_error);
+  return true;  // Indicates that we may return suboptimal results.
+}
+
+S2Cap S2MinDistanceCellUnionTarget::GetCapBound() {
+  return cell_union_.GetCapBound();
+}
+
+inline bool S2MinDistanceCellUnionTarget::UpdateMinDistance(
+    S2MinDistanceTarget* target, S2MinDistance* min_dist) {
+  query_->mutable_options()->set_max_distance(*min_dist);
+  S2ClosestCellQuery::Result r = query_->FindClosestCell(target);
+  if (r.is_empty()) return false;
+  *min_dist = r.distance();
+  return true;
+}
+
+bool S2MinDistanceCellUnionTarget::UpdateMinDistance(
+    const S2Point& p, S2MinDistance* min_dist) {
+  S2ClosestCellQuery::PointTarget target(p);
+  return UpdateMinDistance(&target, min_dist);
+}
+
+bool S2MinDistanceCellUnionTarget::UpdateMinDistance(
+    const S2Point& v0, const S2Point& v1, S2MinDistance* min_dist) {
+  S2ClosestCellQuery::EdgeTarget target(v0, v1);
+  return UpdateMinDistance(&target, min_dist);
+}
+
+bool S2MinDistanceCellUnionTarget::UpdateMinDistance(
+    const S2Cell& cell, S2MinDistance* min_dist) {
+  S2ClosestCellQuery::CellTarget target(cell);
+  return UpdateMinDistance(&target, min_dist);
+}
+
+bool S2MinDistanceCellUnionTarget::VisitContainingShapes(
+    const S2ShapeIndex& query_index, const ShapeVisitor& visitor) {
+  for (S2CellId cell_id : cell_union_) {
+    S2MinDistancePointTarget target(cell_id.ToPoint());
+    if (!target.VisitContainingShapes(query_index, visitor)) {
+      return false;
+    }
+  }
+  return true;
+}
+
+S2MinDistanceShapeIndexTarget::S2MinDistanceShapeIndexTarget(
+    const S2ShapeIndex* index)
+    : index_(index), query_(absl::make_unique<S2ClosestEdgeQuery>(index)) {
+}
+
+S2MinDistanceShapeIndexTarget::~S2MinDistanceShapeIndexTarget() {
+}
+
+bool S2MinDistanceShapeIndexTarget::include_interiors() const {
+  return query_->options().include_interiors();
+}
+
+void S2MinDistanceShapeIndexTarget::set_include_interiors(
+    bool include_interiors) {
+  query_->mutable_options()->set_include_interiors(include_interiors);
+}
+
+bool S2MinDistanceShapeIndexTarget::use_brute_force() const {
+  return query_->options().use_brute_force();
+}
+
+void S2MinDistanceShapeIndexTarget::set_use_brute_force(
+    bool use_brute_force) {
+  query_->mutable_options()->set_use_brute_force(use_brute_force);
+}
+
+bool S2MinDistanceShapeIndexTarget::set_max_error(
+    const S1ChordAngle& max_error) {
+  query_->mutable_options()->set_max_error(max_error);
+  return true;  // Indicates that we may return suboptimal results.
+}
+
+S2Cap S2MinDistanceShapeIndexTarget::GetCapBound() {
+  return MakeS2ShapeIndexRegion(index_).GetCapBound();
+}
+
+inline bool S2MinDistanceShapeIndexTarget::UpdateMinDistance(
+    S2MinDistanceTarget* target, S2MinDistance* min_dist) {
+  query_->mutable_options()->set_max_distance(*min_dist);
+  S2ClosestEdgeQuery::Result r = query_->FindClosestEdge(target);
+  if (r.is_empty()) return false;
+  *min_dist = r.distance();
+  return true;
+}
+
+bool S2MinDistanceShapeIndexTarget::UpdateMinDistance(
+    const S2Point& p, S2MinDistance* min_dist) {
+  S2ClosestEdgeQuery::PointTarget target(p);
+  return UpdateMinDistance(&target, min_dist);
+}
+
+bool S2MinDistanceShapeIndexTarget::UpdateMinDistance(
+    const S2Point& v0, const S2Point& v1, S2MinDistance* min_dist) {
+  S2ClosestEdgeQuery::EdgeTarget target(v0, v1);
+  return UpdateMinDistance(&target, min_dist);
+}
+
+bool S2MinDistanceShapeIndexTarget::UpdateMinDistance(
+    const S2Cell& cell, S2MinDistance* min_dist) {
+  S2ClosestEdgeQuery::CellTarget target(cell);
+  return UpdateMinDistance(&target, min_dist);
+}
+
+bool S2MinDistanceShapeIndexTarget::VisitContainingShapes(
+    const S2ShapeIndex& query_index, const ShapeVisitor& visitor) {
+  // It is sufficient to find the set of chain starts in the target index
+  // (i.e., one vertex per connected component of edges) that are contained by
+  // the query index, except for one special case to handle full polygons.
+  //
+  // TODO(ericv): Do this by merge-joining the two S2ShapeIndexes, and share
+  // the code with S2BooleanOperation.
+
+  for (S2Shape* shape : *index_) {
+    if (shape == nullptr) continue;
+    int num_chains = shape->num_chains();
+    // Shapes that don't have any edges require a special case (below).
+    bool tested_point = false;
+    for (int c = 0; c < num_chains; ++c) {
+      S2Shape::Chain chain = shape->chain(c);
+      if (chain.length == 0) continue;
+      tested_point = true;
+      S2Point v0 = shape->chain_edge(c, 0).v0;
+      S2MinDistancePointTarget target(v0);
+      if (!target.VisitContainingShapes(query_index, visitor)) {
+        return false;
+      }
+    }
+    if (!tested_point) {
+      // Special case to handle full polygons.
+      S2Shape::ReferencePoint ref = shape->GetReferencePoint();
+      if (!ref.contained) continue;
+      S2MinDistancePointTarget target(ref.point);
+      if (!target.VisitContainingShapes(query_index, visitor)) {
+        return false;
+      }
+    }
+  }
+  return true;
+}
diff --git a/src/s2/s2min_distance_targets.h b/src/s2/s2min_distance_targets.h
new file mode 100644 (file)
index 0000000..6911c1a
--- /dev/null
@@ -0,0 +1,273 @@
+// Copyright 2017 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// Author: ericv@google.com (Eric Veach)
+//
+// This file defines a collection of classes that are useful for computing
+// minimum distances on the sphere.  Their purpose is to allow code to be
+// shared among the various query classes that find nearby geometry, such as
+// S2ClosestEdgeQuery, S2ClosestPointQuery, and S2ClosestCellQuery.
+
+#ifndef S2_S2MIN_DISTANCE_TARGETS_H_
+#define S2_S2MIN_DISTANCE_TARGETS_H_
+
+#include <memory>
+
+#include "s2/_fp_contract_off.h"
+#include "s2/s1angle.h"
+#include "s2/s1chord_angle.h"
+#include "s2/s2cell.h"
+#include "s2/s2cell_index.h"
+#include "s2/s2distance_target.h"
+#include "s2/s2edge_distances.h"
+#include "s2/s2shape_index.h"
+
+// Forward references because these classes depend on the types defined here.
+class S2ClosestCellQuery;
+class S2ClosestEdgeQuery;
+
+// S2MinDistance is a thin wrapper around S1ChordAngle that is used by classes
+// such as S2ClosestEdgeQuery to compute minimum distances on the sphere (as
+// opposed to maximum distances, ellipsoidal distances, etc).
+//
+// It implements the Distance concept defined by S2DistanceTarget (see
+// s2distance_target.h for details).
+class S2MinDistance : public S1ChordAngle {
+ public:
+  using Delta = S1ChordAngle;
+
+  S2MinDistance() : S1ChordAngle() {}
+  explicit S2MinDistance(S1Angle x) : S1ChordAngle(x) {}
+  explicit S2MinDistance(S1ChordAngle x) : S1ChordAngle(x) {}
+  static S2MinDistance Zero();
+  static S2MinDistance Infinity();
+  static S2MinDistance Negative();
+  friend S2MinDistance operator-(S2MinDistance x, S1ChordAngle delta);
+  S1ChordAngle GetChordAngleBound() const;
+
+  // If (dist < *this), updates *this and returns true (used internally).
+  bool UpdateMin(const S2MinDistance& dist);
+};
+
+// S2MinDistanceTarget represents a geometric object to which distances are
+// measured.  Specifically, it is used to compute minimum distances on the
+// sphere (as opposed to maximum distances, ellipsoidal distances, etc).
+//
+// Subtypes are defined below for measuring the distance to a point, an edge,
+// an S2Cell, or an S2ShapeIndex (an arbitrary collection of geometry).
+using S2MinDistanceTarget = S2DistanceTarget<S2MinDistance>;
+
+// An S2DistanceTarget subtype for computing the minimum distance to a point.
+class S2MinDistancePointTarget : public S2MinDistanceTarget {
+ public:
+  explicit S2MinDistancePointTarget(const S2Point& point);
+  S2Cap GetCapBound() final;
+  bool UpdateMinDistance(const S2Point& p, S2MinDistance* min_dist) final;
+  bool UpdateMinDistance(const S2Point& v0, const S2Point& v1,
+                         S2MinDistance* min_dist) final;
+  bool UpdateMinDistance(const S2Cell& cell,
+                         S2MinDistance* min_dist) final;
+  bool VisitContainingShapes(const S2ShapeIndex& index,
+                             const ShapeVisitor& visitor) final;
+
+ private:
+  S2Point point_;
+};
+
+// An S2DistanceTarget subtype for computing the minimum distance to a edge.
+class S2MinDistanceEdgeTarget : public S2MinDistanceTarget {
+ public:
+  S2MinDistanceEdgeTarget(const S2Point& a, const S2Point& b);
+  S2Cap GetCapBound() final;
+  bool UpdateMinDistance(const S2Point& p, S2MinDistance* min_dist) final;
+  bool UpdateMinDistance(const S2Point& v0, const S2Point& v1,
+                         S2MinDistance* min_dist) final;
+  bool UpdateMinDistance(const S2Cell& cell,
+                         S2MinDistance* min_dist) final;
+  bool VisitContainingShapes(const S2ShapeIndex& index,
+                             const ShapeVisitor& visitor) final;
+
+ private:
+  S2Point a_, b_;
+};
+
+// An S2DistanceTarget subtype for computing the minimum distance to an S2Cell
+// (including the interior of the cell).
+class S2MinDistanceCellTarget : public S2MinDistanceTarget {
+ public:
+  explicit S2MinDistanceCellTarget(const S2Cell& cell);
+  S2Cap GetCapBound() final;
+  bool UpdateMinDistance(const S2Point& p, S2MinDistance* min_dist) final;
+  bool UpdateMinDistance(const S2Point& v0, const S2Point& v1,
+                         S2MinDistance* min_dist) final;
+  bool UpdateMinDistance(const S2Cell& cell,
+                         S2MinDistance* min_dist) final;
+  bool VisitContainingShapes(const S2ShapeIndex& index,
+                             const ShapeVisitor& visitor) final;
+
+ private:
+  S2Cell cell_;
+};
+
+// An S2DistanceTarget subtype for computing the minimum distance to an
+// S2CellUnion (including the interior of all cells).
+class S2MinDistanceCellUnionTarget : public S2MinDistanceTarget {
+ public:
+  explicit S2MinDistanceCellUnionTarget(S2CellUnion cell_union);
+  ~S2MinDistanceCellUnionTarget() override;
+
+  // Specifies that the distances should be computed by examining every cell
+  // in the S2CellIndex (for testing and debugging purposes).
+  //
+  // DEFAULT: false
+  bool use_brute_force() const;
+  void set_use_brute_force(bool use_brute_force);
+
+  // Note that set_max_error() should not be called directly by clients; it is
+  // used internally by the S2Closest*Query implementations.
+  bool set_max_error(const S1ChordAngle& max_error) override;
+
+  S2Cap GetCapBound() final;
+  bool UpdateMinDistance(const S2Point& p, S2MinDistance* min_dist) final;
+  bool UpdateMinDistance(const S2Point& v0, const S2Point& v1,
+                         S2MinDistance* min_dist) final;
+  bool UpdateMinDistance(const S2Cell& cell,
+                         S2MinDistance* min_dist) final;
+  bool VisitContainingShapes(const S2ShapeIndex& query_index,
+                             const ShapeVisitor& visitor) final;
+
+ private:
+  bool UpdateMinDistance(S2MinDistanceTarget* target, S2MinDistance* min_dist);
+
+  S2CellUnion cell_union_;
+  S2CellIndex index_;
+  std::unique_ptr<S2ClosestCellQuery> query_;
+};
+
+// An S2DistanceTarget subtype for computing the minimum distance to an
+// S2ShapeIndex (a collection of points, polylines, and/or polygons).
+//
+// Note that ShapeIndexTarget has its own options:
+//
+//   include_interiors()
+//     - specifies that distances are measured to the boundary and interior
+//       of polygons in the S2ShapeIndex.  (If set to false, distance is
+//       measured to the polygon boundary only.)
+//       DEFAULT: true.
+//
+//   brute_force()
+//     - specifies that the distances should be computed by examining every
+//       edge in the S2ShapeIndex (for testing and debugging purposes).
+//       DEFAULT: false.
+//
+// These options are specified independently of the corresponding
+// S2ClosestEdgeQuery options.  For example, if include_interiors is true for
+// a ShapeIndexTarget but false for the S2ClosestEdgeQuery where the target
+// is used, then distances will be measured from the boundary of one
+// S2ShapeIndex to the boundary and interior of the other.
+//
+// Note that when the distance to a ShapeIndexTarget is zero because the
+// target intersects the interior of the query index, you can find a point
+// that achieves this zero distance by calling the VisitContainingShapes()
+// method directly.  For example:
+//
+//   S2ClosestEdgeQuery::ShapeIndexTarget target(&target_index);
+//   target.VisitContainingShapes(
+//       query_index, [](S2Shape* containing_shape,
+//                       const S2Point& target_point) {
+//         ... do something with "target_point" ...
+//         return false;  // Terminate search
+//       }));
+class S2MinDistanceShapeIndexTarget : public S2MinDistanceTarget {
+ public:
+  explicit S2MinDistanceShapeIndexTarget(const S2ShapeIndex* index);
+  ~S2MinDistanceShapeIndexTarget() override;
+
+  // Specifies that distance will be measured to the boundary and interior
+  // of polygons in the S2ShapeIndex rather than to polygon boundaries only.
+  //
+  // DEFAULT: true
+  bool include_interiors() const;
+  void set_include_interiors(bool include_interiors);
+
+  // Specifies that the distances should be computed by examining every edge
+  // in the S2ShapeIndex (for testing and debugging purposes).
+  //
+  // DEFAULT: false
+  bool use_brute_force() const;
+  void set_use_brute_force(bool use_brute_force);
+
+  // Note that set_max_error() should not be called directly by clients; it is
+  // used internally by the S2Closest*Query implementations.
+  bool set_max_error(const S1ChordAngle& max_error) override;
+
+  S2Cap GetCapBound() final;
+  bool UpdateMinDistance(const S2Point& p, S2MinDistance* min_dist) final;
+  bool UpdateMinDistance(const S2Point& v0, const S2Point& v1,
+                         S2MinDistance* min_dist) final;
+  bool UpdateMinDistance(const S2Cell& cell,
+                         S2MinDistance* min_dist) final;
+  bool VisitContainingShapes(const S2ShapeIndex& query_index,
+                             const ShapeVisitor& visitor) final;
+
+ private:
+  bool UpdateMinDistance(S2MinDistanceTarget* target, S2MinDistance* min_dist);
+
+  const S2ShapeIndex* index_;
+  std::unique_ptr<S2ClosestEdgeQuery> query_;
+};
+
+
+//////////////////   Implementation details follow   ////////////////////
+
+
+inline S2MinDistance S2MinDistance::Zero() {
+  return S2MinDistance(S1ChordAngle::Zero());
+}
+
+inline S2MinDistance S2MinDistance::Infinity() {
+  return S2MinDistance(S1ChordAngle::Infinity());
+}
+
+inline S2MinDistance S2MinDistance::Negative() {
+  return S2MinDistance(S1ChordAngle::Negative());
+}
+
+inline S2MinDistance operator-(S2MinDistance x, S1ChordAngle delta) {
+  return S2MinDistance(S1ChordAngle(x) - delta);
+}
+
+inline S1ChordAngle S2MinDistance::GetChordAngleBound() const {
+  return PlusError(GetS1AngleConstructorMaxError());
+}
+
+inline bool S2MinDistance::UpdateMin(const S2MinDistance& dist) {
+  if (dist < *this) {
+    *this = dist;
+    return true;
+  }
+  return false;
+}
+
+inline S2MinDistancePointTarget::S2MinDistancePointTarget(const S2Point& point)
+    : point_(point) {
+}
+
+inline S2MinDistanceEdgeTarget::S2MinDistanceEdgeTarget(const S2Point& a,
+                                                        const S2Point& b)
+    : a_(a), b_(b) {
+}
+
+#endif  // S2_S2MIN_DISTANCE_TARGETS_H_
diff --git a/src/s2/s2padded_cell.cc b/src/s2/s2padded_cell.cc
new file mode 100644 (file)
index 0000000..3b79f78
--- /dev/null
@@ -0,0 +1,162 @@
+// Copyright 2013 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// Author: ericv@google.com (Eric Veach)
+
+#include "s2/s2padded_cell.h"
+
+#include <algorithm>
+#include <cfloat>
+
+#include "s2/util/bits/bits.h"
+#include "s2/r1interval.h"
+#include "s2/s2coords.h"
+
+using std::max;
+using std::min;
+using S2::internal::kSwapMask;
+using S2::internal::kInvertMask;
+using S2::internal::kIJtoPos;
+using S2::internal::kPosToOrientation;
+
+S2PaddedCell::S2PaddedCell(S2CellId id, double padding)
+    : id_(id), padding_(padding) {
+  if (id_.is_face()) {
+    // Fast path for constructing a top-level face (the most common case).
+    double limit = 1 + padding;
+    bound_ = R2Rect(R1Interval(-limit, limit), R1Interval(-limit, limit));
+    middle_ = R2Rect(R1Interval(-padding, padding),
+                     R1Interval(-padding, padding));
+    ij_lo_[0] = ij_lo_[1] = 0;
+    orientation_ = id_.face() & 1;
+    level_ = 0;
+  } else {
+    int ij[2];
+    id.ToFaceIJOrientation(&ij[0], &ij[1], &orientation_);
+    level_ = id.level();
+    bound_ = S2CellId::IJLevelToBoundUV(ij, level_).Expanded(padding);
+    int ij_size = S2CellId::GetSizeIJ(level_);
+    ij_lo_[0] = ij[0] & -ij_size;
+    ij_lo_[1] = ij[1] & -ij_size;
+  }
+}
+
+S2PaddedCell::S2PaddedCell(const S2PaddedCell& parent, int i, int j)
+    : padding_(parent.padding_),
+      bound_(parent.bound_),
+      level_(parent.level_ + 1) {
+  // Compute the position and orientation of the child incrementally from the
+  // orientation of the parent.
+  int pos = kIJtoPos[parent.orientation_][2*i+j];
+  id_ = parent.id_.child(pos);
+  int ij_size = S2CellId::GetSizeIJ(level_);
+  ij_lo_[0] = parent.ij_lo_[0] + i * ij_size;
+  ij_lo_[1] = parent.ij_lo_[1] + j * ij_size;
+  orientation_ = parent.orientation_ ^ kPosToOrientation[pos];
+  // For each child, one corner of the bound is taken directly from the parent
+  // while the diagonally opposite corner is taken from middle().
+  const R2Rect& middle = parent.middle();
+  bound_[0][1-i] = middle[0][1-i];
+  bound_[1][1-j] = middle[1][1-j];
+}
+
+const R2Rect& S2PaddedCell::middle() const {
+  // We compute this field lazily because it is not needed the majority of the
+  // time (i.e., for cells where the recursion terminates).
+  if (middle_.is_empty()) {
+    int ij_size = S2CellId::GetSizeIJ(level_);
+    double u = S2::STtoUV(S2::SiTitoST(2 * ij_lo_[0] + ij_size));
+    double v = S2::STtoUV(S2::SiTitoST(2 * ij_lo_[1] + ij_size));
+    middle_ = R2Rect(R1Interval(u - padding_, u + padding_),
+                     R1Interval(v - padding_, v + padding_));
+  }
+  return middle_;
+}
+
+S2Point S2PaddedCell::GetCenter() const {
+  int ij_size = S2CellId::GetSizeIJ(level_);
+  unsigned int si = 2 * ij_lo_[0] + ij_size;
+  unsigned int ti = 2 * ij_lo_[1] + ij_size;
+  return S2::FaceSiTitoXYZ(id_.face(), si, ti).Normalize();
+}
+
+S2Point S2PaddedCell::GetEntryVertex() const {
+  // The curve enters at the (0,0) vertex unless the axis directions are
+  // reversed, in which case it enters at the (1,1) vertex.
+  unsigned int i = ij_lo_[0];
+  unsigned int j = ij_lo_[1];
+  if (orientation_ & kInvertMask) {
+    int ij_size = S2CellId::GetSizeIJ(level_);
+    i += ij_size;
+    j += ij_size;
+  }
+  return S2::FaceSiTitoXYZ(id_.face(), 2 * i, 2 * j).Normalize();
+}
+
+S2Point S2PaddedCell::GetExitVertex() const {
+  // The curve exits at the (1,0) vertex unless the axes are swapped or
+  // inverted but not both, in which case it exits at the (0,1) vertex.
+  unsigned int i = ij_lo_[0];
+  unsigned int j = ij_lo_[1];
+  int ij_size = S2CellId::GetSizeIJ(level_);
+  if (orientation_ == 0 || orientation_ == kSwapMask + kInvertMask) {
+    i += ij_size;
+  } else {
+    j += ij_size;
+  }
+  return S2::FaceSiTitoXYZ(id_.face(), 2 * i, 2 * j).Normalize();
+}
+
+S2CellId S2PaddedCell::ShrinkToFit(const R2Rect& rect) const {
+  S2_DCHECK(bound().Intersects(rect));
+
+  // Quick rejection test: if "rect" contains the center of this cell along
+  // either axis, then no further shrinking is possible.
+  int ij_size = S2CellId::GetSizeIJ(level_);
+  if (level_ == 0) {
+    // Fast path (most calls to this function start with a face cell).
+    if (rect[0].Contains(0) || rect[1].Contains(0)) return id();
+  } else {
+    if (rect[0].Contains(S2::STtoUV(S2::SiTitoST(2 * ij_lo_[0] + ij_size))) ||
+        rect[1].Contains(S2::STtoUV(S2::SiTitoST(2 * ij_lo_[1] + ij_size)))) {
+      return id();
+    }
+  }
+  // Otherwise we expand "rect" by the given padding() on all sides and find
+  // the range of coordinates that it spans along the i- and j-axes.  We then
+  // compute the highest bit position at which the min and max coordinates
+  // differ.  This corresponds to the first cell level at which at least two
+  // children intersect "rect".
+
+  // Increase the padding to compensate for the error in S2::UVtoST().
+  // (The constant below is a provable upper bound on the additional error.)
+  R2Rect padded = rect.Expanded(padding() + 1.5 * DBL_EPSILON);
+  int ij_min[2];  // Min i- or j- coordinate spanned by "padded"
+  int ij_xor[2];  // XOR of the min and max i- or j-coordinates
+  for (int d = 0; d < 2; ++d) {
+    ij_min[d] = max(ij_lo_[d], S2::STtoIJ(S2::UVtoST(padded[d][0])));
+    int ij_max = min(ij_lo_[d] + ij_size - 1,
+                     S2::STtoIJ(S2::UVtoST(padded[d][1])));
+    ij_xor[d] = ij_min[d] ^ ij_max;
+  }
+  // Compute the highest bit position where the two i- or j-endpoints differ,
+  // and then choose the cell level that includes both of these endpoints.  So
+  // if both pairs of endpoints are equal we choose kMaxLevel; if they differ
+  // only at bit 0, we choose (kMaxLevel - 1), and so on.
+  int level_msb = ((ij_xor[0] | ij_xor[1]) << 1) + 1;
+  int level = S2CellId::kMaxLevel - Bits::FindMSBSetNonZero(level_msb);
+  if (level <= level_) return id();
+  return S2CellId::FromFaceIJ(id().face(), ij_min[0], ij_min[1]).parent(level);
+}
diff --git a/src/s2/s2padded_cell.h b/src/s2/s2padded_cell.h
new file mode 100644 (file)
index 0000000..e53e003
--- /dev/null
@@ -0,0 +1,108 @@
+// Copyright 2013 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// Author: ericv@google.com (Eric Veach)
+
+#ifndef S2_S2PADDED_CELL_H_
+#define S2_S2PADDED_CELL_H_
+
+#include "s2/_fp_contract_off.h"
+#include "s2/r2rect.h"
+#include "s2/s2cell_id.h"
+
+// S2PaddedCell represents an S2Cell whose (u,v)-range has been expanded on
+// all sides by a given amount of "padding".  Unlike S2Cell, its methods and
+// representation are optimized for clipping edges against S2Cell boundaries
+// to determine which cells are intersected by a given set of edges.
+//
+// This class is intended to be copied by value as desired.
+class S2PaddedCell {
+ public:
+  // Construct an S2PaddedCell for the given cell id and padding.
+  S2PaddedCell(S2CellId id, double padding);
+
+  // Construct the child of "parent" with the given (i,j) index.  The four
+  // child cells have indices of (0,0), (0,1), (1,0), (1,1), where the i and j
+  // indices correspond to increasing u- and v-values respectively.
+  S2PaddedCell(const S2PaddedCell& parent, int i, int j);
+
+  S2CellId id() const { return id_; }
+  double padding() const { return padding_; }
+  int level() const { return level_; }
+
+  // Return the bound for this cell (including padding).
+  const R2Rect& bound() const { return bound_; }
+
+  // Return the "middle" of the padded cell, defined as the rectangle that
+  // belongs to all four children.
+  //
+  // Note that this method is *not* thread-safe, because the return value is
+  // computed on demand and cached.  (It is expected that this class will be
+  // mainly useful in the context of single-threaded recursive algorithms.)
+  const R2Rect& middle() const;
+
+  // Return the (i,j) coordinates for the child cell at the given traversal
+  // position.  The traversal position corresponds to the order in which child
+  // cells are visited by the Hilbert curve.
+  void GetChildIJ(int pos, int* i, int* j) const;
+
+  // Return the smallest cell that contains all descendants of this cell whose
+  // bounds intersect "rect".  For algorithms that use recursive subdivision
+  // to find the cells that intersect a particular object, this method can be
+  // used to skip all the initial subdivision steps where only one child needs
+  // to be expanded.
+  //
+  // Note that this method is not the same as returning the smallest cell that
+  // contains the intersection of this cell with "rect".  Because of the
+  // padding, even if one child completely contains "rect" it is still
+  // possible that a neighboring child also intersects "rect".
+  //
+  // REQUIRES: bound().Intersects(rect)
+  S2CellId ShrinkToFit(const R2Rect& rect) const;
+
+  // Return the center of this cell.
+  S2Point GetCenter() const;
+
+  // Return the vertex where the S2 space-filling curve enters this cell.
+  S2Point GetEntryVertex() const;
+
+  // Return the vertex where the S2 space-filling curve exits this cell.
+  S2Point GetExitVertex() const;
+
+ private:
+  S2CellId id_;
+  double padding_;
+  R2Rect bound_;     // Bound in (u,v)-space
+
+  // The rectangle in (u,v)-space that belongs to all four padded children.
+  // It is computed on demand by the middle() accessor method.
+  mutable R2Rect middle_;
+
+  int ij_lo_[2];     // Minimum (i,j)-coordinates of this cell, before padding
+  int orientation_;  // Hilbert curve orientation of this cell (see s2coords.h)
+  int level_;        // Level of this cell (see s2coords.h)
+};
+
+
+//////////////////   Implementation details follow   ////////////////////
+
+
+inline void S2PaddedCell::GetChildIJ(int pos, int* i, int* j) const {
+  int ij = S2::internal::kPosToIJ[orientation_][pos];
+  *i = ij >> 1;
+  *j = ij & 1;
+}
+
+#endif  // S2_S2PADDED_CELL_H_
diff --git a/src/s2/s2point.h b/src/s2/s2point.h
new file mode 100644 (file)
index 0000000..26da021
--- /dev/null
@@ -0,0 +1,38 @@
+// Copyright 2005 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// Author: ericv@google.com (Eric Veach)
+
+#ifndef S2_S2POINT_H_
+#define S2_S2POINT_H_
+
+#include "s2/_fp_contract_off.h"
+#include "s2/util/math/vector.h"  // IWYU pragma: export
+#include "s2/util/math/vector3_hash.h"
+
+// An S2Point represents a point on the unit sphere as a 3D vector.  Usually
+// points are normalized to be unit length, but some methods do not require
+// this.  See util/math/vector.h for the methods available.  Among other
+// things, there are overloaded operators that make it convenient to write
+// arithmetic expressions (e.g. (1-x)*p1 + x*p2).
+using S2Point = Vector3_d;
+
+// S2PointHash can be used with standard containers (e.g., unordered_set) or
+// nonstandard extensions (e.g., hash_map).  It is defined such that if two
+// S2Points compare equal to each other, they have the same hash.  (This
+// requires that positive and negative zero hash to the same value.)
+using S2PointHash = GoodFastHash<S2Point>;
+
+#endif  // S2_S2POINT_H_
diff --git a/src/s2/s2point_compression.cc b/src/s2/s2point_compression.cc
new file mode 100644 (file)
index 0000000..31eb2ad
--- /dev/null
@@ -0,0 +1,388 @@
+// Copyright 2011 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+
+#include "s2/s2point_compression.h"
+
+#include <utility>
+#include <vector>
+
+#include "s2/base/integral_types.h"
+#include "s2/base/logging.h"
+#include "s2/s2cell_id.h"
+#include "s2/s2coords.h"
+#include "absl/base/casts.h"
+#include "absl/base/macros.h"
+#include "absl/container/fixed_array.h"
+#include "absl/types/span.h"
+#include "s2/util/bits/bit-interleave.h"
+#include "s2/util/coding/coder.h"
+#include "s2/util/coding/nth-derivative.h"
+#include "s2/util/coding/transforms.h"
+#include "s2/util/endian/endian.h"
+
+using absl::Span;
+using std::pair;
+using std::vector;
+
+namespace {
+
+const int kDerivativeEncodingOrder = 2;
+
+// Pair of face number and count for run-length encoding.
+struct FaceRun {
+  FaceRun() : face(-1), count(0) {}
+  FaceRun(int initial_face, int initial_count)
+      : face(initial_face), count(initial_count) {}
+
+  // Encodes each face as a varint64 with value kNumFaces * count + face.
+  // 21 faces can fit in a single byte.  Varint64 is used so that 4G faces
+  // can be encoded instead of just 4G / 6 = ~700M.
+  void Encode(Encoder* encoder) const {
+    encoder->Ensure(Encoder::kVarintMax64);
+
+    // It isn't necessary to encode the number of faces left for the last run,
+    // but since this would only help if there were more than 21 faces, it will
+    // be a small overall savings, much smaller than the bound encoding.
+    encoder->put_varint64(
+        S2CellId::kNumFaces * absl::implicit_cast<int64>(count) + face);
+    S2_DCHECK_GE(encoder->avail(), 0);
+  }
+
+  bool Decode(Decoder* decoder) {
+    uint64 face_and_count;
+    if (!decoder->get_varint64(&face_and_count)) return false;
+
+    face = face_and_count % S2CellId::kNumFaces;
+    // Make sure large counts don't wrap on malicious or random input.
+    const uint64 count64 = face_and_count / S2CellId::kNumFaces;
+    count = count64;
+
+    return count > 0 && count == count64;
+  }
+
+  int face;
+  int count;
+};
+
+// Run-length encoder/decoder for face numbers.
+class Faces {
+ public:
+  class Iterator {
+   public:
+    explicit Iterator(const Faces& faces);
+
+    // Return the next face.
+    int Next();
+
+   private:
+    // The faces_ vector of the Faces object for which this is an iterator.
+    const vector<FaceRun>& faces_;
+
+    // The index that the next face will come from.
+    int face_index_;
+
+    // Number of faces already consumed for face_index_.
+    int num_faces_used_for_index_;
+  };
+
+  Faces() {}
+
+  // Add the face to the list of face runs, combining with the last if
+  // possible.
+  void AddFace(int face);
+
+  // Encodes the faces to encoder.
+  void Encode(Encoder* encoder) const;
+
+  // Decodes the faces, returning true on success.
+  bool Decode(int num_vertices, Decoder* decoder);
+
+  Iterator GetIterator() const {
+    Iterator iterator(*this);
+    return iterator;
+  }
+
+ private:
+  // Run-length encoded list of faces.
+  vector<FaceRun> faces_;
+
+  Faces(const Faces&) = delete;
+  void operator=(const Faces&) = delete;
+};
+
+void Faces::AddFace(int face) {
+  if (!faces_.empty() && faces_.back().face == face) {
+    ++faces_.back().count;
+  } else {
+    faces_.push_back(FaceRun(face, 1));
+  }
+}
+
+void Faces::Encode(Encoder* encoder) const {
+  for (const FaceRun& face_run : faces_)
+    face_run.Encode(encoder);
+}
+
+bool Faces::Decode(int num_vertices, Decoder* decoder) {
+  for (int num_faces_parsed = 0; num_faces_parsed < num_vertices; ) {
+    FaceRun face_run;
+    if (!face_run.Decode(decoder)) return false;
+    faces_.push_back(face_run);
+
+    num_faces_parsed += face_run.count;
+  }
+
+  return true;
+}
+
+Faces::Iterator::Iterator(const Faces& faces)
+    : faces_(faces.faces_), face_index_(0),
+      num_faces_used_for_index_(0) {
+}
+
+int Faces::Iterator::Next() {
+  S2_DCHECK_NE(faces_.size(), face_index_);
+  S2_DCHECK_LE(num_faces_used_for_index_, faces_[face_index_].count);
+  if (num_faces_used_for_index_ == faces_[face_index_].count) {
+    ++face_index_;
+    num_faces_used_for_index_ = 0;
+  }
+
+  ++num_faces_used_for_index_;
+  return faces_[face_index_].face;
+}
+
+// Unused function (for documentation purposes only).
+inline int STtoPiQi(double s, int level) {
+  // We introduce a new coordinate system (pi, qi), which is (si, ti)
+  // with the bits that are constant for cells of that level shifted
+  // off to the right.
+  // si = round(s * 2^31)
+  // pi = si >> (31 - level)
+  //    = floor(s * 2^level)
+  // If the point has been snapped to the level, the bits that are
+  // shifted off will be a 1 in the msb, then 0s after that, so the
+  // fractional part discarded by the cast is (close to) 0.5.
+  return static_cast<int>(s * (1 << level));
+}
+
+inline int SiTitoPiQi(unsigned int si, int level) {
+  // See STtoPiQi for the definition of the PiQi coordinate system.
+  //
+  // EncodeFirstPointFixedLength encodes the return value using "level" bits,
+  // so we clamp "si" to the range [0, 2**level - 1] before trying to encode
+  // it.  This is okay because if si == kMaxSiTi, then it is not a cell center
+  // anyway and will be encoded separately as an "off-center" point.
+  si = std::min(si, S2::kMaxSiTi - 1);
+  return si >> (S2::kMaxCellLevel + 1 - level);
+}
+
+inline double PiQitoST(int pi, int level) {
+  // We want to recover the position at the center of the cell.  If the point
+  // was snapped to the center of the cell, then modf(s * 2^level) == 0.5.
+  // Inverting STtoPiQi gives:
+  // s = (pi + 0.5) / 2^level.
+  return (pi + 0.5) / (1 << level);
+}
+
+S2Point FacePiQitoXYZ(int face, int pi, int qi, int level) {
+  return S2::FaceUVtoXYZ(face,
+                         S2::STtoUV(PiQitoST(pi, level)),
+                         S2::STtoUV(PiQitoST(qi, level))).Normalize();
+}
+
+void EncodeFirstPointFixedLength(const pair<int, int>& vertex_pi_qi,
+                                 int level,
+                                 NthDerivativeCoder* pi_coder,
+                                 NthDerivativeCoder* qi_coder,
+                                 Encoder* encoder) {
+  // Do not ZigZagEncode the first point, since it cannot be negative.
+  const uint32 pi = pi_coder->Encode(vertex_pi_qi.first);
+  const uint32 qi = qi_coder->Encode(vertex_pi_qi.second);
+  // Interleave to reduce overhead from two partial bytes to one.
+  const uint64 interleaved_pi_qi = util_bits::InterleaveUint32(pi, qi);
+
+  // Convert to little endian for architecture independence.
+  const uint64 little_endian_interleaved_pi_qi =
+      LittleEndian::FromHost64(interleaved_pi_qi);
+
+  const int bytes_required = (level + 7) / 8 * 2;
+  encoder->Ensure(bytes_required);
+  encoder->putn(&little_endian_interleaved_pi_qi, bytes_required);
+  S2_DCHECK_GE(encoder->avail(), 0);
+}
+
+void EncodePointCompressed(const pair<int, int>& vertex_pi_qi,
+                           int level,
+                           NthDerivativeCoder* pi_coder,
+                           NthDerivativeCoder* qi_coder,
+                           Encoder* encoder) {
+  // ZigZagEncode, as varint requires the maximum number of bytes for
+  // negative numbers.
+  const uint32 zig_zag_encoded_deriv_pi =
+      ZigZagEncode(pi_coder->Encode(vertex_pi_qi.first));
+  const uint32 zig_zag_encoded_deriv_qi =
+      ZigZagEncode(qi_coder->Encode(vertex_pi_qi.second));
+  // Interleave to reduce overhead from two partial bytes to one.
+  const uint64 interleaved_zig_zag_encoded_derivs =
+      util_bits::InterleaveUint32(zig_zag_encoded_deriv_pi,
+                                  zig_zag_encoded_deriv_qi);
+
+  encoder->Ensure(Encoder::kVarintMax64);
+  encoder->put_varint64(interleaved_zig_zag_encoded_derivs);
+  S2_DCHECK_GE(encoder->avail(), 0);
+}
+
+void EncodePointsCompressed(Span<const pair<int, int>> vertices_pi_qi,
+                            int level, Encoder* encoder) {
+  NthDerivativeCoder pi_coder(kDerivativeEncodingOrder);
+  NthDerivativeCoder qi_coder(kDerivativeEncodingOrder);
+  for (int i = 0; i < vertices_pi_qi.size(); ++i) {
+    if (i == 0) {
+      // The first point will be just the (pi, qi) coordinates
+      // of the S2Point.  NthDerivativeCoder will not save anything
+      // in that case, so we encode in fixed format rather than varint
+      // to avoid the varint overhead.
+      EncodeFirstPointFixedLength(vertices_pi_qi[i], level,
+                                  &pi_coder, &qi_coder, encoder);
+    } else {
+      EncodePointCompressed(vertices_pi_qi[i], level,
+                            &pi_coder, &qi_coder, encoder);
+    }
+  }
+
+  S2_DCHECK_GE(encoder->avail(), 0);
+}
+
+bool DecodeFirstPointFixedLength(Decoder* decoder,
+                                 int level,
+                                 NthDerivativeCoder* pi_coder,
+                                 NthDerivativeCoder* qi_coder,
+                                 pair<int, int>* vertex_pi_qi) {
+  const int bytes_required = (level + 7) / 8 * 2;
+  if (decoder->avail() < bytes_required) return false;
+  uint64 little_endian_interleaved_pi_qi = 0;
+  decoder->getn(&little_endian_interleaved_pi_qi, bytes_required);
+
+  const uint64 interleaved_pi_qi =
+      LittleEndian::ToHost64(little_endian_interleaved_pi_qi);
+
+  uint32 pi, qi;
+  util_bits::DeinterleaveUint32(interleaved_pi_qi, &pi, &qi);
+
+  vertex_pi_qi->first = pi_coder->Decode(pi);
+  vertex_pi_qi->second = qi_coder->Decode(qi);
+
+  return true;
+}
+
+bool DecodePointCompressed(Decoder* decoder,
+                           int level,
+                           NthDerivativeCoder* pi_coder,
+                           NthDerivativeCoder* qi_coder,
+                           pair<int, int>* vertex_pi_qi) {
+  uint64 interleaved_zig_zag_encoded_deriv_pi_qi;
+  if (!decoder->get_varint64(&interleaved_zig_zag_encoded_deriv_pi_qi)) {
+    return false;
+  }
+
+  uint32 zig_zag_encoded_deriv_pi, zig_zag_encoded_deriv_qi;
+  util_bits::DeinterleaveUint32(interleaved_zig_zag_encoded_deriv_pi_qi,
+                                &zig_zag_encoded_deriv_pi,
+                                &zig_zag_encoded_deriv_qi);
+
+  vertex_pi_qi->first =
+      pi_coder->Decode(ZigZagDecode(zig_zag_encoded_deriv_pi));
+  vertex_pi_qi->second =
+      qi_coder->Decode(ZigZagDecode(zig_zag_encoded_deriv_qi));
+
+  return true;
+}
+
+}  // namespace
+
+void S2EncodePointsCompressed(Span<const S2XYZFaceSiTi> points,
+                              int level,
+                              Encoder* encoder) {
+  absl::FixedArray<pair<int, int>> vertices_pi_qi(points.size());
+  vector<int> off_center;
+  Faces faces;
+  for (int i = 0; i < points.size(); ++i) {
+    faces.AddFace(points[i].face);
+    vertices_pi_qi[i].first = SiTitoPiQi(points[i].si, level);
+    vertices_pi_qi[i].second = SiTitoPiQi(points[i].ti, level);
+    if (points[i].cell_level != level) {
+      off_center.push_back(i);
+    }
+  }
+  faces.Encode(encoder);
+  EncodePointsCompressed(vertices_pi_qi, level, encoder);
+  int num_off_center = off_center.size();
+  encoder->Ensure(Encoder::kVarintMax32 +
+                  (Encoder::kVarintMax32 + sizeof(S2Point)) * num_off_center);
+  encoder->put_varint32(num_off_center);
+  S2_DCHECK_GE(encoder->avail(), 0);
+  for (int index : off_center) {
+    encoder->put_varint32(index);
+    encoder->putn(&points[index].xyz, sizeof(points[index].xyz));
+    S2_DCHECK_GE(encoder->avail(), 0);
+  }
+}
+
+bool S2DecodePointsCompressed(Decoder* decoder, int level,
+                              Span<S2Point> points) {
+  Faces faces;
+  if (!faces.Decode(points.size(), decoder)) {
+    return false;
+  }
+
+  NthDerivativeCoder pi_coder(kDerivativeEncodingOrder);
+  NthDerivativeCoder qi_coder(kDerivativeEncodingOrder);
+  Faces::Iterator faces_iterator = faces.GetIterator();
+  for (int i = 0; i < points.size(); ++i) {
+    pair<int, int> vertex_pi_qi;
+    if (i == 0) {
+      if (!DecodeFirstPointFixedLength(decoder, level, &pi_coder, &qi_coder,
+                                       &vertex_pi_qi)) {
+        return false;
+      }
+    } else {
+      if (!DecodePointCompressed(decoder, level, &pi_coder, &qi_coder,
+                                 &vertex_pi_qi)) {
+        return false;
+      }
+    }
+
+    int face = faces_iterator.Next();
+    points[i] =
+        FacePiQitoXYZ(face, vertex_pi_qi.first, vertex_pi_qi.second, level);
+  }
+
+  unsigned int num_off_center;
+  if (!decoder->get_varint32(&num_off_center) ||
+      num_off_center > points.size()) {
+    return false;
+  }
+  for (int i = 0; i < num_off_center; ++i) {
+    uint32 index;
+    if (!decoder->get_varint32(&index) || index >= points.size()) {
+      return false;
+    }
+    if (decoder->avail() < sizeof(points[index])) return false;
+    decoder->getn(&points[index], sizeof(points[index]));
+  }
+  return true;
+}
diff --git a/src/s2/s2point_compression.h b/src/s2/s2point_compression.h
new file mode 100644 (file)
index 0000000..ed4742c
--- /dev/null
@@ -0,0 +1,78 @@
+// Copyright 2011 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+//
+// Given a sequence of S2Points assumed to be the center of level-k cells,
+// compresses it into a stream using the following method:
+// - decompose the points into (face, si, ti) tuples (see s2coords.h)
+// - run-length encode the faces, combining face number and count into a
+//     varint32.  See the Faces class in s2point_compression.cc.
+// - right shift the (si, ti) to remove the part that's constant for all cells
+//     of level-k.  The result is called the (pi, qi) space.
+// - 2nd derivative encode the pi and qi sequences (linear prediction)
+// - zig-zag encode all derivative values but the first, which cannot be
+//     negative
+// - interleave the zig-zag encoded values
+// - encode the first interleaved value in a fixed length encoding
+//     (varint would make this value larger)
+// - encode the remaining interleaved values as varint64s, as the
+//     derivative encoding should make the values small.
+// In addition, provides a lossless method to compress a sequence of points even
+// if some points are not the center of level-k cells. These points are stored
+// exactly, using 3 double precision values, after the above encoded string,
+// together with their index in the sequence (this leads to some redundancy - it
+// is expected that only a small fraction of the points are not cell centers).
+//
+// Require that the encoder was constructed with the no-arg constructor, as
+// Ensure() will be called to allocate space.
+
+//
+// To encode leaf cells, this requires 8 bytes for the first vertex plus
+// an average of 3.8 bytes for each additional vertex, when computed on
+// Google's geographic repository.
+
+#ifndef S2_S2POINT_COMPRESSION_H_
+#define S2_S2POINT_COMPRESSION_H_
+
+#include "absl/types/span.h"
+#include "s2/_fp_contract_off.h"
+#include "s2/s1angle.h"
+
+class Decoder;
+class Encoder;
+
+// The XYZ and face,si,ti coordinates of an S2Point and, if this point is equal
+// to the center of an S2Cell, the level of this cell (-1 otherwise).
+struct S2XYZFaceSiTi {
+  S2Point xyz;
+  int face;
+  unsigned int si;
+  unsigned int ti;
+  int cell_level;
+};
+
+// Encode the points in the encoder, using an optimized compressed format for
+// points at the center of a cell at 'level', plus 3 double values for the
+// others.
+void S2EncodePointsCompressed(absl::Span<const S2XYZFaceSiTi> points,
+                              int level, Encoder* encoder);
+
+// Decode points encoded with S2EncodePointsCompressed. Requires that the
+// level is the level that was used in S2EncodePointsCompressed. Ensures
+// that the decoded points equal the encoded points. Returns true on success.
+bool S2DecodePointsCompressed(Decoder* decoder, int level,
+                              absl::Span<S2Point> points);
+
+#endif  // S2_S2POINT_COMPRESSION_H_
diff --git a/src/s2/s2point_index.h b/src/s2/s2point_index.h
new file mode 100644 (file)
index 0000000..7bb671b
--- /dev/null
@@ -0,0 +1,345 @@
+// Copyright 2015 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// Author: ericv@google.com (Eric Veach)
+
+#ifndef S2_S2POINT_INDEX_H_
+#define S2_S2POINT_INDEX_H_
+
+#include <tuple>
+#include <type_traits>
+#include "absl/container/btree_map.h"
+#include "s2/s2cell_id.h"
+
+// S2PointIndex maintains an index of points sorted by leaf S2CellId.  Each
+// point can optionally store auxiliary data such as an integer or pointer.
+// This can be used to map results back to client data structures.
+//
+// The class supports adding or removing points dynamically, and provides a
+// seekable iterator interface for navigating the index.
+//
+// You can use this class in conjuction with S2ClosestPointQuery to find the
+// closest index points to a given query point.  For example:
+//
+// void Test(const vector<S2Point>& index_points,
+//           const vector<S2Point>& target_points) {
+//   // The template argument allows auxiliary data to be attached to each
+//   // point (in this case, the array index).
+//   S2PointIndex<int> index;
+//   for (int i = 0; i < index_points.size(); ++i) {
+//     index.Add(index_points[i], i);
+//   }
+//   S2ClosestPointQuery<int> query(&index);
+//   query.mutable_options()->set_max_results(5);
+//   for (const S2Point& target_point : target_points) {
+//     S2ClosestPointQueryPointTarget target(target_point);
+//     for (const auto& result : query.FindClosestPoints(&target)) {
+//       // The Result class contains the following methods:
+//       //   distance() is the distance to the target.
+//       //   point() is the indexed point.
+//       //   data() is the auxiliary data.
+//       DoSomething(target_point, result);
+//     }
+//   }
+// }
+//
+// The Data argument defaults to an empty class, which uses no additional
+// space beyond the S2Point itself.  In this case the Data argument is
+// required.  For example:
+//
+//   S2PointIndex<> index;
+//   index.Add(point);
+//
+// Points can be added or removed from the index at any time by calling Add()
+// or Remove().  However when the index is modified, you must call Init() on
+// each iterator before using it again (or simply create a new iterator).
+//
+//   index.Add(new_point, 123456);
+//   it.Init(&index);
+//   it.Seek(target.range_min());
+//
+// You can also access the index directly using the iterator interface.  For
+// example, here is how to iterate through all the points in a given S2CellId
+// "target_id":
+//
+//   S2PointIndex<int>::Iterator it(&index);
+//   it.Seek(target_id.range_min());
+//   for (; !it.done() && it.id() <= target_id.range_max(); it.Next()) {
+//     DoSomething(it.id(), it.point(), it.data());
+//   }
+//
+// TODO(ericv): Consider adding an S2PointIndexRegion class, which could be
+// used to efficiently compute coverings of a collection of S2Points.
+//
+// REQUIRES: "Data" has default and copy constructors.
+// REQUIRES: "Data" has operator== and operator<.
+template <class Data = std::tuple<> /*empty class*/>
+class S2PointIndex {
+ public:
+  // PointData is essentially std::pair with named fields.  It stores an
+  // S2Point and its associated data, taking advantage of the "empty base
+  // optimization" to ensure that no extra space is used when Data is empty.
+  class PointData {
+   public:
+    PointData() {}  // Needed by STL
+    PointData(const S2Point& point, const Data& data) : tuple_(point, data) {}
+
+    const S2Point& point() const { return std::get<0>(tuple_); }
+    const Data& data() const { return std::get<1>(tuple_); }
+
+    friend bool operator==(const PointData& x, const PointData& y) {
+      return x.tuple_ == y.tuple_;
+    }
+    friend bool operator<(const PointData& x, const PointData& y) {
+      return x.tuple_ < y.tuple_;
+    }
+
+   private:
+    // Note that std::tuple has special template magic to ensure that Data
+    // doesn't take up any space when it is empty.  (This is not true if you
+    // simply declare a member of type Data.)
+    std::tuple<S2Point, Data> tuple_;
+  };
+
+  // Default constructor.
+  S2PointIndex();
+
+  // Returns the number of points in the index.
+  int num_points() const;
+
+  // Adds the given point to the index.  Invalidates all iterators.
+  void Add(const S2Point& point, const Data& data);
+  void Add(const PointData& point_data);
+
+  // Convenience function for the case when Data is an empty class.
+  void Add(const S2Point& point);
+
+  // Removes the given point from the index.  Both the "point" and "data"
+  // fields must match the point to be removed.  Returns false if the given
+  // point was not present.  Invalidates all iterators.
+  bool Remove(const S2Point& point, const Data& data);
+  bool Remove(const PointData& point_data);
+
+  // Convenience function for the case when Data is an empty class.
+  void Remove(const S2Point& point);
+
+  // Resets the index to its original empty state.  Invalidates all iterators.
+  void Clear();
+
+ private:
+  // Defined here because the Iterator class below uses it.
+  using Map = absl::btree_multimap<S2CellId, PointData>;
+
+ public:
+  class Iterator {
+   public:
+    // Default constructor; must be followed by a call to Init().
+    Iterator();
+
+    // Convenience constructor that calls Init().
+    explicit Iterator(const S2PointIndex* index);
+
+    // Initializes an iterator for the given S2PointIndex.  If the index is
+    // non-empty, the iterator is positioned at the first cell.
+    //
+    // This method may be called multiple times, e.g. to make an iterator
+    // valid again after the index is modified.
+    void Init(const S2PointIndex* index);
+
+    // The S2CellId for the current index entry.
+    // REQUIRES: !done()
+    S2CellId id() const;
+
+    // The point associated with the current index entry.
+    // REQUIRES: !done()
+    const S2Point& point() const;
+
+    // The client-supplied data associated with the current index entry.
+    // REQUIRES: !done()
+    const Data& data() const;
+
+    // The (S2Point, data) pair associated with the current index entry.
+    const PointData& point_data() const;
+
+    // Returns true if the iterator is positioned past the last index entry.
+    bool done() const;
+
+    // Positions the iterator at the first index entry (if any).
+    void Begin();
+
+    // Positions the iterator so that done() is true.
+    void Finish();
+
+    // Advances the iterator to the next index entry.
+    // REQUIRES: !done()
+    void Next();
+
+    // If the iterator is already positioned at the beginning, returns false.
+    // Otherwise positions the iterator at the previous entry and returns true.
+    bool Prev();
+
+    // Positions the iterator at the first entry with id() >= target, or at the
+    // end of the index if no such entry exists.
+    void Seek(S2CellId target);
+
+   private:
+    const Map* map_;
+    typename Map::const_iterator iter_, end_;
+  };
+
+ private:
+  friend class Iterator;
+  Map map_;
+
+  S2PointIndex(const S2PointIndex&) = delete;
+  void operator=(const S2PointIndex&) = delete;
+};
+
+
+//////////////////   Implementation details follow   ////////////////////
+
+
+template <class Data>
+S2PointIndex<Data>::S2PointIndex() {
+}
+
+template <class Data>
+inline int S2PointIndex<Data>::num_points() const {
+  return map_.size();
+}
+
+template <class Data>
+void S2PointIndex<Data>::Add(const PointData& point_data) {
+  S2CellId id(point_data.point());
+  map_.insert(std::make_pair(id, point_data));
+}
+
+template <class Data>
+void S2PointIndex<Data>::Add(const S2Point& point, const Data& data) {
+  Add(PointData(point, data));
+}
+
+template <class Data>
+void S2PointIndex<Data>::Add(const S2Point& point) {
+  static_assert(std::is_empty<Data>::value, "Data must be empty");
+  Add(point, {});
+}
+
+template <class Data>
+bool S2PointIndex<Data>::Remove(const PointData& point_data) {
+  S2CellId id(point_data.point());
+  for (typename Map::iterator it = map_.lower_bound(id), end = map_.end();
+       it != end && it->first == id; ++it) {
+    if (it->second == point_data) {
+      map_.erase(it);
+      return true;
+    }
+  }
+  return false;
+}
+
+template <class Data>
+bool S2PointIndex<Data>::Remove(const S2Point& point, const Data& data) {
+  return Remove(PointData(point, data));
+}
+
+template <class Data>
+void S2PointIndex<Data>::Remove(const S2Point& point) {
+  static_assert(std::is_empty<Data>::value, "Data must be empty");
+  Remove(point, {});
+}
+
+template <class Data>
+void S2PointIndex<Data>::Clear() {
+  map_.clear();
+}
+
+template <class Data>
+inline S2PointIndex<Data>::Iterator::Iterator() : map_(nullptr) {
+}
+
+template <class Data>
+inline S2PointIndex<Data>::Iterator::Iterator(
+    const S2PointIndex<Data>* index) {
+  Init(index);
+}
+
+template <class Data>
+inline void S2PointIndex<Data>::Iterator::Init(
+    const S2PointIndex<Data>* index) {
+  map_ = &index->map_;
+  iter_ = map_->begin();
+  end_ = map_->end();
+}
+
+template <class Data>
+inline S2CellId S2PointIndex<Data>::Iterator::id() const {
+  S2_DCHECK(!done());
+  return iter_->first;
+}
+
+template <class Data>
+inline const S2Point& S2PointIndex<Data>::Iterator::point() const {
+  S2_DCHECK(!done());
+  return iter_->second.point();
+}
+
+template <class Data>
+inline const Data& S2PointIndex<Data>::Iterator::data() const {
+  S2_DCHECK(!done());
+  return iter_->second.data();
+}
+
+template <class Data>
+inline const typename S2PointIndex<Data>::PointData&
+S2PointIndex<Data>::Iterator::point_data() const {
+  S2_DCHECK(!done());
+  return iter_->second;
+}
+
+template <class Data>
+inline bool S2PointIndex<Data>::Iterator::done() const {
+  return iter_ == end_;
+}
+
+template <class Data>
+inline void S2PointIndex<Data>::Iterator::Begin() {
+  iter_ = map_->begin();
+}
+
+template <class Data>
+inline void S2PointIndex<Data>::Iterator::Finish() {
+  iter_ = end_;
+}
+
+template <class Data>
+inline void S2PointIndex<Data>::Iterator::Next() {
+  S2_DCHECK(!done());
+  ++iter_;
+}
+
+template <class Data>
+inline bool S2PointIndex<Data>::Iterator::Prev() {
+  if (iter_ == map_->begin()) return false;
+  --iter_;
+  return true;
+}
+
+template <class Data>
+inline void S2PointIndex<Data>::Iterator::Seek(S2CellId target) {
+  iter_ = map_->lower_bound(target);
+}
+
+#endif  // S2_S2POINT_INDEX_H_
diff --git a/src/s2/s2point_region.cc b/src/s2/s2point_region.cc
new file mode 100644 (file)
index 0000000..be4edd2
--- /dev/null
@@ -0,0 +1,72 @@
+// Copyright 2005 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// Author: ericv@google.com (Eric Veach)
+
+#include "s2/s2point_region.h"
+
+#include "s2/base/logging.h"
+#include "s2/util/coding/coder.h"
+#include "s2/s2cap.h"
+#include "s2/s2cell.h"
+#include "s2/s2latlng.h"
+#include "s2/s2latlng_rect.h"
+#include "s2/s2pointutil.h"
+
+static const unsigned char kCurrentLosslessEncodingVersionNumber = 1;
+
+S2PointRegion::~S2PointRegion() {
+}
+
+S2PointRegion* S2PointRegion::Clone() const {
+  return new S2PointRegion(point_);
+}
+
+S2Cap S2PointRegion::GetCapBound() const {
+  return S2Cap::FromPoint(point_);
+}
+
+S2LatLngRect S2PointRegion::GetRectBound() const {
+  S2LatLng ll(point_);
+  return S2LatLngRect(ll, ll);
+}
+
+bool S2PointRegion::MayIntersect(const S2Cell& cell) const {
+  return cell.Contains(point_);
+}
+
+void S2PointRegion::Encode(Encoder* encoder) const {
+  encoder->Ensure(30);  // sufficient
+
+  encoder->put8(kCurrentLosslessEncodingVersionNumber);
+  for (int i = 0; i < 3; ++i) {
+    encoder->putdouble(point_[i]);
+  }
+  S2_DCHECK_GE(encoder->avail(), 0);
+}
+
+bool S2PointRegion::Decode(Decoder* decoder) {
+  if (decoder->avail() < sizeof(unsigned char) + 3 * sizeof(double))
+    return false;
+  unsigned char version = decoder->get8();
+  if (version > kCurrentLosslessEncodingVersionNumber) return false;
+
+  for (int i = 0; i < 3; ++i) {
+    point_[i] = decoder->getdouble();
+  }
+  if (!S2::IsUnitLength(point_)) return false;
+
+  return true;
+}
diff --git a/src/s2/s2point_region.h b/src/s2/s2point_region.h
new file mode 100644 (file)
index 0000000..9123d6b
--- /dev/null
@@ -0,0 +1,76 @@
+// Copyright 2005 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// Author: ericv@google.com (Eric Veach)
+
+#ifndef S2_S2POINT_REGION_H_
+#define S2_S2POINT_REGION_H_
+
+#include "s2/base/logging.h"
+#include "s2/_fp_contract_off.h"
+#include "s2/s1angle.h"
+#include "s2/s2pointutil.h"
+#include "s2/s2region.h"
+#include "absl/base/macros.h"
+
+class Decoder;
+class Encoder;
+class S2Cap;
+class S2Cell;
+class S2LatLngRect;
+
+// An S2PointRegion is a region that contains a single point.  It is more
+// expensive than the raw S2Point type and is useful mainly for completeness.
+//
+// This class is intended to be copied by value as desired.  It uses
+// the default copy constructor and assignment operator.
+class S2PointRegion final : public S2Region {
+ public:
+  // Create a region containing the given point, which must be unit length.
+  explicit S2PointRegion(const S2Point& point);
+
+  ~S2PointRegion() override;
+
+  const S2Point& point() const { return point_; }
+
+  ////////////////////////////////////////////////////////////////////////
+  // S2Region interface (see s2region.h for details):
+
+  S2PointRegion* Clone() const override;
+  S2Cap GetCapBound() const override;
+  S2LatLngRect GetRectBound() const override;
+  bool Contains(const S2Cell& cell) const override { return false; }
+  bool MayIntersect(const S2Cell& cell) const override;
+  bool Contains(const S2Point& p) const override { return (point_ == p); }
+
+  // Appends a serialized representation of the S2Point to "encoder".
+  //
+  // REQUIRES: "encoder" uses the default constructor, so that its buffer
+  //           can be enlarged as necessary by calling Ensure(int).
+  void Encode(Encoder* const encoder) const;
+
+  // Decodes an S2Point encoded with Encode().  Returns true on success.
+  // (Returns false if the encoded point is not unit length.)
+  bool Decode(Decoder* const decoder);
+
+ private:
+  S2Point point_;
+};
+
+inline S2PointRegion::S2PointRegion(const S2Point& point) : point_(point) {
+  S2_DCHECK(S2::IsUnitLength(point));
+}
+
+#endif  // S2_S2POINT_REGION_H_
diff --git a/src/s2/s2point_span.h b/src/s2/s2point_span.h
new file mode 100644 (file)
index 0000000..9423518
--- /dev/null
@@ -0,0 +1,57 @@
+// Copyright 2018 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// Author: ericv@google.com (Eric Veach)
+
+#ifndef S2_S2POINT_SPAN_H_
+#define S2_S2POINT_SPAN_H_
+
+#include "s2/base/logging.h"
+#include "absl/types/span.h"
+#include "s2/s2point.h"
+
+// S2PointSpan represents a view of an S2Point array.  It is used to pass
+// vertex arrays to functions that don't care about the actual array type
+// (e.g. std::vector<S2Point> or S2Point[]).
+//
+// NOTE: S2PointSpan has an implicit constructor from any container type with
+// data() and size() methods (such as std::vector and std::array).  Therefore
+// you can use such containers as arguments for any S2PointSpan parameter.
+using S2PointSpan = absl::Span<const S2Point>;
+
+// Like S2PointSpan, except that operator[] maps index values in the range
+// [n, 2*n-1] to the range [0, n-1] by subtracting n (where n == size()).
+// In other words, two full copies of the vertex array are available.  (This
+// is a compromise between convenience and efficiency, since computing the
+// index modulo "n" is surprisingly expensive.)
+//
+// This property is useful for implementing algorithms where the elements of
+// the span represent the vertices of a loop.
+class S2PointLoopSpan : public S2PointSpan {
+ public:
+  // Inherit all constructors.
+  using absl::Span<const S2Point>::Span;
+
+  // Like operator[], but allows index values in the range [0, 2*size()-1]
+  // where each index i >= size() is mapped to i - size().
+  reference operator[](int i) const noexcept {
+    S2_DCHECK_GE(i, 0);
+    S2_DCHECK_LT(i, 2 * size());
+    int j = i - static_cast<int>(size());
+    return S2PointSpan::operator[](j < 0 ? i : j);
+  }
+};
+
+#endif  // S2_S2POINT_SPAN_H_
diff --git a/src/s2/s2point_vector_shape.h b/src/s2/s2point_vector_shape.h
new file mode 100644 (file)
index 0000000..4aa5bc9
--- /dev/null
@@ -0,0 +1,127 @@
+// Copyright 2013 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// Author: ericv@google.com (Eric Veach)
+
+#ifndef S2_S2POINT_VECTOR_SHAPE_H_
+#define S2_S2POINT_VECTOR_SHAPE_H_
+
+#include <vector>
+#include "s2/encoded_s2point_vector.h"
+#include "s2/s2shape.h"
+
+// S2PointVectorShape is an S2Shape representing a set of S2Points. Each point
+// is reprsented as a degenerate edge with the same starting and ending
+// vertices.
+//
+// This class is useful for adding a collection of points to an S2ShapeIndex.
+class S2PointVectorShape : public S2Shape {
+ public:
+  static constexpr TypeTag kTypeTag = 3;
+
+  // Constructs an empty point vector.
+  S2PointVectorShape() {}
+
+  // Constructs an S2PointVectorShape from a vector of points.
+  explicit S2PointVectorShape(std::vector<S2Point> points) {
+    points_ = std::move(points);
+  }
+
+  ~S2PointVectorShape() override = default;
+
+  int num_points() const { return static_cast<int>(points_.size()); }
+  const S2Point& point(int i) const { return points_[i]; }
+
+  // Appends an encoded representation of the S2PointVectorShape to "encoder".
+  //
+  // REQUIRES: "encoder" uses the default constructor, so that its buffer
+  //           can be enlarged as necessary by calling Ensure(int).
+  void Encode(Encoder* encoder,
+              s2coding::CodingHint hint = s2coding::CodingHint::COMPACT) const {
+    s2coding::EncodeS2PointVector(points_, hint, encoder);
+  }
+
+  // Decodes an S2PointVectorShape, returning true on success.  (The method
+  // name is chosen for compatibility with EncodedS2PointVectorShape below.)
+  bool Init(Decoder* decoder) {
+    s2coding::EncodedS2PointVector points;
+    if (!points.Init(decoder)) return false;
+    points_ = points.Decode();
+    return true;
+  }
+
+  // S2Shape interface:
+  int num_edges() const final { return num_points(); }
+  Edge edge(int e) const final { return Edge(points_[e], points_[e]); }
+  int dimension() const final { return 0; }
+  ReferencePoint GetReferencePoint() const final {
+    return ReferencePoint::Contained(false);
+  }
+  int num_chains() const final { return num_points(); }
+  Chain chain(int i) const final { return Chain(i, 1); }
+  Edge chain_edge(int i, int j) const final {
+    S2_DCHECK_EQ(j, 0);
+    return Edge(points_[i], points_[i]);
+  }
+  ChainPosition chain_position(int e) const final {
+    return ChainPosition(e, 0);
+  }
+  TypeTag type_tag() const override { return kTypeTag; }
+
+ private:
+  std::vector<S2Point> points_;
+};
+
+// Exactly like S2PointVectorShape, except that the points are kept in an
+// encoded form and are decoded only as they are accessed.  This allows for
+// very fast initialization and no additional memory use beyond the encoded
+// data.  The encoded data is not owned by this class; typically it points
+// into a large contiguous buffer that contains other encoded data as well.
+class EncodedS2PointVectorShape : public S2Shape {
+ public:
+  // Constructs an uninitialized object; requires Init() to be called.
+  EncodedS2PointVectorShape() {}
+
+  // Initializes an EncodedS2PointVectorShape.
+  //
+  // REQUIRES: The Decoder data buffer must outlive this object.
+  bool Init(Decoder* decoder) { return points_.Init(decoder); }
+
+  int num_points() const { return static_cast<int>(points_.size()); }
+  S2Point point(int i) const { return points_[i]; }
+
+  // S2Shape interface:
+  int num_edges() const final { return num_points(); }
+  Edge edge(int e) const final { return Edge(points_[e], points_[e]); }
+  int dimension() const final { return 0; }
+  ReferencePoint GetReferencePoint() const final {
+    return ReferencePoint::Contained(false);
+  }
+  int num_chains() const final { return num_points(); }
+  Chain chain(int i) const final { return Chain(i, 1); }
+  Edge chain_edge(int i, int j) const final {
+    S2_DCHECK_EQ(j, 0);
+    return Edge(points_[i], points_[i]);
+  }
+  ChainPosition chain_position(int e) const final {
+    return ChainPosition(e, 0);
+  }
+
+ private:
+  s2coding::EncodedS2PointVector points_;
+};
+
+
+#endif  // S2_S2POINT_VECTOR_SHAPE_H_
diff --git a/src/s2/s2pointutil.cc b/src/s2/s2pointutil.cc
new file mode 100644 (file)
index 0000000..de66a70
--- /dev/null
@@ -0,0 +1,131 @@
+// Copyright 2005 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// Author: ericv@google.com (Eric Veach)
+
+#include "s2/s2pointutil.h"
+
+#include <cfloat>
+#include <cmath>
+
+using std::fabs;
+
+namespace S2 {
+
+bool IsUnitLength(const S2Point& p) {
+  // Normalize() is guaranteed to return a vector whose L2-norm differs from 1
+  // by less than 2 * DBL_EPSILON.  Thus the squared L2-norm differs by less
+  // than 4 * DBL_EPSILON.  The actual calculated Norm2() can have up to 1.5 *
+  // DBL_EPSILON of additional error.  The total error of 5.5 * DBL_EPSILON
+  // can then be rounded down since the result must be a representable
+  // double-precision value.
+  return fabs(p.Norm2() - 1) <= 5 * DBL_EPSILON;  // About 1.11e-15
+}
+
+bool ApproxEquals(const S2Point& a, const S2Point& b, S1Angle max_error) {
+  S2_DCHECK_NE(a, S2Point());
+  S2_DCHECK_NE(b, S2Point());
+  return S1Angle(a, b) <= max_error;
+}
+
+S2Point Ortho(const S2Point& a) {
+#ifdef S2_TEST_DEGENERACIES
+  // Vector3::Ortho() always returns a point on the X-Y, Y-Z, or X-Z planes.
+  // This leads to many more degenerate cases in polygon operations.
+  return a.Ortho();
+#else
+  int k = a.LargestAbsComponent() - 1;
+  if (k < 0) k = 2;
+  S2Point temp(0.012, 0.0053, 0.00457);
+  temp[k] = 1;
+  return a.CrossProd(temp).Normalize();
+#endif
+}
+
+Vector3_d RobustCrossProd(const S2Point& a, const S2Point& b) {
+  // The direction of a.CrossProd(b) becomes unstable as (a + b) or (a - b)
+  // approaches zero.  This leads to situations where a.CrossProd(b) is not
+  // very orthogonal to "a" and/or "b".  We could fix this using Gram-Schmidt,
+  // but we also want b.RobustCrossProd(a) == -a.RobustCrossProd(b).
+  //
+  // The easiest fix is to just compute the cross product of (b+a) and (b-a).
+  // Mathematically, this cross product is exactly twice the cross product of
+  // "a" and "b", but it has the numerical advantage that (b+a) and (b-a)
+  // are always perpendicular (since "a" and "b" are unit length).  This
+  // yields a result that is nearly orthogonal to both "a" and "b" even if
+  // these two values differ only in the lowest bit of one component.
+
+  S2_DCHECK(IsUnitLength(a));
+  S2_DCHECK(IsUnitLength(b));
+  Vector3_d x = (b + a).CrossProd(b - a);
+  if (x != S2Point(0, 0, 0)) return x;
+
+  // The only result that makes sense mathematically is to return zero, but
+  // we find it more convenient to return an arbitrary orthogonal vector.
+  return Ortho(a);
+}
+
+S2Point Rotate(const S2Point& p, const S2Point& axis, S1Angle angle) {
+  S2_DCHECK(IsUnitLength(p));
+  S2_DCHECK(IsUnitLength(axis));
+  // Let M be the plane through P that is perpendicular to "axis", and let
+  // "center" be the point where M intersects "axis".  We construct a
+  // right-handed orthogonal frame (dx, dy, center) such that "dx" is the
+  // vector from "center" to P, and "dy" has the same length as "dx".  The
+  // result can then be expressed as (cos(angle)*dx + sin(angle)*dy + center).
+  S2Point center = p.DotProd(axis) * axis;
+  S2Point dx = p - center;
+  S2Point dy = axis.CrossProd(p);
+  // Mathematically the result is unit length, but normalization is necessary
+  // to ensure that numerical errors don't accumulate.
+  return (cos(angle) * dx + sin(angle) * dy + center).Normalize();
+}
+
+Matrix3x3_d GetFrame(const S2Point& z) {
+  Matrix3x3_d m;
+  GetFrame(z, &m);
+  return m;
+}
+
+void GetFrame(const S2Point& z, Matrix3x3_d* m) {
+  S2_DCHECK(IsUnitLength(z));
+  m->SetCol(2, z);
+  m->SetCol(1, Ortho(z));
+  m->SetCol(0, m->Col(1).CrossProd(z));  // Already unit-length.
+}
+
+S2Point ToFrame(const Matrix3x3_d& m, const S2Point& p) {
+  // The inverse of an orthonormal matrix is its transpose.
+  return m.Transpose() * p;
+}
+
+S2Point FromFrame(const Matrix3x3_d& m, const S2Point& q) {
+  return m * q;
+}
+
+bool SimpleCCW(const S2Point& a, const S2Point& b, const S2Point& c) {
+  // We compute the signed volume of the parallelepiped ABC.  The usual
+  // formula for this is (AxB).C, but we compute it here using (CxA).B
+  // in order to ensure that ABC and CBA are not both CCW.  This follows
+  // from the following identities (which are true numerically, not just
+  // mathematically):
+  //
+  //     (1) x.CrossProd(y) == -(y.CrossProd(x))
+  //     (2) (-x).DotProd(y) == -(x.DotProd(y))
+
+  return c.CrossProd(a).DotProd(b) > 0;
+}
+
+}  // namespace S2
diff --git a/src/s2/s2pointutil.h b/src/s2/s2pointutil.h
new file mode 100644 (file)
index 0000000..b2aa0cf
--- /dev/null
@@ -0,0 +1,139 @@
+// Copyright 2005 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// Author: ericv@google.com (Eric Veach)
+//
+// Defines additional operations for points on the unit sphere (in addition to
+// the standard vector operations defined in "util/math/vector.h").
+
+#ifndef S2_S2POINTUTIL_H_
+#define S2_S2POINTUTIL_H_
+
+#include "s2/_fp_contract_off.h"
+#include "s2/s1angle.h"
+#include "s2/s2point.h"
+#include "s2/util/math/matrix3x3.h"
+
+// S2 is a namespace for constants and simple utility functions that are used
+// throughout the S2 library.  The name "S2" is derived from the mathematical
+// symbol for the two-dimensional unit sphere (note that the "2" refers to the
+// dimension of the surface, not the space it is embedded in).
+namespace S2 {
+
+// Return a unique "origin" on the sphere for operations that need a fixed
+// reference point.  In particular, this is the "point at infinity" used for
+// point-in-polygon testing (by counting the number of edge crossings).
+inline S2Point Origin();
+
+// Return true if the given point is approximately unit length
+// (this is mainly useful for assertions).
+bool IsUnitLength(const S2Point& p);
+
+// Return true if two points are within the given distance of each other (this
+// is mainly useful for testing). It is an error if either point is a
+// zero-length vector (default S2Point), but this is only checked in debug mode.
+// In non-debug mode it will always return true.
+bool ApproxEquals(const S2Point& a, const S2Point& b,
+                  S1Angle max_error = S1Angle::Radians(1e-15));
+
+// Return a unit-length vector that is orthogonal to "a".  Satisfies
+// Ortho(-a) = -Ortho(a) for all a.
+//
+// Note that Vector3_d also defines an "Ortho" method, but this one is
+// preferred for use in S2 code because it explicitly tries to avoid result
+// result coordinates that are zero.  (This is a performance optimization that
+// reduces the amount of time spent in functions which handle degeneracies.)
+S2Point Ortho(const S2Point& a);
+
+// Return a vector "c" that is orthogonal to the given unit-length vectors
+// "a" and "b".  This function is similar to a.CrossProd(b) except that it
+// does a better job of ensuring orthogonality when "a" is nearly parallel
+// to "b", and it returns a non-zero result even when a == b or a == -b.
+//
+// It satisfies the following properties (RCP == RobustCrossProd):
+//
+//   (1) RCP(a,b) != 0 for all a, b
+//   (2) RCP(b,a) == -RCP(a,b) unless a == b or a == -b
+//   (3) RCP(-a,b) == -RCP(a,b) unless a == b or a == -b
+//   (4) RCP(a,-b) == -RCP(a,b) unless a == b or a == -b
+//
+// The result is not guaranteed to be unit length.
+S2Point RobustCrossProd(const S2Point& a, const S2Point& b);
+
+// Rotate the given point about the given axis by the given angle.  "p" and
+// "axis" must be unit length; "angle" has no restrictions (e.g., it can be
+// positive, negative, greater than 360 degrees, etc).
+S2Point Rotate(const S2Point& p, const S2Point& axis, S1Angle angle);
+
+// Extend the given point "z" on the unit sphere into a right-handed
+// coordinate frame of unit-length column vectors m = (x,y,z).  Note that the
+// vectors (x,y) are an orthonormal frame for the tangent space at "z", while
+// "z" itself is an orthonormal frame for the normal space at "z".
+Matrix3x3_d GetFrame(const S2Point& z);
+void GetFrame(const S2Point& z, Matrix3x3_d* m);
+
+// Given an orthonormal basis "m" of column vectors and a point "p", return
+// the coordinates of "p" with respect to the basis "m".  The resulting
+// point "q" satisfies the identity (m * q == p).
+S2Point ToFrame(const Matrix3x3_d& m, const S2Point& p);
+
+// Given an orthonormal basis "m" of column vectors and a point "q" with
+// respect to that basis, return the equivalent point "p" with respect to
+// the standard axis-aligned basis.  The result satisfies (p == m * q).
+Matrix3x3_d GetFrame(const S2Point& z);
+S2Point FromFrame(const Matrix3x3_d& m, const S2Point& q);
+
+// Return true if the points A, B, C are strictly counterclockwise.  Return
+// false if the points are clockwise or collinear (i.e. if they are all
+// contained on some great circle).
+//
+// Due to numerical errors, situations may arise that are mathematically
+// impossible, e.g. ABC may be considered strictly CCW while BCA is not.
+// However, the implementation guarantees the following:
+//
+//   If SimpleCCW(a,b,c), then !SimpleCCW(c,b,a) for all a,b,c.
+// ABSL_DEPRECATED("Use s2pred::Sign instead.")
+bool SimpleCCW(const S2Point& a, const S2Point& b, const S2Point& c);
+
+
+//////////////////   Implementation details follow   ////////////////////
+
+// Uncomment the following line for testing purposes only.
+// #define S2_TEST_DEGENERACIES
+
+inline S2Point Origin() {
+#ifdef S2_TEST_DEGENERACIES
+  // This value makes polygon operations much slower, because it greatly
+  // increases the number of degenerate cases that need to be handled using
+  // s2pred::ExpensiveSign().
+  return S2Point(0, 0, 1);
+#else
+  // The origin should not be a point that is commonly used in edge tests in
+  // order to avoid triggering code to handle degenerate cases.  (This rules
+  // out the north and south poles.)  It should also not be on the boundary of
+  // any low-level S2Cell for the same reason.
+  //
+  // The point chosen here is about 66km from the north pole towards the East
+  // Siberian Sea.  See the unittest for more details.  It is written out
+  // explicitly using floating-point literals because the optimizer doesn't
+  // seem willing to evaluate Normalize() at compile time.
+  return S2Point(-0.0099994664350250197, 0.0025924542609324121,
+                 0.99994664350250195);
+#endif
+}
+
+}  // namespace S2
+
+#endif  // S2_S2POINTUTIL_H_
diff --git a/src/s2/s2polygon.cc b/src/s2/s2polygon.cc
new file mode 100644 (file)
index 0000000..60ec5eb
--- /dev/null
@@ -0,0 +1,1564 @@
+// Copyright 2005 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// Author: ericv@google.com (Eric Veach)
+
+#include "s2/s2polygon.h"
+
+#include <algorithm>
+#include <array>
+#include <cmath>
+#include <cstddef>
+#include <set>
+#include <stack>
+#include <utility>
+#include <vector>
+
+
+#include "s2/base/casts.h"
+#include "s2/base/commandlineflags.h"
+#include "s2/base/logging.h"
+#include "s2/mutable_s2shape_index.h"
+#include "s2/s1angle.h"
+#include "s2/s1interval.h"
+#include "s2/s2boolean_operation.h"
+#include "s2/s2builder.h"
+#include "s2/s2builderutil_s2polygon_layer.h"
+#include "s2/s2builderutil_s2polyline_layer.h"
+#include "s2/s2builderutil_s2polyline_vector_layer.h"
+#include "s2/s2builderutil_snap_functions.h"
+#include "s2/s2cap.h"
+#include "s2/s2cell.h"
+#include "s2/s2cell_id.h"
+#include "s2/s2cell_union.h"
+#include "s2/s2closest_edge_query.h"
+#include "s2/s2contains_point_query.h"
+#include "s2/s2coords.h"
+#include "s2/s2crossing_edge_query.h"
+#include "s2/s2debug.h"
+#include "s2/s2edge_clipping.h"
+#include "s2/s2edge_crosser.h"
+#include "s2/s2edge_crossings.h"
+#include "s2/s2error.h"
+#include "s2/s2latlng.h"
+#include "s2/s2latlng_rect.h"
+#include "s2/s2latlng_rect_bounder.h"
+#include "s2/s2loop.h"
+#include "s2/s2measures.h"
+#include "s2/s2metrics.h"
+#include "s2/s2point_compression.h"
+#include "s2/s2polyline.h"
+#include "s2/s2predicates.h"
+#include "s2/s2shape_index.h"
+#include "s2/s2shape_index_region.h"
+#include "s2/s2shapeutil_visit_crossing_edge_pairs.h"
+#include "absl/container/fixed_array.h"
+#include "absl/container/inlined_vector.h"
+#include "absl/memory/memory.h"
+#include "s2/util/coding/coder.h"
+
+using absl::make_unique;
+using s2builderutil::IdentitySnapFunction;
+using s2builderutil::S2PolygonLayer;
+using s2builderutil::S2PolylineLayer;
+using s2builderutil::S2PolylineVectorLayer;
+using s2builderutil::S2CellIdSnapFunction;
+using std::fabs;
+using std::max;
+using std::min;
+using std::pair;
+using std::set;
+using std::sqrt;
+using std::unique_ptr;
+using std::vector;
+
+DEFINE_bool(
+    s2polygon_lazy_indexing, true,
+    "Build the S2ShapeIndex only when it is first needed.  This can save "
+    "significant amounts of memory and time when geometry is constructed but "
+    "never queried, for example when converting from one format to another.");
+
+// The maximum number of loops we'll allow when decoding a polygon.
+// The default value of 10 million is 200x bigger than the number of
+DEFINE_int32(
+    s2polygon_decode_max_num_loops, 10000000,
+    "The upper limit on the number of loops that are allowed by the "
+    "S2Polygon::Decode method.");
+
+// When adding a new encoding, be aware that old binaries will not
+// be able to decode it.
+static const unsigned char kCurrentUncompressedEncodingVersionNumber = 1;
+static const unsigned char kCurrentCompressedEncodingVersionNumber = 4;
+
+S2Polygon::S2Polygon()
+    : s2debug_override_(S2Debug::ALLOW),
+      error_inconsistent_loop_orientations_(false),
+      num_vertices_(0),
+      unindexed_contains_calls_(0) {
+}
+
+S2Polygon::S2Polygon(vector<unique_ptr<S2Loop>> loops, S2Debug override)
+    : s2debug_override_(override) {
+  InitNested(std::move(loops));
+}
+
+S2Polygon::S2Polygon(unique_ptr<S2Loop> loop, S2Debug override)
+    : s2debug_override_(override) {
+  Init(std::move(loop));
+}
+
+S2Polygon::S2Polygon(const S2Cell& cell)
+    : s2debug_override_(S2Debug::ALLOW) {
+  Init(make_unique<S2Loop>(cell));
+}
+
+void S2Polygon::set_s2debug_override(S2Debug override) {
+  s2debug_override_ = override;
+}
+
+S2Debug S2Polygon::s2debug_override() const {
+  return s2debug_override_;
+}
+
+void S2Polygon::Copy(const S2Polygon* src) {
+  ClearLoops();
+  for (int i = 0; i < src->num_loops(); ++i) {
+    loops_.emplace_back(src->loop(i)->Clone());
+  }
+  s2debug_override_ = src->s2debug_override_;
+  // Don't copy error_inconsistent_loop_orientations_, since this is not a
+  // property of the polygon but only of the way the polygon was constructed.
+  num_vertices_ = src->num_vertices();
+  unindexed_contains_calls_.store(0, std::memory_order_relaxed);
+  bound_ = src->bound_;
+  subregion_bound_ = src->subregion_bound_;
+  InitIndex();  // TODO(ericv): Copy the index efficiently.
+}
+
+S2Polygon* S2Polygon::Clone() const {
+  S2Polygon* result = new S2Polygon;
+  result->Copy(this);
+  return result;
+}
+
+vector<unique_ptr<S2Loop>> S2Polygon::Release() {
+  // Reset the polygon to be empty.
+  vector<unique_ptr<S2Loop>> loops;
+  loops.swap(loops_);
+  ClearLoops();
+  num_vertices_ = 0;
+  bound_ = S2LatLngRect::Empty();
+  subregion_bound_ = S2LatLngRect::Empty();
+  return loops;
+}
+
+void S2Polygon::ClearLoops() {
+  ClearIndex();
+  loops_.clear();
+  error_inconsistent_loop_orientations_ = false;
+}
+
+S2Polygon::~S2Polygon() {
+  ClearLoops();
+}
+
+bool S2Polygon::IsValid() const {
+  S2Error error;
+  if (FindValidationError(&error)) {
+    S2_LOG_IF(ERROR, FLAGS_s2debug) << error;
+    return false;
+  }
+  return true;
+}
+
+bool S2Polygon::FindValidationError(S2Error* error) const {
+  for (int i = 0; i < num_loops(); ++i) {
+    // Check for loop errors that don't require building an S2ShapeIndex.
+    if (loop(i)->FindValidationErrorNoIndex(error)) {
+      error->Init(error->code(),
+                  "Loop %d: %s", i, error->text().c_str());
+      return true;
+    }
+    // Check that no loop is empty, and that the full loop only appears in the
+    // full polygon.
+    if (loop(i)->is_empty()) {
+      error->Init(S2Error::POLYGON_EMPTY_LOOP,
+                  "Loop %d: empty loops are not allowed", i);
+      return true;
+    }
+    if (loop(i)->is_full() && num_loops() > 1) {
+      error->Init(S2Error::POLYGON_EXCESS_FULL_LOOP,
+                  "Loop %d: full loop appears in non-full polygon", i);
+      return true;
+    }
+  }
+
+  // Check for loop self-intersections and loop pairs that cross
+  // (including duplicate edges and vertices).
+  if (s2shapeutil::FindSelfIntersection(index_, error)) return true;
+
+  // Check whether InitOriented detected inconsistent loop orientations.
+  if (error_inconsistent_loop_orientations_) {
+    error->Init(S2Error::POLYGON_INCONSISTENT_LOOP_ORIENTATIONS,
+                "Inconsistent loop orientations detected");
+    return true;
+  }
+
+  // Finally, verify the loop nesting hierarchy.
+  return FindLoopNestingError(error);
+}
+
+bool S2Polygon::FindLoopNestingError(S2Error* error) const {
+  // First check that the loop depths make sense.
+  for (int last_depth = -1, i = 0; i < num_loops(); ++i) {
+    int depth = loop(i)->depth();
+    if (depth < 0 || depth > last_depth + 1) {
+      error->Init(S2Error::POLYGON_INVALID_LOOP_DEPTH,
+                  "Loop %d: invalid loop depth (%d)", i, depth);
+      return true;
+    }
+    last_depth = depth;
+  }
+  // Then check that they correspond to the actual loop nesting.  This test
+  // is quadratic in the number of loops but the cost per iteration is small.
+  for (int i = 0; i < num_loops(); ++i) {
+    int last = GetLastDescendant(i);
+    for (int j = 0; j < num_loops(); ++j) {
+      if (i == j) continue;
+      bool nested = (j >= i + 1) && (j <= last);
+      const bool reverse_b = false;
+      if (loop(i)->ContainsNonCrossingBoundary(loop(j), reverse_b) != nested) {
+        error->Init(S2Error::POLYGON_INVALID_LOOP_NESTING,
+                    "Invalid nesting: loop %d should %scontain loop %d",
+                    i, nested ? "" : "not ", j);
+        return true;
+      }
+    }
+  }
+  return false;
+}
+
+void S2Polygon::InsertLoop(S2Loop* new_loop, S2Loop* parent,
+                           LoopMap* loop_map) {
+  vector<S2Loop*>* children;
+  for (bool done = false; !done; ) {
+    children = &(*loop_map)[parent];
+    done = true;
+    for (S2Loop* child : *children) {
+      if (child->ContainsNested(new_loop)) {
+        parent = child;
+        done = false;
+        break;
+      }
+    }
+  }
+
+  // Some of the children of the parent loop may now be children of
+  // the new loop.
+  vector<S2Loop*>* new_children = &(*loop_map)[new_loop];
+  for (int i = 0; i < children->size();) {
+    S2Loop* child = (*children)[i];
+    if (new_loop->ContainsNested(child)) {
+      new_children->push_back(child);
+      children->erase(children->begin() + i);
+    } else {
+      ++i;
+    }
+  }
+  children->push_back(new_loop);
+}
+
+void S2Polygon::InitLoops(LoopMap* loop_map) {
+  std::stack<S2Loop*> loop_stack({nullptr});
+  int depth = -1;
+  while (!loop_stack.empty()) {
+    S2Loop* loop = loop_stack.top();
+    loop_stack.pop();
+    if (loop != nullptr) {
+      depth = loop->depth();
+      loops_.emplace_back(loop);
+    }
+    const vector<S2Loop*>& children = (*loop_map)[loop];
+    for (int i = children.size() - 1; i >= 0; --i) {
+      S2Loop* child = children[i];
+      S2_DCHECK(child != nullptr);
+      child->set_depth(depth + 1);
+      loop_stack.push(child);
+    }
+  }
+}
+
+void S2Polygon::InitIndex() {
+  S2_DCHECK_EQ(0, index_.num_shape_ids());
+  index_.Add(make_unique<Shape>(this));
+  if (!FLAGS_s2polygon_lazy_indexing) {
+    index_.ForceBuild();
+  }
+  if (FLAGS_s2debug && s2debug_override_ == S2Debug::ALLOW) {
+    // Note that FLAGS_s2debug is false in optimized builds (by default).
+    S2_CHECK(IsValid());
+  }
+}
+
+void S2Polygon::ClearIndex() {
+  unindexed_contains_calls_.store(0, std::memory_order_relaxed);
+  index_.Clear();
+}
+
+void S2Polygon::InitNested(vector<unique_ptr<S2Loop>> loops) {
+  ClearLoops();
+  loops_.swap(loops);
+
+  if (num_loops() == 1) {
+    InitOneLoop();
+    return;
+  }
+  LoopMap loop_map;
+  for (int i = 0; i < num_loops(); ++i) {
+    InsertLoop(loop(i), nullptr, &loop_map);
+  }
+  // Reorder the loops in depth-first traversal order.
+  // Loops are now owned by loop_map, don't let them be
+  // deleted by clear().
+  for (auto& loop : loops_) loop.release();
+  loops_.clear();
+  InitLoops(&loop_map);
+
+  // Compute num_vertices_, bound_, subregion_bound_.
+  InitLoopProperties();
+}
+
+void S2Polygon::Init(unique_ptr<S2Loop> loop) {
+  // We don't allow empty loops in the other Init() methods because deleting
+  // them changes the number of loops, which is awkward to handle.
+  ClearLoops();
+  if (loop->is_empty()) {
+    InitLoopProperties();
+  } else {
+    loops_.push_back(std::move(loop));
+    InitOneLoop();
+  }
+}
+
+// This is an internal method that expects that loops_ has already been
+// initialized with a single non-empty loop.
+void S2Polygon::InitOneLoop() {
+  S2_DCHECK_EQ(1, num_loops());
+  S2Loop* loop = loops_[0].get();
+  loop->set_depth(0);
+  error_inconsistent_loop_orientations_ = false;
+  num_vertices_ = loop->num_vertices();
+  bound_ = loop->GetRectBound();
+  subregion_bound_ = S2LatLngRectBounder::ExpandForSubregions(bound_);
+  InitIndex();
+}
+
+void S2Polygon::InitOriented(vector<unique_ptr<S2Loop>> loops) {
+  // Here is the algorithm:
+  //
+  // 1. Remember which of the given loops contain S2::Origin().
+  //
+  // 2. Invert loops as necessary to ensure that they are nestable (i.e., no
+  //    loop contains the complement of any other loop).  This may result in a
+  //    set of loops corresponding to the complement of the given polygon, but
+  //    we will fix that problem later.
+  //
+  //    We make the loops nestable by first normalizing all the loops (i.e.,
+  //    inverting any loops whose curvature is negative).  This handles
+  //    all loops except those whose curvature is very close to zero
+  //    (within the maximum error tolerance).  Any such loops are inverted if
+  //    and only if they contain S2::Origin().  (In theory this step is only
+  //    necessary if there are at least two such loops.)  The resulting set of
+  //    loops is guaranteed to be nestable.
+  //
+  // 3. Build the polygon.  This yields either the desired polygon or its
+  //    complement.
+  //
+  // 4. If there is at least one loop, we find a loop L that is adjacent to
+  //    S2::Origin() (where "adjacent" means that there exists a path
+  //    connecting S2::Origin() to some vertex of L such that the path does
+  //    not cross any loop).  There may be a single such adjacent loop, or
+  //    there may be several (in which case they should all have the same
+  //    contains_origin() value).  We choose L to be the loop containing the
+  //    origin whose depth is greatest, or loop(0) (a top-level shell) if no
+  //    such loop exists.
+  //
+  // 5. If (L originally contained origin) != (polygon contains origin), we
+  //    invert the polygon.  This is done by inverting a top-level shell whose
+  //    curvature is minimal and then fixing the nesting hierarchy.  Note
+  //    that because we normalized all the loops initially, this step is only
+  //    necessary if the polygon requires at least one non-normalized loop to
+  //    represent it.
+
+  set<const S2Loop*> contained_origin;
+  for (int i = 0; i < loops.size(); ++i) {
+    S2Loop* loop = loops[i].get();
+    if (loop->contains_origin()) {
+      contained_origin.insert(loop);
+    }
+    double angle = loop->GetCurvature();
+    if (fabs(angle) > loop->GetCurvatureMaxError()) {
+      // Normalize the loop.
+      if (angle < 0) loop->Invert();
+    } else {
+      // Ensure that the loop does not contain the origin.
+      if (loop->contains_origin()) loop->Invert();
+    }
+  }
+  InitNested(std::move(loops));
+  if (num_loops() > 0) {
+    S2Loop* origin_loop = loop(0);
+    bool polygon_contains_origin = false;
+    for (int i = 0; i < num_loops(); ++i) {
+      if (loop(i)->contains_origin()) {
+        polygon_contains_origin ^= true;
+        origin_loop = loop(i);
+      }
+    }
+    if (contained_origin.count(origin_loop) != polygon_contains_origin) {
+      Invert();
+    }
+  }
+  // Verify that the original loops had consistent shell/hole orientations.
+  // Each original loop L should have been inverted if and only if it now
+  // represents a hole.
+  for (int i = 0; i < loops_.size(); ++i) {
+    if ((contained_origin.count(loop(i)) != loop(i)->contains_origin()) !=
+        loop(i)->is_hole()) {
+      // There is no point in saving the loop index, because the error is a
+      // property of the entire set of loops.  In general there is no way to
+      // determine which ones are incorrect.
+      error_inconsistent_loop_orientations_ = true;
+      if (FLAGS_s2debug && s2debug_override_ == S2Debug::ALLOW) {
+        // The FLAGS_s2debug validity checking usually happens in InitIndex(),
+        // but this error is detected too late for that.
+        S2_CHECK(IsValid());  // Always fails.
+      }
+    }
+  }
+}
+
+void S2Polygon::InitLoopProperties() {
+  num_vertices_ = 0;
+  bound_ = S2LatLngRect::Empty();
+  for (int i = 0; i < num_loops(); ++i) {
+    if (loop(i)->depth() == 0) {
+      bound_ = bound_.Union(loop(i)->GetRectBound());
+    }
+    num_vertices_ += loop(i)->num_vertices();
+  }
+  subregion_bound_ = S2LatLngRectBounder::ExpandForSubregions(bound_);
+  InitIndex();
+}
+
+int S2Polygon::GetParent(int k) const {
+  int depth = loop(k)->depth();
+  if (depth == 0) return -1;  // Optimization.
+  while (--k >= 0 && loop(k)->depth() >= depth) continue;
+  return k;
+}
+
+int S2Polygon::GetLastDescendant(int k) const {
+  if (k < 0) return num_loops() - 1;
+  int depth = loop(k)->depth();
+  while (++k < num_loops() && loop(k)->depth() > depth) continue;
+  return k - 1;
+}
+
+double S2Polygon::GetArea() const {
+  double area = 0;
+  for (int i = 0; i < num_loops(); ++i) {
+    area += loop(i)->sign() * loop(i)->GetArea();
+  }
+  return area;
+}
+
+S2Point S2Polygon::GetCentroid() const {
+  S2Point centroid;
+  for (int i = 0; i < num_loops(); ++i) {
+    centroid += loop(i)->sign() * loop(i)->GetCentroid();
+  }
+  return centroid;
+}
+
+int S2Polygon::GetSnapLevel() const {
+  int snap_level = -1;
+  for (const unique_ptr<S2Loop>& child : loops_) {
+    for (int j = 0; j < child->num_vertices(); ++j) {
+      int face;
+      unsigned int si, ti;
+      int level = S2::XYZtoFaceSiTi(child->vertex(j), &face, &si, &ti);
+      if (level < 0) return level;  // Vertex is not a cell center.
+      if (level != snap_level) {
+        if (snap_level < 0) {
+          snap_level = level;  // First vertex.
+        } else {
+          return -1;  // Vertices at more than one cell level.
+        }
+      }
+    }
+  }
+  return snap_level;
+}
+
+S1Angle S2Polygon::GetDistance(const S2Point& x) const {
+  // Note that S2Polygon::Contains(S2Point) is slightly more efficient than
+  // the generic version used by S2ClosestEdgeQuery.
+  if (Contains(x)) return S1Angle::Zero();
+  return GetDistanceToBoundary(x);
+}
+
+S1Angle S2Polygon::GetDistanceToBoundary(const S2Point& x) const {
+  S2ClosestEdgeQuery::Options options;
+  options.set_include_interiors(false);
+  S2ClosestEdgeQuery::PointTarget t(x);
+  return S2ClosestEdgeQuery(&index_, options).GetDistance(&t).ToAngle();
+}
+
+/*static*/ pair<double, double> S2Polygon::GetOverlapFractions(
+    const S2Polygon* a, const S2Polygon* b) {
+  S2Polygon intersection;
+  intersection.InitToIntersection(a, b);
+  double intersection_area = intersection.GetArea();
+  double a_area = a->GetArea();
+  double b_area = b->GetArea();
+  return std::make_pair(
+      intersection_area >= a_area ? 1 : intersection_area / a_area,
+      intersection_area >= b_area ? 1 : intersection_area / b_area);
+}
+
+S2Point S2Polygon::Project(const S2Point& x) const {
+  if (Contains(x)) return x;
+  return ProjectToBoundary(x);
+}
+
+S2Point S2Polygon::ProjectToBoundary(const S2Point& x) const {
+  S2ClosestEdgeQuery::Options options;
+  options.set_include_interiors(false);
+  S2ClosestEdgeQuery q(&index_, options);
+  S2ClosestEdgeQuery::PointTarget target(x);
+  S2ClosestEdgeQuery::Result edge = q.FindClosestEdge(&target);
+  return q.Project(x, edge);
+}
+
+bool S2Polygon::Contains(const S2Polygon* b) const {
+  // It's worth checking bounding rectangles, since they are precomputed.
+  // Note that the first bound has been expanded to account for possible
+  // numerical errors in the second bound.
+  if (!subregion_bound_.Contains(b->bound_)) {
+    // It is possible that A contains B even though Bound(A) does not contain
+    // Bound(B).  This can only happen when polygon B has at least two outer
+    // shells and the union of the two bounds spans all longitudes.  For
+    // example, suppose that B consists of two shells with a longitude gap
+    // between them, while A consists of one shell that surrounds both shells
+    // of B but goes the other way around the sphere (so that it does not
+    // intersect the longitude gap).
+    //
+    // For convenience we just check whether B has at least two loops rather
+    // than two outer shells.
+    if (b->num_loops() == 1 || !bound_.lng().Union(b->bound_.lng()).is_full()) {
+      return false;
+    }
+  }
+
+  // The following case is not handled by S2BooleanOperation because it only
+  // determines whether the boundary of the result is empty (which does not
+  // distinguish between the full and empty polygons).
+  if (is_empty() && b->is_full()) return false;
+
+  return S2BooleanOperation::Contains(index_, b->index_);
+}
+
+bool S2Polygon::Intersects(const S2Polygon* b) const {
+  // It's worth checking bounding rectangles, since they are precomputed.
+  if (!bound_.Intersects(b->bound_)) return false;
+
+  // The following case is not handled by S2BooleanOperation because it only
+  // determines whether the boundary of the result is empty (which does not
+  // distinguish between the full and empty polygons).
+  if (is_full() && b->is_full()) return true;
+
+  return S2BooleanOperation::Intersects(index_, b->index_);
+}
+
+S2Cap S2Polygon::GetCapBound() const {
+  return bound_.GetCapBound();
+}
+
+void S2Polygon::GetCellUnionBound(vector<S2CellId> *cell_ids) const {
+  return MakeS2ShapeIndexRegion(&index_).GetCellUnionBound(cell_ids);
+}
+
+bool S2Polygon::Contains(const S2Cell& target) const {
+  return MakeS2ShapeIndexRegion(&index_).Contains(target);
+}
+
+bool S2Polygon::ApproxContains(const S2Polygon* b, S1Angle tolerance) const {
+  S2Polygon difference;
+  difference.InitToApproxDifference(b, this, tolerance);
+  return difference.is_empty();
+}
+
+bool S2Polygon::ApproxDisjoint(const S2Polygon* b, S1Angle tolerance) const {
+  S2Polygon intersection;
+  intersection.InitToApproxIntersection(b, this, tolerance);
+  return intersection.is_empty();
+}
+
+bool S2Polygon::ApproxEquals(const S2Polygon* b, S1Angle tolerance) const {
+  // TODO(ericv): This can be implemented more cheaply with S2Builder, by
+  // simply adding all the edges from one polygon, adding the reversed edge
+  // from the other polygon, and turning on the options to split edges and
+  // discard sibling pairs.  Then the polygons are approximately equal if the
+  // output graph has no edges.
+  S2Polygon symmetric_difference;
+  symmetric_difference.InitToApproxSymmetricDifference(b, this, tolerance);
+  return symmetric_difference.is_empty();
+}
+
+bool S2Polygon::MayIntersect(const S2Cell& target) const {
+  return MakeS2ShapeIndexRegion(&index_).MayIntersect(target);
+}
+
+bool S2Polygon::Contains(const S2Point& p) const {
+  // NOTE(ericv): A bounds check slows down this function by about 50%.  It is
+  // worthwhile only when it might allow us to delay building the index.
+  if (!index_.is_fresh() && !bound_.Contains(p)) return false;
+
+  // For small polygons it is faster to just check all the crossings.
+  // Otherwise we keep track of the number of calls to Contains() and only
+  // build the index once enough calls have been made so that we think it is
+  // worth the effort.  See S2Loop::Contains(S2Point) for detailed comments.
+  static const int kMaxBruteForceVertices = 32;
+  static const int kMaxUnindexedContainsCalls = 20;
+  if (num_vertices() <= kMaxBruteForceVertices ||
+      (!index_.is_fresh() &&
+       ++unindexed_contains_calls_ != kMaxUnindexedContainsCalls)) {
+    bool inside = false;
+    for (int i = 0; i < num_loops(); ++i) {
+      // Use brute force to avoid building the loop's S2ShapeIndex.
+      inside ^= loop(i)->BruteForceContains(p);
+    }
+    return inside;
+  }
+  // Otherwise we look up the S2ShapeIndex cell containing this point.
+  return MakeS2ContainsPointQuery(&index_).Contains(p);
+}
+
+void S2Polygon::Encode(Encoder* const encoder) const {
+  if (num_vertices_ == 0) {
+    EncodeCompressed(encoder, nullptr, S2::kMaxCellLevel);
+    return;
+  }
+  // Converts all the polygon vertices to S2XYZFaceSiTi format.
+  absl::FixedArray<S2XYZFaceSiTi> all_vertices(num_vertices_);
+  S2XYZFaceSiTi* current_loop_vertices = all_vertices.data();
+  for (const unique_ptr<S2Loop>& loop : loops_) {
+    loop->GetXYZFaceSiTiVertices(current_loop_vertices);
+    current_loop_vertices += loop->num_vertices();
+  }
+  // Computes a histogram of the cell levels at which the vertices are snapped.
+  // cell_level is -1 for unsnapped, or 0 through kMaxCellLevel if snapped,
+  // so we add one to it to get a non-negative index.  (histogram[0] is the
+  // number of unsnapped vertices, histogram[i] the number of vertices
+  // snapped at level i-1).
+  std::array<int, S2::kMaxCellLevel + 2> histogram;
+  histogram.fill(0);
+  for (const auto& v : all_vertices) {
+    histogram[v.cell_level + 1] += 1;
+  }
+  // Compute the level at which most of the vertices are snapped.
+  // If multiple levels have the same maximum number of vertices
+  // snapped to it, the first one (lowest level number / largest
+  // area / smallest encoding length) will be chosen, so this
+  // is desired.  Start with histogram[1] since histogram[0] is
+  // the number of unsnapped vertices, which we don't care about.
+  const auto max_iter =
+      std::max_element(histogram.begin() + 1, histogram.end());
+  // snap_level will be at position histogram[snap_level + 1], see above.
+  const int snap_level = max_iter - (histogram.begin() + 1);
+  const int num_snapped = *max_iter;
+  // Choose an encoding format based on the number of unsnapped vertices and a
+  // rough estimate of the encoded sizes.
+
+  // The compressed encoding requires approximately 4 bytes per vertex plus
+  // "exact_point_size" for each unsnapped vertex (encoded as an S2Point plus
+  // the index at which it is located).
+  int exact_point_size = sizeof(S2Point) + 2;
+  int num_unsnapped = num_vertices_ - num_snapped;
+  int compressed_size = 4 * num_vertices_ + exact_point_size * num_unsnapped;
+  int lossless_size = sizeof(S2Point) * num_vertices_;
+  if (compressed_size < lossless_size) {
+    EncodeCompressed(encoder, all_vertices.data(), snap_level);
+  } else {
+    EncodeUncompressed(encoder);
+  }
+}
+
+void S2Polygon::EncodeUncompressed(Encoder* const encoder) const {
+  encoder->Ensure(10);  // Sufficient
+  encoder->put8(kCurrentUncompressedEncodingVersionNumber);
+  // This code used to write "owns_loops_", so write "true" for compatibility.
+  encoder->put8(true);
+  // Encode obsolete "has_holes_" field for backwards compatibility.
+  bool has_holes = false;
+  for (int i = 0; i < num_loops(); ++i) {
+    if (loop(i)->is_hole()) has_holes = true;
+  }
+  encoder->put8(has_holes);
+  encoder->put32(loops_.size());
+  S2_DCHECK_GE(encoder->avail(), 0);
+
+  for (int i = 0; i < num_loops(); ++i) {
+    loop(i)->Encode(encoder);
+  }
+  bound_.Encode(encoder);
+}
+
+bool S2Polygon::Decode(Decoder* const decoder) {
+  if (decoder->avail() < sizeof(unsigned char)) return false;
+  unsigned char version = decoder->get8();
+  switch (version) {
+    case kCurrentUncompressedEncodingVersionNumber:
+      return DecodeUncompressed(decoder, false);
+    case kCurrentCompressedEncodingVersionNumber:
+      return DecodeCompressed(decoder);
+  }
+  return false;
+}
+
+bool S2Polygon::DecodeWithinScope(Decoder* const decoder) {
+  if (decoder->avail() < sizeof(unsigned char)) return false;
+  unsigned char version = decoder->get8();
+  switch (version) {
+    case kCurrentUncompressedEncodingVersionNumber:
+      return DecodeUncompressed(decoder, true);
+    case kCurrentCompressedEncodingVersionNumber:
+      return DecodeCompressed(decoder);
+  }
+  return false;
+}
+
+bool S2Polygon::DecodeUncompressed(Decoder* const decoder, bool within_scope) {
+  if (decoder->avail() < 2 * sizeof(uint8) + sizeof(uint32)) return false;
+  ClearLoops();
+  decoder->get8();  // Ignore irrelevant serialized owns_loops_ value.
+  decoder->get8();  // Ignore irrelevant serialized has_holes_ value.
+  // Polygons with no loops are explicitly allowed here: a newly created
+  // polygon has zero loops and such polygons encode and decode properly.
+  const uint32 num_loops = decoder->get32();
+  if (num_loops > FLAGS_s2polygon_decode_max_num_loops) return false;
+  loops_.reserve(num_loops);
+  num_vertices_ = 0;
+  for (int i = 0; i < num_loops; ++i) {
+    loops_.push_back(make_unique<S2Loop>());
+    loops_.back()->set_s2debug_override(s2debug_override());
+    if (within_scope) {
+      if (!loops_.back()->DecodeWithinScope(decoder)) return false;
+    } else {
+      if (!loops_.back()->Decode(decoder)) return false;
+    }
+    num_vertices_ += loops_.back()->num_vertices();
+  }
+  if (!bound_.Decode(decoder)) return false;
+  subregion_bound_ = S2LatLngRectBounder::ExpandForSubregions(bound_);
+  InitIndex();
+  return true;
+}
+
+// TODO(ericv): Consider adding this to the S2Loop API.  (May also want an
+// undirected version (CompareDirected vs CompareUndirected); should they
+// return a sign, or have separate "<" and "==" methods?)
+int S2Polygon::CompareLoops(const S2Loop* a, const S2Loop* b) {
+  if (a->num_vertices() != b->num_vertices()) {
+    return a->num_vertices() - b->num_vertices();
+  }
+  S2::LoopOrder ao = a->GetCanonicalLoopOrder();
+  S2::LoopOrder bo = b->GetCanonicalLoopOrder();
+  if (ao.dir != bo.dir) return ao.dir - bo.dir;
+  for (int n = a->num_vertices(), ai = ao.first, bi = bo.first;
+       --n >= 0; ai += ao.dir, bi += bo.dir) {
+    if (a->vertex(ai) < b->vertex(bi)) return -1;
+    if (a->vertex(ai) > b->vertex(bi)) return 1;
+  }
+  return 0;
+}
+
+void S2Polygon::Invert() {
+  // Inverting any one loop will invert the polygon.  The best loop to invert
+  // is the one whose area is largest, since this yields the smallest area
+  // after inversion.  The loop with the largest area is always at depth 0.
+  // The descendents of this loop all have their depth reduced by 1, while the
+  // former siblings of this loop all have their depth increased by 1.
+
+  // The empty and full polygons are handled specially.
+  if (is_empty()) {
+    loops_.push_back(make_unique<S2Loop>(S2Loop::kFull()));
+  } else if (is_full()) {
+    ClearLoops();
+  } else {
+    // Find the loop whose area is largest (i.e., whose curvature is
+    // smallest), minimizing calls to GetCurvature().  In particular, for
+    // polygons with a single shell at level 0 there is not need to call
+    // GetCurvature() at all.  (This method is relatively expensive.)
+    int best = 0;
+    const double kNone = 10.0;  // Flag that means "not computed yet"
+    double best_angle = kNone;
+    for (int i = 1; i < num_loops(); ++i) {
+      if (loop(i)->depth() == 0) {
+        // We defer computing the curvature of loop 0 until we discover
+        // that the polygon has another top-level shell.
+        if (best_angle == kNone) best_angle = loop(best)->GetCurvature();
+        double angle = loop(i)->GetCurvature();
+        // We break ties deterministically in order to avoid having the output
+        // depend on the input order of the loops.
+        if (angle < best_angle ||
+            (angle == best_angle && CompareLoops(loop(i), loop(best)) < 0)) {
+          best = i;
+          best_angle = angle;
+        }
+      }
+    }
+    // Build the new loops vector, starting with the inverted loop.
+    loop(best)->Invert();
+    vector<unique_ptr<S2Loop>> new_loops;
+    new_loops.reserve(num_loops());
+    // Add the former siblings of this loop as descendants.
+    int last_best = GetLastDescendant(best);
+    new_loops.push_back(std::move(loops_[best]));
+    for (int i = 0; i < num_loops(); ++i) {
+      if (i < best || i > last_best) {
+        loop(i)->set_depth(loop(i)->depth() + 1);
+        new_loops.push_back(std::move(loops_[i]));
+      }
+    }
+    // Add the former children of this loop as siblings.
+    for (int i = 0; i < num_loops(); ++i) {
+      if (i > best && i <= last_best) {
+        loop(i)->set_depth(loop(i)->depth() - 1);
+        new_loops.push_back(std::move(loops_[i]));
+      }
+    }
+    loops_.swap(new_loops);
+    S2_DCHECK_EQ(new_loops.size(), num_loops());
+  }
+  ClearIndex();
+  InitLoopProperties();
+}
+
+void S2Polygon::InitToComplement(const S2Polygon* a) {
+  Copy(a);
+  Invert();
+}
+
+bool S2Polygon::InitToOperation(S2BooleanOperation::OpType op_type,
+                                const S2Builder::SnapFunction& snap_function,
+                                const S2Polygon& a, const S2Polygon& b,
+                                S2Error* error) {
+  S2BooleanOperation::Options options;
+  options.set_snap_function(snap_function);
+  S2BooleanOperation op(op_type, make_unique<S2PolygonLayer>(this),
+                         options);
+  return op.Build(a.index_, b.index_, error);
+}
+
+void S2Polygon::InitToOperation(S2BooleanOperation::OpType op_type,
+                                const S2Builder::SnapFunction& snap_function,
+                                const S2Polygon& a, const S2Polygon& b) {
+  S2Error error;
+  if (!InitToOperation(op_type, snap_function, a, b, &error)) {
+    S2_LOG(DFATAL) << S2BooleanOperation::OpTypeToString(op_type)
+                << " operation failed: " << error;
+  }
+}
+
+void S2Polygon::InitToIntersection(const S2Polygon* a, const S2Polygon* b) {
+  InitToApproxIntersection(a, b, S2::kIntersectionMergeRadius);
+}
+
+void S2Polygon::InitToApproxIntersection(const S2Polygon* a, const S2Polygon* b,
+                                         S1Angle snap_radius) {
+  InitToIntersection(*a, *b, IdentitySnapFunction(snap_radius));
+}
+
+void S2Polygon::InitToIntersection(
+    const S2Polygon& a, const S2Polygon& b,
+    const S2Builder::SnapFunction& snap_function) {
+  if (!a.bound_.Intersects(b.bound_)) return;
+  InitToOperation(S2BooleanOperation::OpType::INTERSECTION,
+                  snap_function, a, b);
+}
+
+bool S2Polygon::InitToIntersection(
+    const S2Polygon& a, const S2Polygon& b,
+    const S2Builder::SnapFunction& snap_function, S2Error* error) {
+  if (!a.bound_.Intersects(b.bound_)) return true;  // Success.
+  return InitToOperation(S2BooleanOperation::OpType::INTERSECTION,
+                         snap_function, a, b, error);
+}
+
+void S2Polygon::InitToUnion(const S2Polygon* a, const S2Polygon* b) {
+  InitToApproxUnion(a, b, S2::kIntersectionMergeRadius);
+}
+
+void S2Polygon::InitToApproxUnion(const S2Polygon* a, const S2Polygon* b,
+                                  S1Angle snap_radius) {
+  InitToUnion(*a, *b, IdentitySnapFunction(snap_radius));
+}
+
+void S2Polygon::InitToUnion(
+    const S2Polygon& a, const S2Polygon& b,
+    const S2Builder::SnapFunction& snap_function) {
+  InitToOperation(S2BooleanOperation::OpType::UNION, snap_function, a, b);
+}
+
+bool S2Polygon::InitToUnion(
+    const S2Polygon& a, const S2Polygon& b,
+    const S2Builder::SnapFunction& snap_function, S2Error* error) {
+  return InitToOperation(S2BooleanOperation::OpType::UNION,
+                         snap_function, a, b, error);
+}
+
+void S2Polygon::InitToDifference(const S2Polygon* a, const S2Polygon* b) {
+  InitToApproxDifference(a, b, S2::kIntersectionMergeRadius);
+}
+
+void S2Polygon::InitToApproxDifference(const S2Polygon* a, const S2Polygon* b,
+                                       S1Angle snap_radius) {
+  InitToDifference(*a, *b, IdentitySnapFunction(snap_radius));
+}
+
+void S2Polygon::InitToDifference(
+    const S2Polygon& a, const S2Polygon& b,
+    const S2Builder::SnapFunction& snap_function) {
+  InitToOperation(S2BooleanOperation::OpType::DIFFERENCE, snap_function, a, b);
+}
+
+bool S2Polygon::InitToDifference(
+    const S2Polygon& a, const S2Polygon& b,
+    const S2Builder::SnapFunction& snap_function, S2Error* error) {
+  return InitToOperation(S2BooleanOperation::OpType::DIFFERENCE,
+                         snap_function, a, b, error);
+}
+
+void S2Polygon::InitToSymmetricDifference(const S2Polygon* a,
+                                          const S2Polygon* b) {
+  InitToApproxSymmetricDifference(a, b, S2::kIntersectionMergeRadius);
+}
+
+void S2Polygon::InitToApproxSymmetricDifference(const S2Polygon* a,
+                                                const S2Polygon* b,
+                                                S1Angle snap_radius) {
+  InitToSymmetricDifference(*a, *b, IdentitySnapFunction(snap_radius));
+}
+
+void S2Polygon::InitToSymmetricDifference(
+    const S2Polygon& a, const S2Polygon& b,
+    const S2Builder::SnapFunction& snap_function) {
+  InitToOperation(S2BooleanOperation::OpType::SYMMETRIC_DIFFERENCE,
+                  snap_function, a, b);
+}
+
+bool S2Polygon::InitToSymmetricDifference(
+    const S2Polygon& a, const S2Polygon& b,
+    const S2Builder::SnapFunction& snap_function, S2Error* error) {
+  return InitToOperation(S2BooleanOperation::OpType::SYMMETRIC_DIFFERENCE,
+                         snap_function, a, b, error);
+}
+
+void S2Polygon::InitFromBuilder(const S2Polygon& a, S2Builder* builder) {
+  builder->StartLayer(make_unique<S2PolygonLayer>(this));
+  builder->AddPolygon(a);
+  S2Error error;
+  if (!builder->Build(&error)) {
+    S2_LOG(DFATAL) << "Could not build polygon: " << error;
+  }
+  // If there are no loops, check whether the result should be the full
+  // polygon rather than the empty one.  (See InitToApproxIntersection.)
+  if (num_loops() == 0) {
+    if (a.bound_.Area() > 2 * M_PI && a.GetArea() > 2 * M_PI) Invert();
+  }
+}
+
+void S2Polygon::InitToSnapped(const S2Polygon* a, int snap_level) {
+  S2Builder builder{S2Builder::Options(S2CellIdSnapFunction(snap_level))};
+  InitFromBuilder(*a, &builder);
+}
+
+void S2Polygon::InitToSimplified(const S2Polygon& a,
+                                 const S2Builder::SnapFunction& snap_function) {
+  S2Builder::Options options(snap_function);
+  options.set_simplify_edge_chains(true);
+  S2Builder builder(options);
+  InitFromBuilder(a, &builder);
+}
+
+// Given a point "p" inside an S2Cell or on its boundary, return a mask
+// indicating which of the S2Cell edges the point lies on.  All boundary
+// comparisons are to within a maximum "u" or "v" error of "tolerance_uv".
+// Bit "i" in the result is set if and only "p" is incident to the edge
+// corresponding to S2Cell::edge(i).
+uint8 GetCellEdgeIncidenceMask(const S2Cell& cell, const S2Point& p,
+                               double tolerance_uv) {
+  uint8 mask = 0;
+  R2Point uv;
+  if (S2::FaceXYZtoUV(cell.face(), p, &uv)) {
+    R2Rect bound = cell.GetBoundUV();
+    if (FLAGS_s2debug) S2_DCHECK(bound.Expanded(tolerance_uv).Contains(uv));
+    if (fabs(uv[1] - bound[1][0]) <= tolerance_uv) mask |= 1;
+    if (fabs(uv[0] - bound[0][1]) <= tolerance_uv) mask |= 2;
+    if (fabs(uv[1] - bound[1][1]) <= tolerance_uv) mask |= 4;
+    if (fabs(uv[0] - bound[0][0]) <= tolerance_uv) mask |= 8;
+  }
+  return mask;
+}
+
+void S2Polygon::InitToSimplifiedInCell(
+    const S2Polygon* a, const S2Cell& cell,
+    S1Angle snap_radius, S1Angle boundary_tolerance) {
+  // The polygon to be simplified consists of "boundary edges" that follow the
+  // cell boundary and "interior edges" that do not.  We want to simplify the
+  // interior edges while leaving the boundary edges unchanged.  It's not
+  // sufficient to call S2Builder::ForceVertex() on all boundary vertices.
+  // For example, suppose the polygon includes a triangle ABC where all three
+  // vertices are on the cell boundary and B is a cell corner.  Then if
+  // interior edge AC snaps to vertex B, this loop would become degenerate and
+  // be removed.  Similarly, we don't want boundary edges to snap to interior
+  // vertices, since this also would cause portions of the polygon along the
+  // boundary to be removed.
+  //
+  // Instead we use a two-pass algorithm.  In the first pass, we simplify
+  // *only* the interior edges, using ForceVertex() to ensure that any edge
+  // endpoints on the cell boundary do not move.  In the second pass, we add
+  // the boundary edges (which are guaranteed to still form loops with the
+  // interior edges) and build the output polygon.
+  //
+  // Note that in theory, simplifying the interior edges could create an
+  // intersection with one of the boundary edges, since if two interior edges
+  // intersect very near the boundary then the intersection point could be
+  // slightly outside the cell (by at most S2::kIntersectionError).
+  // This is the *only* way that a self-intersection can be created, and it is
+  // expected to be extremely rare.  Nevertheless we use a small snap radius
+  // in the second pass in order to eliminate any such self-intersections.
+  //
+  // We also want to preserve the cyclic vertex order of loops, so that the
+  // original polygon can be reconstructed when no simplification is possible
+  // (i.e., idempotency).  In order to do this, we group the input edges into
+  // a sequence of polylines.  Each polyline contains only one type of edge
+  // (interior or boundary).  We use S2Builder to simplify the interior
+  // polylines, while the boundary polylines are passed through unchanged.
+  // Each interior polyline is in its own S2Builder layer in order to keep the
+  // edges in sequence.  This lets us ensure that in the second pass, the
+  // edges are added in their original order so that S2PolygonLayer can
+  // reconstruct the original loops.
+
+  // We want an upper bound on how much "u" or "v" can change when a point on
+  // the boundary of the S2Cell is moved away by up to "boundary_tolerance".
+  // Inverting this, instead we could compute a lower bound on how far a point
+  // can move away from an S2Cell edge when "u" or "v" is changed by a given
+  // amount.  The latter quantity is simply (S2::kMinWidth.deriv() / 2)
+  // under the S2_LINEAR_PROJECTION model, where we divide by 2 because we
+  // want the bound in terms of (u = 2 * s - 1) rather than "s" itself.
+  // Consulting s2metrics.cc, this value is sqrt(2/3)/2 = sqrt(1/6).
+  // Going back to the original problem, this gives:
+  double boundary_tolerance_uv = sqrt(6.0) * boundary_tolerance.radians();
+
+  // The first pass yields a collection of simplified polylines that preserve
+  // the original cyclic vertex order.
+  auto polylines = SimplifyEdgesInCell(*a, cell, boundary_tolerance_uv,
+                                       snap_radius);
+
+  // The second pass eliminates any intersections between interior edges and
+  // boundary edges, and then assembles the edges into a polygon.
+  S2Builder::Options options(
+      (IdentitySnapFunction(S2::kIntersectionError)));
+  options.set_idempotent(false);  // Force snapping up to the given radius
+  S2Builder builder(options);
+  builder.StartLayer(make_unique<S2PolygonLayer>(this));
+  for (const auto& polyline : polylines) {
+    builder.AddPolyline(*polyline);
+  }
+  S2Error error;
+  if (!builder.Build(&error)) {
+    S2_LOG(DFATAL) << "Could not build polygon: " << error;
+    return;
+  }
+  // If there are no loops, check whether the result should be the full
+  // polygon rather than the empty one.  (See InitToApproxIntersection.)
+  if (num_loops() == 0) {
+    if (a->bound_.Area() > 2 * M_PI && a->GetArea() > 2 * M_PI) Invert();
+  }
+}
+
+// See comments in InitToSimplifiedInCell.
+vector<unique_ptr<S2Polyline>> S2Polygon::SimplifyEdgesInCell(
+    const S2Polygon& a, const S2Cell& cell,
+    double tolerance_uv, S1Angle snap_radius) {
+  S2Builder::Options options((IdentitySnapFunction(snap_radius)));
+  options.set_simplify_edge_chains(true);
+  S2Builder builder(options);
+  // The output consists of a sequence of polylines.  Polylines consisting of
+  // interior edges are simplified using S2Builder, while polylines consisting
+  // of boundary edges are returned unchanged.
+  vector<unique_ptr<S2Polyline>> polylines;
+  for (int i = 0; i < a.num_loops(); ++i) {
+    const S2Loop& a_loop = *a.loop(i);
+    const S2Point* v0 = &a_loop.oriented_vertex(0);
+    uint8 mask0 = GetCellEdgeIncidenceMask(cell, *v0, tolerance_uv);
+    bool in_interior = false;  // Was the last edge an interior edge?
+    for (int j = 1; j <= a_loop.num_vertices(); ++j) {
+      const S2Point* v1 = &a_loop.oriented_vertex(j);
+      uint8 mask1 = GetCellEdgeIncidenceMask(cell, *v1, tolerance_uv);
+      if ((mask0 & mask1) != 0) {
+        // This is an edge along the cell boundary.  Such edges do not get
+        // simplified; we add them directly to the output.  (We create a
+        // separate polyline for each edge to keep things simple.)  We call
+        // ForceVertex on all boundary vertices to ensure that they don't
+        // move, and so that nearby interior edges are snapped to them.
+        S2_DCHECK(!in_interior);
+        builder.ForceVertex(*v1);
+        polylines.emplace_back(new S2Polyline(vector<S2Point>{*v0, *v1}));
+      } else {
+        // This is an interior edge.  If this is the first edge of an interior
+        // chain, then start a new S2Builder layer.  Also ensure that any
+        // polyline vertices on the boundary do not move, so that they will
+        // still connect with any boundary edge(s) there.
+        if (!in_interior) {
+          S2Polyline* polyline = new S2Polyline;
+          builder.StartLayer(make_unique<S2PolylineLayer>(polyline));
+          polylines.emplace_back(polyline);
+          in_interior = true;
+        }
+        builder.AddEdge(*v0, *v1);
+        if (mask1 != 0) {
+          builder.ForceVertex(*v1);
+          in_interior = false;  // Terminate this polyline.
+        }
+      }
+      v0 = v1;
+      mask0 = mask1;
+    }
+  }
+  S2Error error;
+  if (!builder.Build(&error)) {
+    S2_LOG(DFATAL) << "InitToSimplifiedInCell failed: " << error;
+  }
+  return polylines;
+}
+
+vector<unique_ptr<S2Polyline>> S2Polygon::OperationWithPolyline(
+    S2BooleanOperation::OpType op_type,
+    const S2Builder::SnapFunction& snap_function,
+    const S2Polyline& a) const {
+  S2BooleanOperation::Options options;
+  options.set_snap_function(snap_function);
+  vector<unique_ptr<S2Polyline>> result;
+  S2PolylineVectorLayer::Options layer_options;
+  layer_options.set_polyline_type(
+      S2PolylineVectorLayer::Options::PolylineType::WALK);
+  S2BooleanOperation op(
+      op_type, make_unique<S2PolylineVectorLayer>(&result, layer_options),
+      options);
+  MutableS2ShapeIndex a_index;
+  a_index.Add(make_unique<S2Polyline::Shape>(&a));
+  S2Error error;
+  if (!op.Build(a_index, index_, &error)) {
+    S2_LOG(DFATAL) << "Polyline " << S2BooleanOperation::OpTypeToString(op_type)
+                << " operation failed: " << error;
+  }
+  return result;
+}
+
+vector<unique_ptr<S2Polyline>> S2Polygon::IntersectWithPolyline(
+    const S2Polyline& a) const {
+  return ApproxIntersectWithPolyline(a, S2::kIntersectionMergeRadius);
+}
+
+vector<unique_ptr<S2Polyline>> S2Polygon::ApproxIntersectWithPolyline(
+    const S2Polyline& a, S1Angle snap_radius) const {
+  return IntersectWithPolyline(a, IdentitySnapFunction(snap_radius));
+}
+
+vector<unique_ptr<S2Polyline>> S2Polygon::IntersectWithPolyline(
+    const S2Polyline& a, const S2Builder::SnapFunction& snap_function) const {
+  return OperationWithPolyline(S2BooleanOperation::OpType::INTERSECTION,
+                               snap_function, a);
+}
+
+vector<unique_ptr<S2Polyline>> S2Polygon::SubtractFromPolyline(
+    const S2Polyline& a) const {
+  return ApproxSubtractFromPolyline(a, S2::kIntersectionMergeRadius);
+}
+
+vector<unique_ptr<S2Polyline>> S2Polygon::ApproxSubtractFromPolyline(
+    const S2Polyline& a, S1Angle snap_radius) const {
+  return SubtractFromPolyline(a, IdentitySnapFunction(snap_radius));
+}
+
+vector<unique_ptr<S2Polyline>> S2Polygon::SubtractFromPolyline(
+    const S2Polyline& a, const S2Builder::SnapFunction& snap_function) const {
+  return OperationWithPolyline(S2BooleanOperation::OpType::DIFFERENCE,
+                               snap_function, a);
+}
+
+bool S2Polygon::Contains(const S2Polyline& b) const {
+  return ApproxContains(b, S2::kIntersectionMergeRadius);
+}
+
+bool S2Polygon::ApproxContains(const S2Polyline& b, S1Angle tolerance) const {
+  auto difference = ApproxSubtractFromPolyline(b, tolerance);
+  return difference.empty();
+}
+
+bool S2Polygon::Intersects(const S2Polyline& b) const {
+  return !ApproxDisjoint(b, S2::kIntersectionMergeRadius);
+}
+
+bool S2Polygon::ApproxDisjoint(const S2Polyline& b, S1Angle tolerance) const {
+  auto intersection = ApproxIntersectWithPolyline(b, tolerance);
+  return intersection.empty();
+}
+
+unique_ptr<S2Polygon> S2Polygon::DestructiveUnion(
+    vector<unique_ptr<S2Polygon>> polygons) {
+  return DestructiveApproxUnion(std::move(polygons),
+                                S2::kIntersectionMergeRadius);
+}
+
+unique_ptr<S2Polygon> S2Polygon::DestructiveApproxUnion(
+    vector<unique_ptr<S2Polygon>> polygons, S1Angle snap_radius) {
+  // Effectively create a priority queue of polygons in order of number of
+  // vertices.  Repeatedly union the two smallest polygons and add the result
+  // to the queue until we have a single polygon to return.
+  using QueueType = std::multimap<int, unique_ptr<S2Polygon>>;
+  QueueType queue;  // Map from # of vertices to polygon.
+  for (auto& polygon : polygons)
+    queue.insert(std::make_pair(polygon->num_vertices(), std::move(polygon)));
+
+  while (queue.size() > 1) {
+    // Pop two simplest polygons from queue.
+    QueueType::iterator smallest_it = queue.begin();
+    int a_size = smallest_it->first;
+    unique_ptr<S2Polygon> a_polygon(std::move(smallest_it->second));
+    queue.erase(smallest_it);
+    smallest_it = queue.begin();
+    int b_size = smallest_it->first;
+    unique_ptr<S2Polygon> b_polygon(std::move(smallest_it->second));
+    queue.erase(smallest_it);
+
+    // Union and add result back to queue.
+    auto union_polygon = make_unique<S2Polygon>();
+    union_polygon->InitToApproxUnion(a_polygon.get(), b_polygon.get(),
+                                     snap_radius);
+    queue.insert(std::make_pair(a_size + b_size, std::move(union_polygon)));
+    // We assume that the number of vertices in the union polygon is the
+    // sum of the number of vertices in the original polygons, which is not
+    // always true, but will almost always be a decent approximation, and
+    // faster than recomputing.
+  }
+
+  if (queue.empty())
+    return make_unique<S2Polygon>();
+  else
+    return std::move(queue.begin()->second);
+}
+
+void S2Polygon::InitToCellUnionBorder(const S2CellUnion& cells) {
+  // We use S2Builder to compute the union.  Due to rounding errors, we can't
+  // compute an exact union - when a small cell is adjacent to a larger cell,
+  // the shared edges can fail to line up exactly.  Two cell edges cannot come
+  // closer then kMinWidth, so if we have S2Builder snap edges within half
+  // that distance, then we should always merge shared edges without merging
+  // different edges.
+  double snap_radius = 0.5 * S2::kMinWidth.GetValue(S2CellId::kMaxLevel);
+  S2Builder builder{S2Builder::Options(
+      IdentitySnapFunction(S1Angle::Radians(snap_radius)))};
+  builder.StartLayer(make_unique<S2PolygonLayer>(this));
+  for (S2CellId id : cells) {
+    builder.AddLoop(S2Loop{S2Cell{id}});
+  }
+  S2Error error;
+  if (!builder.Build(&error)) {
+    S2_LOG(DFATAL) << "InitToCellUnionBorder failed: " << error;
+  }
+  // If there are no loops, check whether the result should be the full
+  // polygon rather than the empty one.  There are only two ways that this can
+  // happen: either the cell union is empty, or it consists of all six faces.
+  if (num_loops() == 0) {
+    if (cells.empty()) return;
+    S2_DCHECK_EQ(uint64{6} << (2 * S2CellId::kMaxLevel),
+              cells.LeafCellsCovered());
+    Invert();
+  }
+}
+
+bool S2Polygon::IsNormalized() const {
+  // TODO(ericv): The condition tested here is insufficient.  The correct
+  // condition is that each *connected component* of child loops can share at
+  // most one vertex with their parent loop.  Example: suppose loop A has
+  // children B, C, D, and the following pairs are connected: AB, BC, CD, DA.
+  // Then the polygon is not normalized.
+  set<S2Point> vertices;
+  const S2Loop* last_parent = nullptr;
+  for (int i = 0; i < num_loops(); ++i) {
+    const S2Loop* child = loop(i);
+    if (child->depth() == 0) continue;
+    const S2Loop* parent = loop(GetParent(i));
+    if (parent != last_parent) {
+      vertices.clear();
+      for (int j = 0; j < parent->num_vertices(); ++j) {
+        vertices.insert(parent->vertex(j));
+      }
+      last_parent = parent;
+    }
+    int count = 0;
+    for (int j = 0; j < child->num_vertices(); ++j) {
+      if (vertices.count(child->vertex(j)) > 0) ++count;
+    }
+    if (count > 1) return false;
+  }
+  return true;
+}
+
+bool S2Polygon::Equals(const S2Polygon* b) const {
+  if (num_loops() != b->num_loops()) return false;
+  for (int i = 0; i < num_loops(); ++i) {
+    const S2Loop* a_loop = loop(i);
+    const S2Loop* b_loop = b->loop(i);
+    if ((b_loop->depth() != a_loop->depth()) || !b_loop->Equals(a_loop)) {
+      return false;
+    }
+  }
+  return true;
+}
+
+bool S2Polygon::BoundaryEquals(const S2Polygon* b) const {
+  if (num_loops() != b->num_loops()) return false;
+
+  for (int i = 0; i < num_loops(); ++i) {
+    const S2Loop* a_loop = loop(i);
+    bool success = false;
+    for (int j = 0; j < num_loops(); ++j) {
+      const S2Loop* b_loop = b->loop(j);
+      if ((b_loop->depth() == a_loop->depth()) &&
+          b_loop->BoundaryEquals(a_loop)) {
+        success = true;
+        break;
+      }
+    }
+    if (!success) return false;
+  }
+  return true;
+}
+
+bool S2Polygon::BoundaryApproxEquals(const S2Polygon& b,
+                                     S1Angle max_error) const {
+  if (num_loops() != b.num_loops()) return false;
+
+  // For now, we assume that there is at most one candidate match for each
+  // loop.  (So far this method is just used for testing.)
+
+  for (int i = 0; i < num_loops(); ++i) {
+    const S2Loop& a_loop = *loop(i);
+    bool success = false;
+    for (int j = 0; j < num_loops(); ++j) {
+      const S2Loop& b_loop = *b.loop(j);
+      if (b_loop.depth() == a_loop.depth() &&
+          b_loop.BoundaryApproxEquals(a_loop, max_error)) {
+        success = true;
+        break;
+      }
+    }
+    if (!success) return false;
+  }
+  return true;
+}
+
+bool S2Polygon::BoundaryNear(const S2Polygon& b, S1Angle max_error) const {
+  if (num_loops() != b.num_loops()) return false;
+
+  // For now, we assume that there is at most one candidate match for each
+  // loop.  (So far this method is just used for testing.)
+
+  for (int i = 0; i < num_loops(); ++i) {
+    const S2Loop& a_loop = *loop(i);
+    bool success = false;
+    for (int j = 0; j < num_loops(); ++j) {
+      const S2Loop& b_loop = *b.loop(j);
+      if (b_loop.depth() == a_loop.depth() &&
+          b_loop.BoundaryNear(a_loop, max_error)) {
+        success = true;
+        break;
+      }
+    }
+    if (!success) return false;
+  }
+  return true;
+}
+
+void S2Polygon::EncodeCompressed(Encoder* encoder,
+                                 const S2XYZFaceSiTi* all_vertices,
+                                 int snap_level) const {
+  S2_CHECK_GE(snap_level, 0);
+  // Sufficient for what we write. Typically enough for a 4 vertex polygon.
+  encoder->Ensure(40);
+  encoder->put8(kCurrentCompressedEncodingVersionNumber);
+  encoder->put8(snap_level);
+  encoder->put_varint32(num_loops());
+  S2_DCHECK_GE(encoder->avail(), 0);
+  const S2XYZFaceSiTi* current_loop_vertices = all_vertices;
+  for (int i = 0; i < num_loops(); ++i) {
+    loops_[i]->EncodeCompressed(encoder, current_loop_vertices, snap_level);
+    current_loop_vertices += loops_[i]->num_vertices();
+  }
+  // Do not write the bound or num_vertices as they can be cheaply recomputed
+  // by DecodeCompressed.  Microbenchmarks show the speed difference is
+  // inconsequential.
+}
+
+bool S2Polygon::DecodeCompressed(Decoder* decoder) {
+  if (decoder->avail() < sizeof(uint8)) return false;
+  ClearLoops();
+  int snap_level = decoder->get8();
+  if (snap_level > S2CellId::kMaxLevel) return false;
+  // Polygons with no loops are explicitly allowed here: a newly created
+  // polygon has zero loops and such polygons encode and decode properly.
+  uint32 num_loops;
+  if (!decoder->get_varint32(&num_loops)) return false;
+  if (num_loops > FLAGS_s2polygon_decode_max_num_loops) return false;
+  loops_.reserve(num_loops);
+  for (int i = 0; i < num_loops; ++i) {
+    auto loop = make_unique<S2Loop>();
+    loop->set_s2debug_override(s2debug_override());
+    if (!loop->DecodeCompressed(decoder, snap_level)) {
+      return false;
+    }
+    loops_.push_back(std::move(loop));
+  }
+  InitLoopProperties();
+  return true;
+}
+
+S2Polygon::Shape::Shape(const S2Polygon* polygon)
+    : cumulative_edges_(nullptr) {
+  Init(polygon);
+}
+
+void S2Polygon::Shape::Init(const S2Polygon* polygon) {
+  polygon_ = polygon;
+  delete[] cumulative_edges_;
+  cumulative_edges_ = nullptr;
+  num_edges_ = 0;
+  if (!polygon->is_full()) {
+    const int kMaxLinearSearchLoops = 12;  // From benchmarks.
+    int num_loops = polygon->num_loops();
+    if (num_loops > kMaxLinearSearchLoops) {
+      cumulative_edges_ = new int[num_loops];
+    }
+    for (int i = 0; i < num_loops; ++i) {
+      if (cumulative_edges_) cumulative_edges_[i] = num_edges_;
+      num_edges_ += polygon->loop(i)->num_vertices();
+    }
+  }
+}
+
+S2Polygon::Shape::~Shape() {
+  delete[] cumulative_edges_;
+}
+
+S2Shape::Edge S2Polygon::Shape::edge(int e) const {
+  S2_DCHECK_LT(e, num_edges());
+  const S2Polygon* p = polygon();
+  int i;
+  if (cumulative_edges_) {
+    // "upper_bound" finds the loop just beyond the one we want.
+    int* start = std::upper_bound(cumulative_edges_,
+                                  cumulative_edges_ + p->num_loops(), e) - 1;
+    i = start - cumulative_edges_;
+    e -= *start;
+  } else {
+    // When the number of loops is small, linear search is faster.  Most often
+    // there is exactly one loop and the code below executes zero times.
+    for (i = 0; e >= p->loop(i)->num_vertices(); ++i) {
+      e -= p->loop(i)->num_vertices();
+    }
+  }
+  return Edge(p->loop(i)->oriented_vertex(e),
+              p->loop(i)->oriented_vertex(e + 1));
+}
+
+S2Shape::ReferencePoint S2Polygon::Shape::GetReferencePoint() const {
+  const S2Polygon* p = polygon();
+  bool contains_origin = false;
+  for (int i = 0; i < p->num_loops(); ++i) {
+    contains_origin ^= p->loop(i)->contains_origin();
+  }
+  return ReferencePoint(S2::Origin(), contains_origin);
+}
+
+int S2Polygon::Shape::num_chains() const {
+  return polygon_->num_loops();
+}
+
+S2Shape::Chain S2Polygon::Shape::chain(int i) const {
+  S2_DCHECK_LT(i, Shape::num_chains());
+  if (cumulative_edges_) {
+    return Chain(cumulative_edges_[i], polygon_->loop(i)->num_vertices());
+  } else {
+    int e = 0;
+    for (int j = 0; j < i; ++j) e += polygon_->loop(j)->num_vertices();
+    // S2Polygon represents a full loop as a loop with one vertex, while
+    // S2Shape represents a full loop as a chain with no vertices.
+    int num_vertices = polygon_->loop(i)->num_vertices();
+    return Chain(e, (num_vertices == 1) ? 0 : num_vertices);
+  }
+}
+
+S2Shape::Edge S2Polygon::Shape::chain_edge(int i, int j) const {
+  S2_DCHECK_LT(i, Shape::num_chains());
+  S2_DCHECK_LT(j, polygon_->loop(i)->num_vertices());
+  return Edge(polygon()->loop(i)->oriented_vertex(j),
+              polygon()->loop(i)->oriented_vertex(j + 1));
+}
+
+S2Shape::ChainPosition S2Polygon::Shape::chain_position(int e) const {
+  // TODO(ericv): Make inline to remove code duplication with GetEdge.
+  S2_DCHECK_LT(e, num_edges());
+  const S2Polygon* p = polygon();
+  int i;
+  if (cumulative_edges_) {
+    // "upper_bound" finds the loop just beyond the one we want.
+    int* start = std::upper_bound(cumulative_edges_,
+                                  cumulative_edges_ + p->num_loops(), e) - 1;
+    i = start - cumulative_edges_;
+    e -= *start;
+  } else {
+    // When the number of loops is small, linear search is faster.  Most often
+    // there is exactly one loop and the code below executes zero times.
+    for (i = 0; e >= p->loop(i)->num_vertices(); ++i) {
+      e -= p->loop(i)->num_vertices();
+    }
+  }
+  return ChainPosition(i, e);
+}
+
+size_t S2Polygon::SpaceUsed() const {
+  size_t size = sizeof(*this);
+  for (int i = 0; i < num_loops(); ++i) {
+    size += loop(i)->SpaceUsed();
+  }
+  size += index_.SpaceUsed() - sizeof(index_);
+  return size;
+}
diff --git a/src/s2/s2polygon.h b/src/s2/s2polygon.h
new file mode 100644 (file)
index 0000000..5906ad0
--- /dev/null
@@ -0,0 +1,934 @@
+// Copyright 2005 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// Author: ericv@google.com (Eric Veach)
+
+#ifndef S2_S2POLYGON_H_
+#define S2_S2POLYGON_H_
+
+#include <atomic>
+#include <cstddef>
+#include <map>
+#include <vector>
+
+#include "s2/base/integral_types.h"
+#include "absl/base/macros.h"
+#include "s2/_fp_contract_off.h"
+#include "s2/mutable_s2shape_index.h"
+#include "s2/s1angle.h"
+#include "s2/s2boolean_operation.h"
+#include "s2/s2builder.h"
+#include "s2/s2cell_id.h"
+#include "s2/s2debug.h"
+#include "s2/s2latlng_rect.h"
+#include "s2/s2loop.h"
+#include "s2/s2polyline.h"
+#include "s2/s2region.h"
+#include "s2/s2shape_index.h"
+
+class Decoder;
+class Encoder;
+class S1Angle;
+class S2Cap;
+class S2Cell;
+class S2CellUnion;
+class S2Error;
+class S2Loop;
+class S2PolygonBuilder;
+class S2Polyline;
+struct S2XYZFaceSiTi;
+
+// An S2Polygon is an S2Region object that represents a polygon.  A polygon is
+// defined by zero or more loops; recall that the interior of a loop is
+// defined to be its left-hand side (see S2Loop).  There are two different
+// conventions for creating an S2Polygon:
+//
+//   - InitNested() expects the input loops to be nested hierarchically.  The
+//     polygon interior then consists of the set of points contained by an odd
+//     number of loops.  So for example, a circular region with a hole in it
+//     would be defined as two CCW loops, with one loop containing the other.
+//     The loops can be provided in any order.
+//
+//     When the orientation of the input loops is unknown, the nesting
+//     requirement is typically met by calling S2Loop::Normalize() on each
+//     loop (which inverts the loop if necessary so that it encloses at most
+//     half the sphere).  But in fact any set of loops can be used as long as
+//     (1) there is no pair of loops that cross, and (2) there is no pair of
+//     loops whose union is the entire sphere.
+//
+//   - InitOriented() expects the input loops to be oriented such that the
+//     polygon interior is on the left-hand side of every loop.  So for
+//     example, a circular region with a hole in it would be defined using a
+//     CCW outer loop and a CW inner loop.  The loop orientations must all be
+//     consistent; for example, it is not valid to have one CCW loop nested
+//     inside another CCW loop, because the region between the two loops is on
+//     the left-hand side of one loop and the right-hand side of the other.
+//
+// Most clients will not call these methods directly; instead they should use
+// S2Builder, which has better support for dealing with imperfect data.
+//
+// When the polygon is initialized, the given loops are automatically
+// converted into a canonical form consisting of "shells" and "holes".  Shells
+// and holes are both oriented CCW, and are nested hierarchically.  The loops
+// are reordered to correspond to a preorder traversal of the nesting
+// hierarchy; InitOriented may also invert some loops. The set of input S2Loop
+// pointers is always preserved; the caller can use this to determine how the
+// loops were reordered if desired.
+//
+// Polygons may represent any region of the sphere with a polygonal boundary,
+// including the entire sphere (known as the "full" polygon).  The full
+// polygon consists of a single full loop (see S2Loop), whereas the empty
+// polygon has no loops at all.
+//
+// Polygons have the following restrictions:
+//
+//  - Loops may not cross, i.e. the boundary of a loop may not intersect
+//    both the interior and exterior of any other loop.
+//
+//  - Loops may not share edges, i.e. if a loop contains an edge AB, then
+//    no other loop may contain AB or BA.
+//
+//  - Loops may share vertices, however no vertex may appear twice in a
+//    single loop (see S2Loop).
+//
+//  - No loop may be empty.  The full loop may appear only in the full polygon.
+
+class S2Polygon final : public S2Region {
+ public:
+  // The default constructor creates an empty polygon.  It can be made
+  // non-empty by calling Init(), Decode(), etc.
+  S2Polygon();
+
+  // Hide these overloads from SWIG to prevent compilation errors.
+  // TODO(user): Fix the SWIG wrapping in a better way.
+#ifndef SWIG
+  // Convenience constructor that calls InitNested() with the given loops.
+  //
+  // When called with override == S2Debug::ALLOW, the automatic validity
+  // checking is controlled by --s2debug (which is true by default in
+  // non-optimized builds).  When this flag is enabled, a fatal error is
+  // generated whenever an invalid polygon is constructed.
+  //
+  // With override == S2Debug::DISABLE, the automatic validity checking
+  // is disabled.  The main reason to do this is if you intend to call
+  // IsValid() explicitly.  (See set_s2debug_override() for details.)
+  // Example:
+  //
+  //   std::vector<std::unique_ptr<S2Loop>> loops;
+  //   // ... set up loops ...
+  //   S2Polygon* polygon = new S2Polygon(std::move(loops), S2Debug::DISABLE);
+  //
+  // This is equivalent to:
+  //
+  //   S2Polygon* polygon = new S2Polygon;
+  //   polygon->set_s2debug_override(S2Debug::DISABLE);
+  //   polygon->InitNested(std::move(loops));
+  explicit S2Polygon(std::vector<std::unique_ptr<S2Loop> > loops,
+                     S2Debug override = S2Debug::ALLOW);
+#endif
+
+  // Convenience constructor that creates a polygon with a single loop
+  // corresponding to the given cell.
+  explicit S2Polygon(const S2Cell& cell);
+
+#ifndef SWIG
+  // Convenience constructor that calls Init(S2Loop*).  Note that this method
+  // automatically converts the special empty loop (see S2Loop) into an empty
+  // polygon, unlike the vector-of-loops constructor which does not allow
+  // empty loops at all.
+  explicit S2Polygon(std::unique_ptr<S2Loop> loop,
+                     S2Debug override = S2Debug::ALLOW);
+
+  // Create a polygon from a set of hierarchically nested loops.  The polygon
+  // interior consists of the points contained by an odd number of loops.
+  // (Recall that a loop contains the set of points on its left-hand side.)
+  //
+  // This method figures out the loop nesting hierarchy and assigns every
+  // loop a depth.  Shells have even depths, and holes have odd depths.  Note
+  // that the loops are reordered so the hierarchy can be traversed more
+  // easily (see GetParent(), GetLastDescendant(), and S2Loop::depth()).
+  //
+  // This method may be called more than once, in which case any existing
+  // loops are deleted before being replaced by the input loops.
+  void InitNested(std::vector<std::unique_ptr<S2Loop> > loops);
+
+  // Like InitNested(), but expects loops to be oriented such that the polygon
+  // interior is on the left-hand side of all loops.  This implies that shells
+  // and holes should have opposite orientations in the input to this method.
+  // (During initialization, loops representing holes will automatically be
+  // inverted.)
+  void InitOriented(std::vector<std::unique_ptr<S2Loop> > loops);
+
+  // Initialize a polygon from a single loop.  Note that this method
+  // automatically converts the special empty loop (see S2Loop) into an empty
+  // polygon, unlike the vector-of-loops InitNested() method which does not
+  // allow empty loops at all.
+  void Init(std::unique_ptr<S2Loop> loop);
+#endif  // !defined(SWIG)
+
+  // Releases ownership of and returns the loops of this polygon, and resets
+  // the polygon to be empty.
+  std::vector<std::unique_ptr<S2Loop> > Release();
+
+  // Makes a deep copy of the given source polygon.  The destination polygon
+  // will be cleared if necessary.
+  void Copy(const S2Polygon* src);
+
+  // Destroys the polygon and frees its loops.
+  ~S2Polygon() override;
+
+  // Allows overriding the automatic validity checks controlled by
+  // --s2debug (which is true by default in non-optimized builds).
+  // When this flag is enabled, a fatal error is generated whenever
+  // an invalid polygon is constructed.  The main reason to disable
+  // this flag is if you intend to call IsValid() explicitly, like this:
+  //
+  //   S2Polygon polygon;
+  //   polygon.set_s2debug_override(S2Debug::DISABLE);
+  //   polygon.Init(...);
+  //   if (!polygon.IsValid()) { ... }
+  //
+  // This setting is preserved across calls to Init() and Decode().
+  void set_s2debug_override(S2Debug override);
+  S2Debug s2debug_override() const;
+
+  // Returns true if this is a valid polygon (including checking whether all
+  // the loops are themselves valid).  Note that validity is checked
+  // automatically during initialization when --s2debug is enabled (true by
+  // default in debug binaries).
+  bool IsValid() const;
+
+  // Returns true if this is *not* a valid polygon and sets "error"
+  // appropriately.  Otherwise returns false and leaves "error" unchanged.
+  //
+  // Note that in error messages, loops that represent holes have their edges
+  // numbered in reverse order, starting from the last vertex of the loop.
+  //
+  // REQUIRES: error != nullptr
+  bool FindValidationError(S2Error* error) const;
+
+  // Return true if this is the empty polygon (consisting of no loops).
+  bool is_empty() const { return loops_.empty(); }
+
+  // Return true if this is the full polygon (consisting of a single loop that
+  // encompasses the entire sphere).
+  bool is_full() const { return num_loops() == 1 && loop(0)->is_full(); }
+
+  // Return the number of loops in this polygon.
+  int num_loops() const { return static_cast<int>(loops_.size()); }
+
+  // Total number of vertices in all loops.
+  int num_vertices() const { return num_vertices_; }
+
+  // Return the loop at the given index.  Note that during initialization, the
+  // given loops are reordered according to a preorder traversal of the loop
+  // nesting hierarchy.  This implies that every loop is immediately followed
+  // by its descendants.  This hierarchy can be traversed using the methods
+  // GetParent(), GetLastDescendant(), and S2Loop::depth().
+  const S2Loop* loop(int k) const { return loops_[k].get(); }
+  S2Loop* loop(int k) { return loops_[k].get(); }
+
+  // Return the index of the parent of loop k, or -1 if it has no parent.
+  int GetParent(int k) const;
+
+  // Return the index of the last loop that is contained within loop k.
+  // Returns num_loops() - 1 if k < 0.  Note that loops are indexed according
+  // to a preorder traversal of the nesting hierarchy, so the immediate
+  // children of loop k can be found by iterating over loops
+  // (k+1)..GetLastDescendant(k) and selecting those whose depth is equal to
+  // (loop(k)->depth() + 1).
+  int GetLastDescendant(int k) const;
+
+  // Return the area of the polygon interior, i.e. the region on the left side
+  // of an odd number of loops.  The return value is between 0 and 4*Pi.
+  double GetArea() const;
+
+  // Return the true centroid of the polygon multiplied by the area of the
+  // polygon (see s2centroids.h for details on centroids).  The result is not
+  // unit length, so you may want to normalize it.  Also note that in general,
+  // the centroid may not be contained by the polygon.
+  //
+  // We prescale by the polygon area for two reasons: (1) it is cheaper to
+  // compute this way, and (2) it makes it easier to compute the centroid of
+  // more complicated shapes (by splitting them into disjoint regions and
+  // adding their centroids).
+  S2Point GetCentroid() const;
+
+  // If all of the polygon's vertices happen to be the centers of S2Cells at
+  // some level, then return that level, otherwise return -1.  See also
+  // InitToSnapped() and s2builderutil::S2CellIdSnapFunction.
+  // Returns -1 if the polygon has no vertices.
+  int GetSnapLevel() const;
+
+  // Return the distance from the given point to the polygon interior.  If the
+  // polygon is empty, return S1Angle::Infinity().  "x" should be unit length.
+  S1Angle GetDistance(const S2Point& x) const;
+
+  // Return the distance from the given point to the polygon boundary.  If the
+  // polygon is empty or full, return S1Angle::Infinity() (since the polygon
+  // has no boundary).  "x" should be unit length.
+  S1Angle GetDistanceToBoundary(const S2Point& x) const;
+
+  // Return the overlap fractions between two polygons, i.e. the ratios of the
+  // area of intersection to the area of each polygon.
+  static std::pair<double, double> GetOverlapFractions(const S2Polygon* a,
+                                                       const S2Polygon* b);
+
+  // If the given point is contained by the polygon, return it.  Otherwise
+  // return the closest point on the polygon boundary.  If the polygon is
+  // empty, return the input argument.  Note that the result may or may not be
+  // contained by the polygon.  "x" should be unit length.
+  S2Point Project(const S2Point& x) const;
+
+  // Return the closest point on the polygon boundary to the given point.  If
+  // the polygon is empty or full, return the input argument (since the
+  // polygon has no boundary).  "x" should be unit length.
+  S2Point ProjectToBoundary(const S2Point& x) const;
+
+  // Return true if this polygon contains the given other polygon, i.e.
+  // if polygon A contains all points contained by polygon B.
+  bool Contains(const S2Polygon* b) const;
+
+  // Returns true if this polgyon (A) approximately contains the given other
+  // polygon (B). This is true if it is possible to move the vertices of B
+  // no further than "tolerance" such that A contains the modified B.
+  //
+  // For example, the empty polygon will contain any polygon whose maximum
+  // width is no more than "tolerance".
+  bool ApproxContains(const S2Polygon* b, S1Angle tolerance) const;
+
+  // Return true if this polygon intersects the given other polygon, i.e.
+  // if there is a point that is contained by both polygons.
+  bool Intersects(const S2Polygon* b) const;
+
+  // Returns true if this polgyon (A) and the given polygon (B) are
+  // approximately disjoint.  This is true if it is possible to ensure that A
+  // and B do not intersect by moving their vertices no further than
+  // "tolerance".  This implies that in borderline cases where A and B overlap
+  // slightly, this method returns true (A and B are approximately disjoint).
+  //
+  // For example, any polygon is approximately disjoint from a polygon whose
+  // maximum width is no more than "tolerance".
+  bool ApproxDisjoint(const S2Polygon* b, S1Angle tolerance) const;
+
+  // Initialize this polygon to the intersection, union, difference (A - B),
+  // or symmetric difference (XOR) of the given two polygons.
+  //
+  // "snap_function" allows you to specify a minimum spacing between output
+  // vertices, and/or that the vertices should be snapped to a discrete set of
+  // points (e.g. S2CellId centers or E7 lat/lng coordinates).  Any snap
+  // function can be used, including the IdentitySnapFunction with a
+  // snap_radius of zero (which preserves the input vertices exactly).
+  //
+  // The boundary of the output polygon before snapping is guaranteed to be
+  // accurate to within S2::kIntersectionError of the exact result.
+  // Snapping can move the boundary by an additional distance that depends on
+  // the snap function.  Finally, any degenerate portions of the output
+  // polygon are automatically removed (i.e., regions that do not contain any
+  // points) since S2Polygon does not allow such regions.
+  //
+  // See S2Builder and s2builderutil for more details on snap functions.  For
+  // example, you can snap to E7 coordinates by setting "snap_function" to
+  // s2builderutil::IntLatLngSnapFunction(7).
+  //
+  // The default snap function is the IdentitySnapFunction with a snap radius
+  // of S2::kIntersectionMergeRadius (equal to about 1.8e-15 radians
+  // or 11 nanometers on the Earth's surface).  This means that vertices may
+  // be positioned arbitrarily, but vertices that are extremely close together
+  // can be merged together.  The reason for a non-zero default snap radius is
+  // that it helps to eliminate narrow cracks and slivers when T-vertices are
+  // present.  For example, adjacent S2Cells at different levels do not share
+  // exactly the same boundary, so there can be a narrow crack between them.
+  // If a polygon is intersected with those cells and the pieces are unioned
+  // together, the result would have a narrow crack unless the snap radius is
+  // set to a non-zero value.
+  //
+  // Note that if you want to encode the vertices in a lower-precision
+  // representation (such as S2CellIds or E7), it is much better to use a
+  // suitable SnapFunction rather than rounding the vertices yourself, because
+  // this will create self-intersections unless you ensure that the vertices
+  // and edges are sufficiently well-separated first.  In particular you need
+  // to use a snap function whose min_edge_vertex_separation() is at least
+  // twice the maximum distance that a vertex can move when rounded.
+  //
+  // The versions of these functions with an S2Error argument return true on
+  // success and set "error" appropriately otherwise.  However note that these
+  // functions should never return an error provided that both input polygons
+  // are valid (i.e., IsValid() returns true).
+  void InitToIntersection(const S2Polygon* a, const S2Polygon* b);
+  void InitToIntersection(const S2Polygon& a, const S2Polygon& b,
+                          const S2Builder::SnapFunction& snap_function);
+  bool InitToIntersection(const S2Polygon& a, const S2Polygon& b,
+                          const S2Builder::SnapFunction& snap_function,
+                          S2Error *error);
+
+  void InitToUnion(const S2Polygon* a, const S2Polygon* b);
+  void InitToUnion(const S2Polygon& a, const S2Polygon& b,
+                   const S2Builder::SnapFunction& snap_function);
+  bool InitToUnion(const S2Polygon& a, const S2Polygon& b,
+                   const S2Builder::SnapFunction& snap_function,
+                   S2Error *error);
+
+  void InitToDifference(const S2Polygon* a, const S2Polygon* b);
+  void InitToDifference(const S2Polygon& a, const S2Polygon& b,
+                        const S2Builder::SnapFunction& snap_function);
+  bool InitToDifference(const S2Polygon& a, const S2Polygon& b,
+                        const S2Builder::SnapFunction& snap_function,
+                        S2Error *error);
+
+  void InitToSymmetricDifference(const S2Polygon* a, const S2Polygon* b);
+  void InitToSymmetricDifference(const S2Polygon& a, const S2Polygon& b,
+                                 const S2Builder::SnapFunction& snap_function);
+  bool InitToSymmetricDifference(const S2Polygon& a, const S2Polygon& b,
+                                 const S2Builder::SnapFunction& snap_function,
+                                 S2Error *error);
+
+  // Convenience functions that use the IdentitySnapFunction with the given
+  // snap radius.  TODO(ericv): Consider deprecating these and require the
+  // snap function to be specified explcitly?
+  void InitToApproxIntersection(const S2Polygon* a, const S2Polygon* b,
+                                S1Angle snap_radius);
+  void InitToApproxUnion(const S2Polygon* a, const S2Polygon* b,
+                         S1Angle snap_radius);
+  void InitToApproxDifference(const S2Polygon* a, const S2Polygon* b,
+                              S1Angle snap_radius);
+  void InitToApproxSymmetricDifference(const S2Polygon* a, const S2Polygon* b,
+                                       S1Angle snap_radius);
+
+  // Snaps the vertices of the given polygon using the given SnapFunction
+  // (e.g., s2builderutil::IntLatLngSnapFunction(6) snaps to E6 coordinates).
+  // This can change the polygon topology (merging loops, for example), but
+  // the resulting polygon is guaranteed to be valid, and no vertex will move
+  // by more than snap_function.snap_radius().  See S2Builder for other
+  // guarantees (e.g., minimum edge-vertex separation).
+  //
+  // Note that this method is a thin wrapper over S2Builder, so if you are
+  // starting with data that is not in S2Polygon format (e.g., integer E7
+  // coordinates) then it is faster to just use S2Builder directly.
+  void InitToSnapped(const S2Polygon& polygon,
+                     const S2Builder::SnapFunction& snap_function);
+
+  // Convenience function that snaps the vertices to S2CellId centers at the
+  // given level (default level 30, which has S2CellId centers spaced about 1
+  // centimeter apart).  Polygons can be efficiently encoded by Encode() after
+  // they have been snapped.
+  void InitToSnapped(const S2Polygon* polygon,
+                     int snap_level = S2CellId::kMaxLevel);
+
+  // Snaps the input polygon according to the given "snap_function" and
+  // reduces the number of vertices if possible, while ensuring that no vertex
+  // moves further than snap_function.snap_radius().
+  //
+  // Simplification works by replacing nearly straight chains of short edges
+  // with longer edges, in a way that preserves the topology of the input
+  // polygon up to the creation of degeneracies.  This means that loops or
+  // portions of loops may become degenerate, in which case they are removed.
+  // For example, if there is a very small island in the original polygon, it
+  // may disappear completely.  (Even if there are dense islands, they could
+  // all be removed rather than being replaced by a larger simplified island
+  // if more area is covered by water than land.)
+  void InitToSimplified(const S2Polygon& a,
+                        const S2Builder::SnapFunction& snap_function);
+
+  // Like InitToSimplified, except that any vertices or edges on the boundary
+  // of the given S2Cell are preserved if possible.  This method requires that
+  // the polygon has already been clipped so that it does not extend outside
+  // the cell by more than "boundary_tolerance".  In other words, it operates
+  // on polygons that have already been intersected with a cell.
+  //
+  // Typically this method is used in geometry-processing pipelines that
+  // intersect polygons with a collection of S2Cells and then process those
+  // cells in parallel, where each cell generates some geometry that needs to
+  // be simplified.  In contrast, if you just need to simplify the *input*
+  // geometry then it is easier and faster to do the simplification before
+  // computing the intersection with any S2Cells.
+  //
+  // "boundary_tolerance" specifies how close a vertex must be to the cell
+  // boundary to be kept.  The default tolerance is large enough to handle any
+  // reasonable way of interpolating points along the cell boundary, such as
+  // S2::GetIntersection(), S2::Interpolate(), or direct (u,v)
+  // interpolation using S2::FaceUVtoXYZ().  However, if the vertices have
+  // been snapped to a lower-precision representation (e.g., S2CellId centers
+  // or E7 coordinates) then you will need to set this tolerance explicitly.
+  // For example, if the vertices were snapped to E7 coordinates then
+  // "boundary_tolerance" should be set to
+  //
+  //   s2builderutil::IntLatLngSnapFunction::MinSnapRadiusForExponent(7)
+  //
+  // Degenerate portions of loops are always removed, so if a vertex on the
+  // cell boundary belongs only to degenerate regions then it will not be
+  // kept.  For example, if the input polygon is a narrow strip of width less
+  // than "snap_radius" along one side of the cell, then the entire loop may
+  // become degenerate and be removed.
+  //
+  // REQUIRES: all vertices of "a" are within "boundary_tolerance" of "cell".
+  void InitToSimplifiedInCell(
+      const S2Polygon* a, const S2Cell& cell, S1Angle snap_radius,
+      S1Angle boundary_tolerance = S1Angle::Radians(1e-15));
+
+  // Initialize this polygon to the complement of the given polygon.
+  void InitToComplement(const S2Polygon* a);
+
+  // Invert the polygon (replace it by its complement).
+  void Invert();
+
+  // Return true if this polygon contains the given polyline.  This method
+  // returns an exact result, according to the following model:
+  //
+  //  - All edges are geodesics (of course).
+  //
+  //  - Vertices are ignored for the purposes of defining containment.
+  //    (This is because polygons often do not contain their vertices, in
+  //    order to that when a set of polygons tiles the sphere then every point
+  //    is contained by exactly one polygon.)
+  //
+  //  - Points that lie exactly on geodesic edges are resolved using symbolic
+  //    perturbations (i.e., they are considered to be infinitesmally offset
+  //    from the edge).
+  //
+  //  - If the polygon and polyline share an edge, it is handled as follows.
+  //    First, the polygon edges are oriented so that the interior is always
+  //    on the left.  Then the shared polyline edge is contained if and only
+  //    if it is in the same direction as the corresponding polygon edge.
+  //    (This model ensures that when a polyline is intersected with a polygon
+  //    and its complement, the edge only appears in one of the two results.)
+  //
+  // TODO(ericv): Update the implementation to correspond to the model above.
+  bool Contains(const S2Polyline& b) const;
+
+  // Returns true if this polgyon approximately contains the given polyline
+  // This is true if it is possible to move the polyline vertices no further
+  // than "tolerance" such that the polyline is now contained.
+  bool ApproxContains(const S2Polyline& b, S1Angle tolerance) const;
+
+  // Return true if this polygon intersects the given polyline.  This method
+  // returns an exact result; see Contains(S2Polyline) for details.
+  bool Intersects(const S2Polyline& b) const;
+
+  // Returns true if this polgyon is approximately disjoint from the given
+  // polyline.  This is true if it is possible to avoid intersection by moving
+  // their vertices no further than "tolerance".
+  //
+  // This implies that in borderline cases where there is a small overlap,
+  // this method returns true (i.e., they are approximately disjoint).
+  bool ApproxDisjoint(const S2Polyline& b, S1Angle tolerance) const;
+
+#ifndef SWIG
+  // Intersect this polygon with the polyline "in" and return the resulting
+  // zero or more polylines.  The polylines are returned in the order they
+  // would be encountered by traversing "in" from beginning to end.
+  // Note that the output may include polylines with only one vertex,
+  // but there will not be any zero-vertex polylines.
+  //
+  // This is equivalent to calling ApproxIntersectWithPolyline() with the
+  // "snap_radius" set to S2::kIntersectionMergeRadius.
+  std::vector<std::unique_ptr<S2Polyline> > IntersectWithPolyline(
+      const S2Polyline& in) const;
+
+  // Similar to IntersectWithPolyline(), except that vertices will be
+  // dropped as necessary to ensure that all adjacent vertices in the
+  // sequence obtained by concatenating the output polylines will be
+  // farther than "snap_radius" apart.  Note that this can change
+  // the number of output polylines and/or yield single-vertex polylines.
+  std::vector<std::unique_ptr<S2Polyline> > ApproxIntersectWithPolyline(
+      const S2Polyline& in, S1Angle snap_radius) const;
+
+  // TODO(ericv): Update documentation.
+  std::vector<std::unique_ptr<S2Polyline>> IntersectWithPolyline(
+      const S2Polyline& in, const S2Builder::SnapFunction& snap_function) const;
+
+  // Same as IntersectWithPolyline, but subtracts this polygon from
+  // the given polyline.
+  std::vector<std::unique_ptr<S2Polyline> > SubtractFromPolyline(
+      const S2Polyline& in) const;
+
+  // Same as ApproxIntersectWithPolyline, but subtracts this polygon
+  // from the given polyline.
+  std::vector<std::unique_ptr<S2Polyline> > ApproxSubtractFromPolyline(
+      const S2Polyline& in, S1Angle snap_radius) const;
+
+  std::vector<std::unique_ptr<S2Polyline>> SubtractFromPolyline(
+      const S2Polyline& in, const S2Builder::SnapFunction& snap_function) const;
+
+  // Return a polygon which is the union of the given polygons.
+  static std::unique_ptr<S2Polygon> DestructiveUnion(
+      std::vector<std::unique_ptr<S2Polygon> > polygons);
+  static std::unique_ptr<S2Polygon> DestructiveApproxUnion(
+      std::vector<std::unique_ptr<S2Polygon> > polygons,
+      S1Angle snap_radius);
+#endif  // !defined(SWIG)
+
+  // Initialize this polygon to the outline of the given cell union.
+  // In principle this polygon should exactly contain the cell union and
+  // this polygon's inverse should not intersect the cell union, but rounding
+  // issues may cause this not to be the case.
+  void InitToCellUnionBorder(const S2CellUnion& cells);
+
+  // Return true if every loop of this polygon shares at most one vertex with
+  // its parent loop.  Every polygon has a unique normalized form.  A polygon
+  // can be normalized by passing it through S2Builder (with no snapping) in
+  // order to reconstruct the polygon from its edges.
+  //
+  // Generally there is no reason to convert polygons to normalized form.  It
+  // is mainly useful for testing in order to compare whether two polygons
+  // have exactly the same interior, even when they have a different loop
+  // structure.  For example, a diamond nested within a square (touching at
+  // four points) could be represented as a square with a diamond-shaped hole,
+  // or as four triangles.  Methods such as BoundaryApproxEquals() will report
+  // these polygons as being different (because they have different
+  // boundaries) even though they contain the same points.  However if they
+  // are both converted to normalized form (the "four triangles" version) then
+  // they can be compared more easily.
+  //
+  // Also see ApproxEquals(), which can determine whether two polygons contain
+  // approximately the same set of points without any need for normalization.
+  bool IsNormalized() const;
+
+  // Return true if two polygons have exactly the same loops.  The loops must
+  // appear in the same order, and corresponding loops must have the same
+  // linear vertex ordering (i.e., cyclic rotations are not allowed).
+  bool Equals(const S2Polygon* b) const;
+
+  // Return true if two polygons are approximately equal to within the given
+  // tolerance.  This is true if it is possible to move the vertices of the
+  // two polygons so that they contain the same set of points.
+  //
+  // Note that according to this model, small regions less than "tolerance" in
+  // width do not need to be considered, since these regions can be collapsed
+  // into degenerate loops (which contain no points) by moving their vertices.
+  //
+  // This model is not as strict as using the Hausdorff distance would be, and
+  // it is also not as strict as BoundaryNear (defined below).  However, it is
+  // a good choice for comparing polygons that have been snapped, simplified,
+  // unioned, etc, since these operations use a model similar to this one
+  // (i.e., degenerate loops or portions of loops are automatically removed).
+  bool ApproxEquals(const S2Polygon* b, S1Angle tolerance) const;
+
+  // Returns true if two polygons have the same boundary.  More precisely,
+  // this method requires that both polygons have loops with the same cyclic
+  // vertex order and the same nesting hierarchy.  (This implies that vertices
+  // may be cyclically rotated between corresponding loops, and the loop
+  // ordering may be different between the two polygons as long as the nesting
+  // hierarchy is the same.)
+  bool BoundaryEquals(const S2Polygon* b) const;
+
+  // Return true if two polygons have the same boundary except for vertex
+  // perturbations.  Both polygons must have loops with the same cyclic vertex
+  // order and the same nesting hierarchy, but the vertex locations are
+  // allowed to differ by up to "max_error".
+  bool BoundaryApproxEquals(const S2Polygon& b,
+                            S1Angle max_error = S1Angle::Radians(1e-15)) const;
+
+  // Return true if two polygons have boundaries that are within "max_error"
+  // of each other along their entire lengths.  More precisely, there must be
+  // a bijection between the two sets of loops such that for each pair of
+  // loops, "a_loop->BoundaryNear(b_loop)" is true.
+  bool BoundaryNear(const S2Polygon& b,
+                    S1Angle max_error = S1Angle::Radians(1e-15)) const;
+
+  // Returns the total number of bytes used by the polygon.
+  size_t SpaceUsed() const;
+
+  ////////////////////////////////////////////////////////////////////////
+  // S2Region interface (see s2region.h for details):
+
+  // GetRectBound() returns essentially tight results, while GetCapBound()
+  // might have a lot of extra padding.  Both bounds are conservative in that
+  // if the loop contains a point P, then the bound contains P also.
+  S2Polygon* Clone() const override;
+  S2Cap GetCapBound() const override;  // Cap surrounding rect bound.
+  S2LatLngRect GetRectBound() const override { return bound_; }
+  void GetCellUnionBound(std::vector<S2CellId> *cell_ids) const override;
+
+  bool Contains(const S2Cell& cell) const override;
+  bool MayIntersect(const S2Cell& cell) const override;
+
+  // The point 'p' does not need to be normalized.
+  bool Contains(const S2Point& p) const override;
+
+  // Appends a serialized representation of the S2Polygon to "encoder".
+  //
+  // The encoding uses about 4 bytes per vertex for typical polygons in
+  // Google's geographic repository, assuming that most vertices have been
+  // snapped to the centers of S2Cells at some fixed level (typically using
+  // InitToSnapped). The remaining vertices are stored using 24 bytes.
+  // Decoding a polygon encoded this way always returns the original polygon,
+  // without any loss of precision.
+  //
+  // The snap level is chosen to be the one that has the most vertices snapped
+  // to S2Cells at that level.  If most vertices need 24 bytes, then all
+  // vertices are encoded this way (this method automatically chooses the
+  // encoding that has the best chance of giving the smaller output size).
+  //
+  // REQUIRES: "encoder" uses the default constructor, so that its buffer
+  //           can be enlarged as necessary by calling Ensure(int).
+  void Encode(Encoder* const encoder) const;
+
+  // Encodes the polygon's S2Points directly as three doubles using
+  // (40 + 43 * num_loops + 24 * num_vertices) bytes.
+  //
+  // REQUIRES: "encoder" uses the default constructor, so that its buffer
+  //           can be enlarged as necessary by calling Ensure(int).
+  void EncodeUncompressed(Encoder* encoder) const;
+
+  // Decodes a polygon encoded with Encode().  Returns true on success.
+  bool Decode(Decoder* const decoder);
+
+  // Decodes a polygon by pointing the S2Loop vertices directly into the
+  // decoder's memory buffer (which needs to persist for the lifetime of the
+  // decoded S2Polygon).  It is much faster than Decode(), but requires that
+  // all the polygon vertices were encoded exactly using 24 bytes per vertex.
+  // This essentially requires that the polygon was not snapped beforehand to
+  // a given S2Cell level; otherwise this method falls back to Decode().
+  //
+  // Returns true on success.
+  bool DecodeWithinScope(Decoder* const decoder);
+
+#ifndef SWIG
+  // Wrapper class for indexing a polygon (see S2ShapeIndex).  Once this
+  // object is inserted into an S2ShapeIndex it is owned by that index, and
+  // will be automatically deleted when no longer needed by the index.  Note
+  // that this class does not take ownership of the polygon itself (see
+  // OwningShape below).  You can also subtype this class to store additional
+  // data (see S2Shape for details).
+  //
+  // Note that unlike S2Polygon, the edges of S2Polygon::Shape are directed
+  // such that the polygon interior is always on the left.
+  class Shape : public S2Shape {
+   public:
+    static constexpr TypeTag kTypeTag = 1;
+
+    Shape() : polygon_(nullptr), cumulative_edges_(nullptr) {}
+    ~Shape() override;
+
+    // Initialization.  Does not take ownership of "polygon".  May be called
+    // more than once.
+    // TODO(ericv/jrosenstock): Make "polygon" a const reference.
+    explicit Shape(const S2Polygon* polygon);
+    void Init(const S2Polygon* polygon);
+
+    const S2Polygon* polygon() const { return polygon_; }
+
+    // Encodes the polygon using S2Polygon::Encode().
+    void Encode(Encoder* encoder) const {
+      polygon_->Encode(encoder);
+    }
+
+    // Encodes the polygon using S2Polygon::EncodeUncompressed().
+    void EncodeUncompressed(Encoder* encoder) const {
+      polygon_->EncodeUncompressed(encoder);
+    }
+
+    // Decoding is defined only for S2Polyline::OwningShape below.
+
+    // S2Shape interface:
+    int num_edges() const final { return num_edges_; }
+    Edge edge(int e) const final;
+    int dimension() const final { return 2; }
+    ReferencePoint GetReferencePoint() const final;
+    int num_chains() const final;
+    Chain chain(int i) const final;
+    Edge chain_edge(int i, int j) const final;
+    ChainPosition chain_position(int e) const final;
+    TypeTag type_tag() const override { return kTypeTag; }
+
+   private:
+    // The total number of edges in the polygon.  This is the same as
+    // polygon_->num_vertices() except in one case (polygon_->is_full()).  On
+    // the other hand this field doesn't take up any extra space due to field
+    // packing with S2Shape::id_.
+    //
+    // TODO(ericv): Consider using this field instead as an atomic<int> hint to
+    // speed up edge location when there are a large number of loops.  Also
+    // consider changing S2Polygon::num_vertices to num_edges instead.
+    int num_edges_;
+
+    const S2Polygon* polygon_;
+
+    // An array where element "i" is the total number of edges in loops 0..i-1.
+    // This field is only used for polygons that have a large number of loops.
+    int* cumulative_edges_;
+  };
+
+  // Like Shape, except that the S2Polygon is automatically deleted when this
+  // object is deleted by the S2ShapeIndex.  This is useful when an S2Polygon
+  // is constructed solely for the purpose of indexing it.
+  class OwningShape : public Shape {
+   public:
+    OwningShape() {}  // Must call Init().
+
+    explicit OwningShape(std::unique_ptr<const S2Polygon> polygon)
+        : Shape(polygon.get()), owned_polygon_(std::move(polygon)) {}
+
+    void Init(std::unique_ptr<const S2Polygon> polygon) {
+      Shape::Init(polygon.get());
+      owned_polygon_ = std::move(polygon);
+    }
+
+    bool Init(Decoder* decoder) {
+      auto polygon = absl::make_unique<S2Polygon>();
+      if (!polygon->Decode(decoder)) return false;
+      Shape::Init(polygon.get());
+      owned_polygon_ = std::move(polygon);
+      return true;
+    }
+
+    std::unique_ptr<const S2Polygon> owned_polygon_;
+  };
+#endif  // SWIG
+
+  // Returns the built-in S2ShapeIndex associated with every S2Polygon.  This
+  // can be used in conjunction with the various S2ShapeIndex query classes
+  // (S2ClosestEdgeQuery, S2BooleanOperation, etc) to do things beyond what is
+  // possible with S2Polygon built-in convenience methods.
+  //
+  // For example, to measure the distance from one S2Polygon to another, you
+  // can write:
+  //   S2ClosestEdgeQuery query(&polygon1.index());
+  //   S2ClosestEdgeQuery::ShapeIndexTarget target(&polygon2.index());
+  //   S1ChordAngle distance = query.GetDistance(&target);
+  //
+  // The index contains a single S2Polygon::Shape object.
+  const MutableS2ShapeIndex& index() const { return index_; }
+
+ private:
+  friend class S2Stats;
+  friend class PolygonOperation;
+
+  // Given that loops_ contains a single loop, initialize all other fields.
+  void InitOneLoop();
+
+  // Compute num_vertices_, bound_, subregion_bound_.
+  void InitLoopProperties();
+
+  // Deletes the contents of the loops_ vector and resets the polygon state.
+  void ClearLoops();
+
+  // Return true if there is an error in the loop nesting hierarchy.
+  bool FindLoopNestingError(S2Error* error) const;
+
+  // A map from each loop to its immediate children with respect to nesting.
+  // This map is built during initialization of multi-loop polygons to
+  // determine which are shells and which are holes, and then discarded.
+  typedef std::map<S2Loop*, std::vector<S2Loop*> > LoopMap;
+
+  void InsertLoop(S2Loop* new_loop, S2Loop* parent, LoopMap* loop_map);
+  void InitLoops(LoopMap* loop_map);
+
+  // Add the polygon's loops to the S2ShapeIndex.  (The actual work of
+  // building the index only happens when the index is first used.)
+  void InitIndex();
+
+  // When the loop is modified (Invert(), or Init() called again) then the
+  // indexing structures need to be cleared since they become invalid.
+  void ClearIndex();
+
+  // Initializes the polygon to the result of the given boolean operation,
+  // returning an error on failure.
+  bool InitToOperation(S2BooleanOperation::OpType op_type,
+                       const S2Builder::SnapFunction& snap_function,
+                       const S2Polygon& a, const S2Polygon& b, S2Error* error);
+
+  // Initializes the polygon to the result of the given boolean operation,
+  // logging an error on failure (fatal in debug builds).
+  void InitToOperation(S2BooleanOperation::OpType op_type,
+                       const S2Builder::SnapFunction& snap_function,
+                       const S2Polygon& a, const S2Polygon& b);
+
+  // Initializes the polygon from input polygon "a" using the given S2Builder.
+  // If the result has an empty boundary (no loops), also decides whether the
+  // result should be the full polygon rather than the empty one based on the
+  // area of the input polygon.  (See comments in InitToApproxIntersection.)
+  void InitFromBuilder(const S2Polygon& a, S2Builder* builder);
+
+  std::vector<std::unique_ptr<S2Polyline> > OperationWithPolyline(
+      S2BooleanOperation::OpType op_type,
+      const S2Builder::SnapFunction& snap_function,
+      const S2Polyline& a) const;
+
+  // Decode a polygon encoded with EncodeUncompressed().  Used by the Decode
+  // and DecodeWithinScope methods above.  The within_scope parameter
+  // specifies whether to call DecodeWithinScope on the loops.
+  bool DecodeUncompressed(Decoder* const decoder, bool within_scope);
+
+  // Encode the polygon's vertices using about 4 bytes / vertex plus 24 bytes /
+  // unsnapped vertex. All the loop vertices must be converted first to the
+  // S2XYZFaceSiTi format using S2Loop::GetXYZFaceSiTiVertices, and concatenated
+  // in the all_vertices array.
+  //
+  // REQUIRES: snap_level >= 0.
+  void EncodeCompressed(Encoder* encoder, const S2XYZFaceSiTi* all_vertices,
+                        int snap_level) const;
+
+  // Decode a polygon encoded with EncodeCompressed().
+  bool DecodeCompressed(Decoder* decoder);
+
+  static std::vector<std::unique_ptr<S2Polyline> > SimplifyEdgesInCell(
+      const S2Polygon& a, const S2Cell& cell,
+      double tolerance_uv, S1Angle snap_radius);
+
+  // Internal implementation of intersect/subtract polyline functions above.
+  std::vector<std::unique_ptr<S2Polyline> > InternalClipPolyline(
+      bool invert, const S2Polyline& a, S1Angle snap_radius) const;
+
+  // Defines a total ordering on S2Loops that does not depend on the cyclic
+  // order of loop vertices.  This function is used to choose which loop to
+  // invert in the case where several loops have exactly the same area.
+  static int CompareLoops(const S2Loop* a, const S2Loop* b);
+
+  std::vector<std::unique_ptr<S2Loop> > loops_;
+
+  // Allows overriding the automatic validity checking controlled by the
+  // --s2debug flag.
+  S2Debug s2debug_override_;
+
+  // True if InitOriented() was called and the given loops had inconsistent
+  // orientations (i.e., it is not possible to construct a polygon such that
+  // the interior is on the left-hand side of all loops).  We need to remember
+  // this error so that it can be returned later by FindValidationError(),
+  // since it is not possible to detect this error once the polygon has been
+  // initialized.  This field is not preserved by Encode/Decode.
+  uint8 error_inconsistent_loop_orientations_;
+
+  // Cache for num_vertices().
+  int num_vertices_;
+
+  // In general we build the index the first time it is needed, but we make an
+  // exception for Contains(S2Point) because this method has a simple brute
+  // force implementation that is also relatively cheap.  For this one method
+  // we keep track of the number of calls made and only build the index once
+  // enough calls have been made that we think an index would be worthwhile.
+  mutable std::atomic<int32> unindexed_contains_calls_;
+
+  // "bound_" is a conservative bound on all points contained by this polygon:
+  // if A.Contains(P), then A.bound_.Contains(S2LatLng(P)).
+  S2LatLngRect bound_;
+
+  // Since "bound_" is not exact, it is possible that a polygon A contains
+  // another polygon B whose bounds are slightly larger.  "subregion_bound_"
+  // has been expanded sufficiently to account for this error, i.e.
+  // if A.Contains(B), then A.subregion_bound_.Contains(B.bound_).
+  S2LatLngRect subregion_bound_;
+
+  // Spatial index containing this polygon.
+  MutableS2ShapeIndex index_;
+
+#ifndef SWIG
+  S2Polygon(const S2Polygon&) = delete;
+  void operator=(const S2Polygon&) = delete;
+#endif
+};
+
+#endif  // S2_S2POLYGON_H_
diff --git a/src/s2/s2polyline.cc b/src/s2/s2polyline.cc
new file mode 100644 (file)
index 0000000..acd02e5
--- /dev/null
@@ -0,0 +1,645 @@
+// Copyright 2005 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// Author: ericv@google.com (Eric Veach)
+
+#include "s2/s2polyline.h"
+
+#include <algorithm>
+#include <cmath>
+#include <functional>
+#include <set>
+#include <utility>
+#include <vector>
+
+#include "s2/base/commandlineflags.h"
+#include "s2/base/logging.h"
+#include "absl/utility/utility.h"
+#include "s2/util/coding/coder.h"
+#include "s2/s1angle.h"
+#include "s2/s1interval.h"
+#include "s2/s2cap.h"
+#include "s2/s2cell.h"
+#include "s2/s2debug.h"
+#include "s2/s2edge_crosser.h"
+#include "s2/s2edge_distances.h"
+#include "s2/s2error.h"
+#include "s2/s2latlng_rect_bounder.h"
+#include "s2/s2pointutil.h"
+#include "s2/s2polyline_measures.h"
+#include "s2/s2predicates.h"
+#include "s2/util/math/matrix3x3.h"
+
+using std::max;
+using std::min;
+using std::set;
+using std::vector;
+
+static const unsigned char kCurrentLosslessEncodingVersionNumber = 1;
+
+S2Polyline::S2Polyline()
+  : s2debug_override_(S2Debug::ALLOW) {}
+
+S2Polyline::S2Polyline(S2Polyline&& other)
+  : s2debug_override_(other.s2debug_override_),
+    num_vertices_(absl::exchange(other.num_vertices_, 0)),
+    vertices_(std::move(other.vertices_)) {
+}
+
+S2Polyline& S2Polyline::operator=(S2Polyline&& other) {
+  s2debug_override_ = other.s2debug_override_;
+  num_vertices_ = absl::exchange(other.num_vertices_, 0);
+  vertices_ = std::move(other.vertices_);
+  return *this;
+}
+
+S2Polyline::S2Polyline(const vector<S2Point>& vertices)
+  : S2Polyline(vertices, S2Debug::ALLOW) {}
+
+S2Polyline::S2Polyline(const vector<S2LatLng>& vertices)
+  : S2Polyline(vertices, S2Debug::ALLOW) {}
+
+S2Polyline::S2Polyline(const vector<S2Point>& vertices,
+                       S2Debug override)
+  : s2debug_override_(override) {
+  Init(vertices);
+}
+
+S2Polyline::S2Polyline(const vector<S2LatLng>& vertices,
+                       S2Debug override)
+  : s2debug_override_(override) {
+  Init(vertices);
+}
+
+S2Polyline::~S2Polyline() {
+}
+
+void S2Polyline::set_s2debug_override(S2Debug override) {
+  s2debug_override_ = override;
+}
+
+S2Debug S2Polyline::s2debug_override() const {
+  return s2debug_override_;
+}
+
+void S2Polyline::Init(const vector<S2Point>& vertices) {
+  num_vertices_ = vertices.size();
+  vertices_.reset(new S2Point[num_vertices_]);
+  std::copy(vertices.begin(), vertices.end(), &vertices_[0]);
+  if (FLAGS_s2debug && s2debug_override_ == S2Debug::ALLOW) {
+    S2_CHECK(IsValid());
+  }
+}
+
+void S2Polyline::Init(const vector<S2LatLng>& vertices) {
+  num_vertices_ = vertices.size();
+  vertices_.reset(new S2Point[num_vertices_]);
+  for (int i = 0; i < num_vertices_; ++i) {
+    vertices_[i] = vertices[i].ToPoint();
+  }
+  if (FLAGS_s2debug && s2debug_override_ == S2Debug::ALLOW) {
+    S2_CHECK(IsValid());
+  }
+}
+
+bool S2Polyline::IsValid() const {
+  S2Error error;
+  if (FindValidationError(&error)) {
+    S2_LOG_IF(ERROR, FLAGS_s2debug) << error;
+    return false;
+  }
+  return true;
+}
+
+bool S2Polyline::FindValidationError(S2Error* error) const {
+  // All vertices must be unit length.
+  for (int i = 0; i < num_vertices(); ++i) {
+    if (!S2::IsUnitLength(vertex(i))) {
+      error->Init(S2Error::NOT_UNIT_LENGTH, "Vertex %d is not unit length", i);
+      return true;
+    }
+  }
+  // Adjacent vertices must not be identical or antipodal.
+  for (int i = 1; i < num_vertices(); ++i) {
+    if (vertex(i - 1) == vertex(i)) {
+      error->Init(S2Error::DUPLICATE_VERTICES,
+                  "Vertices %d and %d are identical", i - 1, i);
+      return true;
+    }
+    if (vertex(i - 1) == -vertex(i)) {
+      error->Init(S2Error::ANTIPODAL_VERTICES,
+                  "Vertices %d and %d are antipodal", i - 1, i);
+      return true;
+    }
+  }
+  return false;
+}
+
+S2Polyline::S2Polyline(const S2Polyline& src)
+  : num_vertices_(src.num_vertices_),
+    vertices_(new S2Point[num_vertices_]) {
+  std::copy(&src.vertices_[0], &src.vertices_[num_vertices_], &vertices_[0]);
+}
+
+S2Polyline* S2Polyline::Clone() const {
+  return new S2Polyline(*this);
+}
+
+S1Angle S2Polyline::GetLength() const {
+  return S2::GetLength(S2PointSpan(&vertices_[0], num_vertices_));
+}
+
+S2Point S2Polyline::GetCentroid() const {
+  return S2::GetCentroid(S2PointSpan(&vertices_[0], num_vertices_));
+}
+
+S2Point S2Polyline::GetSuffix(double fraction, int* next_vertex) const {
+  S2_DCHECK_GT(num_vertices(), 0);
+  // We intentionally let the (fraction >= 1) case fall through, since
+  // we need to handle it in the loop below in any case because of
+  // possible roundoff errors.
+  if (fraction <= 0) {
+    *next_vertex = 1;
+    return vertex(0);
+  }
+  S1Angle length_sum;
+  for (int i = 1; i < num_vertices(); ++i) {
+    length_sum += S1Angle(vertex(i-1), vertex(i));
+  }
+  S1Angle target = fraction * length_sum;
+  for (int i = 1; i < num_vertices(); ++i) {
+    S1Angle length(vertex(i-1), vertex(i));
+    if (target < length) {
+      // This interpolates with respect to arc length rather than
+      // straight-line distance, and produces a unit-length result.
+      S2Point result = S2::InterpolateAtDistance(target, vertex(i-1),
+                                                         vertex(i));
+      // It is possible that (result == vertex(i)) due to rounding errors.
+      *next_vertex = (result == vertex(i)) ? (i + 1) : i;
+      return result;
+    }
+    target -= length;
+  }
+  *next_vertex = num_vertices();
+  return vertex(num_vertices() - 1);
+}
+
+S2Point S2Polyline::Interpolate(double fraction) const {
+  int next_vertex;
+  return GetSuffix(fraction, &next_vertex);
+}
+
+double S2Polyline::UnInterpolate(const S2Point& point, int next_vertex) const {
+  S2_DCHECK_GT(num_vertices(), 0);
+  if (num_vertices() < 2) {
+    return 0;
+  }
+  S1Angle length_sum;
+  for (int i = 1; i < next_vertex; ++i) {
+    length_sum += S1Angle(vertex(i-1), vertex(i));
+  }
+  S1Angle length_to_point = length_sum + S1Angle(vertex(next_vertex-1), point);
+  for (int i = next_vertex; i < num_vertices(); ++i) {
+    length_sum += S1Angle(vertex(i-1), vertex(i));
+  }
+  // The ratio can be greater than 1.0 due to rounding errors or because the
+  // point is not exactly on the polyline.
+  return min(1.0, length_to_point / length_sum);
+}
+
+S2Point S2Polyline::Project(const S2Point& point, int* next_vertex) const {
+  S2_DCHECK_GT(num_vertices(), 0);
+
+  if (num_vertices() == 1) {
+    // If there is only one vertex, it is always closest to any given point.
+    *next_vertex = 1;
+    return vertex(0);
+  }
+
+  // Initial value larger than any possible distance on the unit sphere.
+  S1Angle min_distance = S1Angle::Radians(10);
+  int min_index = -1;
+
+  // Find the line segment in the polyline that is closest to the point given.
+  for (int i = 1; i < num_vertices(); ++i) {
+    S1Angle distance_to_segment = S2::GetDistance(point, vertex(i-1),
+                                                          vertex(i));
+    if (distance_to_segment < min_distance) {
+      min_distance = distance_to_segment;
+      min_index = i;
+    }
+  }
+  S2_DCHECK_NE(min_index, -1);
+
+  // Compute the point on the segment found that is closest to the point given.
+  S2Point closest_point =
+      S2::Project(point, vertex(min_index - 1), vertex(min_index));
+
+  *next_vertex = min_index + (closest_point == vertex(min_index) ? 1 : 0);
+  return closest_point;
+}
+
+bool S2Polyline::IsOnRight(const S2Point& point) const {
+  S2_DCHECK_GE(num_vertices(), 2);
+
+  int next_vertex;
+  S2Point closest_point = Project(point, &next_vertex);
+
+  S2_DCHECK_GE(next_vertex, 1);
+  S2_DCHECK_LE(next_vertex, num_vertices());
+
+  // If the closest point C is an interior vertex of the polyline, let B and D
+  // be the previous and next vertices.  The given point P is on the right of
+  // the polyline (locally) if B, P, D are ordered CCW around vertex C.
+  if (closest_point == vertex(next_vertex-1) && next_vertex > 1 &&
+      next_vertex < num_vertices()) {
+    if (point == vertex(next_vertex-1))
+      return false;  // Polyline vertices are not on the RHS.
+    return s2pred::OrderedCCW(vertex(next_vertex-2), point, vertex(next_vertex),
+                              vertex(next_vertex-1));
+  }
+
+  // Otherwise, the closest point C is incident to exactly one polyline edge.
+  // We test the point P against that edge.
+  if (next_vertex == num_vertices())
+    --next_vertex;
+
+  return s2pred::Sign(point, vertex(next_vertex), vertex(next_vertex - 1)) > 0;
+}
+
+bool S2Polyline::Intersects(const S2Polyline* line) const {
+  if (num_vertices() <= 0 || line->num_vertices() <= 0) {
+    return false;
+  }
+
+  if (!GetRectBound().Intersects(line->GetRectBound())) {
+    return false;
+  }
+
+  // TODO(ericv): Use S2ShapeIndex here.
+  for (int i = 1; i < num_vertices(); ++i) {
+    S2EdgeCrosser crosser(
+        &vertex(i - 1), &vertex(i), &line->vertex(0));
+    for (int j = 1; j < line->num_vertices(); ++j) {
+      if (crosser.CrossingSign(&line->vertex(j)) >= 0) {
+        return true;
+      }
+    }
+  }
+  return false;
+}
+
+void S2Polyline::Reverse() {
+  std::reverse(&vertices_[0], &vertices_[num_vertices_]);
+}
+
+S2LatLngRect S2Polyline::GetRectBound() const {
+  S2LatLngRectBounder bounder;
+  for (int i = 0; i < num_vertices(); ++i) {
+    bounder.AddPoint(vertex(i));
+  }
+  return bounder.GetBound();
+}
+
+S2Cap S2Polyline::GetCapBound() const {
+  return GetRectBound().GetCapBound();
+}
+
+bool S2Polyline::MayIntersect(const S2Cell& cell) const {
+  if (num_vertices() == 0) return false;
+
+  // We only need to check whether the cell contains vertex 0 for correctness,
+  // but these tests are cheap compared to edge crossings so we might as well
+  // check all the vertices.
+  for (int i = 0; i < num_vertices(); ++i) {
+    if (cell.Contains(vertex(i))) return true;
+  }
+  S2Point cell_vertices[4];
+  for (int i = 0; i < 4; ++i) {
+    cell_vertices[i] = cell.GetVertex(i);
+  }
+  for (int j = 0; j < 4; ++j) {
+    S2EdgeCrosser crosser(&cell_vertices[j], &cell_vertices[(j+1)&3],
+                                    &vertex(0));
+    for (int i = 1; i < num_vertices(); ++i) {
+      if (crosser.CrossingSign(&vertex(i)) >= 0) {
+        // There is a proper crossing, or two vertices were the same.
+        return true;
+      }
+    }
+  }
+  return false;
+}
+
+void S2Polyline::Encode(Encoder* const encoder) const {
+  encoder->Ensure(num_vertices_ * sizeof(vertices_[0]) + 10);  // sufficient
+
+  encoder->put8(kCurrentLosslessEncodingVersionNumber);
+  encoder->put32(num_vertices_);
+  encoder->putn(&vertices_[0], sizeof(vertices_[0]) * num_vertices_);
+
+  S2_DCHECK_GE(encoder->avail(), 0);
+}
+
+bool S2Polyline::Decode(Decoder* const decoder) {
+  if (decoder->avail() < sizeof(unsigned char) + sizeof(uint32)) return false;
+  unsigned char version = decoder->get8();
+  if (version > kCurrentLosslessEncodingVersionNumber) return false;
+
+  num_vertices_ = decoder->get32();
+  vertices_.reset(new S2Point[num_vertices_]);
+  if (decoder->avail() < num_vertices_ * sizeof(vertices_[0])) return false;
+  decoder->getn(&vertices_[0], num_vertices_ * sizeof(vertices_[0]));
+
+  if (FLAGS_s2debug && s2debug_override_ == S2Debug::ALLOW) {
+    S2_CHECK(IsValid());
+  }
+  return true;
+}
+
+namespace {
+
+// Given a polyline, a tolerance distance, and a start index, this function
+// returns the maximal end index such that the line segment between these two
+// vertices passes within "tolerance" of all interior vertices, in order.
+int FindEndVertex(const S2Polyline& polyline,
+                  S1Angle tolerance, int index) {
+  S2_DCHECK_GE(tolerance.radians(), 0);
+  S2_DCHECK_LT((index + 1), polyline.num_vertices());
+
+  // The basic idea is to keep track of the "pie wedge" of angles from the
+  // starting vertex such that a ray from the starting vertex at that angle
+  // will pass through the discs of radius "tolerance" centered around all
+  // vertices processed so far.
+
+  // First we define a "coordinate frame" for the tangent and normal spaces
+  // at the starting vertex.  Essentially this means picking three
+  // orthonormal vectors X,Y,Z such that X and Y span the tangent plane at
+  // the starting vertex, and Z is "up".  We use the coordinate frame to
+  // define a mapping from 3D direction vectors to a one-dimensional "ray
+  // angle" in the range (-Pi, Pi].  The angle of a direction vector is
+  // computed by transforming it into the X,Y,Z basis, and then calculating
+  // atan2(y,x).  This mapping allows us to represent a wedge of angles as a
+  // 1D interval.  Since the interval wraps around, we represent it as an
+  // S1Interval, i.e. an interval on the unit circle.
+  Matrix3x3_d frame;
+  const S2Point& origin = polyline.vertex(index);
+  S2::GetFrame(origin, &frame);
+
+  // As we go along, we keep track of the current wedge of angles and the
+  // distance to the last vertex (which must be non-decreasing).
+  S1Interval current_wedge = S1Interval::Full();
+  double last_distance = 0;
+
+  for (++index; index < polyline.num_vertices(); ++index) {
+    const S2Point& candidate = polyline.vertex(index);
+    double distance = origin.Angle(candidate);
+
+    // We don't allow simplification to create edges longer than 90 degrees,
+    // to avoid numeric instability as lengths approach 180 degrees.  (We do
+    // need to allow for original edges longer than 90 degrees, though.)
+    if (distance > M_PI/2 && last_distance > 0) break;
+
+    // Vertices must be in increasing order along the ray, except for the
+    // initial disc around the origin.
+    if (distance < last_distance && last_distance > tolerance.radians()) break;
+    last_distance = distance;
+
+    // Points that are within the tolerance distance of the origin do not
+    // constrain the ray direction, so we can ignore them.
+    if (distance <= tolerance.radians()) continue;
+
+    // If the current wedge of angles does not contain the angle to this
+    // vertex, then stop right now.  Note that the wedge of possible ray
+    // angles is not necessarily empty yet, but we can't continue unless we
+    // are willing to backtrack to the last vertex that was contained within
+    // the wedge (since we don't create new vertices).  This would be more
+    // complicated and also make the worst-case running time more than linear.
+    S2Point direction = S2::ToFrame(frame, candidate);
+    double center = atan2(direction.y(), direction.x());
+    if (!current_wedge.Contains(center)) break;
+
+    // To determine how this vertex constrains the possible ray angles,
+    // consider the triangle ABC where A is the origin, B is the candidate
+    // vertex, and C is one of the two tangent points between A and the
+    // spherical cap of radius "tolerance" centered at B.  Then from the
+    // spherical law of sines, sin(a)/sin(A) = sin(c)/sin(C), where "a" and
+    // "c" are the lengths of the edges opposite A and C.  In our case C is a
+    // 90 degree angle, therefore A = asin(sin(a) / sin(c)).  Angle A is the
+    // half-angle of the allowable wedge.
+
+    double half_angle = asin(sin(tolerance.radians()) / sin(distance));
+    S1Interval target = S1Interval::FromPoint(center).Expanded(half_angle);
+    current_wedge = current_wedge.Intersection(target);
+    S2_DCHECK(!current_wedge.is_empty());
+  }
+  // We break out of the loop when we reach a vertex index that can't be
+  // included in the line segment, so back up by one vertex.
+  return index - 1;
+}
+}  // namespace
+
+void S2Polyline::SubsampleVertices(S1Angle tolerance,
+                                   vector<int>* indices) const {
+  indices->clear();
+  if (num_vertices() == 0) return;
+
+  indices->push_back(0);
+  S1Angle clamped_tolerance = max(tolerance, S1Angle::Radians(0));
+  for (int index = 0; index + 1 < num_vertices(); ) {
+    int next_index = FindEndVertex(*this, clamped_tolerance, index);
+    // Don't create duplicate adjacent vertices.
+    if (vertex(next_index) != vertex(index)) {
+      indices->push_back(next_index);
+    }
+    index = next_index;
+  }
+}
+
+bool S2Polyline::Equals(const S2Polyline* b) const {
+  if (num_vertices() != b->num_vertices()) return false;
+  for (int offset = 0; offset < num_vertices(); ++offset) {
+    if (vertex(offset) != b->vertex(offset)) return false;
+  }
+  return true;
+}
+
+bool S2Polyline::ApproxEquals(const S2Polyline& b, S1Angle max_error) const {
+  if (num_vertices() != b.num_vertices()) return false;
+  for (int offset = 0; offset < num_vertices(); ++offset) {
+    if (!S2::ApproxEquals(vertex(offset), b.vertex(offset), max_error)) {
+      return false;
+    }
+  }
+  return true;
+}
+
+size_t S2Polyline::SpaceUsed() const {
+  return sizeof(*this) + num_vertices() * sizeof(S2Point);
+}
+
+namespace {
+// Return the first i > "index" such that the ith vertex of "pline" is not at
+// the same point as the "index"th vertex.  Returns pline.num_vertices() if
+// there is no such value of i.
+inline int NextDistinctVertex(const S2Polyline& pline, int index) {
+  const S2Point& initial = pline.vertex(index);
+  do {
+    ++index;
+  } while (index < pline.num_vertices() && pline.vertex(index) == initial);
+  return index;
+}
+
+// This struct represents a search state in the NearlyCovers algorithm
+// below.  See the description of the algorithm for details.
+struct SearchState {
+  inline SearchState(int i_val, int j_val, bool i_in_progress_val)
+      : i(i_val), j(j_val), i_in_progress(i_in_progress_val) {}
+
+  int i;
+  int j;
+  bool i_in_progress;
+};
+
+// This operator is needed for storing SearchStates in a set.  The ordering
+// chosen has no special meaning.
+struct SearchStateKeyCompare {
+  bool operator() (const SearchState& a, const SearchState& b) const {
+    if (a.i != b.i) return a.i < b.i;
+    if (a.j != b.j) return a.j < b.j;
+    return a.i_in_progress < b.i_in_progress;
+  }
+};
+
+}  // namespace
+
+bool S2Polyline::NearlyCovers(const S2Polyline& covered,
+                              S1Angle max_error) const {
+  // NOTE: This algorithm is described assuming that adjacent vertices in a
+  // polyline are never at the same point.  That is, the ith and i+1th vertices
+  // of a polyline are never at the same point in space.  The implementation
+  // does not make this assumption.
+
+  // DEFINITIONS:
+  //   - edge "i" of a polyline is the edge from the ith to i+1th vertex.
+  //   - covered_j is a polyline consisting of edges 0 through j of "covered."
+  //   - this_i is a polyline consisting of edges 0 through i of this polyline.
+  //
+  // A search state is represented as an (int, int, bool) tuple, (i, j,
+  // i_in_progress).  Using the "drive a car" analogy from the header comment, a
+  // search state signifies that you can drive one car along "covered" from its
+  // first vertex through a point on its jth edge, and another car along this
+  // polyline from some point on or before its ith edge to a to a point on its
+  // ith edge, such that no car ever goes backward, and the cars are always
+  // within "max_error" of each other.  If i_in_progress is true, it means that
+  // you can definitely drive along "covered" through the jth vertex (beginning
+  // of the jth edge). Otherwise, you can definitely drive along "covered"
+  // through the point on the jth edge of "covered" closest to the ith vertex of
+  // this polyline.
+  //
+  // The algorithm begins by finding all edges of this polyline that are within
+  // "max_error" of the first vertex of "covered," and adding search states
+  // representing all of these possible starting states to the stack of
+  // "pending" states.
+  //
+  // The algorithm proceeds by popping the next pending state,
+  // (i,j,i_in_progress), off of the stack.  First it checks to see if that
+  // state represents finding a valid covering of "covered" and returns true if
+  // so.  Next, if the state represents reaching the end of this polyline
+  // without finding a successful covering, the algorithm moves on to the next
+  // state in the stack.  Otherwise, if state (i+1,j,false) is valid, it is
+  // added to the stack of pending states.  Same for state (i,j+1,true).
+  //
+  // We need the stack because when "i" and "j" can both be incremented,
+  // sometimes only one choice leads to a solution.  We use a set to keep track
+  // of visited states to avoid duplicating work.  With the set, the worst-case
+  // number of states examined is O(n+m) where n = this->num_vertices() and m =
+  // covered.num_vertices().  Without it, the amount of work could be as high as
+  // O((n*m)^2).  Using set, the running time is O((n*m) log (n*m)).
+  //
+  // TODO(user): Benchmark this, and see if the set is worth it.
+
+  if (covered.num_vertices() == 0) return true;
+  if (this->num_vertices() == 0) return false;
+
+  vector<SearchState> pending;
+  set<SearchState, SearchStateKeyCompare> done;
+
+  // Find all possible starting states.
+  for (int i = 0, next_i = NextDistinctVertex(*this, 0), next_next_i;
+       next_i < this->num_vertices(); i = next_i, next_i = next_next_i) {
+    next_next_i = NextDistinctVertex(*this, next_i);
+    S2Point closest_point = S2::Project(
+        covered.vertex(0), this->vertex(i), this->vertex(next_i));
+
+    // In order to avoid duplicate starting states, we exclude the end vertex
+    // of each edge *except* for the last non-degenerate edge.
+    if ((next_next_i == this->num_vertices() ||
+         closest_point != this->vertex(next_i)) &&
+        S1Angle(closest_point, covered.vertex(0)) <= max_error) {
+      pending.push_back(SearchState(i, 0, true));
+    }
+  }
+
+  while (!pending.empty()) {
+    const SearchState state = pending.back();
+    pending.pop_back();
+    if (!done.insert(state).second) continue;
+
+    const int next_i = NextDistinctVertex(*this, state.i);
+    const int next_j = NextDistinctVertex(covered, state.j);
+    if (next_j == covered.num_vertices()) {
+      return true;
+    } else if (next_i == this->num_vertices()) {
+      continue;
+    }
+
+    S2Point i_begin, j_begin;
+    if (state.i_in_progress) {
+      j_begin = covered.vertex(state.j);
+      i_begin = S2::Project(
+          j_begin, this->vertex(state.i), this->vertex(next_i));
+    } else {
+      i_begin = this->vertex(state.i);
+      j_begin = S2::Project(
+          i_begin, covered.vertex(state.j), covered.vertex(next_j));
+    }
+
+    if (S2::IsEdgeBNearEdgeA(j_begin, covered.vertex(next_j),
+                             i_begin, this->vertex(next_i), max_error)) {
+      pending.push_back(SearchState(next_i, state.j, false));
+    }
+    if (S2::IsEdgeBNearEdgeA(i_begin, this->vertex(next_i),
+                             j_begin, covered.vertex(next_j), max_error)) {
+      pending.push_back(SearchState(state.i, next_j, true));
+    }
+  }
+  return false;
+}
+
+void S2Polyline::Shape::Init(const S2Polyline* polyline) {
+  S2_LOG_IF(WARNING, polyline->num_vertices() == 1)
+      << "S2Polyline::Shape with one vertex has no edges";
+  polyline_ = polyline;
+}
+
+int S2Polyline::Shape::num_chains() const {
+  return min(1, Shape::num_edges());  // Avoid virtual call.
+}
+
+S2Shape::Chain S2Polyline::Shape::chain(int i) const {
+  S2_DCHECK_EQ(i, 0);
+  return Chain(0, Shape::num_edges());  // Avoid virtual call.
+}
diff --git a/src/s2/s2polyline.h b/src/s2/s2polyline.h
new file mode 100644 (file)
index 0000000..4a8eb11
--- /dev/null
@@ -0,0 +1,379 @@
+// Copyright 2005 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// Author: ericv@google.com (Eric Veach)
+
+#ifndef S2_S2POLYLINE_H_
+#define S2_S2POLYLINE_H_
+
+#include <memory>
+#include <vector>
+
+#include "s2/base/logging.h"
+#include "s2/_fp_contract_off.h"
+#include "s2/s1angle.h"
+#include "s2/s2debug.h"
+#include "s2/s2error.h"
+#include "s2/s2latlng_rect.h"
+#include "s2/s2region.h"
+#include "s2/s2shape.h"
+#include "absl/base/macros.h"
+#include "absl/memory/memory.h"
+
+class Decoder;
+class Encoder;
+class S1Angle;
+class S2Cap;
+class S2Cell;
+class S2LatLng;
+
+// An S2Polyline represents a sequence of zero or more vertices connected by
+// straight edges (geodesics).  Edges of length 0 and 180 degrees are not
+// allowed, i.e. adjacent vertices should not be identical or antipodal.
+class S2Polyline final : public S2Region {
+ public:
+  // Creates an empty S2Polyline that should be initialized by calling Init()
+  // or Decode().
+  S2Polyline();
+
+#ifndef SWIG
+  // S2Polyline is movable, but only privately copyable.
+  S2Polyline(S2Polyline&&);
+  S2Polyline& operator=(S2Polyline&&);
+#endif  // SWIG
+
+  // Convenience constructors that call Init() with the given vertices.
+  explicit S2Polyline(const std::vector<S2Point>& vertices);
+  explicit S2Polyline(const std::vector<S2LatLng>& vertices);
+
+  // Convenience constructors to disable the automatic validity checking
+  // controlled by the --s2debug flag.  Example:
+  //
+  //   S2Polyline* line = new S2Polyline(vertices, S2Debug::DISABLE);
+  //
+  // This is equivalent to:
+  //
+  //   S2Polyline* line = new S2Polyline;
+  //   line->set_s2debug_override(S2Debug::DISABLE);
+  //   line->Init(vertices);
+  //
+  // The main reason to use this constructors is if you intend to call
+  // IsValid() explicitly.  See set_s2debug_override() for details.
+  S2Polyline(const std::vector<S2Point>& vertices, S2Debug override);
+  S2Polyline(const std::vector<S2LatLng>& vertices, S2Debug override);
+
+  // Initialize a polyline that connects the given vertices. Empty polylines are
+  // allowed.  Adjacent vertices should not be identical or antipodal.  All
+  // vertices should be unit length.
+  void Init(const std::vector<S2Point>& vertices);
+
+  // Convenience initialization function that accepts latitude-longitude
+  // coordinates rather than S2Points.
+  void Init(const std::vector<S2LatLng>& vertices);
+
+  ~S2Polyline() override;
+
+  // Allows overriding the automatic validity checks controlled by the
+  // --s2debug flag.  If this flag is true, then polylines are automatically
+  // checked for validity as they are initialized.  The main reason to disable
+  // this flag is if you intend to call IsValid() explicitly, like this:
+  //
+  //   S2Polyline line;
+  //   line.set_s2debug_override(S2Debug::DISABLE);
+  //   line.Init(...);
+  //   if (!line.IsValid()) { ... }
+  //
+  // Without the call to set_s2debug_override(), invalid data would cause a
+  // fatal error in Init() whenever the --s2debug flag is enabled.
+  void set_s2debug_override(S2Debug override);
+  S2Debug s2debug_override() const;
+
+  // Return true if the given vertices form a valid polyline.
+  bool IsValid() const;
+
+  // Returns true if this is *not* a valid polyline and sets "error"
+  // appropriately.  Otherwise returns false and leaves "error" unchanged.
+  //
+  // REQUIRES: error != nullptr
+  bool FindValidationError(S2Error* error) const;
+
+  int num_vertices() const { return num_vertices_; }
+  const S2Point& vertex(int k) const {
+    S2_DCHECK_GE(k, 0);
+    S2_DCHECK_LT(k, num_vertices_);
+    return vertices_[k];
+  }
+
+  // Return the length of the polyline.
+  S1Angle GetLength() const;
+
+  // Return the true centroid of the polyline multiplied by the length of the
+  // polyline (see s2centroids.h for details on centroids).  The result is not
+  // unit length, so you may want to normalize it.
+  //
+  // Prescaling by the polyline length makes it easy to compute the centroid
+  // of several polylines (by simply adding up their centroids).
+  S2Point GetCentroid() const;
+
+  // Return the point whose distance from vertex 0 along the polyline is the
+  // given fraction of the polyline's total length.  Fractions less than zero
+  // or greater than one are clamped.  The return value is unit length.  This
+  // cost of this function is currently linear in the number of vertices.
+  // The polyline must not be empty.
+  S2Point Interpolate(double fraction) const;
+
+  // Like Interpolate(), but also return the index of the next polyline
+  // vertex after the interpolated point P.  This allows the caller to easily
+  // construct a given suffix of the polyline by concatenating P with the
+  // polyline vertices starting at "next_vertex".  Note that P is guaranteed
+  // to be different than vertex(*next_vertex), so this will never result in
+  // a duplicate vertex.
+  //
+  // The polyline must not be empty.  Note that if "fraction" >= 1.0, then
+  // "next_vertex" will be set to num_vertices() (indicating that no vertices
+  // from the polyline need to be appended).  The value of "next_vertex" is
+  // always between 1 and num_vertices().
+  //
+  // This method can also be used to construct a prefix of the polyline, by
+  // taking the polyline vertices up to "next_vertex - 1" and appending the
+  // returned point P if it is different from the last vertex (since in this
+  // case there is no guarantee of distinctness).
+  S2Point GetSuffix(double fraction, int* next_vertex) const;
+
+  // The inverse operation of GetSuffix/Interpolate.  Given a point on the
+  // polyline, returns the ratio of the distance to the point from the
+  // beginning of the polyline over the length of the polyline.  The return
+  // value is always betwen 0 and 1 inclusive.  See GetSuffix() for the
+  // meaning of "next_vertex".
+  //
+  // The polyline should not be empty.  If it has fewer than 2 vertices, the
+  // return value is zero.
+  double UnInterpolate(const S2Point& point, int next_vertex) const;
+
+  // Given a point, returns a point on the polyline that is closest to the given
+  // point.  See GetSuffix() for the meaning of "next_vertex", which is chosen
+  // here w.r.t. the projected point as opposed to the interpolated point in
+  // GetSuffix().
+  //
+  // The polyline must be non-empty.
+  S2Point Project(const S2Point& point, int* next_vertex) const;
+
+  // Returns true if the point given is on the right hand side of the polyline,
+  // using a naive definition of "right-hand-sideness" where the point is on
+  // the RHS of the polyline iff the point is on the RHS of the line segment in
+  // the polyline which it is closest to.
+  //
+  // The polyline must have at least 2 vertices.
+  bool IsOnRight(const S2Point& point) const;
+
+  // Return true if this polyline intersects the given polyline. If the
+  // polylines share a vertex they are considered to be intersecting. When a
+  // polyline endpoint is the only intersection with the other polyline, the
+  // function may return true or false arbitrarily.
+  //
+  // The running time is quadratic in the number of vertices.  (To intersect
+  // polylines more efficiently, or compute the actual intersection geometry,
+  // use S2BooleanOperation.)
+  bool Intersects(const S2Polyline* line) const;
+
+  // Reverse the order of the polyline vertices.
+  void Reverse();
+
+  // Return a subsequence of vertex indices such that the polyline connecting
+  // these vertices is never further than "tolerance" from the original
+  // polyline.  Provided the first and last vertices are distinct, they are
+  // always preserved; if they are not, the subsequence may contain only a
+  // single index.
+  //
+  // Some useful properties of the algorithm:
+  //
+  //  - It runs in linear time.
+  //
+  //  - The output is always a valid polyline.  In particular, adjacent
+  //    output vertices are never identical or antipodal.
+  //
+  //  - The method is not optimal, but it tends to produce 2-3% fewer
+  //    vertices than the Douglas-Peucker algorithm with the same tolerance.
+  //
+  //  - The output is *parametrically* equivalent to the original polyline to
+  //    within the given tolerance.  For example, if a polyline backtracks on
+  //    itself and then proceeds onwards, the backtracking will be preserved
+  //    (to within the given tolerance).  This is different than the
+  //    Douglas-Peucker algorithm, which only guarantees geometric equivalence.
+  //
+  // See also S2PolylineSimplifier, which uses the same algorithm but is more
+  // efficient and supports more features, and also S2Builder, which can
+  // simplify polylines and polygons, supports snapping (e.g. to E7 lat/lng
+  // coordinates or S2CellId centers), and can split polylines at intersection
+  // points.
+  void SubsampleVertices(S1Angle tolerance, std::vector<int>* indices) const;
+
+  // Return true if two polylines are exactly the same.
+  bool Equals(const S2Polyline* b) const;
+
+  // Return true if two polylines have the same number of vertices, and
+  // corresponding vertex pairs are separated by no more than "max_error".
+  // (For testing purposes.)
+  bool ApproxEquals(const S2Polyline& b,
+                    S1Angle max_error = S1Angle::Radians(1e-15)) const;
+
+  // Return true if "covered" is within "max_error" of a contiguous subpath of
+  // this polyline over its entire length.  Specifically, this method returns
+  // true if this polyline has parameterization a:[0,1] -> S^2, "covered" has
+  // parameterization b:[0,1] -> S^2, and there is a non-decreasing function
+  // f:[0,1] -> [0,1] such that distance(a(f(t)), b(t)) <= max_error for all t.
+  //
+  // You can think of this as testing whether it is possible to drive a car
+  // along "covered" and a car along some subpath of this polyline such that no
+  // car ever goes backward, and the cars are always within "max_error" of each
+  // other.
+  //
+  // This function is well-defined for empty polylines:
+  //    anything.covers(empty) = true
+  //    empty.covers(nonempty) = false
+  bool NearlyCovers(const S2Polyline& covered, S1Angle max_error) const;
+
+  // Returns the total number of bytes used by the polyline.
+  size_t SpaceUsed() const;
+
+  ////////////////////////////////////////////////////////////////////////
+  // S2Region interface (see s2region.h for details):
+
+  S2Polyline* Clone() const override;
+  S2Cap GetCapBound() const override;
+  S2LatLngRect GetRectBound() const override;
+  bool Contains(const S2Cell& cell) const override { return false; }
+  bool MayIntersect(const S2Cell& cell) const override;
+
+  // Always return false, because "containment" is not numerically
+  // well-defined except at the polyline vertices.
+  bool Contains(const S2Point& p) const override { return false; }
+
+  // Appends a serialized representation of the S2Polyline to "encoder".
+  //
+  // REQUIRES: "encoder" uses the default constructor, so that its buffer
+  //           can be enlarged as necessary by calling Ensure(int).
+  void Encode(Encoder* const encoder) const;
+
+  // Decodes an S2Polyline encoded with Encode().  Returns true on success.
+  bool Decode(Decoder* const decoder);
+
+#ifndef SWIG
+  // Wrapper class for indexing a polyline (see S2ShapeIndex).  Once this
+  // object is inserted into an S2ShapeIndex it is owned by that index, and
+  // will be automatically deleted when no longer needed by the index.  Note
+  // that this class does not take ownership of the polyline itself (see
+  // OwningShape below).  You can also subtype this class to store additional
+  // data (see S2Shape for details).
+  class Shape : public S2Shape {
+   public:
+    static constexpr TypeTag kTypeTag = 2;
+
+    Shape() : polyline_(nullptr) {}  // Must call Init().
+
+    // Initialization.  Does not take ownership of "polyline".
+    //
+    // Note that a polyline with one vertex is defined to have no edges.  Use
+    // S2LaxPolylineShape or S2LaxClosedPolylineShape if you want to define a
+    // polyline consisting of a single degenerate edge.
+    explicit Shape(const S2Polyline* polyline) { Init(polyline); }
+    void Init(const S2Polyline* polyline);
+
+    const S2Polyline* polyline() const { return polyline_; }
+
+    // Encodes the polyline using S2Polyline::Encode().
+    void Encode(Encoder* encoder) const {
+      // TODO(geometry-library): Support compressed encodings.
+      polyline_->Encode(encoder);
+    }
+
+    // Decoding is defined only for S2Polyline::OwningShape below.
+
+    // S2Shape interface:
+
+    int num_edges() const final {
+      return std::max(0, polyline_->num_vertices() - 1);
+    }
+    Edge edge(int e) const final {
+      return Edge(polyline_->vertex(e), polyline_->vertex(e + 1));
+    }
+    int dimension() const final { return 1; }
+    ReferencePoint GetReferencePoint() const final {
+      return ReferencePoint::Contained(false);
+    }
+    int num_chains() const final;
+    Chain chain(int i) const final;
+    Edge chain_edge(int i, int j) const final {
+      S2_DCHECK_EQ(i, 0);
+      return Edge(polyline_->vertex(j), polyline_->vertex(j + 1));
+    }
+    ChainPosition chain_position(int e) const final {
+      return ChainPosition(0, e);
+    }
+    TypeTag type_tag() const override { return kTypeTag; }
+
+   private:
+    const S2Polyline* polyline_;
+  };
+
+  // Like Shape, except that the S2Polyline is automatically deleted when this
+  // object is deleted by the S2ShapeIndex.  This is useful when an S2Polyline
+  // is constructed solely for the purpose of indexing it.
+  class OwningShape : public Shape {
+   public:
+    OwningShape() {}  // Must call Init().
+
+    explicit OwningShape(std::unique_ptr<const S2Polyline> polyline)
+        : Shape(polyline.get()), owned_polyline_(std::move(polyline)) {}
+
+    void Init(std::unique_ptr<const S2Polyline> polyline) {
+      Shape::Init(polyline.get());
+      owned_polyline_ = std::move(polyline);
+    }
+
+    bool Init(Decoder* decoder) {
+      auto polyline = absl::make_unique<S2Polyline>();
+      if (!polyline->Decode(decoder)) return false;
+      Shape::Init(polyline.get());
+      owned_polyline_ = std::move(polyline);
+      return true;
+    }
+
+   private:
+    std::unique_ptr<const S2Polyline> owned_polyline_;
+  };
+#endif  // SWIG
+
+ private:
+  // Internal copy constructor used only by Clone() that makes a deep copy of
+  // its argument.
+  S2Polyline(const S2Polyline& src);
+
+  // Allows overriding the automatic validity checking controlled by the
+  // --s2debug flag.
+  S2Debug s2debug_override_;
+
+  // We store the vertices in an array rather than a vector because we don't
+  // need any STL methods, and computing the number of vertices using size()
+  // would be relatively expensive (due to division by sizeof(S2Point) == 24).
+  int num_vertices_ = 0;
+  std::unique_ptr<S2Point[]> vertices_;
+
+#ifndef SWIG
+  void operator=(const S2Polyline&) = delete;
+#endif  // SWIG
+};
+
+#endif  // S2_S2POLYLINE_H_
diff --git a/src/s2/s2polyline_alignment.cc b/src/s2/s2polyline_alignment.cc
new file mode 100644 (file)
index 0000000..c331dab
--- /dev/null
@@ -0,0 +1,414 @@
+// Copyright 2017 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+
+#include "s2/s2polyline_alignment.h"
+#include "s2/s2polyline_alignment_internal.h"
+
+#include <algorithm>
+#include <numeric>
+#include <sstream>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "s2/base/logging.h"
+#include "absl/memory/memory.h"
+#include "s2/util/math/mathutil.h"
+
+namespace s2polyline_alignment {
+
+Window::Window(const std::vector<ColumnStride>& strides) {
+  S2_DCHECK(!strides.empty()) << "Cannot construct empty window.";
+  S2_DCHECK(strides[0].start == 0) << "First element of start_cols is non-zero.";
+  strides_ = strides;
+  rows_ = strides.size();
+  cols_ = strides.back().end;
+  S2_DCHECK(this->IsValid()) << "Constructor validity check fail.";
+}
+
+Window::Window(const WarpPath& warp_path) {
+  S2_DCHECK(!warp_path.empty()) << "Cannot construct window from empty warp path.";
+  S2_DCHECK(warp_path.front() == std::make_pair(0, 0)) << "Must start at (0, 0).";
+  rows_ = warp_path.back().first + 1;
+  S2_DCHECK(rows_ > 0) << "Must have at least one row.";
+  cols_ = warp_path.back().second + 1;
+  S2_DCHECK(cols_ > 0) << "Must have at least one column.";
+  strides_.resize(rows_);
+
+  int prev_row = 0;
+  int curr_row = 0;
+  int stride_start = 0;
+  int stride_stop = 0;
+  for (const auto& pair : warp_path) {
+    curr_row = pair.first;
+    if (curr_row > prev_row) {
+      strides_[prev_row] = {stride_start, stride_stop};
+      stride_start = pair.second;
+      prev_row = curr_row;
+    }
+    stride_stop = pair.second + 1;
+  }
+  S2_DCHECK_EQ(curr_row, rows_ - 1);
+  strides_[rows_ - 1] = {stride_start, stride_stop};
+  S2_DCHECK(this->IsValid()) << "Constructor validity check fail.";
+}
+
+Window Window::Upsample(const int new_rows, const int new_cols) const {
+  S2_DCHECK(new_rows >= rows_) << "Upsampling: New_rows < current_rows";
+  S2_DCHECK(new_cols >= cols_) << "Upsampling: New_cols < current_cols";
+  const double row_scale = static_cast<double>(new_rows) / rows_;
+  const double col_scale = static_cast<double>(new_cols) / cols_;
+  std::vector<ColumnStride> new_strides(new_rows);
+  ColumnStride from_stride;
+  for (int row = 0; row < new_rows; ++row) {
+    from_stride = strides_[static_cast<int>((row + 0.5) / row_scale)];
+    new_strides[row] = {static_cast<int>(col_scale * from_stride.start + 0.5),
+                        static_cast<int>(col_scale * from_stride.end + 0.5)};
+  }
+  return Window(new_strides);
+}
+
+// This code takes advantage of the fact that the dilation window is square to
+// ensure that we can compute the stride for each output row in constant time.
+// TODO (mrdmnd): a potential optimization might be to combine this method and
+// the Upsample method into a single "Expand" method. For the sake of
+// testing, I haven't done that here, but I think it would be fairly
+// straightforward to do so. This method generally isn't very expensive so it
+// feels unnecessary to combine them.
+Window Window::Dilate(const int radius) const {
+  S2_DCHECK(radius >= 0) << "Negative dilation radius.";
+  std::vector<ColumnStride> new_strides(rows_);
+  int prev_row, next_row;
+  for (int row = 0; row < rows_; ++row) {
+    prev_row = std::max(0, row - radius);
+    next_row = std::min(row + radius, rows_ - 1);
+    new_strides[row] = {std::max(0, strides_[prev_row].start - radius),
+                        std::min(strides_[next_row].end + radius, cols_)};
+  }
+  return Window(new_strides);
+}
+
+// Debug string implemented primarily for testing purposes.
+std::string Window::DebugString() const {
+  std::stringstream buffer;
+  for (int row = 0; row < rows_; ++row) {
+    for (int col = 0; col < cols_; ++col) {
+      buffer << (strides_[row].InRange(col) ? " *" : " .");
+    }
+    buffer << std::endl;
+  }
+  return buffer.str();
+}
+
+// Valid Windows require the following structural conditions to hold:
+// 1) All rows must consist of a single contiguous stride of `true` values.
+// 2) All strides are greater than zero length (i.e. no empty rows).
+// 3) The index of the first `true` column in a row must be at least as
+//    large as the index of the first `true` column in the previous row.
+// 4) The index of the last `true` column in a row must be at least as large
+//    as the index of the last `true` column in the previous row.
+// 5) strides[0].start = 0 (the first cell is always filled).
+// 6) strides[n_rows-1].end = n_cols (the last cell is filled).
+bool Window::IsValid() const {
+  if (rows_ <= 0 || cols_ <= 0 || strides_.front().start != 0 ||
+      strides_.back().end != cols_) {
+    return false;
+  }
+
+  ColumnStride prev = {-1, -1};
+  for (const auto& curr : strides_) {
+    if (curr.end <= curr.start || curr.start < prev.start ||
+        curr.end < prev.end) {
+      return false;
+    }
+    prev = curr;
+  }
+  return true;
+}
+
+inline double BoundsCheckedTableCost(const int row, const int col,
+                                     const ColumnStride& stride,
+                                     const CostTable& table) {
+  if (row < 0 && col < 0) {
+    return 0.0;
+  } else if (row < 0 || col < 0 || !stride.InRange(col)) {
+    return DOUBLE_MAX;
+  } else {
+    return table[row][col];
+  }
+}
+
+// Perform dynamic timewarping by filling in the DP table on cells that are
+// inside our search window. For an exact (all-squares) evaluation, this
+// incurs bounds checking overhead - we don't need to ensure that we're inside
+// the appropriate cells in the window, because it's guaranteed. Structuring
+// the program to reuse code for both the EXACT and WINDOWED cases by
+// abstracting EXACT as a window with full-covering strides is done for
+// maintainability reasons. One potential optimization here might be to overload
+// this function to skip bounds checking when the window is full.
+//
+// As a note of general interest, the Dynamic Timewarp algorithm as stated here
+// prefers shorter warp paths, when two warp paths might be equally costly. This
+// is because it favors progressing in the sequences simultaneously due to the
+// equal weighting of a diagonal step in the cost table with a horizontal or
+// vertical step. This may be counterintuitive, but represents the standard
+// implementation of this algorithm. TODO(user) - future implementations could
+// allow weights on the lookup costs to mitigate this.
+//
+// This is the hottest routine in the whole package, please be careful to
+// profile any future changes made here.
+//
+// This method takes time proportional to the number of cells in the window,
+// which can range from O(max(a, b)) cells (best) to O(a*b) cells (worst)
+VertexAlignment DynamicTimewarp(const S2Polyline& a, const S2Polyline& b,
+                                const Window& w) {
+  const int rows = a.num_vertices();
+  const int cols = b.num_vertices();
+  auto costs = CostTable(rows, std::vector<double>(cols));
+
+  ColumnStride curr;
+  ColumnStride prev = ColumnStride::All();
+  for (int row = 0; row < rows; ++row) {
+    curr = w.GetColumnStride(row);
+    for (int col = curr.start; col < curr.end; ++col) {
+      double d_cost = BoundsCheckedTableCost(row - 1, col - 1, prev, costs);
+      double u_cost = BoundsCheckedTableCost(row - 1, col - 0, prev, costs);
+      double l_cost = BoundsCheckedTableCost(row - 0, col - 1, curr, costs);
+      costs[row][col] = std::min({d_cost, u_cost, l_cost}) +
+                        (a.vertex(row) - b.vertex(col)).Norm2();
+    }
+    prev = curr;
+  }
+
+  // Now we walk back through the cost table and build up the warp path.
+  // Somewhat surprisingly, it is faster to recover the path this way than it
+  // is to save the comparisons from the computation we *already did* to get the
+  // direction we came from. The author speculates that this behavior is
+  // assignment-cost-related: to persist direction, we have to do extra
+  // stores/loads of "directional" information, and the extra assignment cost
+  // this incurs is larger than the cost to simply redo the comparisons.
+  // It's probably worth revisiting this assumption in the future.
+  // As it turns out, the following code ends up effectively free.
+  WarpPath warp_path;
+  warp_path.reserve(std::max(a.num_vertices(), b.num_vertices()));
+  int row = a.num_vertices() - 1;
+  int col = b.num_vertices() - 1;
+  curr = w.GetCheckedColumnStride(row);
+  prev = w.GetCheckedColumnStride(row - 1);
+  while (row >= 0 && col >= 0) {
+    warp_path.push_back({row, col});
+    double d_cost = BoundsCheckedTableCost(row - 1, col - 1, prev, costs);
+    double u_cost = BoundsCheckedTableCost(row - 1, col - 0, prev, costs);
+    double l_cost = BoundsCheckedTableCost(row - 0, col - 1, curr, costs);
+    if (d_cost <= u_cost && d_cost <= l_cost) {
+      row -= 1;
+      col -= 1;
+      curr = w.GetCheckedColumnStride(row);
+      prev = w.GetCheckedColumnStride(row - 1);
+    } else if (u_cost <= l_cost) {
+      row -= 1;
+      curr = w.GetCheckedColumnStride(row);
+      prev = w.GetCheckedColumnStride(row - 1);
+    } else {
+      col -= 1;
+    }
+  }
+  std::reverse(warp_path.begin(), warp_path.end());
+  return VertexAlignment(costs.back().back(), warp_path);
+}
+
+std::unique_ptr<S2Polyline> HalfResolution(const S2Polyline& in) {
+  const int n = in.num_vertices();
+  std::vector<S2Point> vertices;
+  vertices.reserve(n / 2);
+  for (int i = 0; i < n; i += 2) {
+    vertices.push_back(in.vertex(i));
+  }
+  return absl::make_unique<S2Polyline>(vertices);
+}
+
+// Helper methods for GetMedoidPolyline and GetConsensusPolyline to auto-select
+// appropriate cost function / alignment functions.
+double CostFn(const S2Polyline& a, const S2Polyline& b, bool approx) {
+  return approx ? GetApproxVertexAlignment(a, b).alignment_cost
+                : GetExactVertexAlignmentCost(a, b);
+}
+
+VertexAlignment AlignmentFn(const S2Polyline& a, const S2Polyline& b,
+                            bool approx) {
+  return approx ? GetApproxVertexAlignment(a, b)
+                : GetExactVertexAlignment(a, b);
+}
+
+// PUBLIC API IMPLEMENTATION DETAILS
+
+// This is the constant-space implementation of Dynamic Timewarp that can
+// compute the alignment cost, but not the warp path.
+double GetExactVertexAlignmentCost(const S2Polyline& a, const S2Polyline& b) {
+  const int a_n = a.num_vertices();
+  const int b_n = b.num_vertices();
+  S2_CHECK(a_n > 0) << "A is empty polyline.";
+  S2_CHECK(b_n > 0) << "B is empty polyline.";
+  std::vector<double> cost(b_n, DOUBLE_MAX);
+  double left_diag_min_cost = 0;
+  for (int row = 0; row < a_n; ++row) {
+    for (int col = 0; col < b_n; ++col) {
+      double up_cost = cost[col];
+      cost[col] = std::min(left_diag_min_cost, up_cost) +
+                  (a.vertex(row) - b.vertex(col)).Norm2();
+      left_diag_min_cost = std::min(cost[col], up_cost);
+    }
+    left_diag_min_cost = DOUBLE_MAX;
+  }
+  return cost.back();
+}
+
+VertexAlignment GetExactVertexAlignment(const S2Polyline& a,
+                                        const S2Polyline& b) {
+  const int a_n = a.num_vertices();
+  const int b_n = b.num_vertices();
+  S2_CHECK(a_n > 0) << "A is empty polyline.";
+  S2_CHECK(b_n > 0) << "B is empty polyline.";
+  const auto w = Window(std::vector<ColumnStride>(a_n, {0, b_n}));
+  return DynamicTimewarp(a, b, w);
+}
+
+VertexAlignment GetApproxVertexAlignment(const S2Polyline& a,
+                                         const S2Polyline& b,
+                                         const int radius) {
+  // Determined experimentally, through benchmarking, as about the points at
+  // which ExactAlignment is faster than ApproxAlignment, so we use these as
+  // our switchover points to exact computation mode.
+  const int kSizeSwitchover = 32;
+  const double kDensitySwitchover = 0.85;
+  const int a_n = a.num_vertices();
+  const int b_n = b.num_vertices();
+  S2_CHECK(a_n > 0) << "A is empty polyline.";
+  S2_CHECK(b_n > 0) << "B is empty polyline.";
+  S2_CHECK(radius >= 0) << "Radius is negative.";
+
+  // If we've hit the point where doing a full, direct solve is guaranteed to
+  // be faster, then terminate the recursion and do that.
+  if (a_n - radius < kSizeSwitchover || b_n - radius < kSizeSwitchover) {
+    return GetExactVertexAlignment(a, b);
+  }
+
+  // If we've hit the point where the window will be probably be so full that we
+  // might as well compute an exact solution, then terminate recursion to do so.
+  if (std::max(a_n, b_n) * (2 * radius + 1) > a_n * b_n * kDensitySwitchover) {
+    return GetExactVertexAlignment(a, b);
+  }
+
+  // Otherwise, shrink the input polylines, recursively compute the vertex
+  // alignment using this method, and then compute the final alignment using
+  // the projected alignment `proj` on an upsampled, dilated window.
+  const auto a_half = HalfResolution(a);
+  const auto b_half = HalfResolution(b);
+  const auto proj = GetApproxVertexAlignment(*a_half, *b_half, radius);
+  const auto w = Window(proj.warp_path).Upsample(a_n, b_n).Dilate(radius);
+  return DynamicTimewarp(a, b, w);
+}
+
+// This method calls the approx method with a reasonable default for radius.
+VertexAlignment GetApproxVertexAlignment(const S2Polyline& a,
+                                         const S2Polyline& b) {
+  const int max_length = std::max(a.num_vertices(), b.num_vertices());
+  const int radius = static_cast<int>(std::pow(max_length, 0.25));
+  return GetApproxVertexAlignment(a, b, radius);
+}
+
+// We use some of the symmetry of our metric to avoid computing all N^2
+// alignments. Specifically, because cost_fn(a, b) = cost_fn(b, a), and
+// cost_fn(a, a) = 0, we can compute only the lower triangle of cost matrix
+// and then mirror it across the diagonal to save on cost_fn invocations.
+int GetMedoidPolyline(const std::vector<std::unique_ptr<S2Polyline>>& polylines,
+                      const MedoidOptions options) {
+  const int num_polylines = polylines.size();
+  const bool approx = options.approx();
+  S2_CHECK_GT(num_polylines, 0);
+
+  // costs[i] stores total cost of aligning [i] with all other polylines.
+  std::vector<double> costs(num_polylines, 0.0);
+  for (int i = 0; i < num_polylines; ++i) {
+    for (int j = i + 1; j < num_polylines; ++j) {
+      double cost = CostFn(*polylines[i], *polylines[j], approx);
+      costs[i] += cost;
+      costs[j] += cost;
+    }
+  }
+  return std::min_element(costs.begin(), costs.end()) - costs.begin();
+}
+
+// Implements Iterative Dynamic Timewarp Barycenter Averaging algorithm from
+//
+// https://pdfs.semanticscholar.org/a596/8ca9488199291ffe5473643142862293d69d.pdf
+//
+// Algorithm:
+// Initialize consensus sequence with either the medoid or an arbitrary
+// element (chosen here to be the first element in the input collection).
+// While the consensus polyline `consensus` hasn't converged and we haven't
+// exceeded our iteration cap:
+//   For each polyline `p` in the input,
+//     Compute vertex alignment from the current consensus to `p`.
+//     For each (c_index, p_index) pair in the warp path,
+//       Add the S2Point pts->vertex(p_index) to S2Point consensus[c_index]
+//   Normalize (compute centroid) of each consensus point.
+//   Determine if consensus is converging; if no vertex has moved or we've hit
+//   the iteration cap, halt.
+//
+//  This algorithm takes O(iteration_cap * num_polylines) pairwise alignments.
+
+std::unique_ptr<S2Polyline> GetConsensusPolyline(
+    const std::vector<std::unique_ptr<S2Polyline>>& polylines,
+    const ConsensusOptions options) {
+  const int num_polylines = polylines.size();
+  S2_CHECK_GT(num_polylines, 0);
+  const bool approx = options.approx();
+
+  // Seed a consensus polyline, either arbitrarily with first element, or with
+  // the medoid. If seeding with medoid, inherit approx parameter from options.
+  int seed_index = 0;
+  if (options.seed_medoid()) {
+    MedoidOptions medoid_options;
+    medoid_options.set_approx(approx);
+    seed_index = GetMedoidPolyline(polylines, medoid_options);
+  }
+  auto consensus = std::unique_ptr<S2Polyline>(polylines[seed_index]->Clone());
+  const int num_consensus_vertices = consensus->num_vertices();
+  S2_DCHECK_GT(num_consensus_vertices, 1);
+
+  bool converged = false;
+  int iterations = 0;
+  while (!converged && iterations < options.iteration_cap()) {
+    std::vector<S2Point> points(num_consensus_vertices, S2Point());
+    for (const auto& polyline : polylines) {
+      const auto alignment = AlignmentFn(*consensus, *polyline, approx);
+      for (const auto& pair : alignment.warp_path) {
+        points[pair.first] += polyline->vertex(pair.second);
+      }
+    }
+    for (S2Point& p : points) {
+      p = p.Normalize();
+    }
+
+    ++iterations;
+    auto new_consensus = absl::make_unique<S2Polyline>(points);
+    converged = new_consensus->ApproxEquals(*consensus);
+    consensus = std::move(new_consensus);
+  }
+  return consensus;
+}
+}  // namespace s2polyline_alignment
diff --git a/src/s2/s2polyline_alignment.h b/src/s2/s2polyline_alignment.h
new file mode 100644 (file)
index 0000000..ede3ca2
--- /dev/null
@@ -0,0 +1,245 @@
+// Copyright 2017 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+
+#ifndef S2_S2POLYLINE_ALIGNMENT_H_
+#define S2_S2POLYLINE_ALIGNMENT_H_
+
+#include <memory>
+#include <vector>
+
+#include "s2/s2polyline.h"
+
+// This library provides code to compute vertex alignments between S2Polylines.
+//
+// A vertex "alignment" or "warp" between two polylines is a matching between
+// pairs of their vertices. Users can imagine pairing each vertex from
+// S2Polyline `a` with at least one other vertex in S2Polyline `b`. The "cost"
+// of an arbitrary alignment is defined as the summed value of the squared
+// chordal distance between each pair of points in the warp path. An "optimal
+// alignment" for a pair of polylines is defined as the alignment with least
+// cost. Note: optimal alignments are not necessarily unique. The standard way
+// of computing an optimal alignment between two sequences is the use of the
+// `Dynamic Timewarp` algorithm.
+//
+// We provide three methods for computing (via Dynamic Timewarp) the optimal
+// alignment between two S2Polylines. These methods are performance-sensitive,
+// and have been reasonably optimized for space- and time- usage. On modern
+// hardware, it is possible to compute exact alignments between 4096x4096
+// element polylines in ~70ms, and approximate alignments much more quickly.
+//
+// The results of an alignment operation are captured in a VertexAlignment
+// object. In particular, a VertexAlignment keeps track of the total cost of
+// alignment, as well as the warp path (a sequence of pairs of indices into each
+// polyline whose vertices are linked together in the optimal alignment)
+//
+// For a worked example, consider the polylines
+//
+// a = [(1, 0), (5, 0), (6, 0), (9, 0)] and
+// b = [(2, 0), (7, 0), (8, 0)].
+//
+// The "cost matrix" between these two polylines (using squared chordal
+// distance, .Norm2(), as our distance function) looks like this:
+//
+//        (2, 0)  (7, 0)  (8, 0)
+// (1, 0)     1      36      49
+// (5, 0)     9       4       9
+// (6, 0)    16       1       4
+// (9, 0)    49       4       1
+//
+// The Dynamic Timewarp DP table for this cost matrix has cells defined by
+//
+// table[i][j] = cost(i,j) + min(table[i-1][j-1], table[i][j-1], table[i-1, j])
+//
+//        (2, 0)  (7, 0)  (8, 0)
+// (1, 0)     1      37      86
+// (5, 0)    10       5      14
+// (6, 0)    26       6       9
+// (9, 0)    75      10       7
+//
+// Starting at the bottom right corner of the DP table, we can work our way
+// backwards to the upper left corner  to recover the reverse of the warp path:
+// (3, 2) -> (2, 1) -> (1, 1) -> (0, 0). The VertexAlignment produced containing
+// this has alignment_cost = 7 and warp_path = {(0, 0), (1, 1), (2, 1), (3, 2)}.
+//
+// We also provide methods for performing alignment of multiple sequences. These
+// methods return a single, representative polyline from a non-empty collection
+// of polylines, for various definitions of "representative."
+//
+// GetMedoidPolyline() returns a new polyline (point-for-point-equal to some
+// existing polyline from the collection) that minimizes the summed vertex
+// alignment cost to all other polylines in the collection.
+//
+// GetConsensusPolyline() returns a new polyline (unlikely to be present in the
+// input collection) that represents a "weighted consensus" polyline. This
+// polyline is constructed iteratively using the Dynamic Timewarp Barycenter
+// Averaging algorithm of F. Petitjean, A. Ketterlin, and P. Gancarski, which
+// can be found here:
+// https://pdfs.semanticscholar.org/a596/8ca9488199291ffe5473643142862293d69d.pdf
+
+namespace s2polyline_alignment {
+
+typedef std::vector<std::pair<int, int>> WarpPath;
+
+struct VertexAlignment {
+  // `alignment_cost` represents the sum of the squared chordal distances
+  // between each pair of vertices in the warp path. Specifically,
+  // cost = sum_{(i, j) \in path} (a.vertex(i) - b.vertex(j)).Norm2();
+  // This means that the units of alignment_cost are "squared distance". This is
+  // an optimization to avoid the (expensive) atan computation of the true
+  // spherical angular distance between the points, as well as an unnecessary
+  // square root. All we need to compute vertex alignment is a metric that
+  // satisifies the triangle inequality, and squared chordal distance works as
+  // well as spherical S1Angle distance for this purpose.
+  double alignment_cost;
+
+  // Each entry (i, j) of `warp_path` represents a pairing between vertex
+  // a.vertex(i) and vertex b.vertex(j) in the optimal alignment.
+  // The warp_path is defined in forward order, such that the result of
+  // aligning polylines `a` and `b` is always a warp_path with warp_path.front()
+  // = {0,0} and warp_path.back() = {a.num_vertices() - 1, b.num_vertices() - 1}
+  // Note that this DOES NOT define an alignment from a point sequence to an
+  // edge sequence. That functionality may come at a later date.
+  WarpPath warp_path;
+
+  VertexAlignment(const double cost, const WarpPath& path)
+      : alignment_cost(cost), warp_path(path) {}
+};
+
+// GetExactVertexAlignment takes two non-empty polylines as input, and returns
+// the VertexAlignment corresponding to the optimal alignment between them. This
+// method is quadratic O(A*B) in both space and time complexity.
+VertexAlignment GetExactVertexAlignment(const S2Polyline& a,
+                                        const S2Polyline& b);
+
+// GetExactVertexAlignmentCost takes two non-empty polylines as input, and
+// returns the *cost* of their optimal alignment. A standard, traditional
+// dynamic timewarp algorithm can output both a warp path and a cost, but
+// requires quadratic space to reconstruct the path by walking back through the
+// Dynamic Programming cost table. If all you really need is the warp cost (i.e.
+// you're inducing a similarity metric between S2Polylines, or something
+// equivalent), you can overwrite the DP table and use constant space -
+// O(max(A,B)). This method provides that space-efficiency optimization.
+double GetExactVertexAlignmentCost(const S2Polyline& a, const S2Polyline& b);
+
+// GetApproxVertexAlignment takes two non-empty polylines `a` and `b` as input,
+// and a `radius` paramater GetApproxVertexAlignment (quickly) computes an
+// approximately optimal vertex alignment of points between polylines `a` and
+// `b` by implementing the algorithm described in `FastDTW: Toward Accurate
+// Dynamic Time Warping in Linear Time and Space` by Stan Salvador and Philip
+// Chan. Details can be found below:
+//
+// https://pdfs.semanticscholar.org/05a2/0cde15e172fc82f32774dd0cf4fe5827cad2.pdf
+//
+// The `radius` parameter controls the distance we search outside of the
+// projected warp path during the refining step. Smaller values of `radius`
+// correspond to a smaller search window, and therefore distance computation on
+// fewer cells, which leads to a faster (but worse) approximation.
+// This method is O(max(A, B)) in both space and time complexity.
+VertexAlignment GetApproxVertexAlignment(const S2Polyline& a,
+                                         const S2Polyline& b, const int radius);
+
+// A convience overload for GetApproxVertexAlignment which computes and uses
+// suggested default parameter of radius = max(a.size(), b.size())^0.25
+VertexAlignment GetApproxVertexAlignment(const S2Polyline& a,
+                                         const S2Polyline& b);
+
+// GetMedoidPolyline returns the index `p` of a "medoid" polyline from a
+// non-empty collection of `polylines` such that
+//
+// sum_{all j in `polylines`} VertexAlignmentCost(p, j) is minimized.
+//
+// In the case of a tie for minimal summed alignment cost, we return the lowest
+// index - this tie is guaranteed to happen in the two-polyline-input case.
+//
+// ASYMPTOTIC BEHAVIOR:
+// Computation may require up to (N^2 - N) / 2 alignment cost function
+// evaluations, for N input polylines. For polylines of length U, V, the
+// alignment cost function evaluation is O(U+V) if options.approx = true and
+// O(U*V) if options.approx = false.
+
+class MedoidOptions {
+ public:
+  // If options.approx = false, we compute vertex alignment costs exactly.
+  // If options.approx = true, we use approximate vertex alignment
+  // computation, called with the default radius parameter.
+  bool approx() const { return approx_; }
+  void set_approx(bool approx) { approx_ = approx; }
+
+ private:
+  bool approx_ = true;
+};
+
+int GetMedoidPolyline(const std::vector<std::unique_ptr<S2Polyline>>& polylines,
+                      const MedoidOptions options);
+
+// GetConsensusPolyline allocates and returns a new "consensus" polyline from a
+// non-empty collection of polylines. We iteratively apply Dynamic Timewarp
+// Barycenter Averaging to an initial `seed` polyline, which improves the
+// consensus alignment quality each iteration. For implementation details, see
+//
+// https://pdfs.semanticscholar.org/a596/8ca9488199291ffe5473643142862293d69d.pdf
+//
+// The returned polyline from this method is unlikely to be point-for-point
+// equal to an input polyline, whereas a polyline returned from
+// GetMedoidPolyline() is guaranteed to match an input polyline point-for-point.
+// NOTE: the number of points in our returned consensus polyline is always equal
+// to the number of points in the initial seed, which is implementation-defined.
+// If the collection of polylines has a large resolution distribution, it might
+// be a good idea to reinterpolate them to have about the same number of points.
+// In practice, this doesn't seem to matter, but is probably worth noting.
+//
+// ASYMPTOTIC BEHAVIOR:
+// Seeding this algorithm requires O(1) vertex alignments if seed_medoid =
+// false, and O(N^2) vertex alignments if seed_medoid = true. Once the seed
+// polyline is chosen, computing the consensus polyline requires at most
+// (iteration_cap)*N vertex alignments. For polylines of length U, V, the
+// alignment cost function evaluation is O(U+V) if options.approx = true, and
+// O(U*V) if options.approx = false.
+
+class ConsensusOptions {
+ public:
+  // If options.approx = false, vertex alignments are computed with
+  // GetExactVertexAlignment. If options.approx = true, vertex alignments are
+  // computed with GetApproxVertexAlignment, called with default radius
+  // parameter.
+  bool approx() const { return approx_; }
+  void set_approx(bool approx) { approx_ = approx; }
+
+  // If options.seed_medoid = true, we seed the consensus polyline with the
+  // medoid of the collection. This is a more expensive approach, but may result
+  // in higher quality consensus sequences by avoiding bad arbitrary initial
+  // seeds. Seeding with the medoid will incur up to (N^2 - N) / 2 evaluations
+  // of the vertex alignment function. If options.seed_medoid = false, we seed
+  // the consensus polyline by taking an arbitrary element from the collection.
+  bool seed_medoid() const { return seed_medoid_; }
+  void set_seed_medoid(bool seed_medoid) { seed_medoid_ = seed_medoid; }
+
+  // options.iteration_cap controls the maximum number of DBA refining steps we
+  // apply to the initial seed.
+  int iteration_cap() const { return iteration_cap_; }
+  void set_iteration_cap(int iteration_cap) { iteration_cap_ = iteration_cap; }
+
+ private:
+  bool approx_ = true;
+  bool seed_medoid_ = false;
+  int iteration_cap_ = 5;
+};
+
+std::unique_ptr<S2Polyline> GetConsensusPolyline(
+    const std::vector<std::unique_ptr<S2Polyline>>& polylines,
+    const ConsensusOptions options);
+}  // namespace s2polyline_alignment
+#endif  // S2_S2POLYLINE_ALIGNMENT_H_
diff --git a/src/s2/s2polyline_alignment_internal.h b/src/s2/s2polyline_alignment_internal.h
new file mode 100644 (file)
index 0000000..ea7bdd4
--- /dev/null
@@ -0,0 +1,158 @@
+// Copyright 2017 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+
+#ifndef S2_S2POLYLINE_ALIGNMENT_INTERNAL_H_
+#define S2_S2POLYLINE_ALIGNMENT_INTERNAL_H_
+
+#include "s2/s2polyline_alignment.h"
+
+#include <limits>
+#include <vector>
+
+#include "s2/s2polyline.h"
+
+namespace s2polyline_alignment {
+
+static constexpr double DOUBLE_MAX = std::numeric_limits<double>::max();
+
+// Alias for a 2d Dynamic Programming table.
+typedef std::vector<std::vector<double>> CostTable;
+
+// A ColumnStride is a [start, end) range of columns in a search window.
+// It enables us to lazily fill up our CostTable structures by providing bounds
+// checked access for reads. We also use them to keep track of structured,
+// sparse Window matrices by tracking start and end columns for each row.
+struct ColumnStride {
+  int start;
+  int end;
+  inline bool InRange(const int index) const {
+    return start <= index && index < end;
+  }
+  // Returns a ColumnStride where InRange evaluates to `true` for all
+  // non-negative inputs less than INT_MAX;
+  static inline constexpr ColumnStride All() {
+    return ColumnStride{-1, std::numeric_limits<int>::max()};
+  }
+};
+
+// A Window is a sparse binary matrix with specific structural constraints
+// on allowed element configurations. It is used in this library to represent
+// "search windows" for windowed dynamic timewarping.
+//
+// Valid Windows require the following structural conditions to hold:
+// 1) All rows must consist of a single contiguous stride of `true` values.
+// 2) All strides are greater than zero length (i.e. no empty rows).
+// 3) The index of the first `true` column in a row must be at least as
+//    large as the index of the first `true` column in the previous row.
+// 4) The index of the last `true` column in a row must be at least as large
+//    as the index of the last `true` column in the previous row.
+// 5) strides[0].start = 0 (the first cell is always filled).
+// 6) strides[n_rows-1].end = n_cols (the last cell is filled).
+//
+// Example valid strided_masks (* = filled, . = unfilled)
+//   0 1 2 3 4 5
+// 0 * * * . . .
+// 1 . * * * . .
+// 2 . * * * . .
+// 3 . . * * * *
+// 4 . . * * * *
+//   0 1 2 3 4 5
+// 0 * * * * . .
+// 1 . * * * * .
+// 2 . . * * * .
+// 3 . . . . * *
+// 4 . . . . . *
+//   0 1 2 3 4 5
+// 0 * * . . . .
+// 1 . * . . . .
+// 2 . . * * * .
+// 3 . . . . . *
+// 4 . . . . . *
+//
+// Example invalid strided_masks:
+//   0 1 2 3 4 5
+// 0 * * * . * * <-- more than one continuous run
+// 1 . * * * . .
+// 2 . * * * . .
+// 3 . . * * * *
+// 4 . . * * * *
+//   0 1 2 3 4 5
+// 0 * * * . . .
+// 1 . * * * . .
+// 2 . * * * . .
+// 3 * * * * * * <-- start index not monotonically increasing
+// 4 . . * * * *
+//   0 1 2 3 4 5
+// 0 * * * . . .
+// 1 . * * * * .
+// 2 . * * * . . <-- end index not monotonically increasing
+// 3 . . * * * *
+// 4 . . * * * *
+//   0 1 2 3 4 5
+// 0 . * . . . . <-- does not fill upper left corner
+// 1 . * . . . .
+// 2 . * . . . .
+// 3 . * * * . .
+// 4 . . * * * *
+class Window {
+ public:
+  // Construct a Window from a non-empty list of column strides.
+  explicit Window(const std::vector<ColumnStride>& strides);
+
+  // Construct a Window from a non-empty sequence of warp path index pairs.
+  explicit Window(const WarpPath& warp_path);
+
+  // Return the (not-bounds-checked) stride for this row.
+  inline ColumnStride GetColumnStride(const int row) const {
+    return strides_[row];
+  }
+
+  // Return the (bounds-checked) stride for this row.
+  // If row < 0, returns ColumnStride::All()
+  inline ColumnStride GetCheckedColumnStride(const int row) const {
+    return (row > 0) ? strides_[row] : ColumnStride::All();
+  }
+
+  // Return a new, larger Window that is an upscaled version of this window
+  // Used by ApproximateAlignment window expansion step.
+  Window Upsample(const int new_rows, const int new_cols) const;
+
+  // Return a new, equal-size Window by dilating this window with a square
+  // structuring element with half-length `radius`. Radius = 1 corresponds to
+  // a 3x3 square morphological dilation.
+  // Used by ApproximateAlignment window expansion step.
+  Window Dilate(const int radius) const;
+
+  // Return a string representation of this window.
+  std::string DebugString() const;
+
+ private:
+  int rows_;
+  int cols_;
+  std::vector<ColumnStride> strides_;
+  // Returns true if this window's data represents a valid window.
+  bool IsValid() const;
+};
+
+// Reduce the number of vertices of polyline `in` by selecting every other
+// vertex for inclusion in a new polyline. Specifically, we take even-index
+// vertices [0, 2, 4,...]. For an even-length polyline, the last vertex is not
+// selected. For an odd-length polyline, the last vertex is selected.
+// Constructs and returns a new S2Polyline in linear time.
+std::unique_ptr<S2Polyline> HalfResolution(const S2Polyline& in);
+
+}  // namespace s2polyline_alignment
+#endif  // S2_S2POLYLINE_ALIGNMENT_INTERNAL_H_
diff --git a/src/s2/s2polyline_measures.cc b/src/s2/s2polyline_measures.cc
new file mode 100644 (file)
index 0000000..4d66f15
--- /dev/null
@@ -0,0 +1,42 @@
+// Copyright 2018 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// Author: ericv@google.com (Eric Veach)
+
+#include "s2/s2polyline_measures.h"
+
+#include <cmath>
+#include "s2/base/logging.h"
+#include "s2/s2centroids.h"
+
+namespace S2 {
+
+S1Angle GetLength(S2PointSpan polyline) {
+  S1Angle length;
+  for (int i = 1; i < polyline.size(); ++i) {
+    length += S1Angle(polyline[i - 1], polyline[i]);
+  }
+  return length;
+}
+
+S2Point GetCentroid(S2PointSpan polyline) {
+  S2Point centroid;
+  for (int i = 1; i < polyline.size(); ++i) {
+    centroid += S2::TrueCentroid(polyline[i - 1], polyline[i]);
+  }
+  return centroid;
+}
+
+}  // namespace S2
diff --git a/src/s2/s2polyline_measures.h b/src/s2/s2polyline_measures.h
new file mode 100644 (file)
index 0000000..68130fd
--- /dev/null
@@ -0,0 +1,53 @@
+// Copyright 2018 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// Author: ericv@google.com (Eric Veach)
+//
+// Defines various measures for polylines on the sphere.  These are low-level
+// methods that work directly with arrays of S2Points.  They are used to
+// implement the methods in s2shapeindex_measures.h, s2shape_measures.h, and
+// s2polyline.h.
+//
+// See s2loop_measures.h, s2edge_distances.h, and s2measures.h for additional
+// low-level methods.
+
+#ifndef S2_S2POLYLINE_MEASURES_H_
+#define S2_S2POLYLINE_MEASURES_H_
+
+#include "s2/s1angle.h"
+#include "s2/s2point.h"
+#include "s2/s2point_span.h"
+
+namespace S2 {
+
+// Returns the length of the polyline.  Returns zero for polylines with fewer
+// than two vertices.
+S1Angle GetLength(S2PointSpan polyline);
+
+// Returns the true centroid of the polyline multiplied by the length of the
+// polyline (see s2centroids.h for details on centroids).  The result is not
+// unit length, so you may want to normalize it.
+//
+// Scaling by the polyline length makes it easy to compute the centroid of
+// several polylines (by simply adding up their centroids).
+//
+// CAVEAT: Returns S2Point() for degenerate polylines (e.g., AA).  [Note that
+// this answer is correct; the result of this function is a line integral over
+// the polyline, whose value is always zero if the polyline is degenerate.]
+S2Point GetCentroid(S2PointSpan polyline);
+
+}  // namespace S2
+
+#endif  // S2_S2POLYLINE_MEASURES_H_
diff --git a/src/s2/s2polyline_simplifier.cc b/src/s2/s2polyline_simplifier.cc
new file mode 100644 (file)
index 0000000..7a16e2b
--- /dev/null
@@ -0,0 +1,187 @@
+// Copyright 2016 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// Author: ericv@google.com (Eric Veach)
+
+#include "s2/s2polyline_simplifier.h"
+
+#include <cfloat>
+
+#include "s2/s1chord_angle.h"
+#include "s2/s1interval.h"
+
+void S2PolylineSimplifier::Init(const S2Point& src) {
+  src_ = src;
+  window_ = S1Interval::Full();
+
+  // Precompute basis vectors for the tangent space at "src".  This is similar
+  // to GetFrame() except that we don't normalize the vectors.  As it turns
+  // out, the two basis vectors below have the same magnitude (up to the
+  // length error in S2Point::Normalize).
+
+  // Find the index of the component whose magnitude is smallest.
+  S2Point tmp = src.Abs();
+  int i = (tmp[0] < tmp[1] ?
+           (tmp[0] < tmp[2] ? 0 : 2) : (tmp[1] < tmp[2] ? 1 : 2));
+
+  // We define the "y" basis vector as the cross product of "src" and the
+  // basis vector for axis "i".  Let "j" and "k" be the indices of the other
+  // two components in cyclic order.
+  int j = (i == 2 ? 0 : i + 1), k = (i == 0 ? 2 : i - 1);
+  y_dir_[i] = 0;
+  y_dir_[j] = src[k];
+  y_dir_[k] = -src[j];
+
+  // Compute the cross product of "y_dir" and "src".  We write out the cross
+  // product here mainly for documentation purposes; it also happens to save a
+  // few multiplies because unfortunately the optimizer does *not* get rid of
+  // multiplies by zero (since these multiplies propagate NaN, for example).
+  x_dir_[i] = src[j] * src[j] + src[k] * src[k];
+  x_dir_[j] = -src[j] * src[i];
+  x_dir_[k] = -src[k] * src[i];
+}
+
+bool S2PolylineSimplifier::Extend(const S2Point& dst) const {
+  // We limit the maximum edge length to 90 degrees in order to simplify the
+  // error bounds.  (The error gets arbitrarily large as the edge length
+  // approaches 180 degrees.)
+  if (S1ChordAngle(src_, dst) > S1ChordAngle::Right()) return false;
+
+  // Otherwise check whether this vertex is in the acceptable angle range.
+  return window_.Contains(GetAngle(dst));
+}
+
+bool S2PolylineSimplifier::TargetDisc(const S2Point& p, S1ChordAngle r) {
+  // Shrink the target interval by the maximum error from all sources.  This
+  // guarantees that the output edge will intersect the given disc.
+  double semiwidth = GetSemiwidth(p, r, -1 /*round down*/);
+  if (semiwidth >= M_PI) {
+    // The target disc contains "src", so there is nothing to do.
+    return true;
+  }
+  if (semiwidth < 0) {
+    window_ = S1Interval::Empty();
+    return false;
+  }
+  // Otherwise compute the angle interval corresponding to the target disc and
+  // intersect it with the current window.
+  double center = GetAngle(p);
+  S1Interval target = S1Interval::FromPoint(center).Expanded(semiwidth);
+  window_ = window_.Intersection(target);
+  return !window_.is_empty();
+}
+
+bool S2PolylineSimplifier::AvoidDisc(const S2Point& p, S1ChordAngle r,
+                                     bool disc_on_left) {
+  // Expand the interval by the maximum error from all sources.  This
+  // guarantees that the final output edge will avoid the given disc.
+  double semiwidth = GetSemiwidth(p, r, 1 /*round up*/);
+  if (semiwidth >= M_PI) {
+    // The avoidance disc contains "src", so it is impossible to avoid.
+    window_ = S1Interval::Empty();
+    return false;
+  }
+  double center = GetAngle(p);
+  double opposite = (center > 0) ? center - M_PI : center + M_PI;
+  S1Interval target = (disc_on_left ? S1Interval(opposite, center) :
+                       S1Interval(center, opposite));
+  window_ = window_.Intersection(target.Expanded(-semiwidth));
+  return !window_.is_empty();
+}
+
+double S2PolylineSimplifier::GetAngle(const S2Point& p) const {
+  return atan2(p.DotProd(y_dir_), p.DotProd(x_dir_));
+}
+
+double S2PolylineSimplifier::GetSemiwidth(const S2Point& p, S1ChordAngle r,
+                                          int round_direction) const {
+  double constexpr DBL_ERR = 0.5 * DBL_EPSILON;
+
+  // Using spherical trigonometry,
+  //
+  //   sin(semiwidth) = sin(r) / sin(a)
+  //
+  // where "a" is the angle between "src" and "p".  Rather than measuring
+  // these angles, instead we measure the squared chord lengths through the
+  // interior of the sphere (i.e., Cartersian distance).  Letting "r2" be the
+  // squared chord distance corresponding to "r", and "a2" be the squared
+  // chord distance corresponding to "a", we use the relationships
+  //
+  //    sin^2(r) = r2 (1 - r2 / 4)
+  //    sin^2(a) = d2 (1 - d2 / 4)
+  //
+  // which follow from the fact that r2 = (2 * sin(r / 2)) ^ 2, etc.
+
+  // "a2" has a relative error up to 5 * DBL_ERR, plus an absolute error of up
+  // to 64 * DBL_ERR^2 (because "src" and "p" may differ from unit length by
+  // up to 4 * DBL_ERR).  We can correct for the relative error later, but for
+  // the absolute error we use "round_direction" to account for it now.
+  double r2 = r.length2();
+  double a2 = S1ChordAngle(src_, p).length2();
+  a2 -= 64 * DBL_ERR * DBL_ERR * round_direction;
+  if (a2 <= r2) return M_PI;  // The given disc contains "src".
+
+  double sin2_r = r2 * (1 - 0.25 * r2);
+  double sin2_a = a2 * (1 - 0.25 * a2);
+  double semiwidth = asin(sqrt(sin2_r / sin2_a));
+
+  // We compute bounds on the errors from all sources:
+  //
+  //   - The call to GetSemiwidth (this call).
+  //   - The call to GetAngle that computes the center of the interval.
+  //   - The call to GetAngle in Extend that tests whether a given point
+  //     is an acceptable destination vertex.
+  //
+  // Summary of the errors in GetAngle:
+  //
+  // y_dir_ has no error.
+  //
+  // x_dir_ has a relative error of DBL_ERR in two components, a relative
+  // error of 2 * DBL_ERR in the other component, plus an overall relative
+  // length error of 4 * DBL_ERR (compared to y_dir_) because "src" is assumed
+  // to be normalized only to within the tolerances of S2Point::Normalize().
+  //
+  // p.DotProd(y_dir_) has a relative error of 1.5 * DBL_ERR and an
+  // absolute error of 1.5 * DBL_ERR * y_dir_.Norm().
+  //
+  // p.DotProd(x_dir_) has a relative error of 5.5 * DBL_ERR and an absolute
+  // error of 3.5 * DBL_ERR * y_dir_.Norm() (noting that x_dir_ and y_dir_
+  // have the same length to within a relative error of 4 * DBL_ERR).
+  //
+  // It's possible to show by taking derivatives that these errors can affect
+  // the angle atan2(y, x) by up 7.093 * DBL_ERR radians.  Rounding up and
+  // including the call to atan2 gives a final error bound of 10 * DBL_ERR.
+  //
+  // Summary of the errors in GetSemiwidth:
+  //
+  // The distance a2 has a relative error of 5 * DBL_ERR plus an absolute
+  // error of 64 * DBL_ERR^2 because the points "src" and "p" may differ from
+  // unit length (by up to 4 * DBL_ERR).  We have already accounted for the
+  // absolute error above, leaving only the relative error.
+  //
+  // sin2_r has a relative error of 2 * DBL_ERR.
+  //
+  // sin2_a has a relative error of 12 * DBL_ERR assuming that a2 <= 2,
+  // i.e. distance(src, p) <= 90 degrees.  (The relative error gets
+  // arbitrarily larger as this distance approaches 180 degrees.)
+  //
+  // semiwidth has a relative error of 17 * DBL_ERR.
+  //
+  // Finally, (center +/- semiwidth) has a rounding error of up to 4 * DBL_ERR
+  // because in theory, the result magnitude may be as large as 1.5 * M_PI
+  // which is larger than 4.0.  This gives a total error of:
+  double error = (2 * 10 + 4) * DBL_ERR + 17 * DBL_ERR * semiwidth;
+  return semiwidth + round_direction * error;
+}
diff --git a/src/s2/s2polyline_simplifier.h b/src/s2/s2polyline_simplifier.h
new file mode 100644 (file)
index 0000000..69f968c
--- /dev/null
@@ -0,0 +1,109 @@
+// Copyright 2016 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// Author: ericv@google.com (Eric Veach)
+//
+// This is a helper class for simplifying polylines.  It allows you to compute
+// a maximal edge that intersects a sequence of discs, and that optionally
+// avoids a different sequence of discs.  The results are conservative in that
+// the edge is guaranteed to intersect or avoid the specified discs using
+// exact arithmetic (see s2predicates.h).
+//
+// Note that S2Builder can also simplify polylines and supports more features
+// (e.g., snapping to S2CellId centers), so it is only recommended to use this
+// class if S2Builder does not meet your needs.
+//
+// Here is a simple example showing how to simplify a polyline into a sequence
+// of edges that stay within "max_error" of the original edges:
+//
+//   vector<S2Point> v = { ... };
+//   S2PolylineSimplifier simplifier;
+//   simplifier.Init(v[0]);
+//   for (int i = 1; i < v.size(); ++i) {
+//     if (!simplifier.Extend(v[i])) {
+//       OutputEdge(simplifier.src(), v[i-1]);
+//       simplifier.Init(v[i-1]);
+//     }
+//     simplifier.TargetDisc(v[i], max_error);
+//   }
+//   OutputEdge(simplifer.src(), v.back());
+//
+// Note that the points targeted by TargetDisc do not need to be the same as
+// the candidate endpoints passed to Extend.  So for example, you could target
+// the original vertices of a polyline, but only consider endpoints that are
+// snapped to E7 coordinates or S2CellId centers.
+//
+// Please be aware that this class works by maintaining a range of acceptable
+// angles (bearings) from the start vertex to the hypothetical destination
+// vertex.  It does not keep track of distances to any of the discs to be
+// targeted or avoided.  Therefore to use this class correctly, constraints
+// should be added in increasing order of distance.  (The actual requirement
+// is slightly weaker than this, which is why it is not enforced, but
+// basically you should only call TargetDisc() and AvoidDisc() with arguments
+// that you want to constrain the immediately following call to Extend().)
+
+#ifndef S2_S2POLYLINE_SIMPLIFIER_H_
+#define S2_S2POLYLINE_SIMPLIFIER_H_
+
+#include "s2/_fp_contract_off.h"
+#include "s2/s1chord_angle.h"
+#include "s2/s1interval.h"
+
+class S2PolylineSimplifier {
+ public:
+  S2PolylineSimplifier() {}
+
+  // Starts a new simplified edge at "src".
+  void Init(const S2Point& src);
+
+  // Returns the source vertex of the output edge.
+  S2Point src() const;
+
+  // Returns true if the edge (src, dst) satisfies all of the targeting
+  // requirements so far.  Returns false if the edge would be longer than
+  // 90 degrees (such edges are not supported).
+  bool Extend(const S2Point& dst) const;
+
+  // Requires that the output edge must pass through the given disc.
+  bool TargetDisc(const S2Point& point, S1ChordAngle radius);
+
+  // Requires that the output edge must avoid the given disc.  "disc_on_left"
+  // specifies whether the disc must be to the left or right of the edge.
+  // (This feature allows the simplified edge to preserve the topology of the
+  // original polyline with respect to other nearby points.)
+  //
+  // If your input is a polyline, you can compute "disc_on_left" as follows.
+  // Let the polyline be ABCDE and assume that it already avoids a set of
+  // points X_i.  Suppose that you have aleady added ABC to the simplifer, and
+  // now want to extend the edge chain to D.  First find the X_i that are near
+  // the edge CD, then discard the ones such that AX_i <= AC or AX_i >= AD
+  // (since these points have either already been considered or aren't
+  // relevant yet).  Now X_i is to the left of the polyline if and only if
+  // s2pred::OrderedCCW(A, D, X, C) (in other words, if X_i is to the left of
+  // the angle wedge ACD).
+  bool AvoidDisc(const S2Point& point, S1ChordAngle radius,
+                 bool disc_on_left);
+
+ private:
+  double GetAngle(const S2Point& p) const;
+  double GetSemiwidth(const S2Point& p, S1ChordAngle r,
+                      int round_direction) const;
+
+  S2Point src_;
+  S2Point x_dir_, y_dir_;
+  S1Interval window_;
+};
+
+#endif  // S2_S2POLYLINE_SIMPLIFIER_H_
diff --git a/src/s2/s2predicates.cc b/src/s2/s2predicates.cc
new file mode 100644 (file)
index 0000000..a8333b4
--- /dev/null
@@ -0,0 +1,1486 @@
+// Copyright 2016 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// Author: ericv@google.com (Eric Veach)
+
+#include "s2/s2predicates.h"
+#include "s2/s2predicates_internal.h"
+
+#include <algorithm>
+#include <cfloat>
+#include <cmath>
+#include <ostream>
+#include "s2/s1chord_angle.h"
+#include "s2/util/math/exactfloat/exactfloat.h"
+#include "s2/util/math/vector.h"
+
+using std::fabs;
+using std::max;
+using std::min;
+using std::sqrt;
+
+namespace s2pred {
+
+// All error bounds in this file are expressed in terms of the maximum
+// rounding error for a floating-point type.  The rounding error is half of
+// the numeric_limits<T>::epsilon() value.
+constexpr double DBL_ERR = rounding_epsilon<double>();
+constexpr long double LD_ERR = rounding_epsilon<long double>();
+
+// A predefined S1ChordAngle representing (approximately) 45 degrees.
+static const S1ChordAngle k45Degrees = S1ChordAngle::FromLength2(2 - M_SQRT2);
+
+int Sign(const S2Point& a, const S2Point& b, const S2Point& c) {
+  // We don't need RobustCrossProd() here because Sign() does its own
+  // error estimation and calls ExpensiveSign() if there is any uncertainty
+  // about the result.
+  return Sign(a, b, c, a.CrossProd(b));
+}
+
+// Compute the determinant in a numerically stable way.  Unlike TriageSign(),
+// this method can usually compute the correct determinant sign even when all
+// three points are as collinear as possible.  For example if three points are
+// spaced 1km apart along a random line on the Earth's surface using the
+// nearest representable points, there is only a 0.4% chance that this method
+// will not be able to find the determinant sign.  The probability of failure
+// decreases as the points get closer together; if the collinear points are
+// 1 meter apart, the failure rate drops to 0.0004%.
+//
+// This method could be extended to also handle nearly-antipodal points (and
+// in fact an earlier version of this code did exactly that), but antipodal
+// points are rare in practice so it seems better to simply fall back to
+// exact arithmetic in that case.
+int StableSign(const S2Point& a, const S2Point& b, const S2Point& c) {
+  Vector3_d ab = b - a;
+  Vector3_d bc = c - b;
+  Vector3_d ca = a - c;
+  double ab2 = ab.Norm2();
+  double bc2 = bc.Norm2();
+  double ca2 = ca.Norm2();
+
+  // Now compute the determinant ((A-C)x(B-C)).C, where the vertices have been
+  // cyclically permuted if necessary so that AB is the longest edge.  (This
+  // minimizes the magnitude of cross product.)  At the same time we also
+  // compute the maximum error in the determinant.  Using a similar technique
+  // to the one used for kMaxDetError, the error is at most
+  //
+  //   |d| <= (3 + 6/sqrt(3)) * |A-C| * |B-C| * e
+  //
+  // where e = 0.5 * DBL_EPSILON.  If the determinant magnitude is larger than
+  // this value then we know its sign with certainty.
+  const double kDetErrorMultiplier = 3.2321 * DBL_EPSILON;  // see above
+  double det, max_error;
+  if (ab2 >= bc2 && ab2 >= ca2) {
+    // AB is the longest edge, so compute (A-C)x(B-C).C.
+    det = -(ca.CrossProd(bc).DotProd(c));
+    max_error = kDetErrorMultiplier * sqrt(ca2 * bc2);
+  } else if (bc2 >= ca2) {
+    // BC is the longest edge, so compute (B-A)x(C-A).A.
+    det = -(ab.CrossProd(ca).DotProd(a));
+    max_error = kDetErrorMultiplier * sqrt(ab2 * ca2);
+  } else {
+    // CA is the longest edge, so compute (C-B)x(A-B).B.
+    det = -(bc.CrossProd(ab).DotProd(b));
+    max_error = kDetErrorMultiplier * sqrt(bc2 * ab2);
+  }
+  return (fabs(det) <= max_error) ? 0 : (det > 0) ? 1 : -1;
+}
+
+// The following function returns the sign of the determinant of three points
+// A, B, C under a model where every possible S2Point is slightly perturbed by
+// a unique infinitesmal amount such that no three perturbed points are
+// collinear and no four points are coplanar.  The perturbations are so small
+// that they do not change the sign of any determinant that was non-zero
+// before the perturbations, and therefore can be safely ignored unless the
+// determinant of three points is exactly zero (using multiple-precision
+// arithmetic).
+//
+// Since the symbolic perturbation of a given point is fixed (i.e., the
+// perturbation is the same for all calls to this method and does not depend
+// on the other two arguments), the results of this method are always
+// self-consistent.  It will never return results that would correspond to an
+// "impossible" configuration of non-degenerate points.
+//
+// Requirements:
+//   The 3x3 determinant of A, B, C must be exactly zero.
+//   The points must be distinct, with A < B < C in lexicographic order.
+//
+// Returns:
+//   +1 or -1 according to the sign of the determinant after the symbolic
+// perturbations are taken into account.
+//
+// Reference:
+//   "Simulation of Simplicity" (Edelsbrunner and Muecke, ACM Transactions on
+//   Graphics, 1990).
+//
+int SymbolicallyPerturbedSign(
+    const Vector3_xf& a, const Vector3_xf& b,
+    const Vector3_xf& c, const Vector3_xf& b_cross_c) {
+  // This method requires that the points are sorted in lexicographically
+  // increasing order.  This is because every possible S2Point has its own
+  // symbolic perturbation such that if A < B then the symbolic perturbation
+  // for A is much larger than the perturbation for B.
+  //
+  // Alternatively, we could sort the points in this method and keep track of
+  // the sign of the permutation, but it is more efficient to do this before
+  // converting the inputs to the multi-precision representation, and this
+  // also lets us re-use the result of the cross product B x C.
+  S2_DCHECK(a < b && b < c);
+
+  // Every input coordinate x[i] is assigned a symbolic perturbation dx[i].
+  // We then compute the sign of the determinant of the perturbed points,
+  // i.e.
+  //               | a[0]+da[0]  a[1]+da[1]  a[2]+da[2] |
+  //               | b[0]+db[0]  b[1]+db[1]  b[2]+db[2] |
+  //               | c[0]+dc[0]  c[1]+dc[1]  c[2]+dc[2] |
+  //
+  // The perturbations are chosen such that
+  //
+  //   da[2] > da[1] > da[0] > db[2] > db[1] > db[0] > dc[2] > dc[1] > dc[0]
+  //
+  // where each perturbation is so much smaller than the previous one that we
+  // don't even need to consider it unless the coefficients of all previous
+  // perturbations are zero.  In fact, it is so small that we don't need to
+  // consider it unless the coefficient of all products of the previous
+  // perturbations are zero.  For example, we don't need to consider the
+  // coefficient of db[1] unless the coefficient of db[2]*da[0] is zero.
+  //
+  // The follow code simply enumerates the coefficients of the perturbations
+  // (and products of perturbations) that appear in the determinant above, in
+  // order of decreasing perturbation magnitude.  The first non-zero
+  // coefficient determines the sign of the result.  The easiest way to
+  // enumerate the coefficients in the correct order is to pretend that each
+  // perturbation is some tiny value "eps" raised to a power of two:
+  //
+  // eps**    1      2      4      8     16     32     64     128    256
+  //        da[2]  da[1]  da[0]  db[2]  db[1]  db[0]  dc[2]  dc[1]  dc[0]
+  //
+  // Essentially we can then just count in binary and test the corresponding
+  // subset of perturbations at each step.  So for example, we must test the
+  // coefficient of db[2]*da[0] before db[1] because eps**12 > eps**16.
+  //
+  // Of course, not all products of these perturbations appear in the
+  // determinant above, since the determinant only contains the products of
+  // elements in distinct rows and columns.  Thus we don't need to consider
+  // da[2]*da[1], db[1]*da[1], etc.  Furthermore, sometimes different pairs of
+  // perturbations have the same coefficient in the determinant; for example,
+  // da[1]*db[0] and db[1]*da[0] have the same coefficient (c[2]).  Therefore
+  // we only need to test this coefficient the first time we encounter it in
+  // the binary order above (which will be db[1]*da[0]).
+  //
+  // The sequence of tests below also appears in Table 4-ii of the paper
+  // referenced above, if you just want to look it up, with the following
+  // translations: [a,b,c] -> [i,j,k] and [0,1,2] -> [1,2,3].  Also note that
+  // some of the signs are different because the opposite cross product is
+  // used (e.g., B x C rather than C x B).
+
+  int det_sign = b_cross_c[2].sgn();            // da[2]
+  if (det_sign != 0) return det_sign;
+  det_sign = b_cross_c[1].sgn();                // da[1]
+  if (det_sign != 0) return det_sign;
+  det_sign = b_cross_c[0].sgn();                // da[0]
+  if (det_sign != 0) return det_sign;
+
+  det_sign = (c[0]*a[1] - c[1]*a[0]).sgn();     // db[2]
+  if (det_sign != 0) return det_sign;
+  det_sign = c[0].sgn();                        // db[2] * da[1]
+  if (det_sign != 0) return det_sign;
+  det_sign = -(c[1].sgn());                     // db[2] * da[0]
+  if (det_sign != 0) return det_sign;
+  det_sign = (c[2]*a[0] - c[0]*a[2]).sgn();     // db[1]
+  if (det_sign != 0) return det_sign;
+  det_sign = c[2].sgn();                        // db[1] * da[0]
+  if (det_sign != 0) return det_sign;
+  // The following test is listed in the paper, but it is redundant because
+  // the previous tests guarantee that C == (0, 0, 0).
+  S2_DCHECK_EQ(0, (c[1]*a[2] - c[2]*a[1]).sgn());  // db[0]
+
+  det_sign = (a[0]*b[1] - a[1]*b[0]).sgn();     // dc[2]
+  if (det_sign != 0) return det_sign;
+  det_sign = -(b[0].sgn());                     // dc[2] * da[1]
+  if (det_sign != 0) return det_sign;
+  det_sign = b[1].sgn();                        // dc[2] * da[0]
+  if (det_sign != 0) return det_sign;
+  det_sign = a[0].sgn();                        // dc[2] * db[1]
+  if (det_sign != 0) return det_sign;
+  return 1;                                     // dc[2] * db[1] * da[0]
+}
+
+// Compute the determinant using exact arithmetic and/or symbolic
+// permutations.  Requires that the three points are distinct.
+int ExactSign(const S2Point& a, const S2Point& b, const S2Point& c,
+              bool perturb) {
+  S2_DCHECK(a != b && b != c && c != a);
+
+  // Sort the three points in lexicographic order, keeping track of the sign
+  // of the permutation.  (Each exchange inverts the sign of the determinant.)
+  int perm_sign = 1;
+  const S2Point *pa = &a, *pb = &b, *pc = &c;
+  using std::swap;
+  if (*pa > *pb) { swap(pa, pb); perm_sign = -perm_sign; }
+  if (*pb > *pc) { swap(pb, pc); perm_sign = -perm_sign; }
+  if (*pa > *pb) { swap(pa, pb); perm_sign = -perm_sign; }
+  S2_DCHECK(*pa < *pb && *pb < *pc);
+
+  // Construct multiple-precision versions of the sorted points and compute
+  // their exact 3x3 determinant.
+  Vector3_xf xa = Vector3_xf::Cast(*pa);
+  Vector3_xf xb = Vector3_xf::Cast(*pb);
+  Vector3_xf xc = Vector3_xf::Cast(*pc);
+  Vector3_xf xb_cross_xc = xb.CrossProd(xc);
+  ExactFloat det = xa.DotProd(xb_cross_xc);
+
+  // The precision of ExactFloat is high enough that the result should always
+  // be exact (no rounding was performed).
+  S2_DCHECK(!det.is_nan());
+  S2_DCHECK_LT(det.prec(), det.max_prec());
+
+  // If the exact determinant is non-zero, we're done.
+  int det_sign = det.sgn();
+  if (det_sign == 0 && perturb) {
+    // Otherwise, we need to resort to symbolic perturbations to resolve the
+    // sign of the determinant.
+    det_sign = SymbolicallyPerturbedSign(xa, xb, xc, xb_cross_xc);
+    S2_DCHECK_NE(0, det_sign);
+  }
+  return perm_sign * det_sign;
+}
+
+// ExpensiveSign() uses arbitrary-precision arithmetic and the "simulation of
+// simplicity" technique in order to be completely robust (i.e., to return
+// consistent results for all possible inputs).
+//
+// Below we define a floating-point type with enough precision so that it can
+// represent the exact determinant of any 3x3 matrix of floating-point
+// numbers.  It uses ExactFloat, which is based on the OpenSSL Bignum library
+// and therefore has a permissive BSD-style license.  (At one time we also
+// supported an option based on MPFR, but that has an LGPL license and is
+// therefore not suited for some applications.)
+
+using Vector3_xf = Vector3<ExactFloat>;
+
+int ExpensiveSign(const S2Point& a, const S2Point& b, const S2Point& c,
+                  bool perturb) {
+  // Return zero if and only if two points are the same.  This ensures (1).
+  if (a == b || b == c || c == a) return 0;
+
+  // Next we try recomputing the determinant still using floating-point
+  // arithmetic but in a more precise way.  This is more expensive than the
+  // simple calculation done by TriageSign(), but it is still *much* cheaper
+  // than using arbitrary-precision arithmetic.  This optimization is able to
+  // compute the correct determinant sign in virtually all cases except when
+  // the three points are truly collinear (e.g., three points on the equator).
+  int det_sign = StableSign(a, b, c);
+  if (det_sign != 0) return det_sign;
+
+  // TODO(ericv): Create a templated version of StableSign so that we can
+  // retry in "long double" precision before falling back to ExactFloat.
+
+  // TODO(ericv): Optimize ExactFloat so that it stores up to 32 bytes of
+  // mantissa inline (without requiring memory allocation).
+
+  // Otherwise fall back to exact arithmetic and symbolic permutations.
+  return ExactSign(a, b, c, perturb);
+}
+
+bool OrderedCCW(const S2Point& a, const S2Point& b, const S2Point& c,
+                const S2Point& o) {
+  // The last inequality below is ">" rather than ">=" so that we return true
+  // if A == B or B == C, and otherwise false if A == C.  Recall that
+  // Sign(x,y,z) == -Sign(z,y,x) for all x,y,z.
+
+  int sum = 0;
+  if (Sign(b, o, a) >= 0) ++sum;
+  if (Sign(c, o, b) >= 0) ++sum;
+  if (Sign(a, o, c) > 0) ++sum;
+  return sum >= 2;
+}
+
+// Returns cos(XY), and sets "error" to the maximum error in the result.
+// REQUIRES: "x" and "y" satisfy S2::IsNormalized().
+inline double GetCosDistance(const S2Point& x, const S2Point& y,
+                             double* error) {
+  double c = x.DotProd(y);
+  *error = 9.5 * DBL_ERR * fabs(c) + 1.5 * DBL_ERR;
+  return c;
+}
+
+// A high precision "long double" version of the function above.
+inline long double GetCosDistance(const Vector3_ld& x, const Vector3_ld& y,
+                                  long double* error) {
+  // With "long double" precision it is worthwhile to compensate for length
+  // errors in "x" and "y", since they are only unit length to within the
+  // precision of "double".  (This would also reduce the error constant
+  // slightly in the method above but is not worth the additional effort.)
+  long double c = x.DotProd(y) / sqrt(x.Norm2() * y.Norm2());
+  *error = 7 * LD_ERR * fabs(c) + 1.5 * LD_ERR;
+  return c;
+}
+
+// Returns sin**2(XY), where XY is the angle between X and Y, and sets "error"
+// to the maximum error in the result.
+//
+// REQUIRES: "x" and "y" satisfy S2::IsNormalized().
+inline double GetSin2Distance(const S2Point& x, const S2Point& y,
+                              double* error) {
+  // The (x-y).CrossProd(x+y) trick eliminates almost all of error due to "x"
+  // and "y" being not quite unit length.  This method is extremely accurate
+  // for small distances; the *relative* error in the result is O(DBL_ERR) for
+  // distances as small as DBL_ERR.
+  S2Point n = (x - y).CrossProd(x + y);
+  double d2 = 0.25 * n.Norm2();
+  *error = ((21 + 4 * sqrt(3.0)) * DBL_ERR * d2 +
+            32 * sqrt(3.0) * DBL_ERR * DBL_ERR * sqrt(d2) +
+            768 * DBL_ERR * DBL_ERR * DBL_ERR * DBL_ERR);
+  return d2;
+}
+
+// A high precision "long double" version of the function above.
+inline long double GetSin2Distance(const Vector3_ld& x, const Vector3_ld& y,
+                                   long double* error) {
+  // In "long double" precision it is worthwhile to compensate for length
+  // errors in "x" and "y", since they are only unit length to within the
+  // precision of "double".  Otherwise the "d2" error coefficient below would
+  // be (16 * DBL_ERR + (5 + 4 * sqrt(3)) * LD_ERR), which is much larger.
+  // (Dividing by the squared norms of "x" and "y" would also reduce the error
+  // constant slightly in the double-precision version, but this is not worth
+  // the additional effort.)
+  Vector3_ld n = (x - y).CrossProd(x + y);
+  long double d2 = 0.25 * n.Norm2() / (x.Norm2() * y.Norm2());
+  *error = ((13 + 4 * sqrt(3.0)) * LD_ERR * d2 +
+            32 * sqrt(3.0) * DBL_ERR * LD_ERR * sqrt(d2) +
+            768 * DBL_ERR * DBL_ERR * LD_ERR * LD_ERR);
+  return d2;
+}
+
+template <class T>
+int TriageCompareCosDistances(const Vector3<T>& x,
+                              const Vector3<T>& a, const Vector3<T>& b) {
+  T cos_ax_error, cos_bx_error;
+  T cos_ax = GetCosDistance(a, x, &cos_ax_error);
+  T cos_bx = GetCosDistance(b, x, &cos_bx_error);
+  T diff = cos_ax - cos_bx;
+  T error = cos_ax_error + cos_bx_error;
+  return (diff > error) ? -1 : (diff < -error) ? 1 : 0;
+}
+
+template <class T>
+int TriageCompareSin2Distances(const Vector3<T>& x,
+                               const Vector3<T>& a, const Vector3<T>& b) {
+  T sin2_ax_error, sin2_bx_error;
+  T sin2_ax = GetSin2Distance(a, x, &sin2_ax_error);
+  T sin2_bx = GetSin2Distance(b, x, &sin2_bx_error);
+  T diff = sin2_ax - sin2_bx;
+  T error = sin2_ax_error + sin2_bx_error;
+  return (diff > error) ? 1 : (diff < -error) ? -1 : 0;
+}
+
+int ExactCompareDistances(const Vector3_xf& x,
+                          const Vector3_xf& a, const Vector3_xf& b) {
+  // This code produces the same result as though all points were reprojected
+  // to lie exactly on the surface of the unit sphere.  It is based on testing
+  // whether x.DotProd(a.Normalize()) < x.DotProd(b.Normalize()), reformulated
+  // so that it can be evaluated using exact arithmetic.
+  ExactFloat cos_ax = x.DotProd(a);
+  ExactFloat cos_bx = x.DotProd(b);
+  // If the two values have different signs, we need to handle that case now
+  // before squaring them below.
+  int a_sign = cos_ax.sgn(), b_sign = cos_bx.sgn();
+  if (a_sign != b_sign) {
+    return (a_sign > b_sign) ? -1 : 1;  // If cos(AX) > cos(BX), then AX < BX.
+  }
+  ExactFloat cmp = cos_bx * cos_bx * a.Norm2() - cos_ax * cos_ax * b.Norm2();
+  return a_sign * cmp.sgn();
+}
+
+// Given three points such that AX == BX (exactly), returns -1, 0, or +1
+// according whether AX < BX, AX == BX, or AX > BX after symbolic
+// perturbations are taken into account.
+int SymbolicCompareDistances(const S2Point& x,
+                             const S2Point& a, const S2Point& b) {
+  // Our symbolic perturbation strategy is based on the following model.
+  // Similar to "simulation of simplicity", we assign a perturbation to every
+  // point such that if A < B, then the symbolic perturbation for A is much,
+  // much larger than the symbolic perturbation for B.  We imagine that
+  // rather than projecting every point to lie exactly on the unit sphere,
+  // instead each point is positioned on its own tiny pedestal that raises it
+  // just off the surface of the unit sphere.  This means that the distance AX
+  // is actually the true distance AX plus the (symbolic) heights of the
+  // pedestals for A and X.  The pedestals are infinitesmally thin, so they do
+  // not affect distance measurements except at the two endpoints.  If several
+  // points project to exactly the same point on the unit sphere, we imagine
+  // that they are placed on separate pedestals placed close together, where
+  // the distance between pedestals is much, much less than the height of any
+  // pedestal.  (There are a finite number of S2Points, and therefore a finite
+  // number of pedestals, so this is possible.)
+  //
+  // If A < B, then A is on a higher pedestal than B, and therefore AX > BX.
+  return (a < b) ? 1 : (a > b) ? -1 : 0;
+}
+
+static int CompareSin2Distances(const S2Point& x,
+                                const S2Point& a, const S2Point& b) {
+  int sign = TriageCompareSin2Distances(x, a, b);
+  if (sign != 0) return sign;
+  return TriageCompareSin2Distances(ToLD(x), ToLD(a), ToLD(b));
+}
+
+int CompareDistances(const S2Point& x, const S2Point& a, const S2Point& b) {
+  // We start by comparing distances using dot products (i.e., cosine of the
+  // angle), because (1) this is the cheapest technique, and (2) it is valid
+  // over the entire range of possible angles.  (We can only use the sin^2
+  // technique if both angles are less than 90 degrees or both angles are
+  // greater than 90 degrees.)
+  int sign = TriageCompareCosDistances(x, a, b);
+  if (sign != 0) return sign;
+
+  // Optimization for (a == b) to avoid falling back to exact arithmetic.
+  if (a == b) return 0;
+
+  // It is much better numerically to compare distances using cos(angle) if
+  // the distances are near 90 degrees and sin^2(angle) if the distances are
+  // near 0 or 180 degrees.  We only need to check one of the two angles when
+  // making this decision because the fact that the test above failed means
+  // that angles "a" and "b" are very close together.
+  double cos_ax = a.DotProd(x);
+  if (cos_ax > M_SQRT1_2) {
+    // Angles < 45 degrees.
+    sign = CompareSin2Distances(x, a, b);
+  } else if (cos_ax < -M_SQRT1_2) {
+    // Angles > 135 degrees.  sin^2(angle) is decreasing in this range.
+    sign = -CompareSin2Distances(x, a, b);
+  } else {
+    // We've already tried double precision, so continue with "long double".
+    sign = TriageCompareCosDistances(ToLD(x), ToLD(a), ToLD(b));
+  }
+  if (sign != 0) return sign;
+  sign = ExactCompareDistances(ToExact(x), ToExact(a), ToExact(b));
+  if (sign != 0) return sign;
+  return SymbolicCompareDistances(x, a, b);
+}
+
+template <class T>
+int TriageCompareCosDistance(const Vector3<T>& x, const Vector3<T>& y, T r2) {
+  constexpr T T_ERR = rounding_epsilon<T>();
+  T cos_xy_error;
+  T cos_xy = GetCosDistance(x, y, &cos_xy_error);
+  T cos_r = 1 - 0.5 * r2;
+  T cos_r_error = 2 * T_ERR * cos_r;
+  T diff = cos_xy - cos_r;
+  T error = cos_xy_error + cos_r_error;
+  return (diff > error) ? -1 : (diff < -error) ? 1 : 0;
+}
+
+template <class T>
+int TriageCompareSin2Distance(const Vector3<T>& x, const Vector3<T>& y, T r2) {
+  S2_DCHECK_LT(r2, 2.0);  // Only valid for distance limits < 90 degrees.
+
+  constexpr T T_ERR = rounding_epsilon<T>();
+  T sin2_xy_error;
+  T sin2_xy = GetSin2Distance(x, y, &sin2_xy_error);
+  T sin2_r = r2 * (1 - 0.25 * r2);
+  T sin2_r_error = 3 * T_ERR * sin2_r;
+  T diff = sin2_xy - sin2_r;
+  T error = sin2_xy_error + sin2_r_error;
+  return (diff > error) ? 1 : (diff < -error) ? -1 : 0;
+}
+
+int ExactCompareDistance(const Vector3_xf& x, const Vector3_xf& y,
+                         const ExactFloat& r2) {
+  // This code produces the same result as though all points were reprojected
+  // to lie exactly on the surface of the unit sphere.  It is based on
+  // comparing the cosine of the angle XY (when both points are projected to
+  // lie exactly on the sphere) to the given threshold.
+  ExactFloat cos_xy = x.DotProd(y);
+  ExactFloat cos_r = 1 - 0.5 * r2;
+  // If the two values have different signs, we need to handle that case now
+  // before squaring them below.
+  int xy_sign = cos_xy.sgn(), r_sign = cos_r.sgn();
+  if (xy_sign != r_sign) {
+    return (xy_sign > r_sign) ? -1 : 1;  // If cos(XY) > cos(r), then XY < r.
+  }
+  ExactFloat cmp = cos_r * cos_r * x.Norm2() * y.Norm2() - cos_xy * cos_xy;
+  return xy_sign * cmp.sgn();
+}
+
+int CompareDistance(const S2Point& x, const S2Point& y, S1ChordAngle r) {
+  // As with CompareDistances(), we start by comparing dot products because
+  // the sin^2 method is only valid when the distance XY and the limit "r" are
+  // both less than 90 degrees.
+  int sign = TriageCompareCosDistance(x, y, r.length2());
+  if (sign != 0) return sign;
+
+  // Unlike with CompareDistances(), it's not worth using the sin^2 method
+  // when the distance limit is near 180 degrees because the S1ChordAngle
+  // representation itself has has a rounding error of up to 2e-8 radians for
+  // distances near 180 degrees.
+  if (r < k45Degrees) {
+    sign = TriageCompareSin2Distance(x, y, r.length2());
+    if (sign != 0) return sign;
+    sign = TriageCompareSin2Distance(ToLD(x), ToLD(y), ToLD(r.length2()));
+  } else {
+    sign = TriageCompareCosDistance(ToLD(x), ToLD(y), ToLD(r.length2()));
+  }
+  if (sign != 0) return sign;
+  return ExactCompareDistance(ToExact(x), ToExact(y), r.length2());
+}
+
+// Helper function that compares the distance XY against the squared chord
+// distance "r2" using the given precision "T".
+template <class T>
+int TriageCompareDistance(const Vector3<T>& x, const Vector3<T>& y, T r2) {
+  // The Sin2 method is much more accurate for small distances, but it is only
+  // valid when the actual distance and the distance limit are both less than
+  // 90 degrees.  So we always start with the Cos method.
+  int sign = TriageCompareCosDistance(x, y, r2);
+  if (sign == 0 && r2 < k45Degrees.length2()) {
+    sign = TriageCompareSin2Distance(x, y, r2);
+  }
+  return sign;
+}
+
+// Helper function that returns "a0" or "a1", whichever is closer to "x".
+// Also returns the squared distance from the returned point to "x" in "ax2".
+template <class T>
+inline Vector3<T> GetClosestVertex(const Vector3<T>& x, const Vector3<T>& a0,
+                                   const Vector3<T>& a1, T* ax2) {
+  T a0x2 = (a0 - x).Norm2();
+  T a1x2 = (a1 - x).Norm2();
+  if (a0x2 < a1x2 || (a0x2 == a1x2 && a0 < a1)) {
+    *ax2 = a0x2;
+    return a0;
+  } else {
+    *ax2 = a1x2;
+    return a1;
+  }
+}
+
+// Helper function that returns -1, 0, or +1 according to whether the distance
+// from "x" to the great circle through (a0, a1) is less than, equal to, or
+// greater than the given squared chord length "r2".  This method computes the
+// squared sines of the distances involved, which is more accurate when the
+// distances are small (less than 45 degrees).
+//
+// The remaining parameters are functions of (a0, a1) and are passed in
+// because they have already been computed: n = (a0 - a1) x (a0 + a1),
+// n1 = n.Norm(), and n2 = n.Norm2().
+template <class T>
+int TriageCompareLineSin2Distance(const Vector3<T>& x, const Vector3<T>& a0,
+                                  const Vector3<T>& a1, T r2,
+                                  const Vector3<T>& n, T n1, T n2) {
+  constexpr T T_ERR = rounding_epsilon<T>();
+
+  // The minimum distance is to a point on the edge interior.  Since the true
+  // distance to the edge is always less than 90 degrees, we can return
+  // immediately if the limit is 90 degrees or larger.
+  if (r2 >= 2.0) return -1;  // distance < limit
+
+  // Otherwise we compute sin^2(distance to edge) to get the best accuracy
+  // when the distance limit is small (e.g., S2::kIntersectionError).
+  T n2sin2_r = n2 * r2 * (1 - 0.25 * r2);
+  T n2sin2_r_error = 6 * T_ERR * n2sin2_r;
+  T ax2, xDn = (x - GetClosestVertex(x, a0, a1, &ax2)).DotProd(n);
+  T xDn2 = xDn * xDn;
+  const T c1 = (((3.5 + 2 * sqrt(3.0)) * n1 + 32 * sqrt(3.0) * DBL_ERR) *
+                T_ERR * sqrt(ax2));
+  T xDn2_error = 4 * T_ERR * xDn2 + (2 * fabs(xDn) + c1) * c1;
+
+  // If we are using extended precision, then it is worthwhile to recompute
+  // the length of X more accurately.  Otherwise we use the fact that X is
+  // guaranteed to be unit length to with a tolerance of 4 * DBL_ERR.
+  if (T_ERR < DBL_ERR) {
+    n2sin2_r *= x.Norm2();
+    n2sin2_r_error += 4 * T_ERR * n2sin2_r;
+  } else {
+    n2sin2_r_error += 8 * DBL_ERR * n2sin2_r;
+  }
+  T diff = xDn2 - n2sin2_r;
+  T error = xDn2_error + n2sin2_r_error;
+  return (diff > error) ? 1 : (diff < -error) ? -1 : 0;
+}
+
+// Like TriageCompareLineSin2Distance, but this method computes the squared
+// cosines of the distances involved.  It is more accurate when the distances
+// are large (greater than 45 degrees).
+template <class T>
+int TriageCompareLineCos2Distance(const Vector3<T>& x, const Vector3<T>& a0,
+                                  const Vector3<T>& a1, T r2,
+                                  const Vector3<T>& n, T n1, T n2) {
+  constexpr T T_ERR = rounding_epsilon<T>();
+
+  // The minimum distance is to a point on the edge interior.  Since the true
+  // distance to the edge is always less than 90 degrees, we can return
+  // immediately if the limit is 90 degrees or larger.
+  if (r2 >= 2.0) return -1;  // distance < limit
+
+  // Otherwise we compute cos^2(distance to edge).
+  T cos_r = 1 - 0.5 * r2;
+  T n2cos2_r = n2 * cos_r * cos_r;
+  T n2cos2_r_error = 7 * T_ERR * n2cos2_r;
+
+  // The length of M = X.CrossProd(N) is the cosine of the distance.
+  T m2 = x.CrossProd(n).Norm2();
+  T m1 = sqrt(m2);
+  T m1_error = ((1 + 8 / sqrt(3.0)) * n1 + 32 * sqrt(3.0) * DBL_ERR) * T_ERR;
+  T m2_error = 3 * T_ERR * m2 + (2 * m1 + m1_error) * m1_error;
+
+  // If we are using extended precision, then it is worthwhile to recompute
+  // the length of X more accurately.  Otherwise we use the fact that X is
+  // guaranteed to be unit length to within a tolerance of 4 * DBL_ERR.
+  if (T_ERR < DBL_ERR) {
+    n2cos2_r *= x.Norm2();
+    n2cos2_r_error += 4 * T_ERR * n2cos2_r;
+  } else {
+    n2cos2_r_error += 8 * DBL_ERR * n2cos2_r;
+  }
+  T diff = m2 - n2cos2_r;
+  T error = m2_error + n2cos2_r_error;
+  return (diff > error) ? -1 : (diff < -error) ? 1 : 0;
+}
+
+template <class T>
+inline int TriageCompareLineDistance(const Vector3<T>& x, const Vector3<T>& a0,
+                                     const Vector3<T>& a1, T r2,
+                                     const Vector3<T>& n, T n1, T n2) {
+  if (r2 < k45Degrees.length2()) {
+    return TriageCompareLineSin2Distance(x, a0, a1, r2, n, n1, n2);
+  } else {
+    return TriageCompareLineCos2Distance(x, a0, a1, r2, n, n1, n2);
+  }
+}
+
+template <class T>
+int TriageCompareEdgeDistance(const Vector3<T>& x, const Vector3<T>& a0,
+                              const Vector3<T>& a1, T r2) {
+  constexpr T T_ERR = rounding_epsilon<T>();
+
+  // First we need to decide whether the closest point is an edge endpoint or
+  // somewhere in the interior.  To determine this we compute a plane
+  // perpendicular to (a0, a1) that passes through X.  Letting M be the normal
+  // to this plane, the closest point is in the edge interior if and only if
+  // a0.M < 0 and a1.M > 0.  Note that we can use "<" rather than "<=" because
+  // if a0.M or a1.M is zero exactly then it doesn't matter which code path we
+  // follow (since the distance to an endpoint and the distance to the edge
+  // interior are exactly the same in this case).
+  Vector3<T> n = (a0 - a1).CrossProd(a0 + a1);
+  Vector3<T> m = n.CrossProd(x);
+  // For better accuracy when the edge (a0,a1) is very short, we subtract "x"
+  // before computing the dot products with M.
+  Vector3<T> a0_dir = a0 - x;
+  Vector3<T> a1_dir = a1 - x;
+  T a0_sign = a0_dir.DotProd(m);
+  T a1_sign = a1_dir.DotProd(m);
+  T n2 = n.Norm2();
+  T n1 = sqrt(n2);
+  T n1_error = ((3.5 + 8 / sqrt(3.0)) * n1 + 32 * sqrt(3.0) * DBL_ERR) * T_ERR;
+  T a0_sign_error = n1_error * a0_dir.Norm();
+  T a1_sign_error = n1_error * a1_dir.Norm();
+  if (fabs(a0_sign) < a0_sign_error || fabs(a1_sign) < a1_sign_error) {
+    // It is uncertain whether minimum distance is to an edge vertex or to the
+    // edge interior.  We handle this by computing both distances and checking
+    // whether they yield the same result.
+    int vertex_sign = min(TriageCompareDistance(x, a0, r2),
+                          TriageCompareDistance(x, a1, r2));
+    int line_sign = TriageCompareLineDistance(x, a0, a1, r2, n, n1, n2);
+    return (vertex_sign == line_sign) ? line_sign : 0;
+  }
+  if (a0_sign >= 0 || a1_sign <= 0) {
+    // The minimum distance is to an edge endpoint.
+    return min(TriageCompareDistance(x, a0, r2),
+               TriageCompareDistance(x, a1, r2));
+  } else {
+    // The minimum distance is to the edge interior.
+    return TriageCompareLineDistance(x, a0, a1, r2, n, n1, n2);
+  }
+}
+
+// REQUIRES: the closest point to "x" is in the interior of edge (a0, a1).
+int ExactCompareLineDistance(const Vector3_xf& x, const Vector3_xf& a0,
+                             const Vector3_xf& a1, const ExactFloat& r2) {
+  // Since we are given that the closest point is in the edge interior, the
+  // true distance is always less than 90 degrees (which corresponds to a
+  // squared chord length of 2.0).
+  if (r2 >= 2.0) return -1;  // distance < limit
+
+  // Otherwise compute the edge normal
+  Vector3_xf n = a0.CrossProd(a1);
+  ExactFloat sin_d = x.DotProd(n);
+  ExactFloat sin2_r = r2 * (1 - 0.25 * r2);
+  ExactFloat cmp = sin_d * sin_d - sin2_r * x.Norm2() * n.Norm2();
+  return cmp.sgn();
+}
+
+int ExactCompareEdgeDistance(const S2Point& x, const S2Point& a0,
+                             const S2Point& a1, S1ChordAngle r) {
+  // Even if previous calculations were uncertain, we might not need to do
+  // *all* the calculations in exact arithmetic here.  For example it may be
+  // easy to determine whether "x" is closer to an endpoint or the edge
+  // interior.  The only calculation where we always use exact arithmetic is
+  // when measuring the distance to the extended line (great circle) through
+  // "a0" and "a1", since it is virtually certain that the previous floating
+  // point calculations failed in that case.
+  //
+  // CompareEdgeDirections also checks that no edge has antipodal endpoints.
+  if (CompareEdgeDirections(a0, a1, a0, x) > 0 &&
+      CompareEdgeDirections(a0, a1, x, a1) > 0) {
+    // The closest point to "x" is along the interior of the edge.
+    return ExactCompareLineDistance(ToExact(x), ToExact(a0), ToExact(a1),
+                                    r.length2());
+  } else {
+    // The closest point to "x" is one of the edge endpoints.
+    return min(CompareDistance(x, a0, r), CompareDistance(x, a1, r));
+  }
+}
+
+int CompareEdgeDistance(const S2Point& x, const S2Point& a0, const S2Point& a1,
+                        S1ChordAngle r) {
+  // Check that the edge does not consist of antipodal points.  (This catches
+  // the most common case -- the full test is in ExactCompareEdgeDistance.)
+  S2_DCHECK_NE(a0, -a1);
+
+  int sign = TriageCompareEdgeDistance(x, a0, a1, r.length2());
+  if (sign != 0) return sign;
+
+  // Optimization for the case where the edge is degenerate.
+  if (a0 == a1) return CompareDistance(x, a0, r);
+
+  sign = TriageCompareEdgeDistance(ToLD(x), ToLD(a0), ToLD(a1),
+                                   ToLD(r.length2()));
+  if (sign != 0) return sign;
+  return ExactCompareEdgeDistance(x, a0, a1, r);
+}
+
+template <class T>
+int TriageCompareEdgeDirections(
+    const Vector3<T>& a0, const Vector3<T>& a1,
+    const Vector3<T>& b0, const Vector3<T>& b1) {
+  constexpr T T_ERR = rounding_epsilon<T>();
+  Vector3<T> na = (a0 - a1).CrossProd(a0 + a1);
+  Vector3<T> nb = (b0 - b1).CrossProd(b0 + b1);
+  T na_len = na.Norm(), nb_len = nb.Norm();
+  T cos_ab = na.DotProd(nb);
+  T cos_ab_error = ((5 + 4 * sqrt(3.0)) * na_len * nb_len +
+                    32 * sqrt(3.0) * DBL_ERR * (na_len + nb_len)) * T_ERR;
+  return (cos_ab > cos_ab_error) ? 1 : (cos_ab < -cos_ab_error) ? -1 : 0;
+}
+
+bool ArePointsLinearlyDependent(const Vector3_xf& x, const Vector3_xf& y) {
+  Vector3_xf n = x.CrossProd(y);
+  return n[0].sgn() == 0 && n[1].sgn() == 0 && n[2].sgn() == 0;
+}
+
+bool ArePointsAntipodal(const Vector3_xf& x, const Vector3_xf& y) {
+  return ArePointsLinearlyDependent(x, y) && x.DotProd(y).sgn() < 0;
+}
+
+int ExactCompareEdgeDirections(const Vector3_xf& a0, const Vector3_xf& a1,
+                               const Vector3_xf& b0, const Vector3_xf& b1) {
+  S2_DCHECK(!ArePointsAntipodal(a0, a1));
+  S2_DCHECK(!ArePointsAntipodal(b0, b1));
+  return a0.CrossProd(a1).DotProd(b0.CrossProd(b1)).sgn();
+}
+
+int CompareEdgeDirections(const S2Point& a0, const S2Point& a1,
+                          const S2Point& b0, const S2Point& b1) {
+  // Check that no edge consists of antipodal points.  (This catches the most
+  // common case -- the full test is in ExactCompareEdgeDirections.)
+  S2_DCHECK_NE(a0, -a1);
+  S2_DCHECK_NE(b0, -b1);
+
+  int sign = TriageCompareEdgeDirections(a0, a1, b0, b1);
+  if (sign != 0) return sign;
+
+  // Optimization for the case where either edge is degenerate.
+  if (a0 == a1 || b0 == b1) return 0;
+
+  sign = TriageCompareEdgeDirections(ToLD(a0), ToLD(a1), ToLD(b0), ToLD(b1));
+  if (sign != 0) return sign;
+  return ExactCompareEdgeDirections(ToExact(a0), ToExact(a1),
+                                    ToExact(b0), ToExact(b1));
+}
+
+// If triangle ABC has positive sign, returns its circumcenter.  If ABC has
+// negative sign, returns the negated circumcenter.
+template <class T>
+Vector3<T> GetCircumcenter(const Vector3<T>& a, const Vector3<T>& b,
+                           const Vector3<T>& c, T* error) {
+  constexpr T T_ERR = rounding_epsilon<T>();
+
+  // We compute the circumcenter using the intersection of the perpendicular
+  // bisectors of AB and BC.  The formula is essentially
+  //
+  //    Z = ((A x B) x (A + B)) x ((B x C) x (B + C)),
+  //
+  // except that we compute the cross product (A x B) as (A - B) x (A + B)
+  // (and similarly for B x C) since this is much more stable when the inputs
+  // are unit vectors.
+  Vector3<T> ab_diff = a - b, ab_sum = a + b;
+  Vector3<T> bc_diff = b - c, bc_sum = b + c;
+  Vector3<T> nab = ab_diff.CrossProd(ab_sum);
+  T nab_len = nab.Norm();
+  T ab_len = ab_diff.Norm();
+  Vector3<T> nbc = bc_diff.CrossProd(bc_sum);
+  T nbc_len = nbc.Norm();
+  T bc_len = bc_diff.Norm();
+  Vector3<T> mab = nab.CrossProd(ab_sum);
+  Vector3<T> mbc = nbc.CrossProd(bc_sum);
+  *error = (((16 + 24 * sqrt(3.0)) * T_ERR +
+                8 * DBL_ERR * (ab_len + bc_len)) * nab_len * nbc_len +
+               128 * sqrt(3.0) * DBL_ERR * T_ERR * (nab_len + nbc_len) +
+               3 * 4096 * DBL_ERR * DBL_ERR * T_ERR * T_ERR);
+  return mab.CrossProd(mbc);
+}
+
+template <class T>
+int TriageEdgeCircumcenterSign(const Vector3<T>& x0, const Vector3<T>& x1,
+                               const Vector3<T>& a, const Vector3<T>& b,
+                               const Vector3<T>& c, int abc_sign) {
+  constexpr T T_ERR = rounding_epsilon<T>();
+
+  // Compute the circumcenter Z of triangle ABC, and then test which side of
+  // edge X it lies on.
+  T z_error;
+  Vector3<T> z = GetCircumcenter(a, b, c, &z_error);
+  Vector3<T> nx = (x0 - x1).CrossProd(x0 + x1);
+  // If the sign of triangle ABC is negative, then we have computed -Z and the
+  // result should be negated.
+  T result = abc_sign * nx.DotProd(z);
+
+  T z_len = z.Norm();
+  T nx_len = nx.Norm();
+  T nx_error = ((1 + 2 * sqrt(3.0)) * nx_len + 32 * sqrt(3.0) * DBL_ERR) * T_ERR;
+  T result_error = ((3 * T_ERR * nx_len + nx_error) * z_len + z_error * nx_len);
+  return (result > result_error) ? 1 : (result < -result_error) ? -1 : 0;
+}
+
+int ExactEdgeCircumcenterSign(const Vector3_xf& x0, const Vector3_xf& x1,
+                              const Vector3_xf& a, const Vector3_xf& b,
+                              const Vector3_xf& c, int abc_sign) {
+  // Return zero if the edge X is degenerate.  (Also see the comments in
+  // SymbolicEdgeCircumcenterSign.)
+  if (ArePointsLinearlyDependent(x0, x1)) {
+    S2_DCHECK_GT(x0.DotProd(x1), 0);  // Antipodal edges not allowed.
+    return 0;
+  }
+  // The simplest predicate for testing whether the sign is positive is
+  //
+  // (1)  (X0 x X1) . (|C|(A x B) + |A|(B x C) + |B|(C x A)) > 0
+  //
+  // where |A| denotes A.Norm() and the expression after the "." represents
+  // the circumcenter of triangle ABC.  (This predicate is terrible from a
+  // numerical accuracy point of view, but that doesn't matter since we are
+  // going to use exact arithmetic.)  This predicate also assumes that
+  // triangle ABC is CCW (positive sign); we correct for that below.
+  //
+  // The only problem with evaluating this inequality is that computing |A|,
+  // |B| and |C| requires square roots.  To avoid this problem we use the
+  // standard technique of rearranging the inequality to isolate at least one
+  // square root and then squaring both sides.  We need to repeat this process
+  // twice in order to eliminate all the square roots, which leads to a
+  // polynomial predicate of degree 20 in the input arguments.
+  //
+  // Rearranging (1) we get
+  //
+  //      (X0 x X1) . (|C|(A x B) + |A|(B x C)) > |B|(X0 x X1) . (A x C)
+  //
+  // Before squaring we need to check the sign of each side.  If the signs are
+  // different then we know the result without squaring, and if the signs are
+  // both negative then after squaring both sides we need to invert the
+  // result.  Define
+  //
+  //      dAB = (X0 x X1) . (A x B)
+  //      dBC = (X0 x X1) . (B x C)
+  //      dCA = (X0 x X1) . (C x A)
+  //
+  // Then we can now write the inequality above as
+  //
+  // (2)  |C| dAB + |A| dBC > -|B| dCA
+  //
+  // The RHS of (2) is positive if dCA < 0, and the LHS of (2) is positive if
+  // (|C| dAB + |A| dBC) > 0.  Since the LHS has square roots, we need to
+  // eliminate them using the same process.  Rewriting the LHS as
+  //
+  // (3)  |C| dAB > -|A| dBC
+  //
+  // we again need to check the signs of both sides.  Let's start with that.
+  // We also precompute the following values because they are used repeatedly
+  // when squaring various expressions below:
+  //
+  //     abc2 = |A|^2 dBC^2
+  //     bca2 = |B|^2 dCA^2
+  //     cab2 = |C|^2 dAB^2
+  Vector3_xf nx = x0.CrossProd(x1);
+  ExactFloat dab = nx.DotProd(a.CrossProd(b));
+  ExactFloat dbc = nx.DotProd(b.CrossProd(c));
+  ExactFloat dca = nx.DotProd(c.CrossProd(a));
+  ExactFloat abc2 = a.Norm2() * (dbc * dbc);
+  ExactFloat bca2 = b.Norm2() * (dca * dca);
+  ExactFloat cab2 = c.Norm2() * (dab * dab);
+
+  // If the two sides of (3) have different signs (including the case where
+  // one side is zero) then we know the result.  Also, if both sides are zero
+  // then we know the result.  The following logic encodes this.
+  int lhs3_sgn = dab.sgn(), rhs3_sgn = -dbc.sgn();
+  int lhs2_sgn = max(-1, min(1, lhs3_sgn - rhs3_sgn));
+  if (lhs2_sgn == 0 && lhs3_sgn != 0) {
+    // Both sides of (3) have the same non-zero sign, so square both sides.
+    // If both sides were negative then invert the result.
+    lhs2_sgn = (cab2 - abc2).sgn() * lhs3_sgn;
+  }
+  // Now if the two sides of (2) have different signs then we know the result
+  // of this entire function.
+  int rhs2_sgn = -dca.sgn();
+  int result = max(-1, min(1, lhs2_sgn - rhs2_sgn));
+  if (result == 0 && lhs2_sgn != 0) {
+    // Both sides of (2) have the same non-zero sign, so square both sides.
+    // (If both sides were negative then we invert the result below.)
+    // This gives
+    //
+    //        |C|^2 dAB^2 + |A|^2 dBC^2 + 2 |A| |C| dAB dBC > |B|^2 dCA^2
+    //
+    // This expression still has square roots (|A| and |C|), so we rewrite as
+    //
+    // (4)    2 |A| |C| dAB dBC > |B|^2 dCA^2 - |C|^2 dAB^2 - |A|^2 dBC^2 .
+    //
+    // Again, if the two sides have different signs then we know the result.
+    int lhs4_sgn = dab.sgn() * dbc.sgn();
+    ExactFloat rhs4 = bca2 - cab2 - abc2;
+    result = max(-1, min(1, lhs4_sgn - rhs4.sgn()));
+    if (result == 0 && lhs4_sgn != 0) {
+      // Both sides of (4) have the same non-zero sign, so square both sides.
+      // If both sides were negative then invert the result.
+      result = (4 * abc2 * cab2 - rhs4 * rhs4).sgn() * lhs4_sgn;
+    }
+    // Correct the sign if both sides of (2) were negative.
+    result *= lhs2_sgn;
+  }
+  // If the sign of triangle ABC is negative, then we have computed -Z and the
+  // result should be negated.
+  return abc_sign * result;
+}
+
+// Like Sign, except this method does not use symbolic perturbations when
+// the input points are exactly coplanar with the origin (i.e., linearly
+// dependent).  Clients should never use this method, but it is useful here in
+// order to implement the combined pedestal/axis-aligned perturbation scheme
+// used by some methods (such as EdgeCircumcenterSign).
+int UnperturbedSign(const S2Point& a, const S2Point& b, const S2Point& c) {
+  int sign = TriageSign(a, b, c, a.CrossProd(b));
+  if (sign == 0) sign = ExpensiveSign(a, b, c, false /*perturb*/);
+  return sign;
+}
+
+// Given arguments such that ExactEdgeCircumcenterSign(x0, x1, a, b, c) == 0,
+// returns the value of Sign(X0, X1, Z) (where Z is the circumcenter of
+// triangle ABC) after symbolic perturbations are taken into account.  The
+// result is zero only if X0 == X1, A == B, B == C, or C == A.  (It is nonzero
+// if these pairs are exactly proportional to each other but not equal.)
+int SymbolicEdgeCircumcenterSign(
+    const S2Point& x0, const S2Point& x1,
+    const S2Point& a_arg, const S2Point& b_arg, const S2Point& c_arg) {
+  // We use the same perturbation strategy as SymbolicCompareDistances.  Note
+  // that pedestal perturbations of X0 and X1 do not affect the result,
+  // because Sign(X0, X1, Z) does not change when its arguments are scaled
+  // by a positive factor.  Therefore we only need to consider A, B, C.
+  // Suppose that A is the smallest lexicographically and therefore has the
+  // largest perturbation.  This has the effect of perturbing the circumcenter
+  // of ABC slightly towards A, and since the circumcenter Z was previously
+  // exactly collinear with edge X, this implies that after the perturbation
+  // Sign(X0, X1, Z) == UnperturbedSign(X0, X1, A).  (We want the result
+  // to be zero if X0, X1, and A are linearly dependent, rather than using
+  // symbolic perturbations, because these perturbations are defined to be
+  // much, much smaller than the pedestal perturbation of B and C that are
+  // considered below.)
+  //
+  // If A is also exactly collinear with edge X, then we move on to the next
+  // smallest point lexicographically out of {B, C}.  It is easy to see that
+  // as long as A, B, C are all distinct, one of these three Sign calls
+  // will be nonzero, because if A, B, C are all distinct and collinear with
+  // edge X then their circumcenter Z coincides with the normal of X, and
+  // therefore Sign(X0, X1, Z) is nonzero.
+  //
+  // This function could be extended to handle the case where X0 and X1 are
+  // linearly dependent as follows.  First, suppose that every point has both
+  // a pedestal peturbation as described above, and also the three
+  // axis-aligned perturbations described in the "Simulation of Simplicity"
+  // paper, where all pedestal perturbations are defined to be much, much
+  // larger than any axis-aligned perturbation.  Note that since pedestal
+  // perturbations have no effect on Sign, we can use this model for *all*
+  // the S2 predicates, which ensures that all the various predicates are
+  // fully consistent with each other.
+  //
+  // With this model, the strategy described above yields the correct result
+  // unless X0 and X1 are exactly linearly dependent.  When that happens, then
+  // no perturbation (pedestal or axis-aligned) of A,B,C affects the result,
+  // and no pedestal perturbation of X0 or X1 affects the result, therefore we
+  // need to consider the smallest axis-aligned perturbation of X0 or X1.  The
+  // first perturbation that makes X0 and X1 linearly independent yields the
+  // result.  Supposing that X0 < X1, this is the perturbation of X0[2] unless
+  // both points are multiples of [0, 0, 1], in which case it is the
+  // perturbation of X0[1].  The sign test can be implemented by computing the
+  // perturbed cross product of X0 and X1 and taking the dot product with the
+  // exact value of Z.  For example if X0[2] is perturbed, the perturbed cross
+  // product is proportional to (0, 0, 1) x X1 = (-X1[1], x1[0], 0).  Note
+  // that if the dot product with Z is exactly zero, then it is still
+  // necessary to fall back to pedestal perturbations of A, B, C, but one of
+  // these perturbations is now guaranteed to succeed.
+
+  // If any two triangle vertices are equal, the result is zero.
+  if (a_arg == b_arg || b_arg == c_arg || c_arg == a_arg) return 0;
+
+  // Sort A, B, C in lexicographic order.
+  const S2Point *a = &a_arg, *b = &b_arg, *c = &c_arg;
+  if (*b < *a) std::swap(a, b);
+  if (*c < *b) std::swap(b, c);
+  if (*b < *a) std::swap(a, b);
+
+  // Now consider the perturbations in decreasing order of size.
+  int sign = UnperturbedSign(x0, x1, *a);
+  if (sign != 0) return sign;
+  sign = UnperturbedSign(x0, x1, *b);
+  if (sign != 0) return sign;
+  return UnperturbedSign(x0, x1, *c);
+}
+
+int EdgeCircumcenterSign(const S2Point& x0, const S2Point& x1,
+                         const S2Point& a, const S2Point& b,
+                         const S2Point& c) {
+  // Check that the edge does not consist of antipodal points.  (This catches
+  // the most common case -- the full test is in ExactEdgeCircumcenterSign.)
+  S2_DCHECK_NE(x0, -x1);
+
+  int abc_sign = Sign(a, b, c);
+  int sign = TriageEdgeCircumcenterSign(x0, x1, a, b, c, abc_sign);
+  if (sign != 0) return sign;
+
+  // Optimization for the cases that are going to return zero anyway, in order
+  // to avoid falling back to exact arithmetic.
+  if (x0 == x1 || a == b || b == c || c == a) return 0;
+
+  sign = TriageEdgeCircumcenterSign(
+      ToLD(x0), ToLD(x1), ToLD(a), ToLD(b), ToLD(c), abc_sign);
+  if (sign != 0) return sign;
+  sign = ExactEdgeCircumcenterSign(
+      ToExact(x0), ToExact(x1), ToExact(a), ToExact(b), ToExact(c), abc_sign);
+  if (sign != 0) return sign;
+
+  // Unlike the other methods, SymbolicEdgeCircumcenterSign does not depend
+  // on the sign of triangle ABC.
+  return SymbolicEdgeCircumcenterSign(x0, x1, a, b, c);
+}
+
+template <class T>
+Excluded TriageVoronoiSiteExclusion(const Vector3<T>& a, const Vector3<T>& b,
+                                    const Vector3<T>& x0, const Vector3<T>& x1,
+                                    T r2) {
+  constexpr T T_ERR = rounding_epsilon<T>();
+
+  // Define the "coverage disc" of a site S to be the disc centered at S with
+  // radius r (i.e., squared chord angle length r2).  Similarly, define the
+  // "coverage interval" of S along an edge X to be the intersection of X with
+  // the coverage disc of S.  The coverage interval can be represented as the
+  // point at the center of the interval and an angle that measures the
+  // semi-width or "radius" of the interval.
+  //
+  // To test whether site A excludes site B along the input edge X, we test
+  // whether the coverage interval of A contains the coverage interval of B.
+  // Let "ra" and "rb" be the radii (semi-widths) of the two intervals, and
+  // let "d" be the angle between their center points.  Then "a" properly
+  // contains "b" if (ra - rb > d), and "b" contains "a" if (rb - ra > d).
+  // Note that only one of these conditions can be true.  Therefore we can
+  // determine whether one site excludes the other by checking whether
+  //
+  // (1)   |rb - ra| > d
+  //
+  // and use the sign of (rb - ra) to determine which site is excluded.
+  //
+  // The actual code is based on the following.  Let A1 and B1 be the unit
+  // vectors A and B scaled by cos(r) (these points are inside the sphere).
+  // The planes perpendicular to OA1 and OA2 cut off two discs of radius r
+  // around A and B.  Now consider the two lines (inside the sphere) where
+  // these planes intersect the plane containing the input edge X, and let A2
+  // and B2 be the points on these lines that are closest to A and B.  The
+  // coverage intervals of A and B can be represented as an interval along
+  // each of these lines, centered at A2 and B2.  Let P1 and P2 be the
+  // endpoints of the coverage interval for A, and let Q1 and Q2 be the
+  // endpoints of the coverage interval for B.  We can view each coverage
+  // interval as either a chord through the sphere's interior, or as a segment
+  // of the original edge X (by projecting the chord onto the sphere's
+  // surface).
+  //
+  // To check whether B's interval is contained by A's interval, we test
+  // whether both endpoints of B's interval (Q1 and Q2) are contained by A's
+  // interval.  E.g., we could test whether Qi.DotProd(A2) > A2.Norm2().
+  //
+  // However rather than constructing the actual points A1, A2, and so on, it
+  // turns out to be more efficient to compute the sines and cosines
+  // ("components") of the various angles and then use trigonometric
+  // identities.  Predicate (1) can be expressed as
+  //
+  //      |sin(rb - ra)| > sin(d)
+  //
+  // provided that |d| <= Pi/2 (which must be checked), and then expanded to
+  //
+  // (2)  |sin(rb) cos(ra) - sin(ra) cos(rb)| > sin(d) .
+  //
+  // The components of the various angles can be expressed using dot and cross
+  // products based on the construction above:
+  //
+  //   sin(ra) = sqrt(sin^2(r) |a|^2 |n|^2 - |a.n|^2) / |aXn|
+  //   cos(ra) = cos(r) |a| |n| / |aXn|
+  //   sin(rb) = sqrt(sin^2(r) |b|^2 |n|^2 - |b.n|^2) / |bXn|
+  //   cos(rb) = cos(r) |b| |n| / |bXn|
+  //   sin(d)  = (aXb).n |n| / (|aXn| |bXn|)
+  //   cos(d)  = (aXn).(bXn) / (|aXn| |bXn|)
+  //
+  // Also, the squared chord length r2 is equal to 4 * sin^2(r / 2), which
+  // yields the following relationships:
+  //
+  //   sin(r)  = sqrt(r2 (1 - r2 / 4))
+  //   cos(r)  = 1 - r2 / 2
+  //
+  // We then scale both sides of (2) by |aXn| |bXn| / |n| (in order to
+  // minimize the number of calculations and to avoid divisions), which gives:
+  //
+  //    cos(r) ||a| sqrt(sin^2(r) |b|^2 |n|^2 - |b.n|^2) -
+  //            |b| sqrt(sin^2(r) |a|^2 |n|^2 - |a.n|^2)| > (aXb).n
+  //
+  // Furthermore we can substitute |a| = |b| = 1 (as long as this is taken
+  // into account in the error bounds), yielding
+  //
+  // (3)   cos(r) |sqrt(sin^2(r) |n|^2 - |b.n|^2) -
+  //               sqrt(sin^2(r) |n|^2 - |a.n|^2)| > (aXb).n
+  //
+  // The code below is more complicated than this because many expressions
+  // have been modified for better numerical stability.  For example, dot
+  // products between unit vectors are computed using (x - y).DotProd(x + y),
+  // and the dot product between a point P and the normal N of an edge X is
+  // measured using (P - Xi).DotProd(N) where Xi is the endpoint of X that is
+  // closer to P.
+
+  Vector3<T> n = (x0 - x1).CrossProd(x0 + x1);  // 2 * x0.CrossProd(x1)
+  T n2 = n.Norm2();
+  T n1 = sqrt(n2);
+  // This factor is used in the error terms of dot products with "n" below.
+  T Dn_error = ((3.5 + 2 * sqrt(3.0)) * n1 + 32 * sqrt(3.0) * DBL_ERR) * T_ERR;
+
+  T cos_r = 1 - 0.5 * r2;
+  T sin2_r = r2 * (1 - 0.25 * r2);
+  T n2sin2_r = n2 * sin2_r;
+
+  // "ra" and "rb" denote sin(ra) and sin(rb) after the scaling above.
+  T ax2, aDn = (a - GetClosestVertex(a, x0, x1, &ax2)).DotProd(n);
+  T aDn2 = aDn * aDn;
+  T aDn_error = Dn_error * sqrt(ax2);
+  T ra2 = n2sin2_r - aDn2;
+  T ra2_error = (8 * DBL_ERR + 4 * T_ERR) * aDn2 +
+      (2 * fabs(aDn) + aDn_error) * aDn_error + 6 * T_ERR * n2sin2_r;
+  // This is the minimum possible value of ra2, which is used to bound the
+  // derivative of sqrt(ra2) in computing ra_error below.
+  T min_ra2 = ra2 - ra2_error;
+  if (min_ra2 < 0) return Excluded::UNCERTAIN;
+  T ra = sqrt(ra2);
+  // Includes the ra2 subtraction error above.
+  T ra_error = 1.5 * T_ERR * ra + 0.5 * ra2_error / sqrt(min_ra2);
+
+  T bx2, bDn = (b - GetClosestVertex(b, x0, x1, &bx2)).DotProd(n);
+  T bDn2 = bDn * bDn;
+  T bDn_error = Dn_error * sqrt(bx2);
+  T rb2 = n2sin2_r - bDn2;
+  T rb2_error = (8 * DBL_ERR + 4 * T_ERR) * bDn2 +
+      (2 * fabs(bDn) + bDn_error) * bDn_error + 6 * T_ERR * n2sin2_r;
+  T min_rb2 = rb2 - rb2_error;
+  if (min_rb2 < 0) return Excluded::UNCERTAIN;
+  T rb = sqrt(rb2);
+  // Includes the rb2 subtraction error above.
+  T rb_error = 1.5 * T_ERR * rb + 0.5 * rb2_error / sqrt(min_rb2);
+
+  // The sign of LHS(3) determines which site may be excluded by the other.
+  T lhs3 = cos_r * (rb - ra);
+  T abs_lhs3 = fabs(lhs3);
+  T lhs3_error = cos_r * (ra_error + rb_error) + 3 * T_ERR * abs_lhs3;
+
+  // Now we evaluate the RHS of (3), which is proportional to sin(d).
+  Vector3<T> aXb = (a - b).CrossProd(a + b);  // 2 * a.CrossProd(b)
+  T aXb1 = aXb.Norm();
+  T sin_d = 0.5 * aXb.DotProd(n);
+  T sin_d_error = (4 * DBL_ERR + (2.5 + 2 * sqrt(3.0)) * T_ERR) * aXb1 * n1 +
+      16 * sqrt(3.0) * DBL_ERR * T_ERR * (aXb1 + n1);
+
+  // If LHS(3) is definitely less than RHS(3), neither site excludes the other.
+  T result = abs_lhs3 - sin_d;
+  T result_error = lhs3_error + sin_d_error;
+  if (result < -result_error) return Excluded::NEITHER;
+
+  // Otherwise, before proceeding further we need to check that |d| <= Pi/2.
+  // In fact, |d| < Pi/2 is enough because of the requirement that r < Pi/2.
+  // The following expression represents cos(d) after scaling; it is
+  // equivalent to (aXn).(bXn) but has about 30% less error.
+  T cos_d = a.DotProd(b) * n2 - aDn * bDn;
+  T cos_d_error =
+      ((8 * DBL_ERR + 5 * T_ERR) * fabs(aDn) + aDn_error) * fabs(bDn) +
+      (fabs(aDn) + aDn_error) * bDn_error + (8 * DBL_ERR + 8 * T_ERR) * n2;
+  if (cos_d <= -cos_d_error) return Excluded::NEITHER;
+
+  // Potential optimization: if the sign of cos(d) is uncertain, then instead
+  // we could check whether cos(d) >= cos(r).  Unfortunately this is fairly
+  // expensive since it requires computing denominator |aXn||bXn| of cos(d)
+  // and the associated error bounds.  In any case this case is relatively
+  // rare so it seems better to punt.
+  if (cos_d < cos_d_error) return Excluded::UNCERTAIN;
+
+  // Normally we have d > 0 because the sites are sorted so that A is closer
+  // to X0 and B is closer to X1.  However if the edge X is longer than Pi/2,
+  // and the sites A and B are beyond its endpoints, then AB can wrap around
+  // the sphere in the opposite direction from X.  In this situation d < 0 but
+  // each site is closest to one endpoint of X, so neither excludes the other.
+  //
+  // It turns out that this can happen only when the site that is further away
+  // from edge X is less than 90 degrees away from whichever endpoint of X it
+  // is closer to.  It is provable that if this distance is less than 90
+  // degrees, then it is also less than r2, and therefore the Voronoi regions
+  // of both sites intersect the edge.
+  if (sin_d < -sin_d_error) {
+    T r90 = S1ChordAngle::Right().length2();
+    // "ca" is negative if Voronoi region A definitely intersects edge X.
+    int ca = (lhs3 < -lhs3_error) ? -1 : TriageCompareCosDistance(a, x0, r90);
+    int cb = (lhs3 > lhs3_error) ? -1 : TriageCompareCosDistance(b, x1, r90);
+    if (ca < 0 && cb < 0) return Excluded::NEITHER;
+    if (ca <= 0 && cb <= 0) return Excluded::UNCERTAIN;
+    if (abs_lhs3 <= lhs3_error) return Excluded::UNCERTAIN;
+  } else if (sin_d <= sin_d_error) {
+    return Excluded::UNCERTAIN;
+  }
+  // Now we can finish checking the results of predicate (3).
+  if (result <= result_error) return Excluded::UNCERTAIN;
+  S2_DCHECK_GT(abs_lhs3, lhs3_error);
+  return (lhs3 > 0) ? Excluded::FIRST : Excluded::SECOND;
+}
+
+Excluded ExactVoronoiSiteExclusion(const Vector3_xf& a, const Vector3_xf& b,
+                                   const Vector3_xf& x0, const Vector3_xf& x1,
+                                   const ExactFloat& r2) {
+  S2_DCHECK(!ArePointsAntipodal(x0, x1));
+
+  // Recall that one site excludes the other if
+  //
+  // (1)  |sin(rb - ra)| > sin(d)
+  //
+  // and that the sign of (rb - ra) determines which site is excluded (see the
+  // comments in TriageVoronoiSiteExclusion).  To evaluate this using exact
+  // arithmetic, we expand this to the same predicate as before:
+  //
+  // (2)    cos(r) ||a| sqrt(sin^2(r) |b|^2 |n|^2 - |b.n|^2) -
+  //                |b| sqrt(sin^2(r) |a|^2 |n|^2 - |a.n|^2)| > (aXb).n
+  //
+  // We also need to verify that d <= Pi/2, which is implemented by checking
+  // that sin(d) >= 0 and cos(d) >= 0.
+  //
+  // To eliminate the square roots we use the standard technique of
+  // rearranging the inequality to isolate at least one square root and then
+  // squaring both sides.  We need to repeat this process twice in order to
+  // eliminate all the square roots, which leads to a polynomial predicate of
+  // degree 20 in the input arguments (i.e., degree 4 in each of "a", "b",
+  // "x0", "x1", and "r2").
+  //
+  // Before squaring we need to check the sign of each side.  We also check
+  // the condition that cos(d) >= 0.  Given what else we need to compute, it
+  // is cheaper use the identity (aXn).(bXn) = (a.b) |n|^2 - (a.n)(b.n) .
+  Vector3_xf n = x0.CrossProd(x1);
+  ExactFloat n2 = n.Norm2();
+  ExactFloat aDn = a.DotProd(n);
+  ExactFloat bDn = b.DotProd(n);
+  ExactFloat cos_d = a.DotProd(b) * n2 - aDn * bDn;
+  if (cos_d.sgn() < 0) return Excluded::NEITHER;
+
+  // Otherwise we continue evaluating the LHS of (2), defining
+  //    sa = |b| sqrt(sin^2(r) |a|^2 |n|^2 - |a.n|^2)
+  //    sb = |a| sqrt(sin^2(r) |b|^2 |n|^2 - |b.n|^2) .
+  // The sign of the LHS of (2) (before taking the absolute value) determines
+  // which coverage interval is larger and therefore which site is potentially
+  // being excluded.
+  ExactFloat a2 = a.Norm2();
+  ExactFloat b2 = b.Norm2();
+  ExactFloat n2sin2_r = r2 * (1 - 0.25 * r2) * n2;
+  ExactFloat sa2 = b2 * (n2sin2_r * a2 - aDn * aDn);
+  ExactFloat sb2 = a2 * (n2sin2_r * b2 - bDn * bDn);
+  int lhs2_sgn = (sb2 - sa2).sgn();
+
+  // If the RHS of (2) is negative (corresponding to sin(d) < 0), then we need
+  // to consider the possibility that the edge AB wraps around the sphere in
+  // the opposite direction from edge X, with the result that neither site
+  // excludes the other (see TriageVoronoiSiteExclusion).
+  ExactFloat rhs2 = a.CrossProd(b).DotProd(n);
+  int rhs2_sgn = rhs2.sgn();
+  if (rhs2_sgn < 0) {
+    ExactFloat r90 = S1ChordAngle::Right().length2();
+    int ca = (lhs2_sgn < 0) ? -1 : ExactCompareDistance(a, x0, r90);
+    int cb = (lhs2_sgn > 0) ? -1 : ExactCompareDistance(b, x1, r90);
+    if (ca <= 0 && cb <= 0) return Excluded::NEITHER;
+    S2_DCHECK(ca != 1 || cb != 1);
+    return ca == 1 ? Excluded::FIRST : Excluded::SECOND;
+  }
+  if (lhs2_sgn == 0) {
+    // If the RHS of (2) is zero as well (i.e., d == 0) then both sites are
+    // equidistant from every point on edge X.  This case requires symbolic
+    // perturbations, but it should already have been handled in
+    // GetVoronoiSiteExclusion() (see the call to CompareDistances).
+    S2_DCHECK_GT(rhs2_sgn, 0);
+    return Excluded::NEITHER;
+  }
+  // Next we square both sides of (2), yielding
+  //
+  //      cos^2(r) (sb^2 + sa^2 - 2 sa sb) > (aXb.n)^2
+  //
+  // which can be rearranged to give
+  //
+  // (3)  cos^2(r) (sb^2 + sa^2) - (aXb.n)^2 > 2 cos^2(r) sa sb .
+  //
+  // The RHS of (3) is always non-negative, but we still need to check the
+  // sign of the LHS.
+  ExactFloat cos_r = 1 - 0.5 * r2;
+  ExactFloat cos2_r = cos_r * cos_r;
+  ExactFloat lhs3 = cos2_r * (sa2 + sb2) - rhs2 * rhs2;
+  if (lhs3.sgn() < 0) return Excluded::NEITHER;
+
+  // Otherwise we square both sides of (3) to obtain:
+  //
+  // (4)  LHS(3)^2  >  4 cos^4(r) sa^2 sb^2
+  ExactFloat lhs4 = lhs3 * lhs3;
+  ExactFloat rhs4 = 4 * cos2_r * cos2_r * sa2 * sb2;
+  int result = (lhs4 - rhs4).sgn();
+  if (result < 0) return Excluded::NEITHER;
+  if (result == 0) {
+    // We have |rb - ra| = d and d > 0.  This implies that one coverage
+    // interval contains the other, but not properly: the two intervals share
+    // a common endpoint.  The distance from each site to that point is
+    // exactly "r", therefore we need to use symbolic perturbations.  Recall
+    // that site A is considered closer to an equidistant point if and only if
+    // A > B.  Therefore if (rb > ra && A > B) or (ra > rb && B > A) then each
+    // site is closer to at least one point and neither site is excluded.
+    //
+    // Ideally this logic would be in a separate SymbolicVoronoiSiteExclusion
+    // method for better testing, but this is not convenient because it needs
+    // lhs_sgn (which requires exact arithmetic to compute).
+    if ((lhs2_sgn > 0) == (a > b)) return Excluded::NEITHER;
+  }
+  // At this point we know that one of the two sites is excluded.  The sign of
+  // the LHS of (2) (before the absolute value) determines which one.
+  return (lhs2_sgn > 0) ? Excluded::FIRST : Excluded::SECOND;
+}
+
+Excluded GetVoronoiSiteExclusion(const S2Point& a, const S2Point& b,
+                                 const S2Point& x0, const S2Point& x1,
+                                 S1ChordAngle r) {
+  S2_DCHECK_LT(r, S1ChordAngle::Right());
+  S2_DCHECK_LT(s2pred::CompareDistances(x0, a, b), 0);  // (implies a != b)
+  S2_DCHECK_LE(s2pred::CompareEdgeDistance(a, x0, x1, r), 0);
+  S2_DCHECK_LE(s2pred::CompareEdgeDistance(b, x0, x1, r), 0);
+  // Check that the edge does not consist of antipodal points.  (This catches
+  // the most common case -- the full test is in ExactVoronoiSiteExclusion.)
+  S2_DCHECK_NE(x0, -x1);
+
+  // If one site is closer than the other to both endpoints of X, then it is
+  // closer to every point on X.  Note that this also handles the case where A
+  // and B are equidistant from every point on X (i.e., X is the perpendicular
+  // bisector of AB), because CompareDistances uses symbolic perturbations to
+  // ensure that either A or B is considered closer (in a consistent way).
+  // This also ensures that the choice of A or B does not depend on the
+  // direction of X.
+  if (s2pred::CompareDistances(x1, a, b) < 0) {
+    return Excluded::SECOND;  // Site A is closer to every point on X.
+  }
+
+  Excluded result = TriageVoronoiSiteExclusion(a, b, x0, x1, r.length2());
+  if (result != Excluded::UNCERTAIN) return result;
+
+  result = TriageVoronoiSiteExclusion(ToLD(a), ToLD(b), ToLD(x0), ToLD(x1),
+                                      ToLD(r.length2()));
+  if (result != Excluded::UNCERTAIN) return result;
+
+  return ExactVoronoiSiteExclusion(ToExact(a), ToExact(b), ToExact(x0),
+                                   ToExact(x1), r.length2());
+}
+
+std::ostream& operator<<(std::ostream& os, Excluded excluded) {
+  switch (excluded) {
+    case Excluded::FIRST: return os << "FIRST";
+    case Excluded::SECOND: return os << "SECOND";
+    case Excluded::NEITHER: return os << "NEITHER";
+    case Excluded::UNCERTAIN: return os << "UNCERTAIN";
+    default: return os << "Unknown enum value";
+  }
+}
+
+// Explicitly instantiate all of the template functions above so that the
+// tests can use them without putting all the definitions in a header file.
+
+template int TriageCompareCosDistances<double>(
+    const S2Point&, const S2Point&, const S2Point&);
+
+template int TriageCompareCosDistances<long double>(
+    const Vector3_ld&, const Vector3_ld&, const Vector3_ld&);
+
+template int TriageCompareSin2Distances<double>(
+    const S2Point&, const S2Point&, const S2Point&);
+
+template int TriageCompareSin2Distances<long double>(
+    const Vector3_ld&, const Vector3_ld&, const Vector3_ld&);
+
+template int TriageCompareCosDistance<double>(
+    const S2Point&, const S2Point&, double r2);
+
+template int TriageCompareCosDistance<long double>(
+    const Vector3_ld&, const Vector3_ld&, long double r2);
+
+template int TriageCompareSin2Distance<double>(
+    const S2Point&, const S2Point&, double r2);
+
+template int TriageCompareSin2Distance<long double>(
+    const Vector3_ld&, const Vector3_ld&, long double r2);
+
+template int TriageCompareEdgeDistance<double>(
+    const S2Point& x, const S2Point& a0, const S2Point& a1, double r2);
+
+template int TriageCompareEdgeDistance<long double>(
+    const Vector3_ld& x, const Vector3_ld& a0, const Vector3_ld& a1,
+    long double r2);
+
+template int TriageCompareEdgeDirections<double>(
+    const S2Point& a0, const S2Point& a1,
+    const S2Point& b0, const S2Point& b1);
+
+template int TriageCompareEdgeDirections<long double>(
+    const Vector3_ld& a0, const Vector3_ld& a1,
+    const Vector3_ld& b0, const Vector3_ld& b1);
+
+template int TriageEdgeCircumcenterSign<double>(
+    const S2Point& x0, const S2Point& x1,
+    const S2Point& a, const S2Point& b, const S2Point& c, int abc_sign);
+
+template int TriageEdgeCircumcenterSign<long double>(
+    const Vector3_ld& x0, const Vector3_ld& x1,
+    const Vector3_ld& a, const Vector3_ld& b, const Vector3_ld& c,
+    int abc_sign);
+
+template Excluded TriageVoronoiSiteExclusion(
+    const S2Point& a, const S2Point& b,
+    const S2Point& x0, const S2Point& x1, double r2);
+
+template Excluded TriageVoronoiSiteExclusion(
+    const Vector3_ld& a, const Vector3_ld& b,
+    const Vector3_ld& x0, const Vector3_ld& x1, long double r2);
+
+}  // namespace s2pred
diff --git a/src/s2/s2predicates.h b/src/s2/s2predicates.h
new file mode 100644 (file)
index 0000000..9b6509e
--- /dev/null
@@ -0,0 +1,282 @@
+// Copyright 2016 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// Author: ericv@google.com (Eric Veach)
+//
+// This class contains various predicates that are guaranteed to produce
+// correct, consistent results.  They are also relatively efficient.  This is
+// achieved by computing conservative error bounds and falling back to high
+// precision or even exact arithmetic when the result is uncertain.  Such
+// predicates are useful in implementing robust algorithms.
+//
+// See also S2EdgeCrosser, which implements various exact
+// edge-crossing predicates more efficiently than can be done here.
+//
+// TODO(ericv): Add InCircleSign() (the Voronoi/Delaunay predicate).
+// (This is trickier than the usual textbook implementations because we want
+// to model S2Points as lying exactly on the mathematical unit sphere.)
+
+#ifndef S2_S2PREDICATES_H_
+#define S2_S2PREDICATES_H_
+
+#include <cfloat>
+#include <iosfwd>
+
+#include "s2/_fp_contract_off.h"
+#include "s2/s1chord_angle.h"
+#include "s2/s2debug.h"
+#include "s2/s2pointutil.h"
+
+namespace s2pred {
+
+// S2EdgeUtil contains the following exact predicates that test for edge
+// crossings.  (Usually you will want to use S2EdgeCrosser, which
+// implements them much more efficiently.)
+//
+// int CrossingSign(const S2Point& a0, const S2Point& a1,
+//                  const S2Point& b0, const S2Point& b1);
+//
+// bool EdgeOrVertexCrossing(const S2Point& a0, const S2Point& a1,
+//                           const S2Point& b0, const S2Point& b1);
+
+// Returns +1 if the points A, B, C are counterclockwise, -1 if the points
+// are clockwise, and 0 if any two points are the same.  This function is
+// essentially like taking the sign of the determinant of ABC, except that
+// it has additional logic to make sure that the above properties hold even
+// when the three points are coplanar, and to deal with the limitations of
+// floating-point arithmetic.
+//
+// Sign satisfies the following conditions:
+//
+//  (1) Sign(a,b,c) == 0 if and only if a == b, b == c, or c == a
+//  (2) Sign(b,c,a) == Sign(a,b,c) for all a,b,c
+//  (3) Sign(c,b,a) == -Sign(a,b,c) for all a,b,c
+//
+// In other words:
+//
+//  (1) The result is zero if and only if two points are the same.
+//  (2) Rotating the order of the arguments does not affect the result.
+//  (3) Exchanging any two arguments inverts the result.
+//
+// On the other hand, note that it is not true in general that
+// Sign(-a,b,c) == -Sign(a,b,c), or any similar identities
+// involving antipodal points.
+int Sign(const S2Point& a, const S2Point& b, const S2Point& c);
+
+// Given 4 points on the unit sphere, return true if the edges OA, OB, and
+// OC are encountered in that order while sweeping CCW around the point O.
+// You can think of this as testing whether A <= B <= C with respect to the
+// CCW ordering around O that starts at A, or equivalently, whether B is
+// contained in the range of angles (inclusive) that starts at A and extends
+// CCW to C.  Properties:
+//
+//  (1) If OrderedCCW(a,b,c,o) && OrderedCCW(b,a,c,o), then a == b
+//  (2) If OrderedCCW(a,b,c,o) && OrderedCCW(a,c,b,o), then b == c
+//  (3) If OrderedCCW(a,b,c,o) && OrderedCCW(c,b,a,o), then a == b == c
+//  (4) If a == b or b == c, then OrderedCCW(a,b,c,o) is true
+//  (5) Otherwise if a == c, then OrderedCCW(a,b,c,o) is false
+bool OrderedCCW(const S2Point& a, const S2Point& b, const S2Point& c,
+                const S2Point& o);
+
+// Returns -1, 0, or +1 according to whether AX < BX, A == B, or AX > BX
+// respectively.  Distances are measured with respect to the positions of X,
+// A, and B as though they were reprojected to lie exactly on the surface of
+// the unit sphere.  Furthermore, this method uses symbolic perturbations to
+// ensure that the result is non-zero whenever A != B, even when AX == BX
+// exactly, or even when A and B project to the same point on the sphere.
+// Such results are guaranteed to be self-consistent, i.e. if AB < BC and
+// BC < AC, then AB < AC.
+int CompareDistances(const S2Point& x, const S2Point& a, const S2Point& b);
+
+// Returns -1, 0, or +1 according to whether the distance XY is less than,
+// equal to, or greater than "r" respectively.  Distances are measured with
+// respect the positions of all points as though they are projected to lie
+// exactly on the surface of the unit sphere.
+int CompareDistance(const S2Point& x, const S2Point& y, S1ChordAngle r);
+
+// Returns -1, 0, or +1 according to whether the distance from the point X to
+// the edge A is less than, equal to, or greater than "r" respectively.
+// Distances are measured with respect the positions of all points as though
+// they were projected to lie exactly on the surface of the unit sphere.
+//
+// REQUIRES: A0 and A1 do not project to antipodal points (e.g., A0 == -A1).
+//           This requires that (A0 != C * A1) for any constant C < 0.
+//
+// NOTE(ericv): All of the predicates defined here could be extended to handle
+// edges consisting of antipodal points by implementing additional symbolic
+// perturbation logic (similar to Sign) in order to rigorously define the
+// direction of such edges.
+int CompareEdgeDistance(const S2Point& x, const S2Point& a0, const S2Point& a1,
+                        S1ChordAngle r);
+
+// Returns -1, 0, or +1 according to whether the normal of edge A has
+// negative, zero, or positive dot product with the normal of edge B.  This
+// essentially measures whether the edges A and B are closer to proceeding in
+// the same direction or in opposite directions around the sphere.
+//
+// This method returns an exact result, i.e. the result is zero if and only if
+// the two edges are exactly perpendicular or at least one edge is degenerate.
+// (i.e., both edge endpoints project to the same point on the sphere).
+//
+// CAVEAT: This method does not use symbolic perturbations.  Therefore it can
+// return zero even when A0 != A1 and B0 != B1, e.g. if (A0 == C * A1) exactly
+// for some constant C > 0 (which is possible even when both points are
+// considered "normalized").
+//
+// REQUIRES: Neither edge can consist of antipodal points (e.g., A0 == -A1)
+//           (see comments in CompareEdgeDistance).
+int CompareEdgeDirections(const S2Point& a0, const S2Point& a1,
+                          const S2Point& b0, const S2Point& b1);
+
+// Returns Sign(X0, X1, Z) where Z is the circumcenter of triangle ABC.
+// The return value is +1 if Z is to the left of edge X, and -1 if Z is to the
+// right of edge X.  The return value is zero if A == B, B == C, or C == A
+// (exactly), and also if X0 and X1 project to identical points on the sphere
+// (e.g., X0 == X1).
+//
+// The result is determined with respect to the positions of all points as
+// though they were projected to lie exactly on the surface of the unit
+// sphere.  Furthermore this method uses symbolic perturbations to compute a
+// consistent non-zero result even when Z lies exactly on edge X.
+//
+// REQUIRES: X0 and X1 do not project to antipodal points (e.g., X0 == -X1)
+//           (see comments in CompareEdgeDistance).
+int EdgeCircumcenterSign(const S2Point& x0, const S2Point& x1,
+                         const S2Point& a, const S2Point& b, const S2Point& c);
+
+// This is a specialized method that is used to compute the intersection of an
+// edge X with the Voronoi diagram of a set of points, where each Voronoi
+// region is intersected with a disc of fixed radius "r".
+//
+// Given two sites A and B and an edge (X0, X1) such that d(A,X0) < d(B,X0)
+// and both sites are within the given distance "r" of edge X, this method
+// intersects the Voronoi region of each site with a disc of radius r and
+// determines whether either region has an empty intersection with edge X.  It
+// returns FIRST if site A has an empty intersection, SECOND if site B has an
+// empty intersection, NEITHER if neither site has an empty intersection, or
+// UNCERTAIN if A == B exactly.  Note that it is not possible for both
+// intersections to be empty because of the requirement that both sites are
+// within distance r of edge X.  (For example, the only reason that Voronoi
+// region A can have an empty intersection with X is that site B is closer to
+// all points on X that are within radius r of site A.)
+//
+// The result is determined with respect to the positions of all points as
+// though they were projected to lie exactly on the surface of the unit
+// sphere.  Furthermore this method uses symbolic perturbations to compute a
+// consistent non-zero result even when A and B lie on opposite sides of X
+// such that the Voronoi edge between them exactly coincides with edge X, or
+// when A and B are distinct but project to the same point on the sphere
+// (i.e., they are linearly dependent).
+//
+// REQUIRES: r < S1ChordAngle::Right() (90 degrees)
+// REQUIRES: s2pred::CompareDistances(x0, a, b) < 0
+// REQUIRES: s2pred::CompareEdgeDistance(a, x0, x1, r) <= 0
+// REQUIRES: s2pred::CompareEdgeDistance(b, x0, x1, r) <= 0
+// REQUIRES: X0 and X1 do not project to antipodal points (e.g., X0 == -X1)
+//           (see comments in CompareEdgeDistance).
+enum class Excluded { FIRST, SECOND, NEITHER, UNCERTAIN };
+std::ostream& operator<<(std::ostream& os, Excluded excluded);
+Excluded GetVoronoiSiteExclusion(const S2Point& a, const S2Point& b,
+                                 const S2Point& x0, const S2Point& x1,
+                                 S1ChordAngle r);
+
+/////////////////////////// Low-Level Methods ////////////////////////////
+//
+// Most clients will not need the following methods.  They can be slightly
+// more efficient but are harder to use, since they require the client to do
+// all the actual crossing tests.
+
+// A more efficient version of Sign that allows the precomputed
+// cross-product of A and B to be specified.  (Unlike the 3 argument
+// version this method is also inlined.)
+inline int Sign(const S2Point& a, const S2Point& b, const S2Point& c,
+                const Vector3_d& a_cross_b);
+
+// This version of Sign returns +1 if the points are definitely CCW, -1 if
+// they are definitely CW, and 0 if two points are identical or the result
+// is uncertain.  Uncertain cases can be resolved, if desired, by calling
+// ExpensiveSign.
+//
+// The purpose of this method is to allow additional cheap tests to be done,
+// where possible, in order to avoid calling ExpensiveSign unnecessarily.
+inline int TriageSign(const S2Point& a, const S2Point& b,
+                      const S2Point& c, const Vector3_d& a_cross_b);
+
+// This function is invoked by Sign() if the sign of the determinant is
+// uncertain.  It always returns a non-zero result unless two of the input
+// points are the same.  It uses a combination of multiple-precision
+// arithmetic and symbolic perturbations to ensure that its results are
+// always self-consistent (cf. Simulation of Simplicity, Edelsbrunner and
+// Muecke).  The basic idea is to assign an infinitesimal symbolic
+// perturbation to every possible S2Point such that no three S2Points are
+// collinear and no four S2Points are coplanar.  These perturbations are so
+// small that they do not affect the sign of any determinant that was
+// non-zero before the perturbations.  If "perturb" is false, then instead
+// the exact sign of the unperturbed input points is returned, which can be
+// zero even when all three points are distinct.
+//
+// Unlike Sign(), this method does not require the input points to be
+// normalized.
+int ExpensiveSign(const S2Point& a, const S2Point& b,
+                  const S2Point& c, bool perturb = true);
+
+//////////////////   Implementation details follow   ////////////////////
+
+inline int Sign(const S2Point& a, const S2Point& b, const S2Point& c,
+                const Vector3_d& a_cross_b) {
+  int sign = TriageSign(a, b, c, a_cross_b);
+  if (sign == 0) sign = ExpensiveSign(a, b, c);
+  return sign;
+}
+
+inline int TriageSign(const S2Point& a, const S2Point& b,
+                      const S2Point& c, const Vector3_d& a_cross_b) {
+  // kMaxDetError is the maximum error in computing (AxB).C where all vectors
+  // are unit length.  Using standard inequalities, it can be shown that
+  //
+  //  fl(AxB) = AxB + D where |D| <= (|AxB| + (2/sqrt(3))*|A|*|B|) * e
+  //
+  // where "fl()" denotes a calculation done in floating-point arithmetic,
+  // |x| denotes either absolute value or the L2-norm as appropriate, and
+  // e = 0.5*DBL_EPSILON.  Similarly,
+  //
+  //  fl(B.C) = B.C + d where |d| <= (1.5*|B.C| + 1.5*|B|*|C|) * e .
+  //
+  // Applying these bounds to the unit-length vectors A,B,C and neglecting
+  // relative error (which does not affect the sign of the result), we get
+  //
+  //  fl((AxB).C) = (AxB).C + d where |d| <= (2.5 + 2/sqrt(3)) * e
+  //
+  // which is about 3.6548 * e, or 1.8274 * DBL_EPSILON.
+  const double kMaxDetError = 1.8274 * DBL_EPSILON;
+  S2_DCHECK(S2::IsUnitLength(a));
+  S2_DCHECK(S2::IsUnitLength(b));
+  S2_DCHECK(S2::IsUnitLength(c));
+  double det = a_cross_b.DotProd(c);
+
+  // Double-check borderline cases in debug mode.
+  S2_DCHECK(!FLAGS_s2debug ||
+         std::fabs(det) <= kMaxDetError ||
+         std::fabs(det) >= 100 * kMaxDetError ||
+         det * ExpensiveSign(a, b, c) > 0);
+
+  if (det > kMaxDetError) return 1;
+  if (det < -kMaxDetError) return -1;
+  return 0;
+}
+
+}  // namespace s2pred
+
+#endif  // S2_S2PREDICATES_H_
diff --git a/src/s2/s2predicates_internal.h b/src/s2/s2predicates_internal.h
new file mode 100644 (file)
index 0000000..5e19369
--- /dev/null
@@ -0,0 +1,135 @@
+// Copyright 2016 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// Author: ericv@google.com (Eric Veach)
+//
+// The following functions are not part of the public API.  Currently they are
+// only used internally for testing purposes.
+
+#ifndef S2_S2PREDICATES_INTERNAL_H_
+#define S2_S2PREDICATES_INTERNAL_H_
+
+#include <limits>
+
+#include "absl/base/casts.h"
+#include "s2/s1chord_angle.h"
+#include "s2/s2predicates.h"
+#include "s2/util/math/exactfloat/exactfloat.h"
+#include "s2/util/math/vector.h"
+
+namespace s2pred {
+
+// Returns 2 ** (-digits).  This could be implemented using "ldexp" except
+// that std::ldexp is not constexpr in C++11.
+constexpr double epsilon_for_digits(int digits) {
+  return (digits < 64 ? 1.0 / (1ULL << digits) :
+          epsilon_for_digits(digits - 63) / (1ULL << 63));
+}
+
+// Returns the maximum rounding error for arithmetic operations in type T.
+// We could simply return 0.5 * numeric_limits<T>::epsilon(), except that some
+// platforms implement "long double" using "double-double" arithmetic, and for
+// those platforms we need to compute the rounding error manually based on
+// numeric_limits<T>::digits (the number of bits of mantissa precision).
+template <typename T> constexpr T rounding_epsilon() {
+  return epsilon_for_digits(std::numeric_limits<T>::digits);
+}
+
+using Vector3_ld = Vector3<long double>;
+using Vector3_xf = Vector3<ExactFloat>;
+
+inline static Vector3_ld ToLD(const S2Point& x) {
+  return Vector3_ld::Cast(x);
+}
+
+inline static long double ToLD(double x) {
+  return absl::implicit_cast<long double>(x);
+}
+
+inline static Vector3_xf ToExact(const S2Point& x) {
+  return Vector3_xf::Cast(x);
+}
+
+int StableSign(const S2Point& a, const S2Point& b, const S2Point& c);
+
+int ExactSign(const S2Point& a, const S2Point& b, const S2Point& c,
+              bool perturb);
+
+int SymbolicallyPerturbedSign(
+    const Vector3_xf& a, const Vector3_xf& b,
+    const Vector3_xf& c, const Vector3_xf& b_cross_c);
+
+template <class T>
+int TriageCompareCosDistances(const Vector3<T>& x,
+                              const Vector3<T>& a, const Vector3<T>& b);
+
+template <class T>
+int TriageCompareSin2Distances(const Vector3<T>& x,
+                               const Vector3<T>& a, const Vector3<T>& b);
+
+int ExactCompareDistances(const Vector3_xf& x,
+                          const Vector3_xf& a, const Vector3_xf& b);
+
+int SymbolicCompareDistances(const S2Point& x,
+                             const S2Point& a, const S2Point& b);
+
+template <class T>
+int TriageCompareSin2Distance(const Vector3<T>& x, const Vector3<T>& y, T r2);
+
+template <class T>
+int TriageCompareCosDistance(const Vector3<T>& x, const Vector3<T>& y, T r2);
+
+int ExactCompareDistance(const Vector3_xf& x, const Vector3_xf& y,
+                         const ExactFloat& r2);
+
+template <class T>
+int TriageCompareEdgeDistance(const Vector3<T>& x, const Vector3<T>& a0,
+                              const Vector3<T>& a1, T r2);
+
+int ExactCompareEdgeDistance(const S2Point& x, const S2Point& a0,
+                             const S2Point& a1, S1ChordAngle r);
+
+template <class T>
+int TriageCompareEdgeDirections(
+    const Vector3<T>& a0, const Vector3<T>& a1,
+    const Vector3<T>& b0, const Vector3<T>& b1);
+
+int ExactCompareEdgeDirections(const Vector3_xf& a0, const Vector3_xf& a1,
+                               const Vector3_xf& b0, const Vector3_xf& b1);
+
+template <class T>
+int TriageEdgeCircumcenterSign(const Vector3<T>& x0, const Vector3<T>& x1,
+                               const Vector3<T>& a, const Vector3<T>& b,
+                               const Vector3<T>& c, int abc_sign);
+
+int ExactEdgeCircumcenterSign(const Vector3_xf& x0, const Vector3_xf& x1,
+                              const Vector3_xf& a, const Vector3_xf& b,
+                              const Vector3_xf& c, int abc_sign);
+
+int SymbolicEdgeCircumcenterSign(
+    const S2Point& x0, const S2Point& x1,
+    const S2Point& a_arg, const S2Point& b_arg, const S2Point& c_arg);
+
+template <class T>
+Excluded TriageVoronoiSiteExclusion(const Vector3<T>& a, const Vector3<T>& b,
+                                    const Vector3<T>& x0, const Vector3<T>& x1,
+                                    T r2);
+
+Excluded ExactVoronoiSiteExclusion(const Vector3_xf& a, const Vector3_xf& b,
+                                   const Vector3_xf& x0, const Vector3_xf& x1,
+                                   const ExactFloat& r2);
+}  // namespace s2pred
+
+#endif  // S2_S2PREDICATES_INTERNAL_H_
diff --git a/src/s2/s2projections.cc b/src/s2/s2projections.cc
new file mode 100644 (file)
index 0000000..0dc96e0
--- /dev/null
@@ -0,0 +1,109 @@
+// Copyright 2017 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// Author: ericv@google.com (Eric Veach)
+
+#include "s2/s2projections.h"
+
+#include <cmath>
+#include "s2/s2latlng.h"
+
+using std::fabs;
+
+namespace S2 {
+
+R2Point Projection::WrapDestination(const R2Point& a, const R2Point& b) const {
+  R2Point wrap = wrap_distance();
+  double x = b.x(), y = b.y();
+  // The code below ensures that "b" is unmodified unless wrapping is required.
+  if (wrap.x() > 0 && fabs(x - a.x()) > 0.5 * wrap.x()) {
+    x = a.x() + remainder(x - a.x(), wrap.x());
+  }
+  if (wrap.y() > 0 && fabs(y - a.y()) > 0.5 * wrap.y()) {
+    y = a.y() + remainder(y - a.y(), wrap.y());
+  }
+  return R2Point(x, y);
+}
+
+// Default implementation, suitable for any projection where edges are defined
+// as straight lines in the 2D projected space.
+R2Point Projection::Interpolate(double f,
+                                const R2Point& a, const R2Point& b) const {
+  return (1 - f) * a + f * b;
+}
+
+PlateCarreeProjection::PlateCarreeProjection(double x_scale)
+    : x_wrap_(2 * x_scale),
+      to_radians_(M_PI / x_scale),
+      from_radians_(x_scale / M_PI) {
+}
+
+R2Point PlateCarreeProjection::Project(const S2Point& p) const {
+  return FromLatLng(S2LatLng(p));
+}
+
+R2Point PlateCarreeProjection::FromLatLng(const S2LatLng& ll) const {
+  return R2Point(from_radians_ * ll.lng().radians(),
+                 from_radians_ * ll.lat().radians());
+}
+
+S2Point PlateCarreeProjection::Unproject(const R2Point& p) const {
+  return ToLatLng(p).ToPoint();
+}
+
+S2LatLng PlateCarreeProjection::ToLatLng(const R2Point& p) const {
+  return S2LatLng::FromRadians(to_radians_ * p.y(),
+                               to_radians_ * remainder(p.x(), x_wrap_));
+}
+
+R2Point PlateCarreeProjection::wrap_distance() const {
+  return R2Point(x_wrap_, 0);
+}
+
+MercatorProjection::MercatorProjection(double max_x)
+    : x_wrap_(2 * max_x),
+      to_radians_(M_PI / max_x),
+      from_radians_(max_x / M_PI) {
+}
+
+R2Point MercatorProjection::Project(const S2Point& p) const {
+  return FromLatLng(S2LatLng(p));
+}
+
+R2Point MercatorProjection::FromLatLng(const S2LatLng& ll) const {
+  // This formula is more accurate near zero than the log(tan()) version.
+  // Note that latitudes of +/- 90 degrees yield "y" values of +/- infinity.
+  double sin_phi = sin(ll.lat());
+  double y = 0.5 * log((1 + sin_phi) / (1 - sin_phi));
+  return R2Point(from_radians_ * ll.lng().radians(), from_radians_ * y);
+}
+
+S2Point MercatorProjection::Unproject(const R2Point& p) const {
+  return ToLatLng(p).ToPoint();
+}
+
+S2LatLng MercatorProjection::ToLatLng(const R2Point& p) const {
+  // This formula is more accurate near zero than the atan(exp()) version.
+  double x = to_radians_ * remainder(p.x(), x_wrap_);
+  double k = exp(2 * to_radians_ * p.y());
+  double y = std::isinf(k) ? M_PI_2 : asin((k - 1) / (k + 1));
+  return S2LatLng::FromRadians(y, x);
+}
+
+R2Point MercatorProjection::wrap_distance() const {
+  return R2Point(x_wrap_, 0);
+}
+
+}  // namespace S2
diff --git a/src/s2/s2projections.h b/src/s2/s2projections.h
new file mode 100644 (file)
index 0000000..2dcc4f0
--- /dev/null
@@ -0,0 +1,161 @@
+// Copyright 2017 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// Author: ericv@google.com (Eric Veach)
+//
+// Defines a few simple map projections.  (Clients that need more complex
+// projections should use a third-party library such as GeographicLib to
+// implement their own projection subtypes.)
+
+#ifndef S2_S2PROJECTIONS_H_
+#define S2_S2PROJECTIONS_H_
+
+#include "s2/r2.h"
+#include "s2/s2latlng.h"
+#include "s2/s2point.h"
+
+namespace S2 {
+
+// For the purposes of the S2 library, a projection is a function that maps
+// between S2Points and R2Points.  It can also define the coordinate wrapping
+// behavior along each axis.
+class Projection {
+ public:
+  virtual ~Projection() {}
+
+  // Converts a point on the sphere to a projected 2D point.
+  virtual R2Point Project(const S2Point& p) const = 0;
+
+  // Converts a projected 2D point to a point on the sphere.
+  //
+  // If wrapping is defined for a given axis (see below), then this method
+  // should accept any real number for the corresponding coordinate.
+  virtual S2Point Unproject(const R2Point& p) const = 0;
+
+  // Convenience function equivalent to Project(ll.ToPoint()), but the
+  // implementation may be more efficient.
+  virtual R2Point FromLatLng(const S2LatLng& ll) const = 0;
+
+  // Convenience function equivalent to S2LatLng(Unproject(p)), but the
+  // implementation may be more efficient.
+  virtual S2LatLng ToLatLng(const R2Point& p) const = 0;
+
+  // Returns the point obtained by interpolating the given fraction of the
+  // distance along the line from A to B.  Almost all projections should
+  // use the default implementation of this method, which simply interpolates
+  // linearly in R2 space.  Fractions < 0 or > 1 result in extrapolation
+  // instead.
+  //
+  // The only reason to override this method is if you want edges to be
+  // defined as something other than straight lines in the 2D projected
+  // coordinate system.  For example, using a third-party library such as
+  // GeographicLib you could define edges as geodesics over an ellipsoid model
+  // of the Earth.  (Note that very few data sets define edges this way.)
+  //
+  // Also note that there is no reason to define a projection where edges are
+  // geodesics over the sphere, because this is the native S2 interpretation.
+  virtual R2Point Interpolate(double f, const R2Point& a, const R2Point& b)
+      const;
+
+  // Defines the coordinate wrapping distance along each axis.  If this value
+  // is non-zero for a given axis, the coordinates are assumed to "wrap" with
+  // the given period.  For example, if wrap_distance.y() == 360 then (x, y)
+  // and (x, y + 360) should map to the same S2Point.
+  //
+  // This information is used to ensure that edges takes the shortest path
+  // between two given points.  For example, if coordinates represent
+  // (latitude, longitude) pairs in degrees and wrap_distance().y() == 360,
+  // then the edge (5:179, 5:-179) would be interpreted as spanning 2 degrees
+  // of longitude rather than 358 degrees.
+  //
+  // If a given axis does not wrap, its wrap_distance should be set to zero.
+  virtual R2Point wrap_distance() const = 0;
+
+  // Helper function that wraps the coordinates of B if necessary in order to
+  // obtain the shortest edge AB.  For example, suppose that A = [170, 20],
+  // B = [-170, 20], and the projection wraps so that [x, y] == [x + 360, y].
+  // Then this function would return [190, 20] for point B (reducing the edge
+  // length in the "x" direction from 340 to 20).
+  R2Point WrapDestination(const R2Point& a, const R2Point& b) const;
+};
+
+// PlateCarreeProjection defines the "plate carree" (square plate) projection,
+// which converts points on the sphere to (longitude, latitude) pairs.
+// Coordinates can be scaled so that they represent radians, degrees, etc, but
+// the projection is always centered around (latitude=0, longitude=0).
+//
+// Note that (x, y) coordinates are backwards compared to the usual (latitude,
+// longitude) ordering, in order to match the usual convention for graphs in
+// which "x" is horizontal and "y" is vertical.
+class PlateCarreeProjection final : public Projection {
+ public:
+  // Constructs the plate carree projection where the x coordinates
+  // (longitude) span [-x_scale, x_scale] and the y coordinates (latitude)
+  // span [-x_scale/2, x_scale/2].  For example if x_scale==180 then the x
+  // range is [-180, 180] and the y range is [-90, 90].
+  //
+  // By default coordinates are expressed in radians, i.e. the x range is
+  // [-Pi, Pi] and the y range is [-Pi/2, Pi/2].
+  explicit PlateCarreeProjection(double x_scale = M_PI);
+
+  R2Point Project(const S2Point& p) const override;
+  S2Point Unproject(const R2Point& p) const override;
+  R2Point FromLatLng(const S2LatLng& ll) const override;
+  S2LatLng ToLatLng(const R2Point& p) const override;
+  R2Point wrap_distance() const override;
+
+ private:
+  double x_wrap_;
+  double to_radians_;    // Multiplier to convert coordinates to radians.
+  double from_radians_;  // Multiplier to convert coordinates from radians.
+};
+
+// MercatorProjection defines the spherical Mercator projection.  Google Maps
+// uses this projection together with WGS84 coordinates, in which case it is
+// known as the "Web Mercator" projection (see Wikipedia).  This class makes
+// no assumptions regarding the coordinate system of its input points, but
+// simply applies the spherical Mercator projection to them.
+//
+// The Mercator projection is finite in width (x) but infinite in height (y).
+// "x" corresponds to longitude, and spans a finite range such as [-180, 180]
+// (with coordinate wrapping), while "y" is a function of latitude and spans
+// an infinite range.  (As "y" coordinates get larger, points get closer to
+// the north pole but never quite reach it.)  The north and south poles have
+// infinite "y" values.  (Note that this will cause problems if you tessellate
+// a Mercator edge where one endpoint is a pole.  If you need to do this, clip
+// the edge first so that the "y" coordinate is no more than about 5 * max_x.)
+class MercatorProjection final : public Projection {
+ public:
+  // Constructs a Mercator projection where "x" corresponds to longitude in
+  // the range [-max_x, max_x] , and "y" corresponds to latitude and can be
+  // any real number.  The horizontal and vertical scales are equal locally.
+  explicit MercatorProjection(double max_x);
+
+  R2Point Project(const S2Point& p) const override;
+  S2Point Unproject(const R2Point& p) const override;
+  R2Point FromLatLng(const S2LatLng& ll) const override;
+  S2LatLng ToLatLng(const R2Point& p) const override;
+  R2Point wrap_distance() const override;
+
+ private:
+  double x_wrap_;
+  double to_radians_;    // Multiplier to convert coordinates to radians.
+  double from_radians_;  // Multiplier to convert coordinates from radians.
+};
+
+}  // namespace S2
+
+
+#endif  // S2_S2PROJECTIONS_H_
diff --git a/src/s2/s2r2rect.cc b/src/s2/s2r2rect.cc
new file mode 100644 (file)
index 0000000..5bda6be
--- /dev/null
@@ -0,0 +1,88 @@
+// Copyright 2005 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// Author: ericv@google.com (Eric Veach)
+
+#include "s2/s2r2rect.h"
+
+#include <iosfwd>
+
+#include "s2/base/logging.h"
+#include "s2/r1interval.h"
+#include "s2/s2cap.h"
+#include "s2/s2cell.h"
+#include "s2/s2cell_id.h"
+#include "s2/s2coords.h"
+#include "s2/s2latlng_rect.h"
+
+S2R2Rect S2R2Rect::FromCell(const S2Cell& cell) {
+  // S2Cells have a more efficient GetSizeST() method than S2CellIds.
+  double size = cell.GetSizeST();
+  return FromCenterSize(cell.id().GetCenterST(), R2Point(size, size));
+}
+
+S2R2Rect S2R2Rect::FromCellId(S2CellId id) {
+  double size = id.GetSizeST();
+  return FromCenterSize(id.GetCenterST(), R2Point(size, size));
+}
+
+S2R2Rect* S2R2Rect::Clone() const {
+  return new S2R2Rect(*this);
+}
+
+S2Point S2R2Rect::ToS2Point(const R2Point& p) {
+  return S2::FaceUVtoXYZ(0, S2::STtoUV(p.x()), S2::STtoUV(p.y())).Normalize();
+}
+
+S2Cap S2R2Rect::GetCapBound() const {
+  if (is_empty()) return S2Cap::Empty();
+
+  // The rectangle is a convex polygon on the sphere, since it is a subset of
+  // one cube face.  Its bounding cap is also a convex region on the sphere,
+  // and therefore we can bound the rectangle by just bounding its vertices.
+  // We use the rectangle's center in (s,t)-space as the cap axis.  This
+  // doesn't yield the minimal cap but it's pretty close.
+  S2Cap cap = S2Cap::FromPoint(ToS2Point(GetCenter()));
+  for (int k = 0; k < 4; ++k) {
+    cap.AddPoint(ToS2Point(GetVertex(k)));
+  }
+  return cap;
+}
+
+S2LatLngRect S2R2Rect::GetRectBound() const {
+  // This is not very tight but hopefully good enough.
+  return GetCapBound().GetRectBound();
+}
+
+bool S2R2Rect::Contains(const S2Point& p) const {
+  if (S2::GetFace(p) != 0) return false;
+  double u, v;
+  S2::ValidFaceXYZtoUV(0, p, &u, &v);
+  return Contains(R2Point(S2::UVtoST(u), S2::UVtoST(v)));
+}
+
+bool S2R2Rect::Contains(const S2Cell& cell) const {
+  if (cell.face() != 0) return false;
+  return Contains(S2R2Rect::FromCell(cell));
+}
+
+bool S2R2Rect::MayIntersect(const S2Cell& cell) const {
+  if (cell.face() != 0) return false;
+  return Intersects(S2R2Rect::FromCell(cell));
+}
+
+std::ostream& operator<<(std::ostream& os, const S2R2Rect& r) {
+  return os << "[Lo" << r.lo() << ", Hi" << r.hi() << "]";
+}
diff --git a/src/s2/s2r2rect.h b/src/s2/s2r2rect.h
new file mode 100644 (file)
index 0000000..61d2699
--- /dev/null
@@ -0,0 +1,292 @@
+// Copyright 2005 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// Author: ericv@google.com (Eric Veach)
+
+#ifndef S2_S2R2RECT_H_
+#define S2_S2R2RECT_H_
+
+#include <iosfwd>
+
+#include "s2/base/logging.h"
+#include "s2/_fp_contract_off.h"
+#include "s2/r1interval.h"
+#include "s2/r2.h"
+#include "s2/r2rect.h"
+#include "s2/s1angle.h"
+#include "s2/s2region.h"
+
+class Decoder;
+class Encoder;
+class R1Interval;
+class S2Cap;
+class S2Cell;
+class S2CellId;
+class S2LatLngRect;
+
+// This class is a stopgap measure that allows some of the S2 spherical
+// geometry machinery to be applied to planar geometry.  An S2R2Rect
+// represents a closed axis-aligned rectangle in the (x,y) plane (an R2Rect),
+// but it also happens to be a subtype of S2Region, which means that you can
+// use an S2RegionCoverer to approximate it as a collection of S2CellIds.
+//
+// With respect to the S2Cell decomposition, an S2R2Rect is interpreted as a
+// region of (s,t)-space on face 0.  In particular, the rectangle [0,1]x[0,1]
+// corresponds to the S2CellId that covers all of face 0.  This means that
+// only rectangles that are subsets of [0,1]x[0,1] can be approximated using
+// the S2RegionCoverer interface.
+//
+// The S2R2Rect class is also a convenient way to find the (s,t)-region
+// covered by a given S2CellId (see the FromCell and FromCellId methods).
+//
+// TODO(ericv): If the geometry library is extended to have better support
+// for planar geometry, then this class should no longer be necessary.
+//
+// This class is intended to be copied by value as desired.  It uses
+// the default copy constructor and assignment operator, however it is
+// not a "plain old datatype" (POD) because it has virtual functions.
+class S2R2Rect final : public S2Region {
+ public:
+  // Construct a rectangle from an R2Rect.
+  explicit S2R2Rect(const R2Rect& rect);
+
+  // Construct a rectangle from the given lower-left and upper-right points.
+  S2R2Rect(const R2Point& lo, const R2Point& hi);
+
+  // Construct a rectangle from the given intervals in x and y.  The two
+  // intervals must either be both empty or both non-empty.
+  S2R2Rect(const R1Interval& x, const R1Interval& y);
+
+  // The canonical empty rectangle.  Use is_empty() to test for empty
+  // rectangles, since they have more than one representation.
+  static S2R2Rect Empty();
+
+  // Construct a rectangle that corresponds to the boundary of the given cell
+  // is (s,t)-space.  Such rectangles are always a subset of [0,1]x[0,1].
+  static S2R2Rect FromCell(const S2Cell& cell);
+  static S2R2Rect FromCellId(S2CellId id);
+
+  // Construct a rectangle from a center point and size in each dimension.
+  // Both components of size should be non-negative, i.e. this method cannot
+  // be used to create an empty rectangle.
+  static S2R2Rect FromCenterSize(const R2Point& center, const R2Point& size);
+
+  // Convenience method to construct a rectangle containing a single point.
+  static S2R2Rect FromPoint(const R2Point& p);
+
+  // Convenience method to construct the minimal bounding rectangle containing
+  // the two given points.  This is equivalent to starting with an empty
+  // rectangle and calling AddPoint() twice.  Note that it is different than
+  // the S2R2Rect(lo, hi) constructor, where the first point is always
+  // used as the lower-left corner of the resulting rectangle.
+  static S2R2Rect FromPointPair(const R2Point& p1, const R2Point& p2);
+
+  // Accessor methods.
+  const R1Interval& x() const;
+  const R1Interval& y() const;
+  R2Point lo() const;
+  R2Point hi() const;
+
+  // Methods that allow the S2R2Rect to be accessed as a vector.
+  const R1Interval& operator[](int i) const;
+  R1Interval& operator[](int i);
+
+  // Return true if the rectangle is valid, which essentially just means
+  // that if the bound for either axis is empty then both must be.
+  bool is_valid() const;
+
+  // Return true if the rectangle is empty, i.e. it contains no points at all.
+  bool is_empty() const;
+
+  // Return the k-th vertex of the rectangle (k = 0,1,2,3) in CCW order.
+  // Vertex 0 is in the lower-left corner.  For convenience, the argument is
+  // reduced modulo 4 to the range [0..3].
+  R2Point GetVertex(int k) const;
+
+  // Return the vertex in direction "i" along the x-axis (0=left, 1=right) and
+  // direction "j" along the y-axis (0=down, 1=up).  Equivalently, return the
+  // vertex constructed by selecting endpoint "i" of the x-interval (0=lo,
+  // 1=hi) and vertex "j" of the y-interval.
+  R2Point GetVertex(int i, int j) const;
+
+  // Return the center of the rectangle in (x,y)-space
+  // (in general this is not the center of the region on the sphere).
+  R2Point GetCenter() const;
+
+  // Return the width and height of this rectangle in (x,y)-space.  Empty
+  // rectangles have a negative width and height.
+  R2Point GetSize() const;
+
+  // Return true if the rectangle contains the given point.  Note that
+  // rectangles are closed regions, i.e. they contain their boundary.
+  bool Contains(const R2Point& p) const;
+
+  // Return true if and only if the given point is contained in the interior
+  // of the region (i.e. the region excluding its boundary).
+  bool InteriorContains(const R2Point& p) const;
+
+  // Return true if and only if the rectangle contains the given other
+  // rectangle.
+  bool Contains(const S2R2Rect& other) const;
+
+  // Return true if and only if the interior of this rectangle contains all
+  // points of the given other rectangle (including its boundary).
+  bool InteriorContains(const S2R2Rect& other) const;
+
+  // Return true if this rectangle and the given other rectangle have any
+  // points in common.
+  bool Intersects(const S2R2Rect& other) const;
+
+  // Return true if and only if the interior of this rectangle intersects
+  // any point (including the boundary) of the given other rectangle.
+  bool InteriorIntersects(const S2R2Rect& other) const;
+
+  // Increase the size of the bounding rectangle to include the given point.
+  // The rectangle is expanded by the minimum amount possible.
+  void AddPoint(const R2Point& p);
+
+  // Return the closest point in the rectangle to the given point "p".
+  // The rectangle must be non-empty.
+  R2Point Project(const R2Point& p) const;
+
+  // Return a rectangle that has been expanded on each side in the x-direction
+  // by margin.x(), and on each side in the y-direction by margin.y().  If
+  // either margin is negative, then shrink the interval on the corresponding
+  // sides instead.  The resulting rectangle may be empty.  Any expansion of
+  // an empty rectangle remains empty.
+  S2R2Rect Expanded(const R2Point& margin) const;
+  S2R2Rect Expanded(double margin) const;
+
+  // Return the smallest rectangle containing the union of this rectangle and
+  // the given rectangle.
+  S2R2Rect Union(const S2R2Rect& other) const;
+
+  // Return the smallest rectangle containing the intersection of this
+  // rectangle and the given rectangle.
+  S2R2Rect Intersection(const S2R2Rect& other) const;
+
+  // Return true if two rectangles contains the same set of points.
+  bool operator==(const S2R2Rect& other) const;
+
+  // Return true if the x- and y-intervals of the two rectangles are the same
+  // up to the given tolerance (see r1interval.h for details).
+  bool ApproxEquals(const S2R2Rect& other,
+                    S1Angle max_error = S1Angle::Radians(1e-15)) const;
+
+  // Return the unit-length S2Point corresponding to the given point "p" in
+  // the (s,t)-plane.  "p" need not be restricted to the range [0,1]x[0,1].
+  static S2Point ToS2Point(const R2Point& p);
+
+  ////////////////////////////////////////////////////////////////////////
+  // S2Region interface (see s2region.h for details):
+
+  S2R2Rect* Clone() const override;
+  S2Cap GetCapBound() const override;
+  S2LatLngRect GetRectBound() const override;
+  bool Contains(const S2Point& p) const override;
+  bool Contains(const S2Cell& cell) const override;
+  bool MayIntersect(const S2Cell& cell) const override;
+
+ private:
+  R2Rect rect_;
+};
+
+std::ostream& operator<<(std::ostream& os, const S2R2Rect& r);
+
+
+//////////////////   Implementation details follow   ////////////////////
+
+
+inline S2R2Rect::S2R2Rect(const R2Rect& rect) : rect_(rect) {}
+
+inline S2R2Rect::S2R2Rect(const R2Point& lo, const R2Point& hi)
+    : rect_(lo, hi) {}
+
+inline S2R2Rect::S2R2Rect(const R1Interval& x, const R1Interval& y)
+    : rect_(x, y) {}
+
+inline S2R2Rect S2R2Rect::FromCenterSize(const R2Point& center,
+                                         const R2Point& size) {
+  return S2R2Rect(R2Rect::FromCenterSize(center, size));
+}
+
+inline S2R2Rect S2R2Rect::FromPoint(const R2Point& p) {
+  return S2R2Rect(R2Rect::FromPoint(p));
+}
+
+inline S2R2Rect S2R2Rect::FromPointPair(const R2Point& p1, const R2Point& p2) {
+  return S2R2Rect(R2Rect::FromPointPair(p1, p2));
+}
+
+inline const R1Interval& S2R2Rect::x() const { return rect_.x(); }
+inline const R1Interval& S2R2Rect::y() const { return rect_.y(); }
+inline R2Point S2R2Rect::lo() const { return rect_.lo(); }
+inline R2Point S2R2Rect::hi() const { return rect_.hi(); }
+inline const R1Interval& S2R2Rect::operator[](int i) const { return rect_[i]; }
+inline R1Interval& S2R2Rect::operator[](int i) { return rect_[i]; }
+inline S2R2Rect S2R2Rect::Empty() { return S2R2Rect(R2Rect::Empty()); }
+inline bool S2R2Rect::is_valid() const { return rect_.is_valid(); }
+inline bool S2R2Rect::is_empty() const { return rect_.is_empty(); }
+inline R2Point S2R2Rect::GetVertex(int k) const { return rect_.GetVertex(k); }
+inline R2Point S2R2Rect::GetVertex(int i, int j) const {
+  return rect_.GetVertex(i, j);
+}
+inline R2Point S2R2Rect::GetCenter() const { return rect_.GetCenter(); }
+inline R2Point S2R2Rect::GetSize() const { return rect_.GetSize(); }
+inline bool S2R2Rect::Contains(const R2Point& p) const {
+  return rect_.Contains(p);
+}
+inline bool S2R2Rect::InteriorContains(const R2Point& p) const {
+  return rect_.InteriorContains(p);
+}
+inline bool S2R2Rect::Contains(const S2R2Rect& other) const {
+  return rect_.Contains(other.rect_);
+}
+inline bool S2R2Rect::InteriorContains(const S2R2Rect& other) const {
+  return rect_.InteriorContains(other.rect_);
+}
+inline bool S2R2Rect::Intersects(const S2R2Rect& other) const {
+  return rect_.Intersects(other.rect_);
+}
+inline bool S2R2Rect::InteriorIntersects(const S2R2Rect& other) const {
+  return rect_.InteriorIntersects(other.rect_);
+}
+inline void S2R2Rect::AddPoint(const R2Point& p) {
+  rect_.AddPoint(p);
+}
+inline R2Point S2R2Rect::Project(const R2Point& p) const {
+  return rect_.Project(p);
+}
+inline S2R2Rect S2R2Rect::Expanded(const R2Point& margin) const {
+  return S2R2Rect(rect_.Expanded(margin));
+}
+inline S2R2Rect S2R2Rect::Expanded(double margin) const {
+  return S2R2Rect(rect_.Expanded(margin));
+}
+inline S2R2Rect S2R2Rect::Union(const S2R2Rect& other) const {
+  return S2R2Rect(rect_.Union(other.rect_));
+}
+inline S2R2Rect S2R2Rect::Intersection(const S2R2Rect& other) const {
+  return S2R2Rect(rect_.Intersection(other.rect_));
+}
+inline bool S2R2Rect::operator==(const S2R2Rect& other) const {
+  return rect_ == other.rect_;
+}
+inline bool S2R2Rect::ApproxEquals(const S2R2Rect& other,
+                                   S1Angle max_error) const {
+  return rect_.ApproxEquals(other.rect_, max_error.radians());
+}
+
+#endif  // S2_S2R2RECT_H_
diff --git a/src/s2/s2region.cc b/src/s2/s2region.cc
new file mode 100644 (file)
index 0000000..45f05f0
--- /dev/null
@@ -0,0 +1,26 @@
+// Copyright 2005 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// Author: ericv@google.com (Eric Veach)
+
+#include "s2/s2region.h"
+
+#include <vector>
+
+#include "s2/s2cap.h"
+
+void S2Region::GetCellUnionBound(std::vector<S2CellId> *cell_ids) const {
+  return GetCapBound().GetCellUnionBound(cell_ids);
+}
diff --git a/src/s2/s2region.h b/src/s2/s2region.h
new file mode 100644 (file)
index 0000000..cb1c489
--- /dev/null
@@ -0,0 +1,142 @@
+// Copyright 2005 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// Author: ericv@google.com (Eric Veach)
+
+#ifndef S2_S2REGION_H_
+#define S2_S2REGION_H_
+
+#include <vector>
+
+#include "s2/_fp_contract_off.h"
+#include "s2/s1angle.h"
+
+class Decoder;
+class Encoder;
+
+class S2Cap;
+class S2Cell;
+class S2CellId;
+class S2LatLngRect;
+
+// An S2Region represents a two-dimensional region over the unit sphere.
+// It is an abstract interface with various concrete subtypes.
+//
+// The main purpose of this interface is to allow complex regions to be
+// approximated as simpler regions.  So rather than having a wide variety
+// of virtual methods that are implemented by all subtypes, the interface
+// is restricted to methods that are useful for computing approximations.
+class S2Region {
+ public:
+  S2Region() = default;
+  S2Region(const S2Region& other) = default;
+  S2Region& operator=(const S2Region&) = default;
+  virtual ~S2Region() {}
+
+  // Returns a deep copy of the region.
+  //
+  // Note that each subtype of S2Region returns a pointer to an object of its
+  // own type (e.g., S2Cap::Clone() returns an S2Cap*).
+  virtual S2Region* Clone() const = 0;
+
+  // Returns a bounding spherical cap that contains the region.  The bound may
+  // not be tight.
+  virtual S2Cap GetCapBound() const = 0;
+
+  // Returns a bounding latitude-longitude rectangle that contains the region.
+  // The bound may not be tight.
+  virtual S2LatLngRect GetRectBound() const = 0;
+
+  // Returns a small collection of S2CellIds whose union covers the region.
+  // The cells are not sorted, may have redundancies (such as cells that
+  // contain other cells), and may cover much more area than necessary.
+  //
+  // This method is not intended for direct use by client code.  Clients
+  // should typically use S2RegionCoverer::GetCovering, which has options to
+  // control the size and accuracy of the covering.  Alternatively, if you
+  // want a fast covering and don't care about accuracy, consider calling
+  // S2RegionCoverer::GetFastCovering (which returns a cleaned-up version of
+  // the covering computed by this method).
+  //
+  // GetCellUnionBound() implementations should attempt to return a small
+  // covering (ideally 4 cells or fewer) that covers the region and can be
+  // computed quickly.  The result is used by S2RegionCoverer as a starting
+  // point for further refinement.
+  //
+  // TODO(ericv): Remove the default implementation.
+  virtual void GetCellUnionBound(std::vector<S2CellId> *cell_ids) const;
+
+  // Returns true if the region completely contains the given cell, otherwise
+  // returns false.
+  virtual bool Contains(const S2Cell& cell) const = 0;
+
+  // If this method returns false, the region does not intersect the given
+  // cell.  Otherwise, either region intersects the cell, or the intersection
+  // relationship could not be determined.
+  //
+  // Note that there is currently exactly one implementation of this method
+  // (S2LatLngRect::MayIntersect) that takes advantage of the semantics above
+  // to be more efficient.  For all other S2Region subtypes, this method
+  // returns true if the region intersect the cell and false otherwise.
+  virtual bool MayIntersect(const S2Cell& cell) const = 0;
+
+  // Returns true if and only if the given point is contained by the region.
+  // The point 'p' is generally required to be unit length, although some
+  // subtypes may relax this restriction.
+  virtual bool Contains(const S2Point& p) const = 0;
+
+  //////////////////////////////////////////////////////////////////////////
+  // Many S2Region subtypes also define the following non-virtual methods.
+  //////////////////////////////////////////////////////////////////////////
+
+  // Appends a serialized representation of the region to "encoder".
+  //
+  // The representation chosen is left up to the sub-classes but it should
+  // satisfy the following constraints:
+  // - It should encode a version number.
+  // - It should be deserializable using the corresponding Decode method.
+  // - Performance, not space, should be the chief consideration. Encode() and
+  //   Decode() should be implemented such that the combination is equivalent
+  //   to calling Clone().
+  //
+  // REQUIRES: "encoder" uses the default constructor, so that its buffer
+  //           can be enlarged as necessary by calling Ensure(int).
+  //
+  // void Encode(Encoder* const encoder) const;
+
+  // Decodes an S2Region encoded with Encode().  Note that this method
+  // requires that an S2Region object of the appropriate concrete type has
+  // already been constructed.  It is not possible to decode regions of
+  // unknown type.
+  //
+  // Whenever the Decode method is changed to deal with new serialized
+  // representations, it should be done so in a manner that allows for
+  // older versions to be decoded i.e. the version number in the serialized
+  // representation should be used to decide how to decode the data.
+  //
+  // Returns true on success.
+  //
+  // bool Decode(Decoder* const decoder);
+
+  // Provides the same functionality as Decode, except that decoded regions
+  // are allowed to point directly into the Decoder's memory buffer rather
+  // than copying the data.  This method can be much faster for regions that
+  // have a lot of data (such as polygons), but the decoded region is only
+  // valid within the scope (lifetime) of the Decoder's memory buffer.
+  //
+  // bool DecodeWithinScope(Decoder* const decoder);
+};
+
+#endif  // S2_S2REGION_H_
diff --git a/src/s2/s2region_coverer.cc b/src/s2/s2region_coverer.cc
new file mode 100644 (file)
index 0000000..7bd66ce
--- /dev/null
@@ -0,0 +1,514 @@
+// Copyright 2005 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// Author: ericv@google.com (Eric Veach)
+
+#include "s2/s2region_coverer.h"
+
+#include <algorithm>
+#include <cstddef>
+#include <cstdlib>
+#include <cstring>
+#include <functional>
+#include <queue>
+#include <unordered_set>
+#include <vector>
+
+#include "s2/base/logging.h"
+#include "s2/s1angle.h"
+#include "s2/s2cap.h"
+#include "s2/s2cell_union.h"
+#include "s2/s2metrics.h"
+#include "s2/s2region.h"
+#include "absl/base/casts.h"
+
+using std::is_sorted;
+using std::max;
+using std::min;
+using std::unordered_set;
+using std::vector;
+
+// Define storage for header file constants (the values are not needed here).
+constexpr int S2RegionCoverer::Options::kDefaultMaxCells;
+
+S2RegionCoverer::S2RegionCoverer(const S2RegionCoverer::Options& options) :
+  options_(options) {
+  S2_DCHECK_LE(options.min_level(), options.max_level());
+}
+
+// Defaulted in the implementation to prevent inline bloat.
+S2RegionCoverer::S2RegionCoverer() = default;
+S2RegionCoverer::~S2RegionCoverer() = default;
+S2RegionCoverer::S2RegionCoverer(S2RegionCoverer&&) = default;
+S2RegionCoverer& S2RegionCoverer::operator=(S2RegionCoverer&&) = default;
+
+void S2RegionCoverer::Options::set_max_cells(int max_cells) {
+  max_cells_ = max_cells;
+}
+
+void S2RegionCoverer::Options::set_min_level(int min_level) {
+  S2_DCHECK_GE(min_level, 0);
+  S2_DCHECK_LE(min_level, S2CellId::kMaxLevel);
+  // min_level() <= max_level() is checked by S2RegionCoverer.
+  min_level_ = max(0, min(S2CellId::kMaxLevel, min_level));
+}
+
+void S2RegionCoverer::Options::set_max_level(int max_level) {
+  S2_DCHECK_GE(max_level, 0);
+  S2_DCHECK_LE(max_level, S2CellId::kMaxLevel);
+  // min_level() <= max_level() is checked by S2RegionCoverer.
+  max_level_ = max(0, min(S2CellId::kMaxLevel, max_level));
+}
+
+void S2RegionCoverer::Options::set_fixed_level(int level) {
+  set_min_level(level);
+  set_max_level(level);
+}
+
+void S2RegionCoverer::Options::set_level_mod(int level_mod) {
+  S2_DCHECK_GE(level_mod, 1);
+  S2_DCHECK_LE(level_mod, 3);
+  level_mod_ = max(1, min(3, level_mod));
+}
+
+int S2RegionCoverer::Options::true_max_level() const {
+  if (level_mod_ == 1) return max_level_;
+  return max_level_ - (max_level_ - min_level_) % level_mod_;
+}
+
+S2RegionCoverer::Candidate* S2RegionCoverer::NewCandidate(const S2Cell& cell) {
+  if (!region_->MayIntersect(cell)) return nullptr;
+
+  bool is_terminal = false;
+  if (cell.level() >= options_.min_level()) {
+    if (interior_covering_) {
+      if (region_->Contains(cell)) {
+        is_terminal = true;
+      } else if (cell.level() + options_.level_mod() > options_.max_level()) {
+        return nullptr;
+      }
+    } else {
+      if (cell.level() + options_.level_mod() > options_.max_level() ||
+          region_->Contains(cell)) {
+        is_terminal = true;
+      }
+    }
+  }
+  ++candidates_created_counter_;
+  const std::size_t max_children = is_terminal ? 0 : 1 << max_children_shift();
+  return new (max_children) Candidate(cell, max_children);
+}
+
+void S2RegionCoverer::DeleteCandidate(Candidate* candidate,
+                                      bool delete_children) {
+  if (delete_children) {
+    for (int i = 0; i < candidate->num_children; ++i)
+      DeleteCandidate(candidate->children[i], true);
+  }
+  delete candidate;
+}
+
+int S2RegionCoverer::ExpandChildren(Candidate* candidate,
+                                    const S2Cell& cell, int num_levels) {
+  num_levels--;
+  S2Cell child_cells[4];
+  cell.Subdivide(child_cells);
+  int num_terminals = 0;
+  for (int i = 0; i < 4; ++i) {
+    if (num_levels > 0) {
+      if (region_->MayIntersect(child_cells[i])) {
+        num_terminals += ExpandChildren(candidate, child_cells[i], num_levels);
+      }
+      continue;
+    }
+    Candidate* child = NewCandidate(child_cells[i]);
+    if (child) {
+      candidate->children[candidate->num_children++] = child;
+      if (child->is_terminal) ++num_terminals;
+    }
+  }
+  return num_terminals;
+}
+
+void S2RegionCoverer::AddCandidate(Candidate* candidate) {
+  if (candidate == nullptr) return;
+
+  if (candidate->is_terminal) {
+    result_.push_back(candidate->cell.id());
+    DeleteCandidate(candidate, true);
+    return;
+  }
+  S2_DCHECK_EQ(0, candidate->num_children);
+
+  // Expand one level at a time until we hit min_level() to ensure that we
+  // don't skip over it.
+  int num_levels = ((candidate->cell.level() < options_.min_level()) ?
+                    1 : options_.level_mod());
+  int num_terminals = ExpandChildren(candidate, candidate->cell, num_levels);
+
+  if (candidate->num_children == 0) {
+    DeleteCandidate(candidate, false);
+
+  } else if (!interior_covering_ &&
+             num_terminals == 1 << max_children_shift() &&
+             candidate->cell.level() >= options_.min_level()) {
+    // Optimization: add the parent cell rather than all of its children.
+    // We can't do this for interior coverings, since the children just
+    // intersect the region, but may not be contained by it - we need to
+    // subdivide them further.
+    candidate->is_terminal = true;
+    AddCandidate(candidate);
+
+  } else {
+    // We negate the priority so that smaller absolute priorities are returned
+    // first.  The heuristic is designed to refine the largest cells first,
+    // since those are where we have the largest potential gain.  Among cells
+    // of the same size, we prefer the cells with the fewest children.
+    // Finally, among cells with equal numbers of children we prefer those
+    // with the smallest number of children that cannot be refined further.
+    int priority = -((((candidate->cell.level() << max_children_shift())
+                       + candidate->num_children) << max_children_shift())
+                     + num_terminals);
+    pq_.push(std::make_pair(priority, candidate));
+    S2_VLOG(2) << "Push: " << candidate->cell.id() << " (" << priority << ") ";
+  }
+}
+
+inline int S2RegionCoverer::AdjustLevel(int level) const {
+  if (options_.level_mod() > 1 && level > options_.min_level()) {
+    level -= (level - options_.min_level()) % options_.level_mod();
+  }
+  return level;
+}
+
+void S2RegionCoverer::AdjustCellLevels(vector<S2CellId>* cells) const {
+  S2_DCHECK(is_sorted(cells->begin(), cells->end()));
+  if (options_.level_mod() == 1) return;
+
+  int out = 0;
+  for (S2CellId id : *cells) {
+    int level = id.level();
+    int new_level = AdjustLevel(level);
+    if (new_level != level) id = id.parent(new_level);
+    if (out > 0 && (*cells)[out-1].contains(id)) continue;
+    while (out > 0 && id.contains((*cells)[out-1])) --out;
+    (*cells)[out++] = id;
+  }
+  cells->resize(out);
+}
+
+void S2RegionCoverer::GetInitialCandidates() {
+  // Optimization: start with a small (usually 4 cell) covering of the
+  // region's bounding cap.
+  S2RegionCoverer tmp_coverer;
+  tmp_coverer.mutable_options()->set_max_cells(min(4, options_.max_cells()));
+  tmp_coverer.mutable_options()->set_max_level(options_.max_level());
+  vector<S2CellId> cells;
+  tmp_coverer.GetFastCovering(*region_, &cells);
+  AdjustCellLevels(&cells);
+  for (S2CellId cell_id : cells) {
+    AddCandidate(NewCandidate(S2Cell(cell_id)));
+  }
+}
+
+void S2RegionCoverer::GetCoveringInternal(const S2Region& region) {
+  // We check this on each call because of mutable_options().
+  S2_DCHECK_LE(options_.min_level(), options_.max_level());
+
+  // Strategy: Start with the 6 faces of the cube.  Discard any
+  // that do not intersect the shape.  Then repeatedly choose the
+  // largest cell that intersects the shape and subdivide it.
+  //
+  // result_ contains the cells that will be part of the output, while pq_
+  // contains cells that we may still subdivide further.  Cells that are
+  // entirely contained within the region are immediately added to the output,
+  // while cells that do not intersect the region are immediately discarded.
+  // Therefore pq_ only contains cells that partially intersect the region.
+  // Candidates are prioritized first according to cell size (larger cells
+  // first), then by the number of intersecting children they have (fewest
+  // children first), and then by the number of fully contained children
+  // (fewest children first).
+
+  S2_DCHECK(pq_.empty());
+  S2_DCHECK(result_.empty());
+  region_ = &region;
+  candidates_created_counter_ = 0;
+
+  GetInitialCandidates();
+  while (!pq_.empty() &&
+         (!interior_covering_ || result_.size() < options_.max_cells())) {
+    Candidate* candidate = pq_.top().second;
+    pq_.pop();
+    S2_VLOG(2) << "Pop: " << candidate->cell.id();
+    // For interior coverings we keep subdividing no matter how many children
+    // the candidate has.  If we reach max_cells() before expanding all
+    // children, we will just use some of them.  For exterior coverings we
+    // cannot do this, because the result has to cover the whole region, so
+    // all children have to be used.  The (candidate->num_children == 1) case
+    // takes care of the situation when we already have more than max_cells()
+    // in results (min_level is too high).  Subdividing the candidate with one
+    // child does no harm in this case.
+    if (interior_covering_ ||
+        candidate->cell.level() < options_.min_level() ||
+        candidate->num_children == 1 ||
+        (result_.size() + pq_.size() + candidate->num_children <=
+         options_.max_cells())) {
+      // Expand this candidate into its children.
+      for (int i = 0; i < candidate->num_children; ++i) {
+        if (interior_covering_ && result_.size() >= options_.max_cells()) {
+          DeleteCandidate(candidate->children[i], true);
+        } else {
+          AddCandidate(candidate->children[i]);
+        }
+      }
+      DeleteCandidate(candidate, false);
+    } else {
+      candidate->is_terminal = true;
+      AddCandidate(candidate);
+    }
+  }
+  S2_VLOG(2) << "Created " << result_.size() << " cells, " <<
+      candidates_created_counter_ << " candidates created, " <<
+      pq_.size() << " left";
+  while (!pq_.empty()) {
+    DeleteCandidate(pq_.top().second, true);
+    pq_.pop();
+  }
+  region_ = nullptr;
+
+  // Rather than just returning the raw list of cell ids, we construct a cell
+  // union and then denormalize it.  This has the effect of replacing four
+  // child cells with their parent whenever this does not violate the covering
+  // parameters specified (min_level, level_mod, etc).  This significantly
+  // reduces the number of cells returned in many cases, and it is cheap
+  // compared to computing the covering in the first place.
+  S2CellUnion::Normalize(&result_);
+  if (options_.min_level() > 0 || options_.level_mod() > 1) {
+    auto result_copy = result_;
+    S2CellUnion::Denormalize(result_copy, options_.min_level(),
+                             options_.level_mod(), &result_);
+  }
+  S2_DCHECK(IsCanonical(result_));
+}
+
+void S2RegionCoverer::GetCovering(const S2Region& region,
+                                  vector<S2CellId>* covering) {
+  interior_covering_ = false;
+  GetCoveringInternal(region);
+  *covering = std::move(result_);
+}
+
+void S2RegionCoverer::GetInteriorCovering(const S2Region& region,
+                                          vector<S2CellId>* interior) {
+  interior_covering_ = true;
+  GetCoveringInternal(region);
+  *interior = std::move(result_);
+}
+
+S2CellUnion S2RegionCoverer::GetCovering(const S2Region& region) {
+  interior_covering_ = false;
+  GetCoveringInternal(region);
+  return S2CellUnion::FromVerbatim(std::move(result_));
+}
+
+S2CellUnion S2RegionCoverer::GetInteriorCovering(const S2Region& region) {
+  interior_covering_ = true;
+  GetCoveringInternal(region);
+  return S2CellUnion::FromVerbatim(std::move(result_));
+}
+
+void S2RegionCoverer::GetFastCovering(const S2Region& region,
+                                      vector<S2CellId>* covering) {
+  region.GetCellUnionBound(covering);
+  CanonicalizeCovering(covering);
+}
+
+bool S2RegionCoverer::IsCanonical(const S2CellUnion& covering) const {
+  return IsCanonical(covering.cell_ids());
+}
+
+bool S2RegionCoverer::IsCanonical(const vector<S2CellId>& covering) const {
+  // We check this on each call because of mutable_options().
+  S2_DCHECK_LE(options_.min_level(), options_.max_level());
+
+  const int min_level = options_.min_level();
+  const int max_level = options_.true_max_level();
+  const int level_mod = options_.level_mod();
+  const bool too_many_cells = covering.size() > options_.max_cells();
+  int same_parent_count = 1;
+  S2CellId prev_id = S2CellId::None();
+  for (const S2CellId id : covering) {
+    if (!id.is_valid()) return false;
+
+    // Check that the S2CellId level is acceptable.
+    const int level = id.level();
+    if (level < min_level || level > max_level) return false;
+    if (level_mod > 1 && (level - min_level) % level_mod != 0) return false;
+
+    if (prev_id != S2CellId::None()) {
+      // Check that cells are sorted and non-overlapping.
+      if (prev_id.range_max() >= id.range_min()) return false;
+
+      // If there are too many cells, check that no pair of adjacent cells
+      // could be replaced by an ancestor.
+      if (too_many_cells && id.GetCommonAncestorLevel(prev_id) >= min_level) {
+        return false;
+      }
+
+      // Check that there are no sequences of (4 ** level_mod) cells that all
+      // have the same parent (considering only multiples of "level_mod").
+      int plevel = level - level_mod;
+      if (plevel < min_level || level != prev_id.level() ||
+          id.parent(plevel) != prev_id.parent(plevel)) {
+        same_parent_count = 1;
+      } else if (++same_parent_count == (1 << (2 * level_mod))) {
+        return false;
+      }
+    }
+    prev_id = id;
+  }
+  return true;
+}
+
+bool S2RegionCoverer::ContainsAllChildren(const vector<S2CellId>& covering,
+                                          S2CellId id) const {
+  auto it = std::lower_bound(covering.begin(), covering.end(), id.range_min());
+  int level = id.level() + options_.level_mod();
+  for (S2CellId child = id.child_begin(level);
+       child != id.child_end(level); ++it, child = child.next()) {
+    if (it == covering.end() || *it != child) return false;
+  }
+  return true;
+}
+
+// Replaces all descendants of "id" in "covering" with "id".
+// REQUIRES: "covering" contains at least one descendant of "id".
+void S2RegionCoverer::ReplaceCellsWithAncestor(vector<S2CellId>* covering,
+                                               S2CellId id) const {
+  auto begin = std::lower_bound(covering->begin(), covering->end(),
+                                id.range_min());
+  auto end = std::upper_bound(covering->begin(), covering->end(),
+                              id.range_max());
+  S2_DCHECK(begin != end);
+  covering->erase(begin + 1, end);
+  *begin = id;
+}
+
+S2CellUnion S2RegionCoverer::CanonicalizeCovering(const S2CellUnion& covering) {
+  vector<S2CellId> ids = covering.cell_ids();
+  CanonicalizeCovering(&ids);
+  return S2CellUnion(std::move(ids));
+}
+
+void S2RegionCoverer::CanonicalizeCovering(vector<S2CellId>* covering) {
+  // We check this on each call because of mutable_options().
+  S2_DCHECK_LE(options_.min_level(), options_.max_level());
+
+  // Note that when the covering parameters have their default values, almost
+  // all of the code in this function is skipped.
+
+  // If any cells are too small, or don't satisfy level_mod(), then replace
+  // them with ancestors.
+  if (options_.max_level() < S2CellId::kMaxLevel || options_.level_mod() > 1) {
+    for (S2CellId& id : *covering) {
+      int level = id.level();
+      int new_level = AdjustLevel(min(level, options_.max_level()));
+      if (new_level != level) {
+        id = id.parent(new_level);
+      }
+    }
+  }
+
+  // Sort the cells and simplify them.
+  S2CellUnion::Normalize(covering);
+
+  // Make sure that the covering satisfies min_level() and level_mod(),
+  // possibly at the expense of satisfying max_cells().
+  if (options_.min_level() > 0 || options_.level_mod() > 1) {
+    S2CellUnion::Denormalize(*covering, options_.min_level(),
+                             options_.level_mod(), &result_);
+    *covering = std::move(result_);
+  }
+
+  // If there are too many cells and the covering is very large, use the
+  // S2RegionCoverer to compute a new covering.  (This avoids possible O(n^2)
+  // behavior of the simpler algorithm below.)
+  int64 excess = covering->size() - options_.max_cells();
+  if (excess <= 0 || IsCanonical(*covering)) {
+    return;
+  }
+  if (excess * covering->size() > 10000) {
+    GetCovering(S2CellUnion(std::move(*covering)), covering);
+  } else {
+    // Repeatedly replace two adjacent cells in S2CellId order by their lowest
+    // common ancestor until the number of cells is acceptable.
+    while (covering->size() > options_.max_cells()) {
+      int best_index = -1, best_level = -1;
+      for (int i = 0; i + 1 < covering->size(); ++i) {
+        int level = (*covering)[i].GetCommonAncestorLevel((*covering)[i+1]);
+        level = AdjustLevel(level);
+        if (level > best_level) {
+          best_level = level;
+          best_index = i;
+        }
+      }
+      if (best_level < options_.min_level()) break;
+
+      // Replace all cells contained by the new ancestor cell.
+      S2CellId id = (*covering)[best_index].parent(best_level);
+      ReplaceCellsWithAncestor(covering, id);
+
+      // Now repeatedly check whether all children of the parent cell are
+      // present, in which case we can replace those cells with their parent.
+      while (best_level > options_.min_level()) {
+        best_level -= options_.level_mod();
+        id = id.parent(best_level);
+        if (!ContainsAllChildren(*covering, id)) break;
+        ReplaceCellsWithAncestor(covering, id);
+      }
+    }
+  }
+  S2_DCHECK(IsCanonical(*covering));
+}
+
+void S2RegionCoverer::FloodFill(const S2Region& region, S2CellId start,
+                                vector<S2CellId>* output) {
+  unordered_set<S2CellId, S2CellIdHash> all;
+  vector<S2CellId> frontier;
+  output->clear();
+  all.insert(start);
+  frontier.push_back(start);
+  while (!frontier.empty()) {
+    S2CellId id = frontier.back();
+    frontier.pop_back();
+    if (!region.MayIntersect(S2Cell(id))) continue;
+    output->push_back(id);
+
+    S2CellId neighbors[4];
+    id.GetEdgeNeighbors(neighbors);
+    for (int edge = 0; edge < 4; ++edge) {
+      S2CellId nbr = neighbors[edge];
+      if (all.insert(nbr).second) {
+        frontier.push_back(nbr);
+      }
+    }
+  }
+}
+
+void S2RegionCoverer::GetSimpleCovering(
+    const S2Region& region, const S2Point& start,
+    int level, vector<S2CellId>* output) {
+  return FloodFill(region, S2CellId(start).parent(level), output);
+}
diff --git a/src/s2/s2region_coverer.h b/src/s2/s2region_coverer.h
new file mode 100644 (file)
index 0000000..e88ca9c
--- /dev/null
@@ -0,0 +1,356 @@
+// Copyright 2005 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// Author: ericv@google.com (Eric Veach)
+
+#ifndef S2_S2REGION_COVERER_H_
+#define S2_S2REGION_COVERER_H_
+
+#include <cstddef>
+#include <new>
+#include <queue>
+#include <utility>
+#include <vector>
+
+#include "absl/base/macros.h"
+#include "s2/_fp_contract_off.h"
+#include "s2/s2cell.h"
+#include "s2/s2cell_id.h"
+#include "s2/s2cell_union.h"
+
+class S2Region;
+
+// An S2RegionCoverer is a class that allows arbitrary regions to be
+// approximated as unions of cells (S2CellUnion).  This is useful for
+// implementing various sorts of search and precomputation operations.
+//
+// Typical usage:
+//
+// S2RegionCoverer::Options options;
+// options.set_max_cells(5);
+// S2RegionCoverer coverer(options);
+// S2Cap cap(center, radius);
+// S2CellUnion covering = coverer.GetCovering(cap);
+//
+// This yields a vector of at most 5 cells that is guaranteed to cover the
+// given cap (a disc-shaped region on the sphere).
+//
+// The approximation algorithm is not optimal but does a pretty good job in
+// practice.  The output does not always use the maximum number of cells
+// allowed, both because this would not always yield a better approximation,
+// and because max_cells() is a limit on how much work is done exploring the
+// possible covering as well as a limit on the final output size.
+//
+// Because it is an approximation algorithm, one should not rely on the
+// stability of the output.  In particular, the output of the covering algorithm
+// may change across different versions of the library.
+//
+// One can also generate interior coverings, which are sets of cells which
+// are entirely contained within a region.  Interior coverings can be
+// empty, even for non-empty regions, if there are no cells that satisfy
+// the provided constraints and are contained by the region.  Note that for
+// performance reasons, it is wise to specify a max_level when computing
+// interior coverings - otherwise for regions with small or zero area, the
+// algorithm may spend a lot of time subdividing cells all the way to leaf
+// level to try to find contained cells.
+class S2RegionCoverer {
+ public:
+#ifndef SWIG
+  class Options {
+   public:
+    // Sets the desired maximum number of cells in the approximation.  Note
+    // the following:
+    //
+    //  - For any setting of max_cells(), up to 6 cells may be returned if
+    //    that is the minimum number required (e.g. if the region intersects
+    //    all six cube faces).  Even for very tiny regions, up to 3 cells may
+    //    be returned if they happen to be located at the intersection of
+    //    three cube faces.
+    //
+    //  - min_level() takes priority over max_cells(), i.e. cells below the
+    //    given level will never be used even if this causes a large number of
+    //    cells to be returned.
+    //
+    //  - If max_cells() is less than 4, the area of the covering may be
+    //    arbitrarily large compared to the area of the original region even
+    //    if the region is convex (e.g. an S2Cap or S2LatLngRect).
+    //
+    // Accuracy is measured by dividing the area of the covering by the area
+    // of the original region.  The following table shows the median and worst
+    // case values for this area ratio on a test case consisting of 100,000
+    // spherical caps of random size (generated using s2region_coverer_test):
+    //
+    //   max_cells:        3      4     5     6     8    12    20   100   1000
+    //   median ratio:  5.33   3.32  2.73  2.34  1.98  1.66  1.42  1.11   1.01
+    //   worst case:  215518  14.41  9.72  5.26  3.91  2.75  1.92  1.20   1.02
+    //
+    // The default value of 8 gives a reasonable tradeoff between the number
+    // of cells used and the accuracy of the approximation.
+    //
+    // DEFAULT: kDefaultMaxCells
+    static constexpr int kDefaultMaxCells = 8;
+    int max_cells() const { return max_cells_; }
+    void set_max_cells(int max_cells);
+
+    // Sets the minimum and maximum cell levels to be used.  The default is to
+    // use all cell levels.
+    //
+    // To find the cell level corresponding to a given physical distance, use
+    // the S2Cell metrics defined in s2metrics.h.  For example, to find the
+    // cell level that corresponds to an average edge length of 10km, use:
+    //
+    //   int level =
+    //       S2::kAvgEdge.GetClosestLevel(S2Earth::KmToRadians(length_km));
+    //
+    // Note that min_level() takes priority over max_cells(), i.e. cells below
+    // the given level will never be used even if this causes a large number
+    // of cells to be returned.  (This doesn't apply to interior coverings,
+    // since interior coverings make no completeness guarantees -- the result
+    // is simply a set of cells that covers as much of the interior as
+    // possible while satisfying the given restrictions.)
+    //
+    // REQUIRES: min_level() <= max_level()
+    // DEFAULT: 0
+    int min_level() const { return min_level_; }
+    void set_min_level(int min_level);
+
+    // REQUIRES: min_level() <= max_level()
+    // DEFAULT: S2CellId::kMaxLevel
+    int max_level() const { return max_level_; }
+    void set_max_level(int max_level);
+
+    // Convenience function that sets both the maximum and minimum cell levels.
+    void set_fixed_level(int level);
+
+    // If specified, then only cells where (level - min_level) is a multiple
+    // of "level_mod" will be used (default 1).  This effectively allows the
+    // branching factor of the S2CellId hierarchy to be increased.  Currently
+    // the only parameter values allowed are 1, 2, or 3, corresponding to
+    // branching factors of 4, 16, and 64 respectively.
+    //
+    // DEFAULT: 1
+    int level_mod() const { return level_mod_; }
+    void set_level_mod(int level_mod);
+
+    // Convenience function that returns the maximum level such that
+    //
+    //   (level <= max_level()) && (level - min_level()) % level_mod() == 0.
+    //
+    // This is the maximum level that will actually be used in coverings.
+    int true_max_level() const;
+
+   protected:
+    int max_cells_ = kDefaultMaxCells;
+    int min_level_ = 0;
+    int max_level_ = S2CellId::kMaxLevel;
+    int level_mod_ = 1;
+  };
+
+  // Constructs an S2RegionCoverer with the given options.
+  explicit S2RegionCoverer(const Options& options);
+
+  // S2RegionCoverer is movable but not copyable.
+  S2RegionCoverer(const S2RegionCoverer&) = delete;
+  S2RegionCoverer& operator=(const S2RegionCoverer&) = delete;
+  S2RegionCoverer(S2RegionCoverer&&);
+  S2RegionCoverer& operator=(S2RegionCoverer&&);
+#endif  // SWIG
+
+  // Default constructor.  Options can be set using mutable_options().
+  S2RegionCoverer();
+  ~S2RegionCoverer();
+
+  // Returns the current options.  Options can be modifed between calls.
+  const Options& options() const { return options_; }
+  Options* mutable_options() { return &options_; }
+
+  // Returns an S2CellUnion that covers (GetCovering) or is contained within
+  // (GetInteriorCovering) the given region and satisfies the current options.
+  //
+  // Note that if options().min_level() > 0 or options().level_mod() > 1, the
+  // by definition the S2CellUnion may not be normalized, i.e. there may be
+  // groups of four child cells that can be replaced by their parent cell.
+  S2CellUnion GetCovering(const S2Region& region);
+  S2CellUnion GetInteriorCovering(const S2Region& region);
+
+  // Like the methods above, but works directly with a vector of S2CellIds.
+  // This version can be more efficient when this method is called many times,
+  // since it does not require allocating a new vector on each call.
+  void GetCovering(const S2Region& region, std::vector<S2CellId>* covering);
+  void GetInteriorCovering(const S2Region& region,
+                           std::vector<S2CellId>* interior);
+
+  // Like GetCovering(), except that this method is much faster and the
+  // coverings are not as tight.  All of the usual parameters are respected
+  // (max_cells, min_level, max_level, and level_mod), except that the
+  // implementation makes no attempt to take advantage of large values of
+  // max_cells().  (A small number of cells will always be returned.)
+  //
+  // This function is useful as a starting point for algorithms that
+  // recursively subdivide cells.
+  void GetFastCovering(const S2Region& region, std::vector<S2CellId>* covering);
+
+  // Given a connected region and a starting point on the boundary or inside the
+  // region, returns a set of cells at the given level that cover the region.
+  // The output cells are returned in arbitrary order.
+  //
+  // Note that this method is *not* faster than the regular GetCovering()
+  // method for most region types, such as S2Cap or S2Polygon, and in fact it
+  // can be much slower when the output consists of a large number of cells.
+  // Currently it can be faster at generating coverings of long narrow regions
+  // such as polylines, but this may change in the future, in which case this
+  // method will most likely be removed.
+  static void GetSimpleCovering(const S2Region& region, const S2Point& start,
+                                int level, std::vector<S2CellId>* output);
+
+  // Like GetSimpleCovering(), but accepts a starting S2CellId rather than a
+  // starting point and cell level.  Returns all edge-connected cells at the
+  // same level as "start" that intersect "region", in arbitrary order.
+  static void FloodFill(const S2Region& region, S2CellId start,
+                        std::vector<S2CellId>* output);
+
+  // Returns true if the given S2CellId vector represents a valid covering
+  // that conforms to the current covering parameters.  In particular:
+  //
+  //  - All S2CellIds must be valid.
+  //
+  //  - S2CellIds must be sorted and non-overlapping.
+  //
+  //  - S2CellId levels must satisfy min_level(), max_level(), and level_mod().
+  //
+  //  - If covering.size() > max_cells(), there must be no two cells with
+  //    a common ancestor at min_level() or higher.
+  //
+  //  - There must be no sequence of cells that could be replaced by an
+  //    ancestor (i.e. with level_mod() == 1, the 4 child cells of a parent).
+  bool IsCanonical(const S2CellUnion& covering) const;
+  bool IsCanonical(const std::vector<S2CellId>& covering) const;
+
+  // Modify "covering" if necessary so that it conforms to the current
+  // covering parameters (max_cells, min_level, max_level, and level_mod).
+  // There are no restrictions on the input S2CellIds (they may be unsorted,
+  // overlapping, etc).
+  S2CellUnion CanonicalizeCovering(const S2CellUnion& covering);
+  void CanonicalizeCovering(std::vector<S2CellId>* covering);
+
+ private:
+  struct Candidate {
+    void* operator new(std::size_t size, std::size_t max_children) {
+      return ::operator new (size + max_children * sizeof(Candidate *));
+    }
+
+    void operator delete(void* p) {
+      ::operator delete (p);
+    }
+
+    Candidate(const S2Cell& cell, const std::size_t max_children)
+        : cell(cell), is_terminal(max_children == 0) {
+      std::fill_n(&children[0], max_children,
+                  absl::implicit_cast<Candidate*>(nullptr));
+    }
+
+    // Default destructor is fine; Candidate* is trivially destructible.
+    // children must be deleted by DeleteCandidate.
+    ~Candidate() = default;
+
+    S2Cell cell;
+    bool is_terminal;        // Cell should not be expanded further.
+    int num_children = 0;    // Number of children that intersect the region.
+    __extension__ Candidate* children[0];  // Actual size may be 0, 4, 16, or 64 elements.
+  };
+
+  // If the cell intersects the given region, return a new candidate with no
+  // children, otherwise return nullptr.  Also marks the candidate as "terminal"
+  // if it should not be expanded further.
+  Candidate* NewCandidate(const S2Cell& cell);
+
+  // Returns the log base 2 of the maximum number of children of a candidate.
+  int max_children_shift() const { return 2 * options().level_mod(); }
+
+  // Frees the memory associated with a candidate.
+  static void DeleteCandidate(Candidate* candidate, bool delete_children);
+
+  // Processes a candidate by either adding it to the result_ vector or
+  // expanding its children and inserting it into the priority queue.
+  // Passing an argument of nullptr does nothing.
+  void AddCandidate(Candidate* candidate);
+
+  // Populates the children of "candidate" by expanding the given number of
+  // levels from the given cell.  Returns the number of children that were
+  // marked "terminal".
+  int ExpandChildren(Candidate* candidate, const S2Cell& cell, int num_levels);
+
+  // Computes a set of initial candidates that cover the given region.
+  void GetInitialCandidates();
+
+  // Generates a covering and stores it in result_.
+  void GetCoveringInternal(const S2Region& region);
+
+  // If level > min_level(), then reduces "level" if necessary so that it also
+  // satisfies level_mod().  Levels smaller than min_level() are not affected
+  // (since cells at these levels are eventually expanded).
+  int AdjustLevel(int level) const;
+
+  // Ensures that all cells with level > min_level() also satisfy level_mod(),
+  // by replacing them with an ancestor if necessary.  Cell levels smaller
+  // than min_level() are not modified (see AdjustLevel).  The output is
+  // then normalized to ensure that no redundant cells are present.
+  void AdjustCellLevels(std::vector<S2CellId>* cells) const;
+
+  // Returns true if "covering" contains all children of "id" at level
+  // (id.level() + options_.level_mod()).
+  bool ContainsAllChildren(const std::vector<S2CellId>& covering,
+                           S2CellId id) const;
+
+  // Replaces all descendants of "id" in "covering" with "id".
+  // REQUIRES: "covering" contains at least one descendant of "id".
+  void ReplaceCellsWithAncestor(std::vector<S2CellId>* covering,
+                                S2CellId id) const;
+
+  Options options_;
+
+  // We save a temporary copy of the pointer passed to GetCovering() in order
+  // to avoid passing this parameter around internally.  It is only used (and
+  // only valid) for the duration of a single GetCovering() call.
+  const S2Region* region_ = nullptr;
+
+  // The set of S2CellIds that have been added to the covering so far.
+  std::vector<S2CellId> result_;
+
+  // We keep the candidates in a priority queue.  We specify a vector to hold
+  // the queue entries since for some reason priority_queue<> uses a deque by
+  // default.  We define our own own comparison function on QueueEntries in
+  // order to make the results deterministic.  (Using the default
+  // less<QueueEntry>, entries of equal priority would be sorted according to
+  // the memory address of the candidate.)
+
+  typedef std::pair<int, Candidate*> QueueEntry;
+  struct CompareQueueEntries {
+    bool operator()(const QueueEntry& x, const QueueEntry& y) const {
+      return x.first < y.first;
+    }
+  };
+  typedef std::priority_queue<QueueEntry, std::vector<QueueEntry>,
+                              CompareQueueEntries> CandidateQueue;
+  CandidateQueue pq_;
+
+  // True if we're computing an interior covering.
+  bool interior_covering_;
+
+  // Counter of number of candidates created, for performance evaluation.
+  int candidates_created_counter_;
+};
+
+#endif  // S2_S2REGION_COVERER_H_
diff --git a/src/s2/s2region_intersection.cc b/src/s2/s2region_intersection.cc
new file mode 100644 (file)
index 0000000..623af6a
--- /dev/null
@@ -0,0 +1,84 @@
+// Copyright 2006 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+
+#include "s2/s2region_intersection.h"
+
+#include "s2/s2cap.h"
+#include "s2/s2latlng_rect.h"
+
+using std::vector;
+
+S2RegionIntersection::S2RegionIntersection(
+    vector<std::unique_ptr<S2Region>> regions) {
+  Init(std::move(regions));
+}
+
+void S2RegionIntersection::Init(vector<std::unique_ptr<S2Region>> regions) {
+  S2_DCHECK(regions_.empty());
+  regions_ = std::move(regions);
+}
+
+S2RegionIntersection::S2RegionIntersection(const S2RegionIntersection& src)
+  : regions_(src.num_regions()) {
+  for (int i = 0; i < num_regions(); ++i) {
+    regions_[i].reset(src.region(i)->Clone());
+  }
+}
+
+vector<std::unique_ptr<S2Region>> S2RegionIntersection::Release() {
+  vector<std::unique_ptr<S2Region>> result;
+  result.swap(regions_);
+  return result;
+}
+
+S2RegionIntersection* S2RegionIntersection::Clone() const {
+  return new S2RegionIntersection(*this);
+}
+
+S2Cap S2RegionIntersection::GetCapBound() const {
+  // TODO(ericv): This could be optimized to return a tighter bound, but
+  // doesn't seem worth it unless profiling shows otherwise.
+  return GetRectBound().GetCapBound();
+}
+
+S2LatLngRect S2RegionIntersection::GetRectBound() const {
+  S2LatLngRect result = S2LatLngRect::Full();
+  for (int i = 0; i < num_regions(); ++i) {
+    result = result.Intersection(region(i)->GetRectBound());
+  }
+  return result;
+}
+
+bool S2RegionIntersection::Contains(const S2Cell& cell) const {
+  for (int i = 0; i < num_regions(); ++i) {
+    if (!region(i)->Contains(cell)) return false;
+  }
+  return true;
+}
+
+bool S2RegionIntersection::Contains(const S2Point& p) const {
+  for (int i = 0; i < num_regions(); ++i) {
+    if (!region(i)->Contains(p)) return false;
+  }
+  return true;
+}
+
+bool S2RegionIntersection::MayIntersect(const S2Cell& cell) const {
+  for (int i = 0; i < num_regions(); ++i) {
+    if (!region(i)->MayIntersect(cell)) return false;
+  }
+  return true;
+}
diff --git a/src/s2/s2region_intersection.h b/src/s2/s2region_intersection.h
new file mode 100644 (file)
index 0000000..7aaf597
--- /dev/null
@@ -0,0 +1,79 @@
+// Copyright 2006 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+
+#ifndef S2_S2REGION_INTERSECTION_H_
+#define S2_S2REGION_INTERSECTION_H_
+
+#include <memory>
+#include <vector>
+
+#include "s2/base/logging.h"
+#include "s2/_fp_contract_off.h"
+#include "s2/s2region.h"
+#include "absl/base/macros.h"
+
+class Decoder;
+class Encoder;
+class S2Cap;
+class S2Cell;
+class S2LatLngRect;
+
+// An S2RegionIntersection represents the intersection of a set of regions.
+// It is convenient for computing a covering of the intersection of a set of
+// regions.
+class S2RegionIntersection final : public S2Region {
+ public:
+  // Creates an empty intersection that should be initialized by calling Init().
+  // Note: an intersection of no regions covers the entire sphere.
+  S2RegionIntersection() = default;
+
+  // Create a region representing the intersection of the given regions.
+  explicit S2RegionIntersection(std::vector<std::unique_ptr<S2Region>> regions);
+
+  ~S2RegionIntersection() override = default;
+
+  // Initialize region by taking ownership of the given regions.
+  void Init(std::vector<std::unique_ptr<S2Region>> regions);
+
+  // Releases ownership of the regions of this intersection and returns them,
+  // leaving this region empty.
+  std::vector<std::unique_ptr<S2Region>> Release();
+
+  // Accessor methods.
+  int num_regions() const { return regions_.size(); }
+  const S2Region* region(int i) const { return regions_[i].get(); }
+
+  ////////////////////////////////////////////////////////////////////////
+  // S2Region interface (see s2region.h for details):
+
+  S2RegionIntersection* Clone() const override;
+  S2Cap GetCapBound() const override;
+  S2LatLngRect GetRectBound() const override;
+  bool Contains(const S2Point& p) const override;
+  bool Contains(const S2Cell& cell) const override;
+  bool MayIntersect(const S2Cell& cell) const override;
+
+ private:
+  // Internal copy constructor used only by Clone() that makes a deep copy of
+  // its argument.
+  S2RegionIntersection(const S2RegionIntersection& src);
+
+  std::vector<std::unique_ptr<S2Region>> regions_;
+
+  void operator=(const S2RegionIntersection&) = delete;
+};
+
+#endif  // S2_S2REGION_INTERSECTION_H_
diff --git a/src/s2/s2region_term_indexer.cc b/src/s2/s2region_term_indexer.cc
new file mode 100644 (file)
index 0000000..ed62eb8
--- /dev/null
@@ -0,0 +1,270 @@
+// Copyright 2017 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// Author: ericv@google.com (Eric Veach)
+//
+// Indexing Strategy
+// -----------------
+//
+// Given a query region, we want to find all of the document regions that
+// intersect it.  The first step is to represent all the regions as S2Cell
+// coverings (see S2RegionCoverer).  We then split the problem into two parts,
+// namely finding the document regions that are "smaller" than the query
+// region and those that are "larger" than the query region.
+//
+// We do this by defining two terms for each S2CellId: a "covering term" and
+// an "ancestor term".  (In the implementation below, covering terms are
+// distinguished by prefixing a '$' to them.)  For each document region, we
+// insert a covering term for every cell in the region's covering, and we
+// insert an ancestor term for these cells *and* all of their ancestors.
+//
+// Then given a query region, we can look up all the document regions that
+// intersect its covering by querying the union of the following terms:
+//
+// 1. An "ancestor term" for each cell in the query region.  These terms
+//    ensure that we find all document regions that are "smaller" than the
+//    query region, i.e. where the query region contains a cell that is either
+//    a cell of a document region or one of its ancestors.
+//
+// 2. A "covering term" for every ancestor of the cells in the query region.
+//    These terms ensure that we find all the document regions that are
+//    "larger" than the query region, i.e. where document region contains a
+//    cell that is a (proper) ancestor of a cell in the query region.
+//
+// Together, these terms find all of the document regions that intersect the
+// query region.  Furthermore, the number of terms to be indexed and queried
+// are both fairly small, and can be bounded in terms of max_cells() and the
+// number of cell levels used.
+//
+// Optimizations
+// -------------
+//
+// + Cells at the maximum level being indexed (max_level()) have the special
+//   property that they will never be an ancestor of a cell in the query
+//   region.  Therefore we can safely skip generating "covering terms" for
+//   these cells (see query step 2 above).
+//
+// + If the index will contain only points (rather than general regions), then
+//   we can skip all the covering terms mentioned above because there will
+//   never be any document regions larger than the query region.  This can
+//   significantly reduce the size of queries.
+//
+// + If it is more important to optimize index size rather than query speed,
+//   the number of index terms can be reduced by creating ancestor terms only
+//   for the *proper* ancestors of the cells in a document region, and
+//   compensating for this by including covering terms for all cells in the
+//   query region (in addition to their ancestors).
+//
+//   Effectively, when the query region and a document region contain exactly
+//   the same cell, we have a choice about whether to treat this match as a
+//   "covering term" or an "ancestor term".  One choice minimizes query size
+//   while the other minimizes index size.
+
+#include "s2/s2region_term_indexer.h"
+
+#include <cctype>
+
+#include "s2/base/logging.h"
+#include "s2/s1angle.h"
+#include "s2/s2cap.h"
+#include "s2/s2cell_id.h"
+#include "s2/s2region.h"
+#include "absl/strings/str_cat.h"
+
+using absl::string_view;
+using std::vector;
+
+S2RegionTermIndexer::Options::Options() {
+  // Override the S2RegionCoverer defaults.
+  set_max_cells(8);
+  set_min_level(4);
+  set_max_level(16);
+  set_level_mod(1);
+}
+
+void S2RegionTermIndexer::Options::set_marker_character(char ch) {
+  S2_DCHECK(!std::isalnum(ch));
+  marker_ = std::string(1, ch);
+}
+
+S2RegionTermIndexer::S2RegionTermIndexer(const Options& options)
+    : options_(options) {
+}
+
+// Defaulted in the implementation to prevent inline bloat.
+S2RegionTermIndexer::S2RegionTermIndexer() = default;
+S2RegionTermIndexer::~S2RegionTermIndexer() = default;
+S2RegionTermIndexer::S2RegionTermIndexer(S2RegionTermIndexer&&) = default;
+S2RegionTermIndexer& S2RegionTermIndexer::operator=(S2RegionTermIndexer&&) =
+                                                   default;
+
+std::string S2RegionTermIndexer::GetTerm(TermType term_type, const S2CellId& id,
+                                    string_view prefix) const {
+  // There are generally more ancestor terms than covering terms, so we add
+  // the extra "marker" character to the covering terms to distinguish them.
+  if (term_type == TermType::ANCESTOR) {
+    return absl::StrCat(prefix, id.ToToken());
+  } else {
+    return absl::StrCat(prefix, options_.marker(), id.ToToken());
+  }
+}
+
+vector<std::string> S2RegionTermIndexer::GetIndexTerms(const S2Point& point,
+                                                  string_view prefix) {
+  // See the top of this file for an overview of the indexing strategy.
+  //
+  // The last cell generated by this loop is effectively the covering for
+  // the given point.  You might expect that this cell would be indexed as a
+  // covering term, but as an optimization we always index these cells as
+  // ancestor terms only.  This is possible because query regions will never
+  // contain a descendant of such cells.  Note that this is true even when
+  // max_level() != true_max_level() (see S2RegionCoverer::Options).
+
+  const S2CellId id(point);
+  vector<std::string> terms;
+  for (int level = options_.min_level(); level <= options_.max_level();
+       level += options_.level_mod()) {
+    terms.push_back(GetTerm(TermType::ANCESTOR, id.parent(level), prefix));
+  }
+  return terms;
+}
+
+vector<std::string> S2RegionTermIndexer::GetIndexTerms(const S2Region& region,
+                                                  string_view prefix) {
+  // Note that options may have changed since the last call.
+  *coverer_.mutable_options() = options_;
+  S2CellUnion covering = coverer_.GetCovering(region);
+  return GetIndexTermsForCanonicalCovering(covering, prefix);
+}
+
+vector<std::string> S2RegionTermIndexer::GetIndexTermsForCanonicalCovering(
+    const S2CellUnion& covering, string_view prefix) {
+  // See the top of this file for an overview of the indexing strategy.
+  //
+  // Cells in the covering are normally indexed as covering terms.  If we are
+  // optimizing for query time rather than index space, they are also indexed
+  // as ancestor terms (since this lets us reduce the number of terms in the
+  // query).  Finally, as an optimization we always index true_max_level()
+  // cells as ancestor cells only, since these cells have the special property
+  // that query regions will never contain a descendant of these cells.
+
+  S2_CHECK(!options_.index_contains_points_only());
+  if (google::DEBUG_MODE) {
+    *coverer_.mutable_options() = options_;
+    S2_CHECK(coverer_.IsCanonical(covering));
+  }
+  vector<std::string> terms;
+  S2CellId prev_id = S2CellId::None();
+  int true_max_level = options_.true_max_level();
+  for (S2CellId id : covering) {
+    // IsCanonical() already checks the following conditions, but we repeat
+    // them here for documentation purposes.
+    int level = id.level();
+    S2_DCHECK_GE(level, options_.min_level());
+    S2_DCHECK_LE(level, options_.max_level());
+    S2_DCHECK_EQ(0, (level - options_.min_level()) % options_.level_mod());
+
+    if (level < true_max_level) {
+      // Add a covering term for this cell.
+      terms.push_back(GetTerm(TermType::COVERING, id, prefix));
+    }
+    if (level == true_max_level || !options_.optimize_for_space()) {
+      // Add an ancestor term for this cell at the constrained level.
+      terms.push_back(GetTerm(TermType::ANCESTOR, id.parent(level), prefix));
+    }
+    // Finally, add ancestor terms for all the ancestors of this cell.
+    while ((level -= options_.level_mod()) >= options_.min_level()) {
+      S2CellId ancestor_id = id.parent(level);
+      if (prev_id != S2CellId::None() && prev_id.level() > level &&
+          prev_id.parent(level) == ancestor_id) {
+        break;  // We have already processed this cell and its ancestors.
+      }
+      terms.push_back(GetTerm(TermType::ANCESTOR, ancestor_id, prefix));
+    }
+    prev_id = id;
+  }
+  return terms;
+}
+
+vector<std::string> S2RegionTermIndexer::GetQueryTerms(const S2Point& point,
+                                                  string_view prefix) {
+  // See the top of this file for an overview of the indexing strategy.
+
+  const S2CellId id(point);
+  vector<std::string> terms;
+  // Recall that all true_max_level() cells are indexed only as ancestor terms.
+  int level = options_.true_max_level();
+  terms.push_back(GetTerm(TermType::ANCESTOR, id.parent(level), prefix));
+  if (options_.index_contains_points_only()) return terms;
+
+  // Add covering terms for all the ancestor cells.
+  for (; level >= options_.min_level(); level -= options_.level_mod()) {
+    terms.push_back(GetTerm(TermType::COVERING, id.parent(level), prefix));
+  }
+  return terms;
+}
+
+vector<std::string> S2RegionTermIndexer::GetQueryTerms(const S2Region& region,
+                                                  string_view prefix) {
+  // Note that options may have changed since the last call.
+  *coverer_.mutable_options() = options_;
+  S2CellUnion covering = coverer_.GetCovering(region);
+  return GetQueryTermsForCanonicalCovering(covering, prefix);
+}
+
+vector<std::string> S2RegionTermIndexer::GetQueryTermsForCanonicalCovering(
+    const S2CellUnion& covering, string_view prefix) {
+  // See the top of this file for an overview of the indexing strategy.
+
+  if (google::DEBUG_MODE) {
+    *coverer_.mutable_options() = options_;
+    S2_CHECK(coverer_.IsCanonical(covering));
+  }
+  vector<std::string> terms;
+  S2CellId prev_id = S2CellId::None();
+  int true_max_level = options_.true_max_level();
+  for (S2CellId id : covering) {
+    // IsCanonical() already checks the following conditions, but we repeat
+    // them here for documentation purposes.
+    int level = id.level();
+    S2_DCHECK_GE(level, options_.min_level());
+    S2_DCHECK_LE(level, options_.max_level());
+    S2_DCHECK_EQ(0, (level - options_.min_level()) % options_.level_mod());
+
+    // Cells in the covering are always queried as ancestor terms.
+    terms.push_back(GetTerm(TermType::ANCESTOR, id, prefix));
+
+    // If the index only contains points, there are no covering terms.
+    if (options_.index_contains_points_only()) continue;
+
+    // If we are optimizing for index space rather than query time, cells are
+    // also queried as covering terms (except for true_max_level() cells,
+    // which are indexed and queried as ancestor cells only).
+    if (options_.optimize_for_space() && level < true_max_level) {
+      terms.push_back(GetTerm(TermType::COVERING, id, prefix));
+    }
+    // Finally, add covering terms for all the ancestors of this cell.
+    while ((level -= options_.level_mod()) >= options_.min_level()) {
+      S2CellId ancestor_id = id.parent(level);
+      if (prev_id != S2CellId::None() && prev_id.level() > level &&
+          prev_id.parent(level) == ancestor_id) {
+        break;  // We have already processed this cell and its ancestors.
+      }
+      terms.push_back(GetTerm(TermType::COVERING, ancestor_id, prefix));
+    }
+    prev_id = id;
+  }
+  return terms;
+}
diff --git a/src/s2/s2region_term_indexer.h b/src/s2/s2region_term_indexer.h
new file mode 100644 (file)
index 0000000..ae71990
--- /dev/null
@@ -0,0 +1,299 @@
+// Copyright 2017 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// Author: ericv@google.com (Eric Veach)
+//
+// S2RegionTermIndexer is a helper class for adding spatial data to an
+// information retrieval system.  Such systems work by converting documents
+// into a collection of "index terms" (e.g., representing words or phrases),
+// and then building an "inverted index" that maps each term to a list of
+// documents (and document positions) where that term occurs.
+//
+// This class deals with the problem of converting spatial data into index
+// terms, which can then be indexed along with the other document information.
+//
+// Spatial data is represented using the S2Region type.  Useful S2Region
+// subtypes include:
+//
+//   S2Cap
+//    - a disc-shaped region
+//
+//   S2LatLngRect
+//    - a rectangle in latitude-longitude coordinates
+//
+//   S2Polyline
+//    - a polyline
+//
+//   S2Polygon
+//    - a polygon, possibly with multiple holes and/or shells
+//
+//   S2CellUnion
+//    - a region approximated as a collection of S2CellIds
+//
+//   S2ShapeIndexRegion
+//    - an arbitrary collection of points, polylines, and polygons
+//
+//   S2ShapeIndexBufferedRegion
+//    - like the above, but expanded by a given radius
+//
+//   S2RegionUnion, S2RegionIntersection
+//    - the union or intersection of arbitrary other regions
+//
+// So for example, if you want to query documents that are within 500 meters
+// of a polyline, you could use an S2ShapeIndexBufferedRegion containing the
+// polyline with a radius of 500 meters.
+//
+// Example usage:
+//
+//   // This class is intended to be used with an external key-value store,
+//   // but for this example will we use an unordered_map.  The key is an
+//   // index term, and the value is a set of document ids.
+//   std::unordered_map<std::string, std::vector<int>> index;
+//
+//   // Create an indexer that uses up to 10 cells to approximate each region.
+//   S2RegionTermIndexer::Options options;
+//   options.set_max_cells(10);
+//   S2RegionTermIndexer indexer(options);
+//
+//   // For this example, we index a disc-shaped region with a 10km radius.
+//   S2LatLng center = S2LatLng::FromDegrees(44.1, -56.235);
+//   S1Angle radius = S2Earth::ToAngle(util::units::Kilometers(10.0));
+//   S2Cap cap(center.ToPoint(), radius);
+//
+//   // Add the terms for this disc-shaped region to the index.
+//   for (const auto& term : indexer.GetIndexTerms(cap)) {
+//     index[term].push_back(kSomeDocumentId);
+//   }
+//
+//   // And now at query time: build a latitude-longitude rectangle.
+//   S2LatLngRect rect(S2LatLng::FromDegrees(-12.1, 10.2),
+//                     S2LatLng::FromDegrees(-9.2,  120.5));
+//
+//   // Convert the query region to a set of terms, and compute the union
+//   // of the document ids associated with those terms.
+//   std::set<int> doc_ids;
+//   for (const auto& term : indexer.GetQueryTerms(rect)) {
+//     doc_ids.insert(index[term].begin(), index[term].end());
+//   }
+//
+//   // "doc_ids" now contains all documents that intersect the query region,
+//   // along with some documents that nearly intersect it.  The results can
+//   // be further pruned if desired by retrieving the original regions that
+//   // were indexed (i.e., the document contents) and checking for exact
+//   // intersection with the query region.
+
+#ifndef S2_S2REGION_TERM_INDEXER_H_
+#define S2_S2REGION_TERM_INDEXER_H_
+
+#include <string>
+#include <vector>
+
+#include "s2/s2cell_union.h"
+#include "s2/s2region.h"
+#include "s2/s2region_coverer.h"
+#include "absl/strings/string_view.h"
+
+class S2RegionTermIndexer {
+ public:
+  // The following parameters control the tradeoffs between index size, query
+  // size, and accuracy (see s2region_coverer.h for details).
+  //
+  // IMPORTANT: You must use the same values for min_level(), max_level(), and
+  // level_mod() for both indexing and queries, otherwise queries will return
+  // incorrect results.  However, max_cells() can be changed as often as
+  // desired -- you can even change this parameter for every region.
+
+  class Options : public S2RegionCoverer::Options {
+   public:
+    Options();
+
+    ///////////////// Options Inherited From S2RegionCoverer ////////////////
+
+    // max_cells() controls the maximum number of cells when approximating
+    // each region.  This parameter value may be changed as often as desired
+    // (using mutable_options(), see below), e.g. to approximate some regions
+    // more accurately than others.
+    //
+    // Increasing this value during indexing will make indexes more accurate
+    // but larger.  Increasing this value for queries will make queries more
+    // accurate but slower.  (See s2region_coverer.h for details on how this
+    // parameter affects accuracy.)  For example, if you don't mind large
+    // indexes but want fast serving, it might be reasonable to set
+    // max_cells() == 100 during indexing and max_cells() == 8 for queries.
+    //
+    // DEFAULT: 8  (coarse approximations)
+    using S2RegionCoverer::Options::max_cells;
+    using S2RegionCoverer::Options::set_max_cells;
+
+    // min_level() and max_level() control the minimum and maximum size of the
+    // S2Cells used to approximate regions.  Setting these parameters
+    // appropriately can reduce the size of the index and speed up queries by
+    // reducing the number of terms needed.  For example, if you know that
+    // your query regions will rarely be less than 100 meters in width, then
+    // you could set max_level() as follows:
+    //
+    //   options.set_max_level(S2::kAvgEdge.GetClosestLevel(
+    //       S2Earth::MetersToRadians(100)));
+    //
+    // This restricts the index to S2Cells that are approximately 100 meters
+    // across or larger.  Similar, if you know that query regions will rarely
+    // be larger than 1000km across, then you could set min_level() similarly.
+    //
+    // If min_level() is set too high, then large regions may generate too
+    // many query terms.  If max_level() is set too low, then small query
+    // regions will not be able to discriminate which regions they intersect
+    // very precisely and may return many more candidates than necessary.
+    //
+    // If you have no idea about the scale of the regions being queried,
+    // it is perfectly fine to set min_level() == 0 and max_level() == 30
+    // (== S2::kMaxLevel).  The only drawback is that may result in a larger
+    // index and slower queries.
+    //
+    // The default parameter values are suitable for query regions ranging
+    // from about 100 meters to 3000 km across.
+    //
+    // DEFAULT: 4  (average cell width == 600km)
+    using S2RegionCoverer::Options::min_level;
+    using S2RegionCoverer::Options::set_min_level;
+
+    // DEFAULT: 16 (average cell width == 150m)
+    using S2RegionCoverer::Options::max_level;
+    using S2RegionCoverer::Options::set_max_level;
+
+    // Setting level_mod() to a value greater than 1 increases the effective
+    // branching factor of the S2Cell hierarchy by skipping some levels.  For
+    // example, if level_mod() == 2 then every second level is skipped (which
+    // increases the effective branching factor to 16).  You might want to
+    // consider doing this if your query regions are typically very small
+    // (e.g., single points) and you don't mind increasing the index size
+    // (since skipping levels will reduce the accuracy of cell coverings for a
+    // given max_cells() limit).
+    //
+    // DEFAULT: 1  (don't skip any cell levels)
+    using S2RegionCoverer::Options::level_mod;
+    using S2RegionCoverer::Options::set_level_mod;
+
+    // If your index will only contain points (rather than regions), be sure
+    // to set this flag.  This will generate smaller and faster queries that
+    // are specialized for the points-only case.
+    //
+    // With the default quality settings, this flag reduces the number of
+    // query terms by about a factor of two.  (The improvement gets smaller
+    // as max_cells() is increased, but there is really no reason not to use
+    // this flag if your index consists entirely of points.)
+    //
+    // DEFAULT: false
+    bool index_contains_points_only() const { return points_only_; }
+    void set_index_contains_points_only(bool value) { points_only_ = value; }
+
+    // If true, the index will be optimized for space rather than for query
+    // time.  With the default quality settings, this flag reduces the number
+    // of index terms and increases the number of query terms by the same
+    // factor (approximately 1.3).  The factor increases up to a limiting
+    // ratio of 2.0 as max_cells() is increased.
+    //
+    // CAVEAT: This option has no effect if the index contains only points.
+    //
+    // DEFAULT: false
+    bool optimize_for_space() const { return optimize_for_space_; }
+    void set_optimize_for_space(bool value) { optimize_for_space_ = value; }
+
+    // A non-alphanumeric character that is used internally to distinguish
+    // between two different types of terms (by adding this character).
+    //
+    // REQUIRES: "ch" is non-alphanumeric.
+    // DEFAULT: '$'
+    const std::string& marker() const { return marker_; }
+    char marker_character() const { return marker_[0]; }
+    void set_marker_character(char ch);
+
+   private:
+    bool points_only_ = false;
+    bool optimize_for_space_ = false;
+    std::string marker_ = std::string(1, '$');
+  };
+
+  // Default constructor.  Options can be set using mutable_options().
+  S2RegionTermIndexer();
+  ~S2RegionTermIndexer();
+
+  // Constructs an S2RegionTermIndexer with the given options.
+  explicit S2RegionTermIndexer(const Options& options);
+
+  // S2RegionTermIndexer is movable but not copyable.
+  S2RegionTermIndexer(const S2RegionTermIndexer&) = delete;
+  S2RegionTermIndexer& operator=(const S2RegionTermIndexer&) = delete;
+  S2RegionTermIndexer(S2RegionTermIndexer&&);
+  S2RegionTermIndexer& operator=(S2RegionTermIndexer&&);
+
+  // Returns the current options.  Options can be modifed between calls.
+  const Options& options() const { return options_; }
+  Options* mutable_options() { return &options_; }
+
+  // Converts the given region into a set of terms for indexing.  Terms
+  // consist of lowercase letters, numbers, '$', and an optional prefix.
+  //
+  // "prefix" is a unique prefix used to distinguish S2 terms from other terms
+  // in the repository.  The prefix may also be used to index documents with
+  // multiple types of location information (e.g. store footprint, entrances,
+  // parking lots, etc).  The prefix should be kept short since it is
+  // prepended to every term.
+  std::vector<std::string> GetIndexTerms(const S2Region& region,
+                                    absl::string_view prefix);
+
+  // Converts a given query region into a set of terms.  If you compute the
+  // union of all the documents associated with these terms, the result will
+  // include all documents whose index region intersects the query region.
+  //
+  // "prefix" should match the corresponding value used when indexing.
+  std::vector<std::string> GetQueryTerms(const S2Region& region,
+                                    absl::string_view prefix);
+
+  // Convenience methods that accept an S2Point rather than S2Region.  (These
+  // methods are also faster.)
+  //
+  // Note that you can index an S2LatLng by converting it to an S2Point first:
+  //     auto terms = GetIndexTerms(S2Point(latlng), ...);
+  std::vector<std::string> GetIndexTerms(const S2Point& point,
+                                    absl::string_view prefix);
+  std::vector<std::string> GetQueryTerms(const S2Point& point,
+                                    absl::string_view prefix);
+
+  // Low-level methods that accept an S2CellUnion covering of the region to be
+  // indexed or queried.
+  //
+  // REQUIRES: "covering" satisfies the S2RegionCoverer::Options for this
+  //           class (i.e., max_cells, min_level, max_level, and level_mod).
+  //
+  // If you have a covering that was computed using different options, then
+  // you can either call the regular S2Region methods (since S2CellUnion is a
+  // type of S2Region), or "canonicalize" the covering first by calling
+  // S2RegionCoverer::CanonicalizeCovering() with the same options.
+  std::vector<std::string> GetIndexTermsForCanonicalCovering(
+      const S2CellUnion& covering, absl::string_view prefix);
+  std::vector<std::string> GetQueryTermsForCanonicalCovering(
+      const S2CellUnion& covering, absl::string_view prefix);
+
+ private:
+  enum TermType { ANCESTOR, COVERING };
+
+  std::string GetTerm(TermType term_type, const S2CellId& id,
+                 absl::string_view prefix) const;
+
+  Options options_;
+  S2RegionCoverer coverer_;
+};
+
+#endif  // S2_S2REGION_TERM_INDEXER_H_
diff --git a/src/s2/s2region_union.cc b/src/s2/s2region_union.cc
new file mode 100644 (file)
index 0000000..cd104b0
--- /dev/null
@@ -0,0 +1,90 @@
+// Copyright 2005 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// Author: ericv@google.com (Eric Veach)
+
+#include "s2/s2region_union.h"
+
+#include "s2/s2cap.h"
+#include "s2/s2latlng_rect.h"
+
+using std::vector;
+
+S2RegionUnion::S2RegionUnion(vector<std::unique_ptr<S2Region>> regions) {
+  Init(std::move(regions));
+}
+
+void S2RegionUnion::Init(vector<std::unique_ptr<S2Region>> regions) {
+  S2_DCHECK(regions_.empty());
+  regions_ = std::move(regions);
+}
+
+S2RegionUnion::S2RegionUnion(const S2RegionUnion& src)
+  : regions_(src.num_regions()) {
+  for (int i = 0; i < num_regions(); ++i) {
+    regions_[i].reset(src.region(i)->Clone());
+  }
+}
+
+vector<std::unique_ptr<S2Region>> S2RegionUnion::Release() {
+  vector<std::unique_ptr<S2Region>> result;
+  result.swap(regions_);
+  return result;
+}
+
+void S2RegionUnion::Add(std::unique_ptr<S2Region> region) {
+  regions_.push_back(std::move(region));
+}
+
+S2RegionUnion* S2RegionUnion::Clone() const {
+  return new S2RegionUnion(*this);
+}
+
+S2Cap S2RegionUnion::GetCapBound() const {
+  // TODO(ericv): This could be optimized to return a tighter bound,
+  // but doesn't seem worth it unless profiling shows otherwise.
+  return GetRectBound().GetCapBound();
+}
+
+S2LatLngRect S2RegionUnion::GetRectBound() const {
+  S2LatLngRect result = S2LatLngRect::Empty();
+  for (int i = 0; i < num_regions(); ++i) {
+    result = result.Union(region(i)->GetRectBound());
+  }
+  return result;
+}
+
+bool S2RegionUnion::Contains(const S2Cell& cell) const {
+  // Note that this method is allowed to return false even if the cell
+  // is contained by the region.
+  for (int i = 0; i < num_regions(); ++i) {
+    if (region(i)->Contains(cell)) return true;
+  }
+  return false;
+}
+
+bool S2RegionUnion::Contains(const S2Point& p) const {
+  for (int i = 0; i < num_regions(); ++i) {
+    if (region(i)->Contains(p)) return true;
+  }
+  return false;
+}
+
+bool S2RegionUnion::MayIntersect(const S2Cell& cell) const {
+  for (int i = 0; i < num_regions(); ++i) {
+    if (region(i)->MayIntersect(cell)) return true;
+  }
+  return false;
+}
diff --git a/src/s2/s2region_union.h b/src/s2/s2region_union.h
new file mode 100644 (file)
index 0000000..1ff0cfe
--- /dev/null
@@ -0,0 +1,83 @@
+// Copyright 2005 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// Author: ericv@google.com (Eric Veach)
+
+#ifndef S2_S2REGION_UNION_H_
+#define S2_S2REGION_UNION_H_
+
+#include <memory>
+#include <vector>
+
+#include "s2/base/logging.h"
+#include "s2/_fp_contract_off.h"
+#include "s2/s2region.h"
+#include "absl/base/macros.h"
+
+class Decoder;
+class Encoder;
+class S2Cap;
+class S2Cell;
+class S2LatLngRect;
+
+// An S2RegionUnion represents a union of possibly overlapping regions.
+// It is convenient for computing a covering of a set of regions.
+class S2RegionUnion final : public S2Region {
+ public:
+  // Create an empty region.  Can be made non-empty by calling Init() or Add().
+  S2RegionUnion() = default;
+
+  // Create a region representing the union of the given regions.
+  explicit S2RegionUnion(std::vector<std::unique_ptr<S2Region>> regions);
+
+  // Use {} instead of = default to work around gcc bug.
+  ~S2RegionUnion() override {}
+
+  // Initialize region by taking ownership of the given regions.
+  void Init(std::vector<std::unique_ptr<S2Region>> regions);
+
+  // Releases ownership of the regions of this union and returns them,
+  // leaving this region empty.
+  std::vector<std::unique_ptr<S2Region>> Release();
+
+  // Add the given region to the union.  This method can be called repeatedly
+  // as an alternative to Init().
+  void Add(std::unique_ptr<S2Region> region);
+
+  // Accessor methods.
+  int num_regions() const { return regions_.size(); }
+  const S2Region* region(int i) const { return regions_[i].get(); }
+
+  ////////////////////////////////////////////////////////////////////////
+  // S2Region interface (see s2region.h for details):
+
+  S2RegionUnion* Clone() const override;
+  S2Cap GetCapBound() const override;
+  S2LatLngRect GetRectBound() const override;
+  bool Contains(const S2Point& p) const override;
+  bool Contains(const S2Cell& cell) const override;
+  bool MayIntersect(const S2Cell& cell) const override;
+
+ private:
+  // Internal copy constructor used only by Clone() that makes a deep copy of
+  // its argument.
+  S2RegionUnion(const S2RegionUnion& src);
+
+  std::vector<std::unique_ptr<S2Region>> regions_;
+
+  void operator=(const S2RegionUnion&) = delete;
+};
+
+#endif  // S2_S2REGION_UNION_H_
diff --git a/src/s2/s2shape.h b/src/s2/s2shape.h
new file mode 100644 (file)
index 0000000..8821919
--- /dev/null
@@ -0,0 +1,283 @@
+// Copyright 2012 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// Author: ericv@google.com (Eric Veach)
+
+#ifndef S2_S2SHAPE_H_
+#define S2_S2SHAPE_H_
+
+#include "s2/base/integral_types.h"
+#include "s2/s2point.h"
+#include "s2/s2pointutil.h"
+
+// The purpose of S2Shape is to represent polygonal geometry in a flexible
+// way.  It is organized as a collection of edges that optionally defines an
+// interior.  All geometry represented by an S2Shape must have the same
+// dimension, which means that an S2Shape can represent either a set of
+// points, a set of polylines, or a set of polygons.
+//
+// S2Shape is defined as an abstract base class in order to give clients
+// control over the underlying data representation.  Sometimes an S2Shape does
+// not have any data of its own, but instead "wraps" some other class.  There
+// are various useful subtypes defined in *_shape.h, and some S2 classes also
+// have a nested "Shape" class (e.g., S2Polygon::Shape).  It is easy for
+// clients to implement their own subtypes, since the interface is minimal.
+//
+// S2Shape operations are typically defined on S2ShapeIndex objects rather
+// than individual shapes.  An S2ShapeIndex is simply a collection of
+// S2Shapes, possibly of different dimensions (e.g. 10 points and 3 polygons),
+// organized into a data structure for efficient edge access.
+//
+// The edges of an S2Shape are identified by a contiguous range of "edge ids"
+// starting at 0.  The edges are further subdivided into "chains", where each
+// chain consists of a sequence of edges connected end-to-end (a polyline).
+// For example, an S2Shape representing two polylines AB and CDE would have
+// three edges (AB, CD, DE) grouped into two chains: (AB) and (CD, DE).
+// Similarly, an S2Shape representing 5 points would have 5 chains consisting
+// of one edge each.
+//
+// S2Shape has methods that allow edges to be accessed either using the global
+// numbering (edge id) or within a particular chain.  The global numbering is
+// sufficient for most purposes, but the chain representation is useful for
+// certain algorithms such as intersection (see S2BooleanOperation).
+class S2Shape {
+ public:
+  // An edge, consisting of two vertices "v0" and "v1".  Zero-length edges are
+  // allowed, and can be used to represent points.
+  struct Edge {
+    S2Point v0, v1;
+    Edge() = default;
+    Edge(const S2Point& _v0, const S2Point& _v1) : v0(_v0), v1(_v1) {}
+
+    // TODO(ericv): Define all 6 comparisons.
+    friend bool operator==(const Edge& x, const Edge& y) {
+      return x.v0 == y.v0 && x.v1 == y.v1;
+    }
+    friend bool operator<(const Edge& x, const Edge& y) {
+      return x.v0 < y.v0 || (x.v0 == y.v0 && x.v1 < y.v1); }
+  };
+
+  // A range of edge ids corresponding to a chain of zero or more connected
+  // edges, specified as a (start, length) pair.  The chain is defined to
+  // consist of edge ids {start, start + 1, ..., start + length - 1}.
+  struct Chain {
+    int32 start, length;
+    Chain() = default;
+    Chain(int32 _start, int32 _length) : start(_start), length(_length) {}
+
+    friend bool operator==(const Chain& x, const Chain& y) {
+      return x.start == y.start && x.length == y.length;
+    }
+  };
+
+  // The position of an edge within a given edge chain, specified as a
+  // (chain_id, offset) pair.  Chains are numbered sequentially starting from
+  // zero, and offsets are measured from the start of each chain.
+  struct ChainPosition {
+    int32 chain_id, offset;
+    ChainPosition() = default;
+    ChainPosition(int32 _chain_id, int32 _offset)
+        : chain_id(_chain_id), offset(_offset) {}
+
+    friend bool operator==(const ChainPosition& x, const ChainPosition& y) {
+       return x.chain_id == y.chain_id && x.offset == y.offset;
+    }
+  };
+
+  // A ReferencePoint consists of a point P and a boolean indicating whether P
+  // is contained by a particular shape.
+  struct ReferencePoint {
+    S2Point point;
+    bool contained;
+    ReferencePoint() = default;
+    ReferencePoint(S2Point _point, bool _contained)
+        : point(_point), contained(_contained) {}
+
+    // Returns a ReferencePoint with the given "contained" value and a default
+    // "point".  It should be used when all points or no points are contained.
+    static ReferencePoint Contained(bool _contained) {
+      return ReferencePoint(S2::Origin(), _contained);
+    }
+
+    friend bool operator==(const ReferencePoint& x, const ReferencePoint& y) {
+      return x.point == y.point && x.contained == y.contained;
+    }
+  };
+
+  // A 32-bit tag that can be used to identify the type of an encoded S2Shape.
+  // All encodable types have a non-zero type tag.  The tag associated with a
+  // given shape type can be accessed as Shape::kTypeTag, while the tag
+  // associated with a given object can be accessed as shape.type_tag().
+  //
+  // Type tags in the range 0..8191 are reserved for use by the S2 library.
+  using TypeTag = uint32;
+
+  // Indicates that a given S2Shape type cannot be encoded.
+  static constexpr TypeTag kNoTypeTag = 0;
+
+  // The minimum allowable tag for user-defined S2Shape types.
+  static constexpr TypeTag kMinUserTypeTag = 8192;
+
+  S2Shape() : id_(-1) {}
+  virtual ~S2Shape() {}
+
+  // Returns the number of edges in this shape.  Edges have ids ranging from 0
+  // to num_edges() - 1.
+  virtual int num_edges() const = 0;
+
+  // Returns the endpoints of the given edge id.
+  //
+  // REQUIRES: 0 <= id < num_edges()
+  virtual Edge edge(int edge_id) const = 0;
+
+  // Returns the dimension of the geometry represented by this shape.
+  //
+  //  0 - Point geometry.  Each point is represented as a degenerate edge.
+  //
+  //  1 - Polyline geometry.  Polyline edges may be degenerate.  A shape may
+  //      represent any number of polylines.  Polylines edges may intersect.
+  //
+  //  2 - Polygon geometry.  Edges should be oriented such that the polygon
+  //      interior is always on the left.  In theory the edges may be returned
+  //      in any order, but typically the edges are organized as a collection
+  //      of edge chains where each chain represents one polygon loop.
+  //      Polygons may have degeneracies (e.g., degenerate edges or sibling
+  //      pairs consisting of an edge and its corresponding reversed edge).
+  //      A polygon loop may also be full (containing all points on the
+  //      sphere); by convention this is represented as a chain with no edges.
+  //      (See S2LaxPolygonShape for details.)
+  //
+  // Note that this method allows degenerate geometry of different dimensions
+  // to be distinguished, e.g. it allows a point to be distinguished from a
+  // polyline or polygon that has been simplified to a single point.
+  virtual int dimension() const = 0;
+
+  // Returns true if the shape contains no points.  (Note that the full
+  // polygon is represented as a chain with zero edges.)
+  bool is_empty() const {
+    return num_edges() == 0 && (dimension() < 2 || num_chains() == 0);
+  }
+  // Returns true if the shape contains all points on the sphere.
+  bool is_full() const {
+    return num_edges() == 0 && dimension() == 2 && num_chains() > 0;
+  }
+
+  // Returns an arbitrary point P along with a boolean indicating whether P is
+  // contained by the shape.  (The boolean value must be false for shapes that
+  // do not have an interior.)
+  //
+  // This ReferencePoint may then be used to compute the containment of other
+  // points by counting edge crossings.
+  virtual ReferencePoint GetReferencePoint() const = 0;
+
+  // Returns the number of contiguous edge chains in the shape.  For example,
+  // a shape whose edges are [AB, BC, CD, AE, EF] would consist of two chains
+  // (AB,BC,CD and AE,EF).  Every chain is assigned a "chain id" numbered
+  // sequentially starting from zero.
+  //
+  // Note that it is always acceptable to implement this method by returning
+  // num_edges() (i.e. every chain consists of a single edge), but this may
+  // reduce the efficiency of some algorithms.
+  virtual int num_chains() const = 0;
+
+  // Returns the range of edge ids corresponding to the given edge chain.  The
+  // edge chains must form contiguous, non-overlapping ranges that cover the
+  // entire range of edge ids.  This is spelled out more formally below:
+  //
+  // REQUIRES: 0 <= i < num_chains()
+  // REQUIRES: chain(i).length >= 0, for all i
+  // REQUIRES: chain(0).start == 0
+  // REQUIRES: chain(i).start + chain(i).length == chain(i+1).start,
+  //           for i < num_chains() - 1
+  // REQUIRES: chain(i).start + chain(i).length == num_edges(),
+  //           for i == num_chains() - 1
+  virtual Chain chain(int chain_id) const = 0;
+
+  // Returns the edge at offset "offset" within edge chain "chain_id".
+  // Equivalent to "shape.edge(shape.chain(chain_id).start + offset)"
+  // but may be more efficient.
+  virtual Edge chain_edge(int chain_id, int offset) const = 0;
+
+  // Finds the chain containing the given edge, and returns the position of
+  // that edge as a (chain_id, offset) pair.
+  //
+  // REQUIRES: shape.chain(pos.chain_id).start + pos.offset == edge_id
+  // REQUIRES: shape.chain(pos.chain_id + 1).start > edge_id
+  //
+  // where     pos == shape.chain_position(edge_id).
+  virtual ChainPosition chain_position(int edge_id) const = 0;
+
+  // A unique id assigned to this shape by S2ShapeIndex.  Shape ids are
+  // assigned sequentially starting from 0 in the order shapes are added.
+  //
+  // TODO(ericv): Consider eliminating this method.
+  int id() const { return id_; }
+
+  // Returns an integer that can be used to identify the type of an encoded
+  // S2Shape (see TypeTag above).
+  virtual TypeTag type_tag() const { return kNoTypeTag; }
+
+  // Virtual methods that return pointers of your choice.  These methods are
+  // intended to help with the problem of attaching additional data to S2Shape
+  // objects.  For example, you could return a pointer to a source object, or
+  // a pointer to a bundle of additional data allocated with the S2Shape.
+  // Because this method exists in all S2Shapes, you can override it in each
+  // type of shape you have and call it without knowing the concrete subtype.
+  // For example, if you have polyline and polygon shapes, you can do this:
+  //
+  //   class MyPolyline : public S2Polyline::Shape {
+  //    public:
+  //     virtual void* mutable_user_data() { return &my_data_; }
+  //    private:
+  //     MyData my_data_;
+  //   };
+  //   class MyPolygon : public S2Polygon::Shape {
+  //    public:
+  //     virtual void* mutable_user_data() { return &my_data_; }
+  //    private:
+  //     MyData my_data_;
+  //   };
+  //   ...
+  //   S2Shape* shape = index.shape(id);
+  //   const MyData* data = static_cast<const MyData*>(shape->user_data());
+  //
+  // This is not the only way to map from an S2Shape back to your source
+  // data.  Other reasonable techniques include:
+  //
+  //  - Every shape has an id() assigned by S2ShapeIndex.  Ids are assigned
+  //    sequentially starting from 0 in the order the shapes are added to the
+  //    index.  You can use this id to look up arbitrary data stored in your
+  //    own vector.
+  //
+  //  - If all of your shapes are the same type, then you can create your own
+  //    subclass of some existing S2Shape type (such as S2Polyline::Shape) and
+  //    add your own methods and fields.  You can access this data by
+  //    downcasting the S2Shape pointers returned by S2ShapeIndex methods.
+  virtual const void* user_data() const { return nullptr; }
+  virtual void* mutable_user_data() { return nullptr; }
+
+ private:
+  // Next available type tag available for use within the S2 library: 6.
+
+  friend class EncodedS2ShapeIndex;
+  friend class MutableS2ShapeIndex;
+
+  int id_;  // Assigned by S2ShapeIndex when the shape is added.
+
+  S2Shape(const S2Shape&) = delete;
+  void operator=(const S2Shape&) = delete;
+};
+
+#endif  // S2_S2SHAPE_H_
diff --git a/src/s2/s2shape_index.cc b/src/s2/s2shape_index.cc
new file mode 100644 (file)
index 0000000..b523f11
--- /dev/null
@@ -0,0 +1,321 @@
+// Copyright 2012 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// Author: ericv@google.com (Eric Veach)
+
+#include "s2/s2shape_index.h"
+
+bool S2ClippedShape::ContainsEdge(int id) const {
+  // Linear search is fast because the number of edges per shape is typically
+  // very small (less than 10).
+  for (int e = 0; e < num_edges(); ++e) {
+    if (edge(e) == id) return true;
+  }
+  return false;
+}
+
+S2ShapeIndexCell::~S2ShapeIndexCell() {
+  // Free memory for all shapes owned by this cell.
+  for (S2ClippedShape& s : shapes_)
+    s.Destruct();
+  shapes_.clear();
+}
+
+const S2ClippedShape*
+S2ShapeIndexCell::find_clipped(int shape_id) const {
+  // Linear search is fine because the number of shapes per cell is typically
+  // very small (most often 1), and is large only for pathological inputs
+  // (e.g. very deeply nested loops).
+  for (const auto& s : shapes_) {
+    if (s.shape_id() == shape_id) return &s;
+  }
+  return nullptr;
+}
+
+// Allocate room for "n" additional clipped shapes in the cell, and return a
+// pointer to the first new clipped shape.  Expects that all new clipped
+// shapes will have a larger shape id than any current shape, and that shapes
+// will be added in increasing shape id order.
+S2ClippedShape* S2ShapeIndexCell::add_shapes(int n) {
+  int size = shapes_.size();
+  shapes_.resize(size + n);
+  return &shapes_[size];
+}
+
+void S2ShapeIndexCell::Encode(int num_shape_ids, Encoder* encoder) const {
+  // The encoding is designed to be especially compact in certain common
+  // situations:
+  //
+  // 1. The S2ShapeIndex contains exactly one shape.
+  //
+  // 2. The S2ShapeIndex contains more than one shape, but a particular index
+  //    cell contains only one shape (num_clipped == 1).
+  //
+  // 3. The edge ids for a given shape in a cell form a contiguous range.
+  //
+  // The details were optimized by constructing an S2ShapeIndex for each
+  // feature in Google's geographic repository and measuring their total
+  // encoded size.  The MutableS2ShapeIndex encoding (of which this function
+  // is just one part) uses an average of 1.88 bytes per vertex for features
+  // consisting of polygons or polylines.
+  //
+  // Note that this code does not bother handling num_shapes >= 2**28 or
+  // num_edges >= 2**29.  This could be fixed using varint64 in a few more
+  // places, but if a single cell contains this many shapes or edges then we
+  // have bigger problems than just the encoding format :)
+  if (num_shape_ids == 1) {
+    // If the entire S2ShapeIndex contains just one shape, then we don't need
+    // to encode any shape ids.  This is a very important and common case.
+    S2_DCHECK_EQ(num_clipped(), 1);  // Index invariant: no empty cells.
+    const S2ClippedShape& clipped = this->clipped(0);
+    S2_DCHECK_EQ(clipped.shape_id(), 0);
+    int n = clipped.num_edges();
+    encoder->Ensure(Varint::kMax64 + n * Varint::kMax32);
+    if (n >= 2 && n <= 17 && clipped.edge(n - 1) - clipped.edge(0) == n - 1) {
+      // The cell contains a contiguous range of edges (*most common case*).
+      // If the starting edge id is small then we can encode the cell in one
+      // byte.  (The n == 0 and n == 1 cases are encoded compactly below.)
+      // This encoding uses a 1-bit tag because it is by far the most common.
+      //
+      // Encoding: bit 0: 0
+      //           bit 1: contains_center
+      //           bits 2-5: (num_edges - 2)
+      //           bits 6+: edge_id
+      encoder->put_varint64(static_cast<uint64>(clipped.edge(0)) << 6 |
+                            (n - 2) << 2 | clipped.contains_center() << 1 | 0);
+    } else if (n == 1) {
+      // The cell contains only one edge.  For edge ids up to 15, we can
+      // encode the cell in a single byte.
+      //
+      // Encoding: bits 0-1: 1
+      //           bit 2: contains_center
+      //           bits 3+: edge_id
+      encoder->put_varint64(static_cast<uint64>(clipped.edge(0)) << 3 |
+                            clipped.contains_center() << 2 | 1);
+    } else {
+      // General case (including n == 0, which is encoded compactly here).
+      //
+      // Encoding: bits 0-1: 3
+      //           bit 2: contains_center
+      //           bits 3+: num_edges
+      encoder->put_varint64(static_cast<uint64>(n) << 3 |
+                            clipped.contains_center() << 2 | 3);
+      EncodeEdges(clipped, encoder);
+    }
+  } else {
+    if (num_clipped() > 1) {
+      // The cell contains more than one shape.  The tag for this encoding
+      // must be distinguishable from the cases encoded below.  We can afford
+      // to use a 3-bit tag because num_clipped is generally small.
+      encoder->Ensure(Varint::kMax32);
+      encoder->put_varint32((num_clipped() << 3) | 3);
+    }
+    // The shape ids are delta-encoded.
+    int shape_id_base = 0;
+    for (int j = 0; j < num_clipped(); ++j) {
+      const S2ClippedShape& clipped = this->clipped(j);
+      S2_DCHECK_GE(clipped.shape_id(), shape_id_base);
+      int shape_delta = clipped.shape_id() - shape_id_base;
+      shape_id_base = clipped.shape_id() + 1;
+
+      // Like the code above except that we also need to encode shape_id(s).
+      // Because of this some choices are slightly different.
+      int n = clipped.num_edges();
+      encoder->Ensure((n + 2) * Varint::kMax32);
+      if (n >= 1 && n <= 16 && clipped.edge(n - 1) - clipped.edge(0) == n - 1) {
+        // The clipped shape has a contiguous range of up to 16 edges.  This
+        // encoding uses a 1-bit tag because it is by far the most common.
+        //
+        // Encoding: bit 0: 0
+        //           bit 1: contains_center
+        //           bits 2+: edge_id
+        // Next value: bits 0-3: (num_edges - 1)
+        //             bits 4+: shape_delta
+        encoder->put_varint32(clipped.edge(0) << 2 |
+                              clipped.contains_center() << 1 | 0);
+        encoder->put_varint32(shape_delta << 4 | (n - 1));
+      } else if (n == 0) {
+        // Special encoding for clipped shapes with no edges.  Such shapes are
+        // common in polygon interiors.  This encoding uses a 3-bit tag in
+        // order to leave more bits available for the other encodings.
+        //
+        // NOTE(ericv): When num_clipped > 1, this tag could be 2 bits
+        // (because the tag used to indicate num_clipped > 1 can't appear).
+        // Alternatively, that tag can be considered reserved for future use.
+        //
+        // Encoding: bits 0-2: 7
+        //           bit 3: contains_center
+        //           bits 4+: shape_delta
+        encoder->put_varint32(shape_delta << 4 |
+                              clipped.contains_center() << 3 | 7);
+      } else {
+        // General case.  This encoding uses a 2-bit tag, and the first value
+        // typically is encoded into one byte.
+        //
+        // Encoding: bits 0-1: 1
+        //           bit 2: contains_center
+        //           bits 3+: (num_edges - 1)
+        // Next value: shape_delta
+        encoder->put_varint32((n - 1) << 3 |
+                              clipped.contains_center() << 2 | 1);
+        encoder->put_varint32(shape_delta);
+        EncodeEdges(clipped, encoder);
+      }
+    }
+  }
+}
+
+bool S2ShapeIndexCell::Decode(int num_shape_ids, Decoder* decoder) {
+  // This function inverts the encodings documented above.
+  if (num_shape_ids == 1) {
+    // Entire S2ShapeIndex contains only one shape.
+    S2ClippedShape* clipped = add_shapes(1);
+    uint64 header;
+    if (!decoder->get_varint64(&header)) return false;
+    if ((header & 1) == 0) {
+      // The cell contains a contiguous range of edges.
+      int num_edges = ((header >> 2) & 15) + 2;
+      clipped->Init(0 /*shape_id*/, num_edges);
+      clipped->set_contains_center((header & 2) != 0);
+      for (int i = 0, edge_id = header >> 6; i < num_edges; ++i) {
+        clipped->set_edge(i, edge_id + i);
+      }
+      return true;
+    }
+    if ((header & 2) == 0) {
+      // The cell contains a single edge.
+      clipped->Init(0 /*shape_id*/, 1 /*num_edges*/);
+      clipped->set_contains_center((header & 4) != 0);
+      clipped->set_edge(0, header >> 3);
+      return true;
+    }
+    // The cell contains some other combination of edges.
+    int num_edges = header >> 3;
+    clipped->Init(0 /*shape_id*/, num_edges);
+    clipped->set_contains_center((header & 4) != 0);
+    return DecodeEdges(num_edges, clipped, decoder);
+  }
+  // S2ShapeIndex contains more than one shape.
+  uint32 header;
+  if (!decoder->get_varint32(&header)) return false;
+  int num_clipped = 1;
+  if ((header & 7) == 3) {
+    // This cell contains more than one shape.
+    num_clipped = header >> 3;
+    if (!decoder->get_varint32(&header)) return false;
+  }
+  int shape_id = 0;
+  S2ClippedShape* clipped = add_shapes(num_clipped);
+  for (int j = 0; j < num_clipped; ++j, ++clipped, ++shape_id) {
+    if (j > 0 && !decoder->get_varint32(&header)) return false;
+    if ((header & 1) == 0) {
+      // The clipped shape contains a contiguous range of edges.
+      uint32 shape_id_count = 0;
+      if (!decoder->get_varint32(&shape_id_count)) return false;
+      shape_id += shape_id_count >> 4;
+      int num_edges = (shape_id_count & 15) + 1;
+      clipped->Init(shape_id, num_edges);
+      clipped->set_contains_center((header & 2) != 0);
+      for (int i = 0, edge_id = header >> 2; i < num_edges; ++i) {
+        clipped->set_edge(i, edge_id + i);
+      }
+    } else if ((header & 7) == 7) {
+      // The clipped shape has no edges.
+      shape_id += header >> 4;
+      clipped->Init(shape_id, 0);
+      clipped->set_contains_center((header & 8) != 0);
+    } else {
+      // The clipped shape contains some other combination of edges.
+      S2_DCHECK_EQ(header & 3, 1);
+      uint32 shape_delta;
+      if (!decoder->get_varint32(&shape_delta)) return false;
+      shape_id += shape_delta;
+      int num_edges = (header >> 3) + 1;
+      clipped->Init(shape_id, num_edges);
+      clipped->set_contains_center((header & 4) != 0);
+      if (!DecodeEdges(num_edges, clipped, decoder)) return false;
+    }
+  }
+  return true;
+}
+
+inline void S2ShapeIndexCell::EncodeEdges(const S2ClippedShape& clipped,
+                                          Encoder* encoder) {
+  // Each entry is an (edge_id, count) pair representing a contiguous range of
+  // edges.  The edge ids are delta-encoded such that 0 represents the minimum
+  // valid next edge id.
+  //
+  // Encoding: if bits 0-2 < 7: encodes (count - 1)
+  //            - bits 3+: edge delta
+  //           if bits 0-2 == 7:
+  //            - bits 3+ encode (count - 8)
+  //            - Next value is edge delta
+  //
+  // No count is encoded for the last edge (saving 3 bits).
+  int edge_id_base = 0;
+  int num_edges = clipped.num_edges();
+  for (int i = 0; i < num_edges; ++i) {
+    int edge_id = clipped.edge(i);
+    S2_DCHECK_GE(edge_id, edge_id_base);
+    int delta = edge_id - edge_id_base;
+    if (i + 1 == num_edges) {
+      // This is the last edge; no need to encode an edge count.
+      encoder->put_varint32(delta);
+    } else {
+      // Count the edges in this contiguous range.
+      int count = 1;
+      for (; i + 1 < num_edges && clipped.edge(i + 1) == edge_id + count; ++i) {
+        ++count;
+      }
+      if (count < 8) {
+        // Count is encoded in low 3 bits of delta.
+        encoder->put_varint32(delta << 3 | (count - 1));
+      } else {
+        // Count and delta are encoded separately.
+        encoder->put_varint32((count - 8) << 3 | 7);
+        encoder->put_varint32(delta);
+      }
+      edge_id_base = edge_id + count;
+    }
+  }
+}
+
+inline bool S2ShapeIndexCell::DecodeEdges(int num_edges,
+                                          S2ClippedShape* clipped,
+                                          Decoder* decoder) {
+  // This function inverts the encodings documented above.
+  int32 edge_id = 0;
+  for (int i = 0; i < num_edges; ) {
+    uint32 delta;
+    if (!decoder->get_varint32(&delta)) return false;
+    if (i + 1 == num_edges) {
+      // The last edge is encoded without an edge count.
+      clipped->set_edge(i++, edge_id + delta);
+    } else {
+      // Otherwise decode the count and edge delta.
+      uint32 count = (delta & 7) + 1;
+      delta >>= 3;
+      if (count == 8) {
+        count = delta + 8;
+        if (!decoder->get_varint32(&delta)) return false;
+      }
+      edge_id += delta;
+      for (; count > 0; --count, ++i, ++edge_id) {
+        clipped->set_edge(i, edge_id);
+      }
+    }
+  }
+  return true;
+}
diff --git a/src/s2/s2shape_index.h b/src/s2/s2shape_index.h
new file mode 100644 (file)
index 0000000..e44de6c
--- /dev/null
@@ -0,0 +1,781 @@
+// Copyright 2012 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// Author: ericv@google.com (Eric Veach)
+//
+// S2ShapeIndex is an abstract base class for indexing polygonal geometry in
+// memory.  The main documentation is with the class definition below.
+// (Some helper classes are defined first.)
+
+#ifndef S2_S2SHAPE_INDEX_H_
+#define S2_S2SHAPE_INDEX_H_
+
+#include <array>
+#include <atomic>
+#include <cstddef>
+#include <iterator>
+#include <memory>
+#include <utility>
+#include <vector>
+
+#include "s2/base/integral_types.h"
+#include "s2/base/logging.h"
+#include "s2/base/mutex.h"
+#include "s2/base/spinlock.h"
+#include "s2/_fp_contract_off.h"
+#include "s2/s2cell_id.h"
+#include "s2/s2pointutil.h"
+#include "s2/s2shape.h"
+#include "absl/base/macros.h"
+#include "absl/base/thread_annotations.h"
+#include "absl/memory/memory.h"
+#include "s2/util/gtl/compact_array.h"
+
+class R1Interval;
+class S2PaddedCell;
+
+// S2ClippedShape represents the part of a shape that intersects an S2Cell.
+// It consists of the set of edge ids that intersect that cell, and a boolean
+// indicating whether the center of the cell is inside the shape (for shapes
+// that have an interior).
+//
+// Note that the edges themselves are not clipped; we always use the original
+// edges for intersection tests so that the results will be the same as the
+// original shape.
+class S2ClippedShape {
+ public:
+  // The shape id of the clipped shape.
+  int shape_id() const;
+
+  // Returns true if the center of the S2CellId is inside the shape.  Returns
+  // false for shapes that do not have an interior.
+  bool contains_center() const;
+
+  // The number of edges that intersect the S2CellId.
+  int num_edges() const;
+
+  // Returns the edge id of the given edge in this clipped shape.  Edges are
+  // sorted in increasing order of edge id.
+  //
+  // REQUIRES: 0 <= i < num_edges()
+  int edge(int i) const;
+
+  // Returns true if the clipped shape contains the given edge id.
+  bool ContainsEdge(int id) const;
+
+ private:
+  // This class may be copied by value, but note that it does *not* own its
+  // underlying data.  (It is owned by the containing S2ShapeIndexCell.)
+
+  friend class MutableS2ShapeIndex;
+  friend class S2ShapeIndexCell;
+  friend class S2Stats;
+
+  // Internal methods are documented with their definition.
+  void Init(int32 shape_id, int32 num_edges);
+  void Destruct();
+  bool is_inline() const;
+  void set_contains_center(bool contains_center);
+  void set_edge(int i, int edge);
+
+  // All fields are packed into 16 bytes (assuming 64-bit pointers).  Up to
+  // two edge ids are stored inline; this is an important optimization for
+  // clients that use S2Shapes consisting of a single edge.
+  int32 shape_id_;
+  uint32 contains_center_ : 1;  // shape contains the cell center
+  uint32 num_edges_ : 31;
+
+  // If there are more than two edges, this field holds a pointer.
+  // Otherwise it holds an array of edge ids.
+  union {
+    int32* edges_;  // Owned by the containing S2ShapeIndexCell.
+    std::array<int32, 2> inline_edges_;
+  };
+};
+
+// S2ShapeIndexCell stores the index contents for a particular S2CellId.
+// It consists of a set of clipped shapes.
+class S2ShapeIndexCell {
+ public:
+  S2ShapeIndexCell() {}
+  ~S2ShapeIndexCell();
+
+  // Returns the number of clipped shapes in this cell.
+  int num_clipped() const { return shapes_.size(); }
+
+  // Returns the clipped shape at the given index.  Shapes are kept sorted in
+  // increasing order of shape id.
+  //
+  // REQUIRES: 0 <= i < num_clipped()
+  const S2ClippedShape& clipped(int i) const { return shapes_[i]; }
+
+  // Returns a pointer to the clipped shape corresponding to the given shape,
+  // or nullptr if the shape does not intersect this cell.
+  const S2ClippedShape* find_clipped(const S2Shape* shape) const;
+  const S2ClippedShape* find_clipped(int shape_id) const;
+
+  // Convenience method that returns the total number of edges in all clipped
+  // shapes.
+  int num_edges() const;
+
+  // Appends an encoded representation of the S2ShapeIndexCell to "encoder".
+  // "num_shape_ids" should be set to index.num_shape_ids(); this information
+  // allows the encoding to be more compact in some cases.
+  //
+  // REQUIRES: "encoder" uses the default constructor, so that its buffer
+  //           can be enlarged as necessary by calling Ensure(int).
+  void Encode(int num_shape_ids, Encoder* encoder) const;
+
+  // Decodes an S2ShapeIndexCell, returning true on success.
+  // "num_shape_ids" should be set to index.num_shape_ids().
+  bool Decode(int num_shape_ids, Decoder* decoder);
+
+ private:
+  friend class MutableS2ShapeIndex;
+  friend class EncodedS2ShapeIndex;
+  friend class S2Stats;
+
+  // Internal methods are documented with their definitions.
+  S2ClippedShape* add_shapes(int n);
+  static void EncodeEdges(const S2ClippedShape& clipped, Encoder* encoder);
+  static bool DecodeEdges(int num_edges, S2ClippedShape* clipped,
+                          Decoder* decoder);
+
+  using S2ClippedShapeSet = gtl::compact_array<S2ClippedShape>;
+  S2ClippedShapeSet shapes_;
+
+  S2ShapeIndexCell(const S2ShapeIndexCell&) = delete;
+  void operator=(const S2ShapeIndexCell&) = delete;
+};
+
+// S2ShapeIndex is an abstract base class for indexing polygonal geometry in
+// memory.  The objects in the index are known as "shapes", and may consist of
+// points, polylines, and/or polygons, possibly overlapping.  The index makes
+// it very fast to answer queries such as finding nearby shapes, measuring
+// distances, testing for intersection and containment, etc.
+//
+// Each object in the index implements the S2Shape interface.  An S2Shape is a
+// collection of edges that optionally defines an interior.  The edges do not
+// need to be connected, so for example an S2Shape can represent a polygon
+// with multiple shells and/or holes, or a set of polylines, or a set of
+// points.  All geometry within a single S2Shape must have the same dimension,
+// so for example if you want to create an S2ShapeIndex containing a polyline
+// and 10 points, then you will need at least two different S2Shape objects.
+//
+// The most important type of S2ShapeIndex is MutableS2ShapeIndex, which
+// allows you to build an index incrementally by adding or removing shapes.
+// Soon there will also be an EncodedS2ShapeIndex type that makes it possible
+// to keep the index data in encoded form.  Code that only needs read-only
+// ("const") access to an index should use the S2ShapeIndex base class as the
+// parameter type, so that it will work with any S2ShapeIndex subtype.  For
+// example:
+//
+//   void DoSomething(const S2ShapeIndex& index) {
+//     ... works with MutableS2ShapeIndex or EncodedS2ShapeIndex ...
+//   }
+//
+// There are a number of built-in classes that work with S2ShapeIndex objects.
+// Generally these classes accept any collection of geometry that can be
+// represented by an S2ShapeIndex, i.e. any combination of points, polylines,
+// and polygons.  Such classes include:
+//
+// - S2ContainsPointQuery: returns the shape(s) that contain a given point.
+//
+// - S2ClosestEdgeQuery: returns the closest edge(s) to a given point, edge,
+//                       S2CellId, or S2ShapeIndex.
+//
+// - S2CrossingEdgeQuery: returns the edge(s) that cross a given edge.
+//
+// - S2BooleanOperation: computes boolean operations such as union,
+//                       and boolean predicates such as containment.
+//
+// - S2ShapeIndexRegion: computes approximations for a collection of geometry.
+//
+// - S2ShapeIndexBufferedRegion: computes approximations that have been
+//                               expanded by a given radius.
+//
+// Here is an example showing how to index a set of polygons and then
+// determine which polygon(s) contain each of a set of query points:
+//
+//   void TestContainment(const vector<S2Point>& points,
+//                        const vector<S2Polygon*>& polygons) {
+//     MutableS2ShapeIndex index;
+//     for (auto polygon : polygons) {
+//       index.Add(absl::make_unique<S2Polygon::Shape>(polygon));
+//     }
+//     auto query = MakeS2ContainsPointQuery(&index);
+//     for (const auto& point : points) {
+//       for (S2Shape* shape : query.GetContainingShapes(point)) {
+//         S2Polygon* polygon = polygons[shape->id()];
+//         ... do something with (point, polygon) ...
+//       }
+//     }
+//   }
+//
+// This example uses S2Polygon::Shape, which is one example of an S2Shape
+// object.  S2Polyline and S2Loop also have nested Shape classes, and there are
+// additional S2Shape types defined in *_shape.h.
+//
+// Internally, an S2ShapeIndex is essentially a map from S2CellIds to the set
+// of shapes that intersect each S2CellId.  It is adaptively refined to ensure
+// that no cell contains more than a small number of edges.
+//
+// In addition to implementing a shared set of virtual methods, all
+// S2ShapeIndex subtypes define an Iterator type with the same API.  This
+// makes it easy to convert code that uses a particular S2ShapeIndex subtype
+// to instead use the abstract base class (or vice versa).  You can also
+// choose to avoid the overhead of virtual method calls by making the
+// S2ShapeIndex type a template argument, like this:
+//
+//   template <class IndexType>
+//   void DoSomething(const IndexType& index) {
+//     for (typename IndexType::Iterator it(&index, S2ShapeIndex::BEGIN);
+//          !it.done(); it.Next()) {
+//       ...
+//     }
+//   }
+//
+// Subtypes provided by the S2 library have the same thread-safety properties
+// as std::vector.  That is, const methods may be called concurrently from
+// multiple threads, and non-const methods require exclusive access to the
+// S2ShapeIndex.
+class S2ShapeIndex {
+ protected:
+  class IteratorBase;
+
+ public:
+  virtual ~S2ShapeIndex() {}
+
+  // Returns the number of distinct shape ids in the index.  This is the same
+  // as the number of shapes provided that no shapes have ever been removed.
+  // (Shape ids are never reused.)
+  virtual int num_shape_ids() const = 0;
+
+  // Returns a pointer to the shape with the given id, or nullptr if the shape
+  // has been removed from the index.
+  virtual S2Shape* shape(int id) const = 0;
+
+  // Allows iterating over the indexed shapes using range-based for loops:
+  //
+  //   for (S2Shape* shape : index) { ... }
+  //
+  // CAVEAT: Returns nullptr for shapes that have been removed from the index.
+  class ShapeIterator
+      : public std::iterator<std::forward_iterator_tag, S2Shape*> {
+   public:
+    ShapeIterator() = default;
+    S2Shape* operator*() const;
+    ShapeIterator& operator++();
+    ShapeIterator operator++(int);
+
+    // REQUIRES: "it" and *this must reference the same S2ShapeIndex.
+    bool operator==(ShapeIterator it) const;
+
+    // REQUIRES: "it" and *this must reference the same S2ShapeIndex.
+    bool operator!=(ShapeIterator it) const;
+
+   private:
+    friend class S2ShapeIndex;
+    ShapeIterator(const S2ShapeIndex* index, int shape_id)
+        : index_(index), shape_id_(shape_id) {}
+
+    const S2ShapeIndex* index_ = nullptr;
+    int shape_id_ = 0;
+  };
+  ShapeIterator begin() const;
+  ShapeIterator end() const;
+
+  // Returns the number of bytes currently occupied by the index (including any
+  // unused space at the end of vectors, etc).
+  virtual size_t SpaceUsed() const = 0;
+
+  // Minimizes memory usage by requesting that any data structures that can be
+  // rebuilt should be discarded.  This method invalidates all iterators.
+  //
+  // Like all non-const methods, this method is not thread-safe.
+  virtual void Minimize() = 0;
+
+  // The possible relationships between a "target" cell and the cells of the
+  // S2ShapeIndex.  If the target is an index cell or is contained by an index
+  // cell, it is "INDEXED".  If the target is subdivided into one or more
+  // index cells, it is "SUBDIVIDED".  Otherwise it is "DISJOINT".
+  enum CellRelation {
+    INDEXED,       // Target is contained by an index cell
+    SUBDIVIDED,    // Target is subdivided into one or more index cells
+    DISJOINT       // Target does not intersect any index cells
+  };
+
+  // When passed to an Iterator constructor, specifies whether the iterator
+  // should be positioned at the beginning of the index (BEGIN), the end of
+  // the index (END), or arbitrarily (UNPOSITIONED).  By default iterators are
+  // unpositioned, since this avoids an extra seek in this situation where one
+  // of the seek methods (such as Locate) is immediately called.
+  enum InitialPosition { BEGIN, END, UNPOSITIONED };
+
+  // A random access iterator that provides low-level access to the cells of
+  // the index.  Cells are sorted in increasing order of S2CellId.
+  class Iterator {
+   public:
+    // Default constructor; must be followed by a call to Init().
+    Iterator() : iter_(nullptr) {}
+
+    // Constructs an iterator positioned as specified.  By default iterators
+    // are unpositioned, since this avoids an extra seek in this situation
+    // where one of the seek methods (such as Locate) is immediately called.
+    //
+    // If you want to position the iterator at the beginning, e.g. in order to
+    // loop through the entire index, do this instead:
+    //
+    //   for (S2ShapeIndex::Iterator it(&index, S2ShapeIndex::BEGIN);
+    //        !it.done(); it.Next()) { ... }
+    explicit Iterator(const S2ShapeIndex* index,
+                      InitialPosition pos = UNPOSITIONED)
+        : iter_(index->NewIterator(pos)) {}
+
+    // Initializes an iterator for the given S2ShapeIndex.  This method may
+    // also be called in order to restore an iterator to a valid state after
+    // the underlying index has been updated (although it is usually easier
+    // just to declare a new iterator whenever required, since iterator
+    // construction is cheap).
+    void Init(const S2ShapeIndex* index,
+              InitialPosition pos = UNPOSITIONED) {
+      iter_ = index->NewIterator(pos);
+    }
+
+    // Iterators are copyable and movable.
+    Iterator(const Iterator&);
+    Iterator& operator=(const Iterator&);
+    Iterator(Iterator&&);
+    Iterator& operator=(Iterator&&);
+
+    // Returns the S2CellId of the current index cell.  If done() is true,
+    // returns a value larger than any valid S2CellId (S2CellId::Sentinel()).
+    S2CellId id() const { return iter_->id(); }
+
+    // Returns the center point of the cell.
+    // REQUIRES: !done()
+    S2Point center() const { return id().ToPoint(); }
+
+    // Returns a reference to the contents of the current index cell.
+    // REQUIRES: !done()
+    const S2ShapeIndexCell& cell() const { return iter_->cell(); }
+
+    // Returns true if the iterator is positioned past the last index cell.
+    bool done() const { return iter_->done(); }
+
+    // Positions the iterator at the first index cell (if any).
+    void Begin() { iter_->Begin(); }
+
+    // Positions the iterator past the last index cell.
+    void Finish() { iter_->Finish(); }
+
+    // Positions the iterator at the next index cell.
+    // REQUIRES: !done()
+    void Next() { iter_->Next(); }
+
+    // If the iterator is already positioned at the beginning, returns false.
+    // Otherwise positions the iterator at the previous entry and returns true.
+    bool Prev() { return iter_->Prev(); }
+
+    // Positions the iterator at the first cell with id() >= target, or at the
+    // end of the index if no such cell exists.
+    void Seek(S2CellId target) { iter_->Seek(target); }
+
+    // Positions the iterator at the cell containing "target".  If no such cell
+    // exists, returns false and leaves the iterator positioned arbitrarily.
+    // The returned index cell is guaranteed to contain all edges that might
+    // intersect the line segment between "target" and the cell center.
+    bool Locate(const S2Point& target) {
+      return IteratorBase::LocateImpl(target, this);
+    }
+
+    // Let T be the target S2CellId.  If T is contained by some index cell I
+    // (including equality), this method positions the iterator at I and
+    // returns INDEXED.  Otherwise if T contains one or more (smaller) index
+    // cells, it positions the iterator at the first such cell I and returns
+    // SUBDIVIDED.  Otherwise it returns DISJOINT and leaves the iterator
+    // positioned arbitrarily.
+    CellRelation Locate(S2CellId target) {
+      return IteratorBase::LocateImpl(target, this);
+    }
+
+   private:
+    // Although S2ShapeIndex::Iterator can be used to iterate over any
+    // index subtype, it is more efficient to use the subtype's iterator when
+    // the subtype is known at compile time.  For example, MutableS2ShapeIndex
+    // should use a MutableS2ShapeIndex::Iterator.
+    //
+    // The following declarations prevent accidental use of
+    // S2ShapeIndex::Iterator when the actual subtype is known.  (If you
+    // really want to do this, you can down_cast the index argument to
+    // S2ShapeIndex.)
+    template <class T>
+    explicit Iterator(const T* index, InitialPosition pos = UNPOSITIONED) {}
+
+    template <class T>
+    void Init(const T* index, InitialPosition pos = UNPOSITIONED) {}
+
+    std::unique_ptr<IteratorBase> iter_;
+  };
+
+  // ShapeFactory is an interface for decoding vectors of S2Shapes.  It allows
+  // random access to the shapes in order to support lazy decoding.  See
+  // s2shapeutil_coding.h for useful subtypes.
+  class ShapeFactory {
+   public:
+    virtual ~ShapeFactory() {}
+
+    // Returns the number of S2Shapes in the vector.
+    virtual int size() const = 0;
+
+    // Returns the S2Shape object corresponding to the given "shape_id".
+    // Returns nullptr if a shape cannot be decoded or a shape is missing
+    // (e.g., because MutableS2ShapeIndex::Release() was called).
+    virtual std::unique_ptr<S2Shape> operator[](int shape_id) const = 0;
+
+    // Returns a deep copy of this ShapeFactory.
+    virtual std::unique_ptr<ShapeFactory> Clone() const = 0;
+  };
+
+ protected:
+  // Each subtype of S2ShapeIndex should define an Iterator type derived
+  // from the following base class.
+  class IteratorBase {
+   public:
+    virtual ~IteratorBase() {}
+
+    IteratorBase(const IteratorBase&);
+    IteratorBase& operator=(const IteratorBase&);
+
+    // Returns the S2CellId of the current index cell.  If done() is true,
+    // returns a value larger than any valid S2CellId (S2CellId::Sentinel()).
+    S2CellId id() const;
+
+    // Returns the center point of the cell.
+    // REQUIRES: !done()
+    S2Point center() const;
+
+    // Returns a reference to the contents of the current index cell.
+    // REQUIRES: !done()
+    const S2ShapeIndexCell& cell() const;
+
+    // Returns true if the iterator is positioned past the last index cell.
+    bool done() const;
+
+    // Positions the iterator at the first index cell (if any).
+    virtual void Begin() = 0;
+
+    // Positions the iterator past the last index cell.
+    virtual void Finish() = 0;
+
+    // Positions the iterator at the next index cell.
+    // REQUIRES: !done()
+    virtual void Next() = 0;
+
+    // If the iterator is already positioned at the beginning, returns false.
+    // Otherwise positions the iterator at the previous entry and returns true.
+    virtual bool Prev() = 0;
+
+    // Positions the iterator at the first cell with id() >= target, or at the
+    // end of the index if no such cell exists.
+    virtual void Seek(S2CellId target) = 0;
+
+    // Positions the iterator at the cell containing "target".  If no such cell
+    // exists, returns false and leaves the iterator positioned arbitrarily.
+    // The returned index cell is guaranteed to contain all edges that might
+    // intersect the line segment between "target" and the cell center.
+    virtual bool Locate(const S2Point& target) = 0;
+
+    // Let T be the target S2CellId.  If T is contained by some index cell I
+    // (including equality), this method positions the iterator at I and
+    // returns INDEXED.  Otherwise if T contains one or more (smaller) index
+    // cells, it positions the iterator at the first such cell I and returns
+    // SUBDIVIDED.  Otherwise it returns DISJOINT and leaves the iterator
+    // positioned arbitrarily.
+    virtual CellRelation Locate(S2CellId target) = 0;
+
+   protected:
+    IteratorBase() : id_(S2CellId::Sentinel()), cell_(nullptr) {}
+
+    // Sets the iterator state.  "cell" typically points to the cell contents,
+    // but may also be given as "nullptr" in order to implement decoding on
+    // demand.  In that situation, the first that the client attempts to
+    // access the cell contents, the GetCell() method is called and "cell_" is
+    // updated in a thread-safe way.
+    void set_state(S2CellId id, const S2ShapeIndexCell* cell);
+
+    // Sets the iterator state so that done() is true.
+    void set_finished();
+
+    // Returns the current contents of the "cell_" field, which may be nullptr
+    // if the cell contents have not been decoded yet.
+    const S2ShapeIndexCell* raw_cell() const;
+
+    // This method is called to decode the contents of the current cell, if
+    // set_state() was previously called with a nullptr "cell" argument.  This
+    // allows decoding on demand for subtypes that keep the cell contents in
+    // an encoded state.  It does not need to be implemented at all if
+    // set_state() is always called with (cell != nullptr).
+    //
+    // REQUIRES: This method is thread-safe.
+    // REQUIRES: Multiple calls to this method return the same value.
+    virtual const S2ShapeIndexCell* GetCell() const = 0;
+
+    // Returns an exact copy of this iterator.
+    virtual std::unique_ptr<IteratorBase> Clone() const = 0;
+
+    // Makes a copy of the given source iterator.
+    // REQUIRES: "other" has the same concrete type as "this".
+    virtual void Copy(const IteratorBase& other) = 0;
+
+    // The default implementation of Locate(S2Point).  It is instantiated by
+    // each subtype in order to (1) minimize the number of virtual method
+    // calls (since subtypes are typically "final") and (2) ensure that the
+    // correct versions of non-virtual methods such as cell() are called.
+    template <class Iter>
+    static bool LocateImpl(const S2Point& target, Iter* it);
+
+    // The default implementation of Locate(S2CellId) (see comments above).
+    template <class Iter>
+    static CellRelation LocateImpl(S2CellId target, Iter* it);
+
+   private:
+    friend class Iterator;
+
+    // This method is "const" because it is used internally by "const" methods
+    // in order to implement decoding on demand.
+    void set_cell(const S2ShapeIndexCell* cell) const;
+
+    S2CellId id_;
+    mutable std::atomic<const S2ShapeIndexCell*> cell_;
+  };
+
+  // Returns a new iterator positioned as specified.
+  virtual std::unique_ptr<IteratorBase> NewIterator(InitialPosition pos)
+      const = 0;
+};
+
+//////////////////   Implementation details follow   ////////////////////
+
+
+inline int S2ClippedShape::shape_id() const {
+  return shape_id_;
+}
+
+inline bool S2ClippedShape::contains_center() const {
+  return contains_center_;
+}
+
+inline int S2ClippedShape::num_edges() const {
+  return num_edges_;
+}
+
+inline int S2ClippedShape::edge(int i) const {
+  return is_inline() ? inline_edges_[i] : edges_[i];
+}
+
+// Initialize an S2ClippedShape to hold the given number of edges.
+inline void S2ClippedShape::Init(int32 shape_id, int32 num_edges) {
+  shape_id_ = shape_id;
+  num_edges_ = num_edges;
+  contains_center_ = false;
+  if (!is_inline()) {
+    edges_ = new int32[num_edges];
+  }
+}
+
+// Free any memory allocated by this S2ClippedShape.  We don't do this in
+// the destructor because S2ClippedShapes are copied by STL code, and we
+// don't want to repeatedly copy and free the edge data.  Instead the data
+// is owned by the containing S2ShapeIndexCell.
+inline void S2ClippedShape::Destruct() {
+  if (!is_inline()) delete[] edges_;
+}
+
+inline bool S2ClippedShape::is_inline() const {
+  return num_edges_ <= inline_edges_.size();
+}
+
+// Set "contains_center_" to indicate whether this clipped shape contains the
+// center of the cell to which it belongs.
+inline void S2ClippedShape::set_contains_center(bool contains_center) {
+  contains_center_ = contains_center;
+}
+
+// Set the i-th edge of this clipped shape to be the given edge of the
+// original shape.
+inline void S2ClippedShape::set_edge(int i, int edge) {
+  if (is_inline()) {
+    inline_edges_[i] = edge;
+  } else {
+    edges_[i] = edge;
+  }
+}
+
+inline const S2ClippedShape* S2ShapeIndexCell::find_clipped(
+    const S2Shape* shape) const {
+  return find_clipped(shape->id());
+}
+
+// Inline because an index cell frequently contains just one shape.
+inline int S2ShapeIndexCell::num_edges() const {
+  int n = 0;
+  for (int i = 0; i < num_clipped(); ++i) n += clipped(i).num_edges();
+  return n;
+}
+
+inline S2Shape* S2ShapeIndex::ShapeIterator::operator*() const {
+  return index_->shape(shape_id_);
+}
+
+inline S2ShapeIndex::ShapeIterator& S2ShapeIndex::ShapeIterator::operator++() {
+  ++shape_id_;
+  return *this;
+}
+
+inline S2ShapeIndex::ShapeIterator S2ShapeIndex::ShapeIterator::operator++(
+    int) {
+  return ShapeIterator(index_, shape_id_++);
+}
+
+inline bool S2ShapeIndex::ShapeIterator::operator==(ShapeIterator it) const {
+  S2_DCHECK_EQ(index_, it.index_);
+  return shape_id_ == it.shape_id_;
+}
+
+inline bool S2ShapeIndex::ShapeIterator::operator!=(ShapeIterator it) const {
+  S2_DCHECK_EQ(index_, it.index_);
+  return shape_id_ != it.shape_id_;
+}
+
+inline S2ShapeIndex::ShapeIterator S2ShapeIndex::begin() const {
+  return ShapeIterator(this, 0);
+}
+
+inline S2ShapeIndex::ShapeIterator S2ShapeIndex::end() const {
+  return ShapeIterator(this, num_shape_ids());
+}
+
+inline S2ShapeIndex::IteratorBase::IteratorBase(const IteratorBase& other)
+    : id_(other.id_), cell_(other.raw_cell()) {
+}
+
+inline S2ShapeIndex::IteratorBase&
+S2ShapeIndex::IteratorBase::operator=(const IteratorBase& other) {
+  id_ = other.id_;
+  set_cell(other.raw_cell());
+  return *this;
+}
+
+inline S2CellId S2ShapeIndex::IteratorBase::id() const {
+  return id_;
+}
+
+inline const S2ShapeIndexCell& S2ShapeIndex::IteratorBase::cell() const {
+  // Like other const methods, this method is thread-safe provided that it
+  // does not overlap with calls to non-const methods.
+  S2_DCHECK(!done());
+  auto cell = raw_cell();
+  if (cell == nullptr) {
+    cell = GetCell();
+    set_cell(cell);
+  }
+  return *cell;
+}
+
+inline bool S2ShapeIndex::IteratorBase::done() const {
+  return id_ == S2CellId::Sentinel();
+}
+
+inline S2Point S2ShapeIndex::IteratorBase::center() const {
+  S2_DCHECK(!done());
+  return id().ToPoint();
+}
+
+inline void S2ShapeIndex::IteratorBase::set_state(
+    S2CellId id, const S2ShapeIndexCell* cell) {
+  id_ = id;
+  set_cell(cell);
+}
+
+inline void S2ShapeIndex::IteratorBase::set_finished() {
+  id_ = S2CellId::Sentinel();
+  set_cell(nullptr);
+}
+
+inline const S2ShapeIndexCell* S2ShapeIndex::IteratorBase::raw_cell()
+    const {
+  return cell_.load(std::memory_order_relaxed);
+}
+
+inline void S2ShapeIndex::IteratorBase::set_cell(
+    const S2ShapeIndexCell* cell) const {
+  cell_.store(cell, std::memory_order_relaxed);
+}
+
+template <class Iter>
+inline bool S2ShapeIndex::IteratorBase::LocateImpl(
+    const S2Point& target_point, Iter* it) {
+  // Let I = cell_map_->lower_bound(T), where T is the leaf cell containing
+  // "target_point".  Then if T is contained by an index cell, then the
+  // containing cell is either I or I'.  We test for containment by comparing
+  // the ranges of leaf cells spanned by T, I, and I'.
+
+  S2CellId target(target_point);
+  it->Seek(target);
+  if (!it->done() && it->id().range_min() <= target) return true;
+  if (it->Prev() && it->id().range_max() >= target) return true;
+  return false;
+}
+
+template <class Iter>
+inline S2ShapeIndex::CellRelation
+S2ShapeIndex::IteratorBase::LocateImpl(S2CellId target, Iter* it) {
+  // Let T be the target, let I = cell_map_->lower_bound(T.range_min()), and
+  // let I' be the predecessor of I.  If T contains any index cells, then T
+  // contains I.  Similarly, if T is contained by an index cell, then the
+  // containing cell is either I or I'.  We test for containment by comparing
+  // the ranges of leaf cells spanned by T, I, and I'.
+
+  it->Seek(target.range_min());
+  if (!it->done()) {
+    if (it->id() >= target && it->id().range_min() <= target) return INDEXED;
+    if (it->id() <= target.range_max()) return SUBDIVIDED;
+  }
+  if (it->Prev() && it->id().range_max() >= target) return INDEXED;
+  return DISJOINT;
+}
+
+inline S2ShapeIndex::Iterator::Iterator(const Iterator& other)
+    : iter_(other.iter_->Clone()) {
+}
+
+inline S2ShapeIndex::Iterator& S2ShapeIndex::Iterator::operator=(
+    const Iterator& other) {
+  iter_->Copy(*other.iter_);
+  return *this;
+}
+
+inline S2ShapeIndex::Iterator::Iterator(Iterator&& other)
+    : iter_(std::move(other.iter_)) {
+}
+
+inline S2ShapeIndex::Iterator& S2ShapeIndex::Iterator::operator=(
+    Iterator&& other) {
+  iter_ = std::move(other.iter_);
+  return *this;
+}
+
+#endif  // S2_S2SHAPE_INDEX_H_
diff --git a/src/s2/s2shape_index_buffered_region.cc b/src/s2/s2shape_index_buffered_region.cc
new file mode 100644 (file)
index 0000000..9fc29ba
--- /dev/null
@@ -0,0 +1,113 @@
+// Copyright 2017 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// Author: ericv@google.com (Eric Veach)
+
+#include "s2/s2shape_index_buffered_region.h"
+
+#include <algorithm>
+#include <vector>
+#include "s2/s2metrics.h"
+#include "s2/s2shape_index_region.h"
+
+using std::min;
+using std::vector;
+
+S2ShapeIndexBufferedRegion::S2ShapeIndexBufferedRegion() {
+}
+
+void S2ShapeIndexBufferedRegion::Init(const S2ShapeIndex* index,
+                                      S1ChordAngle radius) {
+  radius_ = radius;
+  radius_successor_ = radius.Successor();
+  query_.Init(index);
+  query_.mutable_options()->set_include_interiors(true);
+}
+
+S2ShapeIndexBufferedRegion* S2ShapeIndexBufferedRegion::Clone() const {
+  return new S2ShapeIndexBufferedRegion(&index(), radius_);
+}
+
+S2Cap S2ShapeIndexBufferedRegion::GetCapBound() const {
+  S2Cap orig_cap = MakeS2ShapeIndexRegion(&index()).GetCapBound();
+  return S2Cap(orig_cap.center(), orig_cap.radius() + radius_);
+}
+
+S2LatLngRect S2ShapeIndexBufferedRegion::GetRectBound() const {
+  S2LatLngRect orig_rect = MakeS2ShapeIndexRegion(&index()).GetRectBound();
+  return orig_rect.ExpandedByDistance(radius_.ToAngle());
+}
+
+void S2ShapeIndexBufferedRegion::GetCellUnionBound(vector<S2CellId> *cellids)
+    const {
+  // We start with a covering of the original S2ShapeIndex, and then expand it
+  // by replacing each cell with a block of 4 cells whose union contains the
+  // original cell buffered by the given radius.
+  //
+  // This increases the number of cells in the covering by a factor of 4 and
+  // increases the covered area by a factor of 16, so it is not a very good
+  // covering, but it is much better than always returning the 6 face cells.
+  vector<S2CellId> orig_cellids;
+  MakeS2ShapeIndexRegion(&index()).GetCellUnionBound(&orig_cellids);
+
+  double radians = radius_.ToAngle().radians();
+  int max_level = S2::kMinWidth.GetLevelForMinValue(radians) - 1;
+  if (max_level < 0) {
+    return S2Cap::Full().GetCellUnionBound(cellids);
+  }
+  cellids->clear();
+  for (S2CellId id : orig_cellids) {
+    if (id.is_face()) {
+      return S2Cap::Full().GetCellUnionBound(cellids);
+    }
+    id.AppendVertexNeighbors(min(max_level, id.level() - 1), cellids);
+  }
+}
+
+bool S2ShapeIndexBufferedRegion::Contains(const S2Cell& cell) const {
+  // To implement this method perfectly would require computing the directed
+  // Hausdorff distance, which is expensive (and not currently implemented).
+  // However the following heuristic is almost as good in practice and much
+  // cheaper to compute.
+
+  // Return true if the unbuffered region contains this cell.
+  if (MakeS2ShapeIndexRegion(&index()).Contains(cell)) return true;
+
+  // Otherwise approximate the cell by its bounding cap.
+  //
+  // NOTE(ericv): It would be slightly more accurate to first find the closest
+  // point in the indexed geometry to the cell, and then measure the actual
+  // maximum distance from that point to the cell (a poor man's Hausdorff
+  // distance).  But based on actual tests this is not worthwhile.
+  S2Cap cap = cell.GetCapBound();
+  if (radius_ < cap.radius()) return false;
+
+  // Return true if the distance to the cell center plus the radius of the
+  // cell's bounding cap is less than or equal to "radius_".
+  S2ClosestEdgeQuery::PointTarget target(cell.GetCenter());
+  return query_.IsDistanceLess(&target, radius_successor_ - cap.radius());
+}
+
+bool S2ShapeIndexBufferedRegion::MayIntersect(const S2Cell& cell) const {
+  // Return true if the distance is less than or equal to "radius_".
+  S2ClosestEdgeQuery::CellTarget target(cell);
+  return query_.IsDistanceLess(&target, radius_successor_);
+}
+
+bool S2ShapeIndexBufferedRegion::Contains(const S2Point& p) const {
+  S2ClosestEdgeQuery::PointTarget target(p);
+  // Return true if the distance is less than or equal to "radius_".
+  return query_.IsDistanceLess(&target, radius_successor_);
+}
diff --git a/src/s2/s2shape_index_buffered_region.h b/src/s2/s2shape_index_buffered_region.h
new file mode 100644 (file)
index 0000000..8bdca16
--- /dev/null
@@ -0,0 +1,135 @@
+// Copyright 2017 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// Author: ericv@google.com (Eric Veach)
+
+#ifndef S2_S2SHAPE_INDEX_BUFFERED_REGION_H_
+#define S2_S2SHAPE_INDEX_BUFFERED_REGION_H_
+
+#include <vector>
+#include "s2/s2cap.h"
+#include "s2/s2cell.h"
+#include "s2/s2cell_union.h"
+#include "s2/s2closest_edge_query.h"
+#include "s2/s2latlng_rect.h"
+#include "s2/s2region.h"
+#include "s2/s2shape_index.h"
+
+// This class provides a way to expand an arbitrary collection of geometry by
+// a fixed radius (an operation variously known as "buffering", "offsetting",
+// or "Minkowski sum with a disc") in order to compute an S2CellId covering
+// (see S2RegionCoverer).  The resulting covering contains all points within
+// the given radius of any point in the original geometry.
+//
+// This class does not actually buffer the geometry; instead it implements the
+// S2Region API by computing the distance from candidate S2CellIds to the
+// original geometry.  If this distance is below the given radius then the
+// S2CellId intersects the buffered geometry.  For example, if the original
+// geometry consists of a single S2Point then the buffered geometry is exactly
+// equivalent to an S2Cap with the given radius.  (Note that the region is not
+// approximated as a polygonal loop.)
+//
+// Example usage:
+//
+// S2CellUnion GetBufferedCovering(const S2ShapeIndex& index, S1Angle radius) {
+//   S2RegionCoverer coverer;
+//   coverer.mutable_options()->set_max_cells(20);
+//   S2CellUnion covering;
+//   S2ShapeIndexBufferedRegion region(&index, radius);
+//   coverer.GetCovering(region, &covering);
+//   return covering;
+// }
+//
+// This class is not thread-safe.  To use it in parallel, each thread should
+// construct its own instance (this is not expensive).
+class S2ShapeIndexBufferedRegion final : public S2Region {
+ public:
+  // Default constructor; requires Init() to be called.
+  S2ShapeIndexBufferedRegion();
+
+  // Constructs a region representing all points within the given radius of
+  // any point in the given S2ShapeIndex.
+  S2ShapeIndexBufferedRegion(const S2ShapeIndex* index,
+                             S1ChordAngle radius);
+
+  // Convenience constructor that accepts an S1Angle for the radius.
+  // REQUIRES: radius >= S1Angle::Zero()
+  S2ShapeIndexBufferedRegion(const S2ShapeIndex* index, S1Angle radius)
+      : S2ShapeIndexBufferedRegion(index, S1ChordAngle(radius)) {}
+
+  // Equivalent to the constructor above.
+  void Init(const S2ShapeIndex* index, S1ChordAngle radius);
+
+  const S2ShapeIndex& index() const;
+  S1ChordAngle radius() const;
+
+  ////////////////////////////////////////////////////////////////////////
+  // S2Region interface (see s2region.h for details):
+
+  // Clone() returns a *shallow* copy; it does not make a copy of the
+  // underlying S2ShapeIndex.
+  S2ShapeIndexBufferedRegion* Clone() const override;
+
+  S2Cap GetCapBound() const override;
+  S2LatLngRect GetRectBound() const override;
+
+  // This method returns a small non-optimal covering that may include
+  // duplicate or overlapping cells.  It should not be used directly.
+  // Instead, use S2RegionCoverer::GetCovering or GetFastCovering.
+  void GetCellUnionBound(std::vector<S2CellId> *cellids) const override;
+
+  // The implementation is approximate but conservative; it always returns
+  // "false" if the cell is not contained by the buffered region, but it may
+  // also return false in some cases where "cell" is in fact contained.
+  bool Contains(const S2Cell& cell) const override;
+
+  // Returns true if any buffered shape intersects "cell" (to within a very
+  // small error margin).
+  bool MayIntersect(const S2Cell& cell) const override;
+
+  // Returns true if the given point is contained by the buffered region,
+  // i.e. if it is within the given radius of any original shape.
+  bool Contains(const S2Point& p) const override;
+
+ private:
+  S1ChordAngle radius_;
+
+  // In order to handle (radius_ == 0) corectly, we need to test whether
+  // distances are less than or equal to "radius_".  This is done by testing
+  // whether distances are less than radius_.Successor().
+  S1ChordAngle radius_successor_;
+
+  mutable S2ClosestEdgeQuery query_;  // This class is not thread-safe!
+};
+
+
+//////////////////   Implementation details follow   ////////////////////
+
+
+inline S2ShapeIndexBufferedRegion::S2ShapeIndexBufferedRegion(
+    const S2ShapeIndex* index, S1ChordAngle radius)
+    : radius_(radius), radius_successor_(radius.Successor()), query_(index) {
+  query_.mutable_options()->set_include_interiors(true);
+}
+
+inline const S2ShapeIndex& S2ShapeIndexBufferedRegion::index() const {
+  return query_.index();
+}
+
+inline S1ChordAngle S2ShapeIndexBufferedRegion::radius() const {
+  return radius_;
+}
+
+#endif  // S2_S2SHAPE_INDEX_BUFFERED_REGION_H_
diff --git a/src/s2/s2shape_index_measures.cc b/src/s2/s2shape_index_measures.cc
new file mode 100644 (file)
index 0000000..ef857bf
--- /dev/null
@@ -0,0 +1,92 @@
+// Copyright 2018 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// Author: ericv@google.com (Eric Veach)
+
+#include "s2/s2shape_index_measures.h"
+
+#include "s2/s2shape_measures.h"
+
+namespace S2 {
+
+int GetDimension(const S2ShapeIndex& index) {
+  int dim = -1;
+  for (int i = 0; i < index.num_shape_ids(); ++i) {
+    S2Shape* shape = index.shape(i);
+    if (shape) dim = std::max(dim, shape->dimension());
+  }
+  return dim;
+}
+
+int GetNumPoints(const S2ShapeIndex& index) {
+  int count = 0;
+  for (int i = 0; i < index.num_shape_ids(); ++i) {
+    S2Shape* shape = index.shape(i);
+    if (shape && shape->dimension() == 0) {
+      count += shape->num_edges();
+    }
+  }
+  return count;
+}
+
+S1Angle GetLength(const S2ShapeIndex& index) {
+  S1Angle length;
+  for (int i = 0; i < index.num_shape_ids(); ++i) {
+    S2Shape* shape = index.shape(i);
+    if (shape) length += S2::GetLength(*shape);
+  }
+  return length;
+}
+
+S1Angle GetPerimeter(const S2ShapeIndex& index) {
+  S1Angle perimeter;
+  for (int i = 0; i < index.num_shape_ids(); ++i) {
+    S2Shape* shape = index.shape(i);
+    if (shape) perimeter += S2::GetPerimeter(*shape);
+  }
+  return perimeter;
+}
+
+double GetArea(const S2ShapeIndex& index) {
+  double area = 0;
+  for (int i = 0; i < index.num_shape_ids(); ++i) {
+    S2Shape* shape = index.shape(i);
+    if (shape) area += S2::GetArea(*shape);
+  }
+  return area;
+}
+
+double GetApproxArea(const S2ShapeIndex& index) {
+  double area = 0;
+  for (int i = 0; i < index.num_shape_ids(); ++i) {
+    S2Shape* shape = index.shape(i);
+    if (shape) area += S2::GetApproxArea(*shape);
+  }
+  return area;
+}
+
+S2Point GetCentroid(const S2ShapeIndex& index) {
+  int dim = GetDimension(index);
+  S2Point centroid;
+  for (int i = 0; i < index.num_shape_ids(); ++i) {
+    S2Shape* shape = index.shape(i);
+    if (shape && shape->dimension() == dim) {
+      centroid += S2::GetCentroid(*shape);
+    }
+  }
+  return centroid;
+}
+
+}  // namespace S2
diff --git a/src/s2/s2shape_index_measures.h b/src/s2/s2shape_index_measures.h
new file mode 100644 (file)
index 0000000..1852b27
--- /dev/null
@@ -0,0 +1,100 @@
+// Copyright 2018 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// Author: ericv@google.com (Eric Veach)
+//
+// Defines various angle and area measures for S2ShapeIndex objects.  In
+// general, these methods return the sum of the corresponding measure for the
+// S2Shapes in the index.
+
+#ifndef S2_S2SHAPE_INDEX_MEASURES_H_
+#define S2_S2SHAPE_INDEX_MEASURES_H_
+
+#include "s2/s1angle.h"
+#include "s2/s2point.h"
+#include "s2/s2shape_index.h"
+
+namespace S2 {
+
+// Returns the maximum dimension of any shape in the index.  Returns -1 if the
+// index does not contain any shapes.
+//
+// Note that the dimension does *not* depend on whether the shapes in the
+// index contain any points; for example, the dimension of an empty point set
+// is 0, and the dimension of an empty polygon is 2.
+int GetDimension(const S2ShapeIndex& index);
+
+// Returns the number of points (objects of dimension zero) in the index.
+// Note that polyline and polygon vertices are *not* included in this count.
+int GetNumPoints(const S2ShapeIndex& index);
+
+// Returns the total length of all polylines in the index.  Returns zero if no
+// polylines are present.
+//
+// All edges are modeled as spherical geodesics.  The result can be converted
+// to a distance on the Earth's surface (with a worst-case error of 0.562%
+// near the equator) using the functions in s2earth.h.
+S1Angle GetLength(const S2ShapeIndex& index);
+
+// Returns the total perimeter of all polygons in the index (including both
+// "shells" and "holes").  Returns zero if no polygons are present.
+//
+// All edges are modeled as spherical geodesics.  The result can be converted
+// to a distance on the Earth's surface (with a worst-case error of 0.562%
+// near the equator) using the functions in s2earth.h.
+S1Angle GetPerimeter(const S2ShapeIndex& index);
+
+// Returns the total area of all polygons in the index.  Returns zero if no
+// polygons are present.  This method has good relative accuracy for both very
+// large and very small regions.  Note that the result may exceed 4*Pi if the
+// index contains overlapping polygons.
+//
+// All edges are modeled as spherical geodesics.  The result can be converted
+// to an area on the Earth's surface (with a worst-case error of 0.900% near
+// the poles) using the functions in s2earth.h.
+double GetArea(const S2ShapeIndex& index);
+
+// Like GetArea(), except that this method is faster and has more error.  The
+// additional error is at most 2.22e-15 steradians per vertex, which works out
+// to about 0.09 square meters per vertex on the Earth's surface.  For
+// example, a loop with 100 vertices has a maximum error of about 9 square
+// meters.  (The actual error is typically much smaller than this.)
+double GetApproxArea(const S2ShapeIndex& index);
+
+// Returns the centroid of all shapes whose dimension is maximal within the
+// index, multiplied by the measure of those shapes.  For example, if the
+// index contains points and polylines, then the result is defined as the
+// centroid of the polylines multiplied by the total length of those
+// polylines.  The points would be ignored when computing the centroid.
+//
+// The measure of a given shape is defined as follows:
+//
+//  - For dimension 0 shapes, the measure is shape->num_edges().
+//  - For dimension 1 shapes, the measure is GetLength(shape).
+//  - For dimension 2 shapes, the measure is GetArea(shape).
+//
+// Note that the centroid is not unit length, so you may need to call
+// Normalize() before passing it to other S2 functions.  Note that this
+// function returns (0, 0, 0) if the index contains no geometry.
+//
+// The centroid is scaled by the total measure of the shapes for two reasons:
+// (1) it is cheaper to compute this way, and (2) this makes it easier to
+// compute the centroid of a collection of shapes (since the individual
+// centroids can simply be summed).
+S2Point GetCentroid(const S2ShapeIndex& index);
+
+}  // namespace S2
+
+#endif  // S2_S2SHAPE_INDEX_MEASURES_H_
diff --git a/src/s2/s2shape_index_region.h b/src/s2/s2shape_index_region.h
new file mode 100644 (file)
index 0000000..9f0644b
--- /dev/null
@@ -0,0 +1,350 @@
+// Copyright 2017 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// Author: ericv@google.com (Eric Veach)
+#ifndef S2_S2SHAPE_INDEX_REGION_H_
+#define S2_S2SHAPE_INDEX_REGION_H_
+
+#include <vector>
+#include "s2/s2cap.h"
+#include "s2/s2cell.h"
+#include "s2/s2cell_union.h"
+#include "s2/s2contains_point_query.h"
+#include "s2/s2edge_clipping.h"
+#include "s2/s2edge_crosser.h"
+#include "s2/s2latlng_rect.h"
+#include "s2/s2region.h"
+#include "s2/s2shape_index.h"
+
+// This class wraps an S2ShapeIndex object with the additional methods needed
+// to implement the S2Region API, in order to allow S2RegionCoverer to compute
+// S2CellId coverings of arbitrary collections of geometry.
+//
+// These methods could conceivably be made part of S2ShapeIndex itself, but
+// there are several advantages to having a separate class:
+//
+//  - The class can be templated in order to avoid virtual calls and memory
+//    allocation (for iterators) when the concrete S2ShapeIndex type is known.
+//
+//  - Implementing these methods efficiently requires an S2ShapeIndex iterator,
+//    and this design allows a single iterator to be allocated and reused.
+//
+//  - S2Region::Clone() is not a good fit for the S2ShapeIndex API because
+//    it can't be implemented for some subtypes (e.g., EncodedS2ShapeIndex).
+//
+// Example usage:
+//
+// S2CellUnion GetCovering(const S2ShapeIndex& index) {
+//   S2RegionCoverer coverer;
+//   coverer.mutable_options()->set_max_cells(20);
+//   S2CellUnion covering;
+//   coverer.GetCovering(MakeS2ShapeIndexRegion(&index), &covering);
+//   return covering;
+// }
+//
+// This class is not thread-safe.  To use it in parallel, each thread should
+// construct its own instance (this is not expensive).
+template <class IndexType>
+class S2ShapeIndexRegion final : public S2Region {
+ public:
+  // Rather than calling this constructor, which requires specifying the
+  // S2ShapeIndex type explicitly, the preferred idiom is to call
+  // MakeS2ShapeIndexRegion(&index) instead.  For example:
+  //
+  //   coverer.GetCovering(MakeS2ShapeIndexRegion(&index), &covering);
+  explicit S2ShapeIndexRegion(const IndexType* index);
+
+  const IndexType& index() const;
+
+  ////////////////////////////////////////////////////////////////////////
+  // S2Region interface (see s2region.h for details):
+
+  // Clone() returns a *shallow* copy; it does not make a copy of the
+  // underlying S2ShapeIndex.
+  S2ShapeIndexRegion<IndexType>* Clone() const override;
+
+  S2Cap GetCapBound() const override;
+  S2LatLngRect GetRectBound() const override;
+
+  // This method currently returns at most 4 cells, unless the index spans
+  // multiple faces in which case it may return up to 6 cells.
+  void GetCellUnionBound(std::vector<S2CellId> *cell_ids) const override;
+
+  // Returns true if "target" is contained by any single shape.  If the cell
+  // is covered by a union of different shapes then it may return false.
+  //
+  // The implementation is conservative but not exact; if a shape just barely
+  // contains the given cell then it may return false.  The maximum error is
+  // less than 10 * DBL_EPSILON radians (or about 15 nanometers).
+  bool Contains(const S2Cell& target) const override;
+
+  // Returns true if any shape intersects "target".
+  //
+  // The implementation is conservative but not exact; if a shape is just
+  // barely disjoint from the given cell then it may return true.  The maximum
+  // error is less than 10 * DBL_EPSILON radians (or about 15 nanometers).
+  bool MayIntersect(const S2Cell& target) const override;
+
+  // Returns true if the given point is contained by any two-dimensional shape
+  // (i.e., polygon).  Boundaries are treated as being semi-open (i.e., the
+  // same rules as S2Polygon).  Zero and one-dimensional shapes are ignored by
+  // this method (if you need more flexibility, see S2BooleanOperation).
+  bool Contains(const S2Point& p) const override;
+
+ private:
+  using Iterator = typename IndexType::Iterator;
+
+  static void CoverRange(S2CellId first, S2CellId last,
+                         std::vector<S2CellId> *cell_ids);
+
+  // Returns true if the indexed shape "clipped" in the indexed cell "id"
+  // contains the point "p".
+  //
+  // REQUIRES: id.contains(S2CellId(p))
+  bool Contains(S2CellId id, const S2ClippedShape& clipped,
+                const S2Point& p) const;
+
+  // Returns true if any edge of the indexed shape "clipped" intersects the
+  // cell "target".  It may also return true if an edge is very close to
+  // "target"; the maximum error is less than 10 * DBL_EPSILON radians (about
+  // 15 nanometers).
+  bool AnyEdgeIntersects(const S2ClippedShape& clipped,
+                         const S2Cell& target) const;
+
+  // This class is not thread-safe!
+  mutable S2ContainsPointQuery<IndexType> contains_query_;
+
+  // Optimization: rather than declaring our own iterator, instead we reuse
+  // the iterator declared by S2ContainsPointQuery.  (This improves benchmark
+  // times significantly for classes that create a new S2ShapeIndexRegion
+  // object on every call to Contains/MayIntersect(S2Cell).
+  Iterator& iter_ = *contains_query_.mutable_iter();
+};
+
+// Returns an S2ShapeIndexRegion that wraps the given S2ShapeIndex.  Note that
+// it is efficient to return S2ShapeIndexRegion objects by value.
+template <class IndexType>
+S2ShapeIndexRegion<IndexType> MakeS2ShapeIndexRegion(const IndexType* index);
+
+
+//////////////////   Implementation details follow   ////////////////////
+
+
+template <class IndexType>
+S2ShapeIndexRegion<IndexType>::S2ShapeIndexRegion(const IndexType* index)
+    : contains_query_(index) {
+}
+
+template <class IndexType>
+inline const IndexType& S2ShapeIndexRegion<IndexType>::index() const {
+  return contains_query_.index();
+}
+
+template <class IndexType>
+S2ShapeIndexRegion<IndexType>* S2ShapeIndexRegion<IndexType>::Clone() const {
+  return new S2ShapeIndexRegion<IndexType>(&index());
+}
+
+template <class IndexType>
+S2Cap S2ShapeIndexRegion<IndexType>::GetCapBound() const {
+  std::vector<S2CellId> covering;
+  GetCellUnionBound(&covering);
+  return S2CellUnion(std::move(covering)).GetCapBound();
+}
+
+template <class IndexType>
+S2LatLngRect S2ShapeIndexRegion<IndexType>::GetRectBound() const {
+  std::vector<S2CellId> covering;
+  GetCellUnionBound(&covering);
+  return S2CellUnion(std::move(covering)).GetRectBound();
+}
+
+template <class IndexType>
+void S2ShapeIndexRegion<IndexType>::GetCellUnionBound(
+    std::vector<S2CellId> *cell_ids) const {
+  // We find the range of S2Cells spanned by the index and choose a level such
+  // that the entire index can be covered with just a few cells.  There are
+  // two cases:
+  //
+  //  - If the index intersects two or more faces, then for each intersected
+  //    face we add one cell to the covering.  Rather than adding the entire
+  //    face, instead we add the smallest S2Cell that covers the S2ShapeIndex
+  //    cells within that face.
+  //
+  //  - If the index intersects only one face, then we first find the smallest
+  //    cell S that contains the index cells (just like the case above).
+  //    However rather than using the cell S itself, instead we repeat this
+  //    process for each of its child cells.  In other words, for each
+  //    child cell C we add the smallest S2Cell C' that covers the index cells
+  //    within C.  This extra step is relatively cheap and produces much
+  //    tighter coverings when the S2ShapeIndex consists of a small region
+  //    near the center of a large S2Cell.
+  //
+  // The following code uses only a single Iterator object because creating an
+  // Iterator may be relatively expensive for some S2ShapeIndex types (e.g.,
+  // it may involve memory allocation).
+  cell_ids->clear();
+  cell_ids->reserve(6);
+
+  // Find the last S2CellId in the index.
+  iter_.Finish();
+  if (!iter_.Prev()) return;  // Empty index.
+  const S2CellId last_index_id = iter_.id();
+  iter_.Begin();
+  if (iter_.id() != last_index_id) {
+    // The index has at least two cells.  Choose an S2CellId level such that
+    // the entire index can be spanned with at most 6 cells (if the index
+    // spans multiple faces) or 4 cells (it the index spans a single face).
+    int level = iter_.id().GetCommonAncestorLevel(last_index_id) + 1;
+
+    // For each cell C at the chosen level, we compute the smallest S2Cell
+    // that covers the S2ShapeIndex cells within C.
+    const S2CellId last_id = last_index_id.parent(level);
+    for (auto id = iter_.id().parent(level); id != last_id; id = id.next()) {
+      // If the cell C does not contain any index cells, then skip it.
+      if (id.range_max() < iter_.id()) continue;
+
+      // Find the range of index cells contained by C and then shrink C so
+      // that it just covers those cells.
+      S2CellId first = iter_.id();
+      iter_.Seek(id.range_max().next());
+      iter_.Prev();
+      CoverRange(first, iter_.id(), cell_ids);
+      iter_.Next();
+    }
+  }
+  CoverRange(iter_.id(), last_index_id, cell_ids);
+}
+
+// Computes the smallest S2Cell that covers the S2Cell range (first, last) and
+// adds this cell to "cell_ids".
+//
+// REQUIRES: "first" and "last" have a common ancestor.
+template <class IndexType>
+inline void S2ShapeIndexRegion<IndexType>::CoverRange(
+    S2CellId first, S2CellId last, std::vector<S2CellId> *cell_ids) {
+  if (first == last) {
+    // The range consists of a single index cell.
+    cell_ids->push_back(first);
+  } else {
+    // Add the lowest common ancestor of the given range.
+    int level = first.GetCommonAncestorLevel(last);
+    S2_DCHECK_GE(level, 0);
+    cell_ids->push_back(first.parent(level));
+  }
+}
+
+template <class IndexType>
+bool S2ShapeIndexRegion<IndexType>::Contains(const S2Cell& target) const {
+  S2ShapeIndex::CellRelation relation = iter_.Locate(target.id());
+
+  // If the relation is DISJOINT, then "target" is not contained.  Similarly if
+  // the relation is SUBDIVIDED then "target" is not contained, since index
+  // cells are subdivided only if they (nearly) intersect too many edges.
+  if (relation != S2ShapeIndex::INDEXED) return false;
+
+  // Otherwise, the iterator points to an index cell containing "target".
+  // If any shape contains the target cell, we return true.
+  S2_DCHECK(iter_.id().contains(target.id()));
+  const S2ShapeIndexCell& cell = iter_.cell();
+  for (int s = 0; s < cell.num_clipped(); ++s) {
+    const S2ClippedShape& clipped = cell.clipped(s);
+    // The shape contains the target cell iff the shape contains the cell
+    // center and none of its edges intersects the (padded) cell interior.
+    if (iter_.id() == target.id()) {
+      if (clipped.num_edges() == 0 && clipped.contains_center()) return true;
+    } else {
+      // It is faster to call AnyEdgeIntersects() before Contains().
+      if (index().shape(clipped.shape_id())->dimension() == 2 &&
+          !AnyEdgeIntersects(clipped, target) &&
+          contains_query_.ShapeContains(iter_, clipped, target.GetCenter())) {
+        return true;
+      }
+    }
+  }
+  return false;
+}
+
+template <class IndexType>
+bool S2ShapeIndexRegion<IndexType>::MayIntersect(const S2Cell& target) const {
+  S2ShapeIndex::CellRelation relation = iter_.Locate(target.id());
+
+  // If "target" does not overlap any index cell, there is no intersection.
+  if (relation == S2ShapeIndex::DISJOINT) return false;
+
+  // If "target" is subdivided into one or more index cells, then there is an
+  // intersection to within the S2ShapeIndex error bound.
+  if (relation == S2ShapeIndex::SUBDIVIDED) return true;
+
+  // Otherwise, the iterator points to an index cell containing "target".
+  //
+  // If "target" is an index cell itself, there is an intersection because index
+  // cells are created only if they have at least one edge or they are
+  // entirely contained by the loop.
+  S2_DCHECK(iter_.id().contains(target.id()));
+  if (iter_.id() == target.id()) return true;
+
+  // Test whether any shape intersects the target cell or contains its center.
+  const S2ShapeIndexCell& cell = iter_.cell();
+  for (int s = 0; s < cell.num_clipped(); ++s) {
+    const S2ClippedShape& clipped = cell.clipped(s);
+    if (AnyEdgeIntersects(clipped, target)) return true;
+    if (contains_query_.ShapeContains(iter_, clipped, target.GetCenter())) {
+      return true;
+    }
+  }
+  return false;
+}
+
+template <class IndexType>
+bool S2ShapeIndexRegion<IndexType>::Contains(const S2Point& p) const {
+  if (iter_.Locate(p)) {
+    const S2ShapeIndexCell& cell = iter_.cell();
+    for (int s = 0; s < cell.num_clipped(); ++s) {
+      if (contains_query_.ShapeContains(iter_, cell.clipped(s), p)) {
+        return true;
+      }
+    }
+  }
+  return false;
+}
+
+template <class IndexType>
+bool S2ShapeIndexRegion<IndexType>::AnyEdgeIntersects(
+    const S2ClippedShape& clipped, const S2Cell& target) const {
+  static const double kMaxError = (S2::kFaceClipErrorUVCoord +
+                                   S2::kIntersectsRectErrorUVDist);
+  const R2Rect bound = target.GetBoundUV().Expanded(kMaxError);
+  const int face = target.face();
+  const S2Shape& shape = *index().shape(clipped.shape_id());
+  const int num_edges = clipped.num_edges();
+  for (int i = 0; i < num_edges; ++i) {
+    const auto edge = shape.edge(clipped.edge(i));
+    R2Point p0, p1;
+    if (S2::ClipToPaddedFace(edge.v0, edge.v1, face, kMaxError, &p0, &p1) &&
+        S2::IntersectsRect(p0, p1, bound)) {
+      return true;
+    }
+  }
+  return false;
+}
+
+template <class IndexType>
+inline S2ShapeIndexRegion<IndexType> MakeS2ShapeIndexRegion(
+    const IndexType* index) {
+  return S2ShapeIndexRegion<IndexType>(index);
+}
+
+#endif  // S2_S2SHAPE_INDEX_REGION_H_
diff --git a/src/s2/s2shape_measures.cc b/src/s2/s2shape_measures.cc
new file mode 100644 (file)
index 0000000..65bdf71
--- /dev/null
@@ -0,0 +1,138 @@
+// Copyright 2018 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// Author: ericv@google.com (Eric Veach)
+
+#include "s2/s2shape_measures.h"
+
+#include <cmath>
+#include <vector>
+#include "s2/s2loop_measures.h"
+#include "s2/s2polyline_measures.h"
+
+using std::fabs;
+using std::vector;
+
+namespace S2 {
+
+S1Angle GetLength(const S2Shape& shape) {
+  if (shape.dimension() != 1) return S1Angle::Zero();
+  S1Angle length;
+  vector<S2Point> vertices;
+  int num_chains = shape.num_chains();
+  for (int chain_id = 0; chain_id < num_chains; ++chain_id) {
+    GetChainVertices(shape, chain_id, &vertices);
+    length += S2::GetLength(vertices);
+  }
+  return length;
+}
+
+S1Angle GetPerimeter(const S2Shape& shape) {
+  if (shape.dimension() != 2) return S1Angle::Zero();
+  S1Angle perimeter;
+  vector<S2Point> vertices;
+  int num_chains = shape.num_chains();
+  for (int chain_id = 0; chain_id < num_chains; ++chain_id) {
+    GetChainVertices(shape, chain_id, &vertices);
+    perimeter += S2::GetPerimeter(S2PointLoopSpan(vertices));
+  }
+  return perimeter;
+}
+
+double GetArea(const S2Shape& shape) {
+  if (shape.dimension() != 2) return 0.0;
+
+  // Since S2Shape uses the convention that the interior of the shape is to
+  // the left of all edges, in theory we could compute the area of the polygon
+  // by simply adding up all the loop areas modulo 4*Pi.  The problem with
+  // this approach is that polygons holes typically have areas near 4*Pi,
+  // which can create large cancellation errors when computing the area of
+  // small polygons with holes.  For example, a shell with an area of 4 square
+  // meters (1e-13 steradians) surrounding a hole with an area of 3 square
+  // meters (7.5e-14 sterians) would lose almost all of its accuracy if the
+  // area of the hole was computed as 12.566370614359098.
+  //
+  // So instead we use S2::GetSignedArea() to ensure that all loops have areas
+  // in the range [-2*Pi, 2*Pi].
+  double area = 0;
+  vector<S2Point> vertices;
+  int num_chains = shape.num_chains();
+  for (int chain_id = 0; chain_id < num_chains; ++chain_id) {
+    GetChainVertices(shape, chain_id, &vertices);
+    area += S2::GetSignedArea(S2PointLoopSpan(vertices));
+  }
+  // Note that S2::GetSignedArea() guarantees that the full loop (containing
+  // all points on the sphere) has a very small negative area.
+  S2_DCHECK_LE(fabs(area), 4 * M_PI);
+  if (area < 0.0) area += 4 * M_PI;
+  return area;
+}
+
+double GetApproxArea(const S2Shape& shape) {
+  if (shape.dimension() != 2) return 0.0;
+
+  double area = 0;
+  vector<S2Point> vertices;
+  int num_chains = shape.num_chains();
+  for (int chain_id = 0; chain_id < num_chains; ++chain_id) {
+    GetChainVertices(shape, chain_id, &vertices);
+    area += S2::GetApproxArea(S2PointLoopSpan(vertices));
+  }
+  // Special case to ensure that full polygons are handled correctly.
+  if (area <= 4 * M_PI) return area;
+  return fmod(area, 4 * M_PI);
+}
+
+S2Point GetCentroid(const S2Shape& shape) {
+  S2Point centroid;
+  vector<S2Point> vertices;
+  int dimension = shape.dimension();
+  int num_chains = shape.num_chains();
+  for (int chain_id = 0; chain_id < num_chains; ++chain_id) {
+    switch (dimension) {
+      case 0:
+        centroid += shape.edge(chain_id).v0;
+        break;
+      case 1:
+        GetChainVertices(shape, chain_id, &vertices);
+        centroid += S2::GetCentroid(S2PointSpan(vertices));
+        break;
+      default:
+        GetChainVertices(shape, chain_id, &vertices);
+        centroid += S2::GetCentroid(S2PointLoopSpan(vertices));
+        break;
+    }
+  }
+  return centroid;
+}
+
+void GetChainVertices(const S2Shape& shape, int chain_id,
+                      std::vector<S2Point>* vertices) {
+  S2Shape::Chain chain = shape.chain(chain_id);
+  int num_vertices = chain.length + (shape.dimension() == 1);
+  vertices->clear();
+  vertices->reserve(num_vertices);
+  int e = 0;
+  if (num_vertices & 1) {
+    vertices->push_back(shape.chain_edge(chain_id, e++).v0);
+  }
+  for (; e < num_vertices; e += 2) {
+    auto edge = shape.chain_edge(chain_id, e);
+    vertices->push_back(edge.v0);
+    vertices->push_back(edge.v1);
+  }
+}
+
+}  // namespace S2
diff --git a/src/s2/s2shape_measures.h b/src/s2/s2shape_measures.h
new file mode 100644 (file)
index 0000000..7b1406c
--- /dev/null
@@ -0,0 +1,95 @@
+// Copyright 2018 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// Author: ericv@google.com (Eric Veach)
+//
+// Defines various angle and area measures for S2Shape objects.  Unlike the
+// built-in S2Polygon and S2Polyline methods, these methods allow the
+// underlying data to be represented arbitrarily.
+
+#ifndef S2_S2SHAPE_MEASURES_H_
+#define S2_S2SHAPE_MEASURES_H_
+
+#include <vector>
+
+#include "s2/s1angle.h"
+#include "s2/s2point.h"
+#include "s2/s2shape.h"
+
+namespace S2 {
+
+// For shapes of dimension 1, returns the sum of all polyline lengths on the
+// unit sphere.  Otherwise returns zero.  (See GetPerimeter for shapes of
+// dimension 2.)
+//
+// All edges are modeled as spherical geodesics.  The result can be converted
+// to a distance on the Earth's surface (with a worst-case error of 0.562%
+// near the equator) using the functions in s2earth.h.
+S1Angle GetLength(const S2Shape& shape);
+
+// For shapes of dimension 2, returns the sum of all loop perimeters on the
+// unit sphere.  Otherwise returns zero.  (See GetLength for shapes of
+// dimension 1.)
+//
+// All edges are modeled as spherical geodesics.  The result can be converted
+// to a distance on the Earth's surface (with a worst-case error of 0.562%
+// near the equator) using the functions in s2earth.h.
+S1Angle GetPerimeter(const S2Shape& shape);
+
+// For shapes of dimension 2, returns the area of the shape on the unit
+// sphere.  The result is between 0 and 4*Pi steradians.  Otherwise returns
+// zero.  This method has good relative accuracy for both very large and very
+// small regions.
+//
+// All edges are modeled as spherical geodesics.  The result can be converted
+// to an area on the Earth's surface (with a worst-case error of 0.900% near
+// the poles) using the functions in s2earth.h.
+double GetArea(const S2Shape& shape);
+
+// Like GetArea(), except that this method is faster and has more error.  The
+// additional error is at most 2.22e-15 steradians per vertex, which works out
+// to about 0.09 square meters per vertex on the Earth's surface.  For
+// example, a loop with 100 vertices has a maximum error of about 9 square
+// meters.  (The actual error is typically much smaller than this.)
+double GetApproxArea(const S2Shape& shape);
+
+// Returns the centroid of the shape multiplied by the measure of the shape,
+// which is defined as follows:
+//
+//  - For dimension 0 shapes, the measure is shape->num_edges().
+//  - For dimension 1 shapes, the measure is GetLength(shape).
+//  - For dimension 2 shapes, the measure is GetArea(shape).
+//
+// Note that the result is not unit length, so you may need to call
+// Normalize() before passing it to other S2 functions.
+//
+// The result is scaled by the measure defined above for two reasons: (1) it
+// is cheaper to compute this way, and (2) this makes it easier to compute the
+// centroid of a collection of shapes.  (This requires simply summing the
+// centroids of all shapes in the collection whose dimension is maximal.)
+S2Point GetCentroid(const S2Shape& shape);
+
+// Overwrites "vertices" with the vertices of the given edge chain of "shape".
+// If dimension == 1, the chain will have (chain.length + 1) vertices, and
+// otherwise it will have (chain.length) vertices.
+//
+// This is a low-level helper method used in the implementations of some of
+// the methods above.
+void GetChainVertices(const S2Shape& shape, int chain_id,
+                      std::vector<S2Point>* vertices);
+
+}  // namespace S2
+
+#endif  // S2_S2SHAPE_MEASURES_H_
diff --git a/src/s2/s2shapeutil_build_polygon_boundaries.cc b/src/s2/s2shapeutil_build_polygon_boundaries.cc
new file mode 100644 (file)
index 0000000..e7a9892
--- /dev/null
@@ -0,0 +1,120 @@
+// Copyright 2013 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// Author: ericv@google.com (Eric Veach)
+
+#include "s2/s2shapeutil_build_polygon_boundaries.h"
+
+#include "absl/container/btree_map.h"
+#include "absl/memory/memory.h"
+#include "s2/mutable_s2shape_index.h"
+#include "s2/s2contains_point_query.h"
+#include "s2/s2shape_index.h"
+#include "s2/s2shapeutil_contains_brute_force.h"
+
+using absl::WrapUnique;
+using std::vector;
+
+namespace s2shapeutil {
+
+void BuildPolygonBoundaries(const vector<vector<S2Shape*>>& components,
+                            vector<vector<S2Shape*>>* polygons) {
+  polygons->clear();
+  if (components.empty()) return;
+
+  // Since the loop boundaries do not cross, a loop nesting hierarchy can be
+  // defined by choosing any point on the sphere as the "point at infinity".
+  // Loop A then contains loop B if (1) A contains the boundary of B and (2)
+  // loop A does not contain the point at infinity.
+  //
+  // We choose S2::Origin() for this purpose.  The loop nesting hierarchy then
+  // determines the face structure.  Here are the details:
+  //
+  // 1. Build an S2ShapeIndex of all loops that do not contain S2::Origin().
+  //    This leaves at most one unindexed loop per connected component
+  //    (the "outer loop").
+  //
+  // 2. For each component, choose a representative vertex and determine
+  //    which indexed loops contain it.  The "depth" of this component is
+  //    defined as the number of such loops.
+  //
+  // 3. Assign the outer loop of each component to the containing loop whose
+  //    depth is one less.  This generates a set of multi-loop polygons.
+  //
+  // 4. The outer loops of all components at depth 0 become a single face.
+
+  MutableS2ShapeIndex index;
+  // A map from shape.id() to the corresponding component number.
+  vector<int> component_ids;
+  vector<S2Shape*> outer_loops;
+  for (int i = 0; i < components.size(); ++i) {
+    const auto& component = components[i];
+    for (S2Shape* loop : component) {
+      if (component.size() > 1 &&
+          !s2shapeutil::ContainsBruteForce(*loop, S2::Origin())) {
+        // Ownership is transferred back at the end of this function.
+        index.Add(WrapUnique(loop));
+        component_ids.push_back(i);
+      } else {
+        outer_loops.push_back(loop);
+      }
+    }
+    // Check that there is exactly one outer loop in each component.
+    S2_DCHECK_EQ(i + 1, outer_loops.size()) << "Component is not a subdivision";
+  }
+  // Find the loops containing each component.
+  vector<vector<S2Shape*>> ancestors(components.size());
+  auto contains_query = MakeS2ContainsPointQuery(&index);
+  for (int i = 0; i < outer_loops.size(); ++i) {
+    auto loop = outer_loops[i];
+    S2_DCHECK_GT(loop->num_edges(), 0);
+    ancestors[i] = contains_query.GetContainingShapes(loop->edge(0).v0);
+  }
+  // Assign each outer loop to the component whose depth is one less.
+  // Components at depth 0 become a single face.
+  absl::btree_map<S2Shape*, vector<S2Shape*>> children;
+  for (int i = 0; i < outer_loops.size(); ++i) {
+    S2Shape* ancestor = nullptr;
+    int depth = ancestors[i].size();
+    if (depth > 0) {
+      for (auto candidate : ancestors[i]) {
+        if (ancestors[component_ids[candidate->id()]].size() == depth - 1) {
+          S2_DCHECK(ancestor == nullptr);
+          ancestor = candidate;
+        }
+      }
+      S2_DCHECK(ancestor != nullptr);
+    }
+    children[ancestor].push_back(outer_loops[i]);
+  }
+  // There is one face per loop that is not an outer loop, plus one for the
+  // outer loops of components at depth 0.
+  polygons->resize(index.num_shape_ids() + 1);
+  for (int i = 0; i < index.num_shape_ids(); ++i) {
+    auto polygon = &(*polygons)[i];
+    auto loop = index.shape(i);
+    auto itr = children.find(loop);
+    if (itr != children.end()) {
+      *polygon = itr->second;
+    }
+    polygon->push_back(loop);
+  }
+  polygons->back() = children[nullptr];
+
+  // Explicitly release the shapes from the index so they are not deleted.
+  for (auto& ptr : index.ReleaseAll()) ptr.release();
+}
+
+}  // namespace s2shapeutil
diff --git a/src/s2/s2shapeutil_build_polygon_boundaries.h b/src/s2/s2shapeutil_build_polygon_boundaries.h
new file mode 100644 (file)
index 0000000..a2d330e
--- /dev/null
@@ -0,0 +1,66 @@
+// Copyright 2013 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// Author: ericv@google.com (Eric Veach)
+
+#ifndef S2_S2SHAPEUTIL_BUILD_POLYGON_BOUNDARIES_H_
+#define S2_S2SHAPEUTIL_BUILD_POLYGON_BOUNDARIES_H_
+
+#include <vector>
+
+#include "s2/s2shape_index.h"
+
+namespace s2shapeutil {
+
+// The purpose of this function is to construct polygons consisting of
+// multiple loops.  It takes as input a collection of loops whose boundaries
+// do not cross, and groups them into polygons whose interiors do not
+// intersect (where the boundary of each polygon may consist of multiple
+// loops).
+//
+// some of those islands have lakes, then the input to this function would
+// islands, and their lakes.  Each loop would actually be present twice, once
+// in each direction (see below).  The output would consist of one polygon
+// representing each lake, one polygon representing each island not including
+// islands or their lakes, and one polygon representing the rest of the world
+//
+// This method is intended for internal use; external clients should use
+// S2Builder, which has more convenient interface.
+//
+// The input consists of a set of connected components, where each component
+// consists of one or more loops.  The components must satisfy the following
+// properties:
+//
+//  - The loops in each component must form a subdivision of the sphere (i.e.,
+//    they must cover the entire sphere without overlap), except that a
+//    component may consist of a single loop if and only if that loop is
+//    degenerate (i.e., its interior is empty).
+//
+//  - The boundaries of different components must be disjoint (i.e. no
+//    crossing edges or shared vertices).
+//
+//  - No component should be empty, and no loop should have zero edges.
+//
+// The output consists of a set of polygons, where each polygon is defined by
+// the collection of loops that form its boundary.  This function does not
+// actually construct any S2Shapes; it simply identifies the loops that belong
+// to each polygon.
+void BuildPolygonBoundaries(
+    const std::vector<std::vector<S2Shape*>>& components,
+    std::vector<std::vector<S2Shape*>>* polygons);
+
+}  // namespace s2shapeutil
+
+#endif  // S2_S2SHAPEUTIL_BUILD_POLYGON_BOUNDARIES_H_
diff --git a/src/s2/s2shapeutil_coding.cc b/src/s2/s2shapeutil_coding.cc
new file mode 100644 (file)
index 0000000..a675a46
--- /dev/null
@@ -0,0 +1,253 @@
+// Copyright 2018 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// Author: ericv@google.com (Eric Veach)
+
+#include "s2/s2shapeutil_coding.h"
+
+#include <memory>
+
+#include "absl/memory/memory.h"
+#include "s2/encoded_s2point_vector.h"
+#include "s2/encoded_string_vector.h"
+#include "s2/s2lax_polygon_shape.h"
+#include "s2/s2lax_polyline_shape.h"
+#include "s2/s2point_vector_shape.h"
+#include "s2/s2polygon.h"
+#include "s2/s2polyline.h"
+
+using absl::make_unique;
+using std::make_shared;
+using std::unique_ptr;
+using std::vector;
+
+using CodingHint = s2coding::CodingHint;
+
+namespace s2shapeutil {
+
+bool FastEncodeShape(const S2Shape& shape, Encoder* encoder) {
+  switch (shape.type_tag()) {
+    case S2Polygon::Shape::kTypeTag: {
+      down_cast<const S2Polygon::Shape*>(&shape)->EncodeUncompressed(encoder);
+      return true;
+    }
+    case S2Polyline::Shape::kTypeTag: {
+      down_cast<const S2Polyline::Shape*>(&shape)->Encode(encoder);
+      return true;
+    }
+    case S2PointVectorShape::kTypeTag: {
+      down_cast<const S2PointVectorShape*>(&shape)->Encode(
+          encoder, CodingHint::FAST);
+      return true;
+    }
+    case S2LaxPolylineShape::kTypeTag: {
+      down_cast<const S2LaxPolylineShape*>(&shape)->Encode(
+          encoder, CodingHint::FAST);
+      return true;
+    }
+    case S2LaxPolygonShape::kTypeTag: {
+      down_cast<const S2LaxPolygonShape*>(&shape)->Encode(
+          encoder, CodingHint::FAST);
+      return true;
+    }
+    default: {
+      S2_LOG(DFATAL) << "Unsupported S2Shape type: " << shape.type_tag();
+      return false;
+    }
+  }
+}
+
+bool CompactEncodeShape(const S2Shape& shape, Encoder* encoder) {
+  switch (shape.type_tag()) {
+    case S2Polygon::Shape::kTypeTag: {
+      down_cast<const S2Polygon::Shape*>(&shape)->Encode(encoder);
+      return true;
+    }
+    case S2PointVectorShape::kTypeTag: {
+      down_cast<const S2PointVectorShape*>(&shape)->Encode(
+          encoder, CodingHint::COMPACT);
+      return true;
+    }
+    case S2LaxPolylineShape::kTypeTag: {
+      down_cast<const S2LaxPolylineShape*>(&shape)->Encode(
+          encoder, CodingHint::COMPACT);
+      return true;
+    }
+    case S2LaxPolygonShape::kTypeTag: {
+      down_cast<const S2LaxPolygonShape*>(&shape)->Encode(
+          encoder, CodingHint::COMPACT);
+      return true;
+    }
+    default: {
+      return FastEncodeShape(shape, encoder);
+    }
+  }
+}
+
+// A ShapeDecoder that fully decodes an S2Shape of the given type.  After this
+// function returns, the underlying Decoder data is no longer needed.
+unique_ptr<S2Shape> FullDecodeShape(S2Shape::TypeTag tag, Decoder* decoder) {
+  switch (tag) {
+    case S2Polygon::Shape::kTypeTag: {
+      auto shape = make_unique<S2Polygon::OwningShape>();
+      if (!shape->Init(decoder)) return nullptr;
+      return std::move(shape);
+    }
+    case S2Polyline::Shape::kTypeTag: {
+      auto shape = make_unique<S2Polyline::OwningShape>();
+      if (!shape->Init(decoder)) return nullptr;
+      return std::move(shape);
+    }
+    case S2PointVectorShape::kTypeTag: {
+      auto shape = make_unique<S2PointVectorShape>();
+      if (!shape->Init(decoder)) return nullptr;
+      return std::move(shape);
+    }
+    case S2LaxPolylineShape::kTypeTag: {
+      auto shape = make_unique<S2LaxPolylineShape>();
+      if (!shape->Init(decoder)) return nullptr;
+      return std::move(shape);
+    }
+    case S2LaxPolygonShape::kTypeTag: {
+      auto shape = make_unique<S2LaxPolygonShape>();
+      if (!shape->Init(decoder)) return nullptr;
+      return std::move(shape);
+    }
+    default: {
+      S2_LOG(DFATAL) << "Unsupported S2Shape type: " << tag;
+      return nullptr;
+    }
+  }
+}
+
+unique_ptr<S2Shape> LazyDecodeShape(S2Shape::TypeTag tag, Decoder* decoder) {
+  switch (tag) {
+    case S2PointVectorShape::kTypeTag: {
+      auto shape = make_unique<EncodedS2PointVectorShape>();
+      if (!shape->Init(decoder)) return nullptr;
+      return std::move(shape);
+    }
+    case S2LaxPolylineShape::kTypeTag: {
+      auto shape = make_unique<EncodedS2LaxPolylineShape>();
+      if (!shape->Init(decoder)) return nullptr;
+      return std::move(shape);
+    }
+    case S2LaxPolygonShape::kTypeTag: {
+      auto shape = make_unique<EncodedS2LaxPolygonShape>();
+      if (!shape->Init(decoder)) return nullptr;
+      return std::move(shape);
+    }
+    default: {
+      return FullDecodeShape(tag, decoder);
+    }
+  }
+}
+
+bool EncodeTaggedShapes(const S2ShapeIndex& index,
+                        const ShapeEncoder& shape_encoder,
+                        Encoder* encoder) {
+  s2coding::StringVectorEncoder shape_vector;
+  for (S2Shape* shape : index) {
+    Encoder* sub_encoder = shape_vector.AddViaEncoder();
+    if (shape == nullptr) continue;  // Encode as zero bytes.
+
+    uint32 tag = shape->type_tag();
+    if (tag == S2Shape::kNoTypeTag) {
+      S2_LOG(DFATAL) << "Unsupported S2Shape type: " << tag;
+      return false;
+    }
+    sub_encoder->Ensure(Encoder::kVarintMax32);
+    sub_encoder->put_varint32(tag);
+    shape_encoder(*shape, sub_encoder);
+  }
+  shape_vector.Encode(encoder);
+  return true;
+}
+
+bool FastEncodeTaggedShapes(const S2ShapeIndex& index, Encoder* encoder) {
+  return EncodeTaggedShapes(index, FastEncodeShape, encoder);
+}
+
+bool CompactEncodeTaggedShapes(const S2ShapeIndex& index, Encoder* encoder) {
+  return EncodeTaggedShapes(index, CompactEncodeShape, encoder);
+}
+
+TaggedShapeFactory::TaggedShapeFactory(const ShapeDecoder& shape_decoder,
+                                       Decoder* decoder)
+    : shape_decoder_(shape_decoder) {
+  if (!encoded_shapes_.Init(decoder)) encoded_shapes_.Clear();
+}
+
+unique_ptr<S2Shape> TaggedShapeFactory::operator[](int shape_id) const {
+  Decoder decoder = encoded_shapes_.GetDecoder(shape_id);
+  S2Shape::TypeTag tag;
+  if (!decoder.get_varint32(&tag)) return nullptr;
+  return shape_decoder_(tag, &decoder);
+}
+
+TaggedShapeFactory FullDecodeShapeFactory(Decoder* decoder) {
+  return TaggedShapeFactory(FullDecodeShape, decoder);
+}
+
+TaggedShapeFactory LazyDecodeShapeFactory(Decoder* decoder) {
+  return TaggedShapeFactory(LazyDecodeShape, decoder);
+}
+
+VectorShapeFactory::VectorShapeFactory(vector<unique_ptr<S2Shape>> shapes)
+    : shared_shapes_(
+          make_shared<vector<unique_ptr<S2Shape>>>(std::move(shapes))) {
+}
+
+unique_ptr<S2Shape> VectorShapeFactory::operator[](int shape_id) const {
+  return std::move((*shared_shapes_)[shape_id]);
+}
+
+VectorShapeFactory SingletonShapeFactory(std::unique_ptr<S2Shape> shape) {
+  vector<unique_ptr<S2Shape>> shapes;
+  shapes.push_back(std::move(shape));
+  return VectorShapeFactory(std::move(shapes));
+}
+
+// An S2Shape that simply wraps some other shape.
+class WrappedShape : public S2Shape {
+ public:
+  explicit WrappedShape(S2Shape* shape) : shape_(*shape) {}
+  // S2Shape interface:
+  int num_edges() const final { return shape_.num_edges(); }
+  Edge edge(int e) const final { return shape_.edge(e); }
+  int dimension() const final { return shape_.dimension(); }
+  ReferencePoint GetReferencePoint() const final {
+    return shape_.GetReferencePoint();
+  }
+  int num_chains() const final { return shape_.num_chains(); }
+  Chain chain(int i) const final { return shape_.chain(i); }
+  Edge chain_edge(int i, int j) const final {
+    return shape_.chain_edge(i, j);
+  }
+  ChainPosition chain_position(int e) const final {
+    return shape_.chain_position(e);
+  }
+
+ private:
+  const S2Shape& shape_;
+};
+
+unique_ptr<S2Shape> WrappedShapeFactory::operator[](int shape_id) const {
+  S2Shape* shape = index_.shape(shape_id);
+  if (shape == nullptr) return nullptr;
+  return make_unique<WrappedShape>(shape);
+}
+
+}  // namespace s2shapeutil
diff --git a/src/s2/s2shapeutil_coding.h b/src/s2/s2shapeutil_coding.h
new file mode 100644 (file)
index 0000000..8a7d5a8
--- /dev/null
@@ -0,0 +1,283 @@
+// Copyright 2018 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// Author: ericv@google.com (Eric Veach)
+//
+// Helper functions for encoding/decoding S2Shapes and S2Shape vectors.
+// Design goals:
+//
+//  - Allow control over encoding tradeoffs (i.e., speed vs encoding size).
+//
+//  - Allow control over decoding tradeoffs (e.g., whether to decode data
+//    immediately or lazily).
+//
+//  - Don't force all S2Shape types to have the same Encode() method.  Some
+//    implementations may want extra parameters.
+//
+//  - Support custom encodings of shape vectors; e.g., if all shapes are
+//    of a known type, then there is no need to tag them individually.
+//
+//  - Support client-defined S2Shape types.
+//
+//  - Support client-defined encodings of standard S2Shape types.
+
+#ifndef S2_S2SHAPEUTIL_CODING_H_
+#define S2_S2SHAPEUTIL_CODING_H_
+
+#include <functional>
+#include <memory>
+#include "s2/util/coding/coder.h"
+#include "s2/encoded_string_vector.h"
+#include "s2/s2shape.h"
+#include "s2/s2shape_index.h"
+
+namespace s2shapeutil {
+
+// A function that appends a serialized representation of the given shape to
+// the given Encoder.  The encoding should *not* include any type information
+// (e.g., shape->type_tag()); the caller is responsible for encoding this
+// separately if necessary.
+//
+// Note that you can add your own encodings and/or shape types by wrapping one
+// of the standard functions and adding exceptions:
+//
+// void MyShapeEncoder(const S2Shape& shape, Encoder* encoder) {
+//   if (shape.type_tag() == MyShape::kTypeTag) {
+//     down_cast<const MyShape*>(&shape)->Encode(encoder);
+//     return true;
+//   } else {
+//     return CompactEncodeShape(shape, encoder);
+//   }
+// }
+//
+// REQUIRES: "encoder" uses the default constructor, so that its buffer
+//           can be enlarged as necessary by calling Ensure(int).
+using ShapeEncoder =
+    std::function<bool (const S2Shape& shape, Encoder* encoder)>;
+
+// A ShapeEncoder that can encode all standard S2Shape types, preferring fast
+// (but larger) encodings.  For example, points are typically represented as
+// uncompressed S2Point values (24 bytes each).
+//
+// REQUIRES: "encoder" uses the default constructor, so that its buffer
+//           can be enlarged as necessary by calling Ensure(int).
+bool FastEncodeShape(const S2Shape& shape, Encoder* encoder);
+
+// A ShapeEncoder that encode all standard S2Shape types, preferring
+// compact (but slower) encodings.  For example, points that have been snapped
+// to S2CellId centers will be encoded using at most 8 bytes.
+//
+// REQUIRES: "encoder" uses the default constructor, so that its buffer
+//           can be enlarged as necessary by calling Ensure(int).
+bool CompactEncodeShape(const S2Shape& shape, Encoder* encoder);
+
+// A function that decodes an S2Shape of the given type, consuming data from
+// the given Decoder.  Returns nullptr on errors.
+using ShapeDecoder =
+    std::function<std::unique_ptr<S2Shape>(S2Shape::TypeTag tag,
+                                           Decoder* decoder)>;
+
+// A ShapeDecoder that fully decodes an S2Shape of the given type.  After this
+// function returns, the underlying Decoder data is no longer needed.
+std::unique_ptr<S2Shape> FullDecodeShape(S2Shape::TypeTag tag,
+                                         Decoder* decoder);
+
+// A ShapeDecoder that prefers to decode the given S2Shape lazily (as data is
+// accessed).  This is only possible when the given shape type (e.g.,
+// LaxPolygonShape) has an alternate implementation that can work directly
+// with encoded data (e.g., EncodedLaxPolygonShape).  All other shape types
+// are handled by decoding them fully (e.g., S2Polygon::Shape).
+std::unique_ptr<S2Shape> LazyDecodeShape(S2Shape::TypeTag tag,
+                                         Decoder* decoder);
+
+// Encodes the shapes in the given S2ShapeIndex.  Each shape is encoded with a
+// type tag allows it to be decoded into an S2Shape of the appropriate type.
+// "shape_encoder" allows control over the encoding strategy.  Note that when
+// an S2ShapeIndex is also being encoded, it should be encoded *after* the
+// shape vector, like this:
+//
+//   s2shapeutil::CompactEncodeTaggedShapes(index, encoder);
+//   index.Encode(encoder);
+//
+// This is because when the index is decoded, the shape vector is required as
+// a parameter.
+//
+// REQUIRES: "encoder" uses the default constructor, so that its buffer
+//           can be enlarged as necessary by calling Ensure(int).
+bool EncodeTaggedShapes(const S2ShapeIndex& index,
+                        const ShapeEncoder& shape_encoder,
+                        Encoder* encoder);
+
+// Convenience function that calls EncodeTaggedShapes using FastEncodeShape as
+// the ShapeEncoder.
+//
+// REQUIRES: "encoder" uses the default constructor, so that its buffer
+//           can be enlarged as necessary by calling Ensure(int).
+bool FastEncodeTaggedShapes(const S2ShapeIndex& index, Encoder* encoder);
+
+// Convenience function that calls EncodeTaggedShapes using CompactEncodeShape
+// as the ShapeEncoder.
+//
+// REQUIRES: "encoder" uses the default constructor, so that its buffer
+//           can be enlarged as necessary by calling Ensure(int).
+bool CompactEncodeTaggedShapes(const S2ShapeIndex& index, Encoder* encoder);
+
+// A ShapeFactory that decodes a vector generated by EncodeTaggedShapes()
+// above.  Example usage:
+//
+//   index.Init(decoder, s2shapeutil::FullDecodeShapeFactory(decoder));
+//
+// Note that the S2Shape vector must be encoded *before* the S2ShapeIndex
+// (like the example code for EncodeTaggedShapes), since the shapes need to be
+// decoded before the index.
+//
+// REQUIRES: The Decoder data buffer must outlive all calls to the given
+//           ShapeFactory (not including its destructor).
+class TaggedShapeFactory : public S2ShapeIndex::ShapeFactory {
+ public:
+  // Returns an empty vector and/or null S2Shapes on decoding errors.
+  TaggedShapeFactory(const ShapeDecoder& shape_decoder, Decoder* decoder);
+
+  int size() const override { return encoded_shapes_.size(); }
+
+  std::unique_ptr<S2Shape> operator[](int shape_id) const override;
+
+  std::unique_ptr<ShapeFactory> Clone() const override {
+    return absl::make_unique<TaggedShapeFactory>(*this);
+  }
+
+ private:
+  ShapeDecoder shape_decoder_;
+  s2coding::EncodedStringVector encoded_shapes_;
+};
+
+// Convenience function that calls TaggedShapeFactory using FullDecodeShape
+// as the ShapeDecoder.
+TaggedShapeFactory FullDecodeShapeFactory(Decoder* decoder);
+
+// Convenience function that calls TaggedShapeFactory using LazyDecodeShape
+// as the ShapeDecoder.
+TaggedShapeFactory LazyDecodeShapeFactory(Decoder* decoder);
+
+// A ShapeFactory that simply returns shapes from the given vector.
+//
+// REQUIRES: Each shape is requested at most once.  (This implies that when
+// the ShapeFactory is passed to an S2ShapeIndex, S2ShapeIndex::Minimize must
+// not be called.)  Additional requests for the same shape return nullptr.
+class VectorShapeFactory : public S2ShapeIndex::ShapeFactory {
+ public:
+  explicit VectorShapeFactory(std::vector<std::unique_ptr<S2Shape>> shapes);
+
+  int size() const override { return shared_shapes_->size(); }
+
+  std::unique_ptr<S2Shape> operator[](int shape_id) const override;
+
+  std::unique_ptr<ShapeFactory> Clone() const override {
+    return absl::make_unique<VectorShapeFactory>(*this);
+  }
+
+ private:
+  // Since this class is copyable, we need to access the shape vector through
+  // a shared pointer.
+  std::shared_ptr<std::vector<std::unique_ptr<S2Shape>>> shared_shapes_;
+};
+
+// A ShapeFactory that returns the single given S2Shape.  Useful for testing.
+VectorShapeFactory SingletonShapeFactory(std::unique_ptr<S2Shape> shape);
+
+// A ShapeFactory that wraps the shapes from the given index.  Used for testing.
+class WrappedShapeFactory : public S2ShapeIndex::ShapeFactory {
+ public:
+  // REQUIRES: The given index must persist for the lifetime of this object.
+  explicit WrappedShapeFactory(const S2ShapeIndex* index) : index_(*index) {}
+
+  int size() const override { return index_.num_shape_ids(); }
+
+  std::unique_ptr<S2Shape> operator[](int shape_id) const override;
+
+  std::unique_ptr<ShapeFactory> Clone() const override {
+    return absl::make_unique<WrappedShapeFactory>(*this);
+  }
+
+ private:
+  const S2ShapeIndex& index_;
+};
+
+
+// Encodes the shapes in the given index, which must all have the same type.
+// The given Shape type does *not* need to have a "type tag" assigned.
+// This is useful for encoding experimental or locally defined types, or when
+// the S2Shape type in a given index is known in advance.
+//
+// REQUIRES: The Shape class must have an Encode(Encoder*) method.
+// REQUIRES: "encoder" uses the default constructor, so that its buffer
+//           can be enlarged as necessary by calling Ensure(int).
+template <class Shape>
+void EncodeHomogeneousShapes(const S2ShapeIndex& index, Encoder* encoder);
+
+// A ShapeFactory that decodes shapes of a given fixed type (e.g.,
+// EncodedS2LaxPolylineShape).  Example usage:
+//
+// REQUIRES: The Shape type must have an Init(Decoder*) method.
+// REQUIRES: The Decoder data buffer must outlive the returned ShapeFactory
+//           and all shapes returned by that factory.
+template <class Shape>
+class HomogeneousShapeFactory : public S2ShapeIndex::ShapeFactory {
+ public:
+  // Returns an empty vector and/or null S2Shapes on decoding errors.
+  explicit HomogeneousShapeFactory(Decoder* decoder);
+
+  int size() const override { return encoded_shapes_.size(); }
+
+  std::unique_ptr<S2Shape> operator[](int shape_id) const override;
+
+  std::unique_ptr<ShapeFactory> Clone() const override {
+    return absl::make_unique<HomogeneousShapeFactory>(*this);
+  }
+
+ private:
+  s2coding::EncodedStringVector encoded_shapes_;
+};
+
+//////////////////   Implementation details follow   ////////////////////
+
+
+template <class Shape>
+void EncodeHomogeneousShapes(const S2ShapeIndex& index, Encoder* encoder) {
+  s2coding::StringVectorEncoder shape_vector;
+  for (S2Shape* shape : index) {
+    S2_DCHECK(shape != nullptr);
+    down_cast<Shape*>(shape)->Encode(shape_vector.AddViaEncoder());
+  }
+  shape_vector.Encode(encoder);
+}
+
+template <class Shape>
+HomogeneousShapeFactory<Shape>::HomogeneousShapeFactory(Decoder* decoder) {
+  if (!encoded_shapes_.Init(decoder)) encoded_shapes_.Clear();
+}
+
+template <class Shape>
+std::unique_ptr<S2Shape> HomogeneousShapeFactory<Shape>::operator[](
+    int shape_id) const {
+  Decoder decoder = encoded_shapes_.GetDecoder(shape_id);
+  auto shape = absl::make_unique<Shape>();
+  if (!shape->Init(&decoder)) return nullptr;
+  return std::move(shape);  // Converts from Shape to S2Shape.
+}
+
+}  // namespace s2shapeutil
+
+#endif  // S2_S2SHAPEUTIL_CODING_H_
diff --git a/src/s2/s2shapeutil_contains_brute_force.cc b/src/s2/s2shapeutil_contains_brute_force.cc
new file mode 100644 (file)
index 0000000..28fcd34
--- /dev/null
@@ -0,0 +1,40 @@
+// Copyright 2017 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// Author: ericv@google.com (Eric Veach)
+
+#include "s2/s2shapeutil_contains_brute_force.h"
+
+#include <utility>
+#include "s2/s2edge_crosser.h"
+
+namespace s2shapeutil {
+
+bool ContainsBruteForce(const S2Shape& shape, const S2Point& point) {
+  if (shape.dimension() < 2) return false;
+
+  S2Shape::ReferencePoint ref_point = shape.GetReferencePoint();
+  if (ref_point.point == point) return ref_point.contained;
+
+  S2CopyingEdgeCrosser crosser(ref_point.point, point);
+  bool inside = ref_point.contained;
+  for (int e = 0; e < shape.num_edges(); ++e) {
+    auto edge = shape.edge(e);
+    inside ^= crosser.EdgeOrVertexCrossing(edge.v0, edge.v1);
+  }
+  return inside;
+}
+
+}  // namespace s2shapeutil
diff --git a/src/s2/s2shapeutil_contains_brute_force.h b/src/s2/s2shapeutil_contains_brute_force.h
new file mode 100644 (file)
index 0000000..9808639
--- /dev/null
@@ -0,0 +1,41 @@
+// Copyright 2017 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// Author: ericv@google.com (Eric Veach)
+
+#ifndef S2_S2SHAPEUTIL_CONTAINS_BRUTE_FORCE_H_
+#define S2_S2SHAPEUTIL_CONTAINS_BRUTE_FORCE_H_
+
+#include "s2/s2point.h"
+#include "s2/s2shape_index.h"
+
+namespace s2shapeutil {
+
+// Returns true if the given shape contains the given point.  Most clients
+// should not use this method, since its running time is linear in the number
+// of shape edges.  Instead clients should create an S2ShapeIndex and use
+// S2ContainsPointQuery, since this strategy is much more efficient when many
+// points need to be tested.
+//
+// Polygon boundaries are treated as being semi-open (see S2ContainsPointQuery
+// and S2VertexModel for other options).
+//
+// CAVEAT: Typically this method is only used internally.  Its running time is
+//         linear in the number of shape edges.
+bool ContainsBruteForce(const S2Shape& shape, const S2Point& point);
+
+}  // namespace s2shapeutil
+
+#endif  // S2_S2SHAPEUTIL_CONTAINS_BRUTE_FORCE_H_
diff --git a/src/s2/s2shapeutil_count_edges.h b/src/s2/s2shapeutil_count_edges.h
new file mode 100644 (file)
index 0000000..8d8456f
--- /dev/null
@@ -0,0 +1,57 @@
+// Copyright 2013 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// Author: ericv@google.com (Eric Veach)
+
+#ifndef S2_S2SHAPEUTIL_COUNT_EDGES_H_
+#define S2_S2SHAPEUTIL_COUNT_EDGES_H_
+
+#include "s2/s2shape_index.h"
+
+namespace s2shapeutil {
+
+// Returns the total number of edges in all indexed shapes.  This method takes
+// time linear in the number of shapes.
+template <class S2ShapeIndexType>
+int CountEdges(const S2ShapeIndexType& index);
+
+// Like CountEdges(), but stops once "max_edges" edges have been found (in
+// which case the current running total is returned).
+template <class S2ShapeIndexType>
+int CountEdgesUpTo(const S2ShapeIndexType& index, int max_edges);
+
+
+//////////////////   Implementation details follow   ////////////////////
+
+
+template <class S2ShapeIndexType>
+inline int CountEdges(const S2ShapeIndexType& index) {
+  return CountEdgesUpTo(index, std::numeric_limits<int>::max());
+}
+
+template <class S2ShapeIndexType>
+int CountEdgesUpTo(const S2ShapeIndexType& index, int max_edges) {
+  int num_edges = 0;
+  for (S2Shape* shape : index) {
+    if (shape == nullptr) continue;
+    num_edges += shape->num_edges();
+    if (num_edges >= max_edges) break;
+  }
+  return num_edges;
+}
+
+}  // namespace s2shapeutil
+
+#endif  // S2_S2SHAPEUTIL_COUNT_EDGES_H_
diff --git a/src/s2/s2shapeutil_edge_iterator.cc b/src/s2/s2shapeutil_edge_iterator.cc
new file mode 100644 (file)
index 0000000..2d2859d
--- /dev/null
@@ -0,0 +1,45 @@
+// Copyright Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#include "s2/s2shapeutil_edge_iterator.h"
+
+#include "absl/strings/str_cat.h"
+
+namespace s2shapeutil {
+
+EdgeIterator::EdgeIterator(const S2ShapeIndex* index)
+    : index_(index), shape_id_(-1), num_edges_(0), edge_id_(-1) {
+  Next();
+}
+
+S2Shape::Edge EdgeIterator::edge() const {
+  S2_DCHECK(!Done());
+  return index_->shape(shape_id_)->edge(edge_id_);
+}
+
+void EdgeIterator::Next() {
+  while (++edge_id_ >= num_edges_) {
+    if (++shape_id_ >= index_->num_shape_ids()) break;
+    S2Shape* shape = index_->shape(shape_id_);
+    num_edges_ = (shape == nullptr) ? 0 : shape->num_edges();
+    edge_id_ = -1;
+  }
+}
+
+std::string EdgeIterator::DebugString() const {
+  return absl::StrCat("(shape=", shape_id_, ", edge=", edge_id_, ")");
+}
+
+}  // namespace s2shapeutil
diff --git a/src/s2/s2shapeutil_edge_iterator.h b/src/s2/s2shapeutil_edge_iterator.h
new file mode 100644 (file)
index 0000000..a65c4b7
--- /dev/null
@@ -0,0 +1,72 @@
+// Copyright Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#ifndef S2_S2SHAPEUTIL_EDGE_ITERATOR_H_
+#define S2_S2SHAPEUTIL_EDGE_ITERATOR_H_
+
+#include "s2/s2shape_index.h"
+#include "s2/s2shapeutil_shape_edge_id.h"
+
+namespace s2shapeutil {
+
+// An iterator that advances through all edges in an S2ShapeIndex.
+//
+// Example usage:
+//
+// for (EdgeIterator it(index); !it.Done(); it.Next()) {
+//   auto edge = it.edge();
+//   //...
+// }
+class EdgeIterator {
+ public:
+  explicit EdgeIterator(const S2ShapeIndex* index);
+
+  // Returns the current shape id.
+  int32 shape_id() const { return shape_id_; }
+
+  // Returns the current edge id.
+  int32 edge_id() const { return edge_id_; }
+
+  // Returns the current (shape_id, edge_id).
+  ShapeEdgeId shape_edge_id() const { return ShapeEdgeId(shape_id_, edge_id_); }
+
+  // Returns the current edge.
+  S2Shape::Edge edge() const;
+
+  // Returns true if there are no more edges in the index.
+  bool Done() const { return shape_id() >= index_->num_shape_ids(); }
+
+  // Advances to the next edge.
+  void Next();
+
+  bool operator==(const EdgeIterator& other) const {
+    return index_ == other.index_ && shape_id_ == other.shape_id_ &&
+           edge_id_ == other.edge_id_;
+  }
+
+  bool operator!=(const EdgeIterator& other) const { return !(*this == other); }
+
+  std::string DebugString() const;
+
+ private:
+  const S2ShapeIndex* index_;
+  int32 shape_id_;
+  int32 num_edges_;
+  int32 edge_id_;
+};
+
+}  // namespace s2shapeutil
+
+#endif  // S2_S2SHAPEUTIL_EDGE_ITERATOR_H_
diff --git a/src/s2/s2shapeutil_get_reference_point.cc b/src/s2/s2shapeutil_get_reference_point.cc
new file mode 100644 (file)
index 0000000..0a03e1a
--- /dev/null
@@ -0,0 +1,107 @@
+// Copyright 2013 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// Author: ericv@google.com (Eric Veach)
+
+#include "s2/s2shapeutil_get_reference_point.h"
+
+#include <algorithm>
+
+#include "s2/base/logging.h"
+#include "s2/s2contains_vertex_query.h"
+
+using std::vector;
+using ReferencePoint = S2Shape::ReferencePoint;
+
+namespace s2shapeutil {
+
+// This is a helper function for GetReferencePoint() below.
+//
+// If the given vertex "vtest" is unbalanced (see definition below), sets
+// "result" to a ReferencePoint indicating whther "vtest" is contained and
+// returns true.  Otherwise returns false.
+static bool GetReferencePointAtVertex(
+    const S2Shape& shape, const S2Point& vtest, ReferencePoint* result) {
+  // Let P be an unbalanced vertex.  Vertex P is defined to be inside the
+  // region if the region contains a particular direction vector starting from
+  // P, namely the direction S2::Ortho(P).  This can be calculated using
+  // S2ContainsVertexQuery.
+  S2ContainsVertexQuery contains_query(vtest);
+  int n = shape.num_edges();
+  for (int e = 0; e < n; ++e) {
+    auto edge = shape.edge(e);
+    if (edge.v0 == vtest) contains_query.AddEdge(edge.v1, 1);
+    if (edge.v1 == vtest) contains_query.AddEdge(edge.v0, -1);
+  }
+  int contains_sign = contains_query.ContainsSign();
+  if (contains_sign == 0) {
+    return false;  // There are no unmatched edges incident to this vertex.
+  }
+  result->point = vtest;
+  result->contained = contains_sign > 0;
+  return true;
+}
+
+// See documentation in header file.
+S2Shape::ReferencePoint GetReferencePoint(const S2Shape& shape) {
+  S2_DCHECK_EQ(shape.dimension(), 2);
+  if (shape.num_edges() == 0) {
+    // A shape with no edges is defined to be full if and only if it
+    // contains at least one chain.
+    return ReferencePoint::Contained(shape.num_chains() > 0);
+  }
+  // Define a "matched" edge as one that can be paired with a corresponding
+  // reversed edge.  Define a vertex as "balanced" if all of its edges are
+  // matched. In order to determine containment, we must find an unbalanced
+  // vertex.  Often every vertex is unbalanced, so we start by trying an
+  // arbitrary vertex.
+  auto edge = shape.edge(0);
+  ReferencePoint result;
+  if (GetReferencePointAtVertex(shape, edge.v0, &result)) {
+    return result;
+  }
+  // That didn't work, so now we do some extra work to find an unbalanced
+  // vertex (if any).  Essentially we gather a list of edges and a list of
+  // reversed edges, and then sort them.  The first edge that appears in one
+  // list but not the other is guaranteed to be unmatched.
+  int n = shape.num_edges();
+  vector<S2Shape::Edge> edges(n), rev_edges(n);
+  for (int i = 0; i < n; ++i) {
+    auto edge = shape.edge(i);
+    edges[i] = edge;
+    rev_edges[i] = S2Shape::Edge(edge.v1, edge.v0);
+  }
+  std::sort(edges.begin(), edges.end());
+  std::sort(rev_edges.begin(), rev_edges.end());
+  for (int i = 0; i < n; ++i) {
+    if (edges[i] < rev_edges[i]) {  // edges[i] is unmatched
+      S2_CHECK(GetReferencePointAtVertex(shape, edges[i].v0, &result));
+      return result;
+    }
+    if (rev_edges[i] < edges[i]) {  // rev_edges[i] is unmatched
+      S2_CHECK(GetReferencePointAtVertex(shape, rev_edges[i].v0, &result));
+      return result;
+    }
+  }
+  // All vertices are balanced, so this polygon is either empty or full except
+  // for degeneracies.  By convention it is defined to be full if it contains
+  // any chain with no edges.
+  for (int i = 0; i < shape.num_chains(); ++i) {
+    if (shape.chain(i).length == 0) return ReferencePoint::Contained(true);
+  }
+  return ReferencePoint::Contained(false);
+}
+
+}  // namespace s2shapeutil
diff --git a/src/s2/s2shapeutil_get_reference_point.h b/src/s2/s2shapeutil_get_reference_point.h
new file mode 100644 (file)
index 0000000..726b7f6
--- /dev/null
@@ -0,0 +1,48 @@
+// Copyright 2013 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// Author: ericv@google.com (Eric Veach)
+
+#ifndef S2_S2SHAPEUTIL_GET_REFERENCE_POINT_H_
+#define S2_S2SHAPEUTIL_GET_REFERENCE_POINT_H_
+
+#include "s2/s2shape_index.h"
+
+namespace s2shapeutil {
+
+// This is a helper function for implementing S2Shape::GetReferencePoint().
+//
+// Given a shape consisting of closed polygonal loops, the interior of the
+// shape is defined as the region to the left of all edges (which must be
+// oriented consistently).  This function then chooses an arbitrary point and
+// returns true if that point is contained by the shape.
+//
+// Unlike S2Loop and S2Polygon, this method allows duplicate vertices and
+// edges, which requires some extra care with definitions.  The rule that we
+// apply is that an edge and its reverse edge "cancel" each other: the result
+// is the same as if that edge pair were not present.  Therefore shapes that
+// consist only of degenerate loop(s) are either empty or full; by convention,
+// the shape is considered full if and only if it contains an empty loop (see
+// S2LaxPolygonShape for details).
+//
+// Determining whether a loop on the sphere contains a point is harder than
+// the corresponding problem in 2D plane geometry.  It cannot be implemented
+// just by counting edge crossings because there is no such thing as a "point
+// at infinity" that is guaranteed to be outside the loop.
+S2Shape::ReferencePoint GetReferencePoint(const S2Shape& shape);
+
+}  // namespace s2shapeutil
+
+#endif  // S2_S2SHAPEUTIL_GET_REFERENCE_POINT_H_
diff --git a/src/s2/s2shapeutil_range_iterator.cc b/src/s2/s2shapeutil_range_iterator.cc
new file mode 100644 (file)
index 0000000..cc5f4a7
--- /dev/null
@@ -0,0 +1,58 @@
+// Copyright 2013 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// Author: ericv@google.com (Eric Veach)
+
+#include "s2/s2shapeutil_range_iterator.h"
+
+namespace s2shapeutil {
+
+RangeIterator::RangeIterator(const S2ShapeIndex& index)
+    : it_(&index, S2ShapeIndex::BEGIN) {
+  Refresh();
+}
+
+void RangeIterator::Next() {
+  it_.Next();
+  Refresh();
+}
+
+void RangeIterator::SeekTo(const RangeIterator& target) {
+  it_.Seek(target.range_min());
+  // If the current cell does not overlap "target", it is possible that the
+  // previous cell is the one we are looking for.  This can only happen when
+  // the previous cell contains "target" but has a smaller S2CellId.
+  if (it_.done() || it_.id().range_min() > target.range_max()) {
+    if (it_.Prev() && it_.id().range_max() < target.id()) it_.Next();
+  }
+  Refresh();
+}
+
+void RangeIterator::SeekBeyond(const RangeIterator& target) {
+  it_.Seek(target.range_max().next());
+  if (!it_.done() && it_.id().range_min() <= target.range_max()) {
+    it_.Next();
+  }
+  Refresh();
+}
+
+// This method is inline, but is only called by non-inline methods defined in
+// this file.  Putting the definition here enforces this requirement.
+inline void RangeIterator::Refresh() {
+  range_min_ = id().range_min();
+  range_max_ = id().range_max();
+}
+
+}  // namespace s2shapeutil
diff --git a/src/s2/s2shapeutil_range_iterator.h b/src/s2/s2shapeutil_range_iterator.h
new file mode 100644 (file)
index 0000000..e4703c6
--- /dev/null
@@ -0,0 +1,65 @@
+// Copyright 2013 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// Author: ericv@google.com (Eric Veach)
+
+#ifndef S2_S2SHAPEUTIL_RANGE_ITERATOR_H_
+#define S2_S2SHAPEUTIL_RANGE_ITERATOR_H_
+
+#include "s2/s2cell_id.h"
+#include "s2/s2shape_index.h"
+
+class S2Loop;
+class S2Error;
+
+namespace s2shapeutil {
+
+// RangeIterator is a wrapper over S2ShapeIndex::Iterator with extra methods
+// that are useful for merging the contents of two or more S2ShapeIndexes.
+class RangeIterator {
+ public:
+  // Construct a new RangeIterator positioned at the first cell of the index.
+  explicit RangeIterator(const S2ShapeIndex& index);
+
+  // The current S2CellId and cell contents.
+  S2CellId id() const { return it_.id(); }
+  const S2ShapeIndexCell& cell() const { return it_.cell(); }
+
+  // The min and max leaf cell ids covered by the current cell.  If done() is
+  // true, these methods return a value larger than any valid cell id.
+  S2CellId range_min() const { return range_min_; }
+  S2CellId range_max() const { return range_max_; }
+
+  void Next();
+  bool done() { return it_.done(); }
+
+  // Position the iterator at the first cell that overlaps or follows
+  // "target", i.e. such that range_max() >= target.range_min().
+  void SeekTo(const RangeIterator& target);
+
+  // Position the iterator at the first cell that follows "target", i.e. the
+  // first cell such that range_min() > target.range_max().
+  void SeekBeyond(const RangeIterator& target);
+
+ private:
+  // Updates internal state after the iterator has been repositioned.
+  void Refresh();
+  S2ShapeIndex::Iterator it_;
+  S2CellId range_min_, range_max_;
+};
+
+}  // namespace s2shapeutil
+
+#endif  // S2_S2SHAPEUTIL_RANGE_ITERATOR_H_
diff --git a/src/s2/s2shapeutil_shape_edge.h b/src/s2/s2shapeutil_shape_edge.h
new file mode 100644 (file)
index 0000000..3562c04
--- /dev/null
@@ -0,0 +1,58 @@
+// Copyright 2013 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// Author: ericv@google.com (Eric Veach)
+
+#ifndef S2_S2SHAPEUTIL_SHAPE_EDGE_H_
+#define S2_S2SHAPEUTIL_SHAPE_EDGE_H_
+
+#include "s2/s2point.h"
+#include "s2/s2shape.h"
+#include "s2/s2shapeutil_shape_edge_id.h"
+
+namespace s2shapeutil {
+
+// A class representing a ShapeEdgeId together with the two endpoints of that
+// edge.  It should be passed by reference.
+struct ShapeEdge {
+ public:
+  ShapeEdge() {}
+  ShapeEdge(const S2Shape& shape, int32 edge_id);
+  ShapeEdge(int32 shape_id, int32 edge_id, const S2Shape::Edge& edge);
+  ShapeEdgeId id() const { return id_; }
+  const S2Point& v0() const { return edge_.v0; }
+  const S2Point& v1() const { return edge_.v1; }
+
+ private:
+  ShapeEdgeId id_;
+  S2Shape::Edge edge_;
+};
+
+
+//////////////////   Implementation details follow   ////////////////////
+
+
+inline ShapeEdge::ShapeEdge(const S2Shape& shape, int32 edge_id)
+    : ShapeEdge(shape.id(), edge_id, shape.edge(edge_id)) {
+}
+
+inline ShapeEdge::ShapeEdge(int32 shape_id, int32 edge_id,
+                            const S2Shape::Edge& edge)
+    : id_(shape_id, edge_id), edge_(edge) {
+}
+
+}  // namespace s2shapeutil
+
+#endif  // S2_S2SHAPEUTIL_SHAPE_EDGE_H_
diff --git a/src/s2/s2shapeutil_shape_edge_id.h b/src/s2/s2shapeutil_shape_edge_id.h
new file mode 100644 (file)
index 0000000..b17affb
--- /dev/null
@@ -0,0 +1,97 @@
+// Copyright 2013 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// Author: ericv@google.com (Eric Veach)
+
+#ifndef S2_S2SHAPEUTIL_SHAPE_EDGE_ID_H_
+#define S2_S2SHAPEUTIL_SHAPE_EDGE_ID_H_
+
+#include <iostream>
+#include "s2/base/integral_types.h"
+
+namespace s2shapeutil {
+
+// ShapeEdgeId is a unique identifier for an edge within an S2ShapeIndex,
+// consisting of a (shape_id, edge_id) pair.  It is similar to
+// std::pair<int32, int32> except that it has named fields.
+// It should be passed and returned by value.
+struct ShapeEdgeId {
+ public:
+  int32 shape_id, edge_id;
+  ShapeEdgeId() : shape_id(-1), edge_id(-1) {}
+  ShapeEdgeId(int32 _shape_id, int32 _edge_id);
+
+  bool operator==(ShapeEdgeId other) const;
+  bool operator!=(ShapeEdgeId other) const;
+  bool operator<(ShapeEdgeId other) const;
+  bool operator>(ShapeEdgeId other) const;
+  bool operator<=(ShapeEdgeId other) const;
+  bool operator>=(ShapeEdgeId other) const;
+};
+std::ostream& operator<<(std::ostream& os, ShapeEdgeId id);
+
+// Hasher for ShapeEdgeId.
+// Example use: std::unordered_set<ShapeEdgeId, ShapeEdgeIdHash>.
+struct ShapeEdgeIdHash;
+
+
+//////////////////   Implementation details follow   ////////////////////
+
+
+inline ShapeEdgeId::ShapeEdgeId(int32 _shape_id, int32 _edge_id)
+    : shape_id(_shape_id), edge_id(_edge_id) {
+}
+
+inline bool ShapeEdgeId::operator==(ShapeEdgeId other) const {
+  return shape_id == other.shape_id && edge_id == other.edge_id;
+}
+
+inline bool ShapeEdgeId::operator!=(ShapeEdgeId other) const {
+  return !(*this == other);
+}
+
+inline bool ShapeEdgeId::operator<(ShapeEdgeId other) const {
+  if (shape_id < other.shape_id) return true;
+  if (other.shape_id < shape_id) return false;
+  return edge_id < other.edge_id;
+}
+
+inline bool ShapeEdgeId::operator>(ShapeEdgeId other) const {
+  return other < *this;
+}
+
+inline bool ShapeEdgeId::operator<=(ShapeEdgeId other) const {
+  return !(other < *this);
+}
+
+inline bool ShapeEdgeId::operator>=(ShapeEdgeId other) const {
+  return !(*this < other);
+}
+
+inline std::ostream& operator<<(std::ostream& os, ShapeEdgeId id) {
+  return os << id.shape_id << ":" << id.edge_id;
+}
+
+struct ShapeEdgeIdHash {
+  size_t operator()(ShapeEdgeId id) const {
+    // The following preserves all bits even when edge_id < 0.
+    return std::hash<uint64>()((static_cast<uint64>(id.shape_id) << 32) |
+                               static_cast<uint32>(id.edge_id));
+  }
+};
+
+}  // namespace s2shapeutil
+
+#endif  // S2_S2SHAPEUTIL_SHAPE_EDGE_ID_H_
diff --git a/src/s2/s2shapeutil_testing.h b/src/s2/s2shapeutil_testing.h
new file mode 100644 (file)
index 0000000..401d1f6
--- /dev/null
@@ -0,0 +1,36 @@
+// Copyright 2018 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// Author: ericv@google.com (Eric Veach)
+
+#ifndef S2_S2SHAPEUTIL_TESTING_H_
+#define S2_S2SHAPEUTIL_TESTING_H_
+
+#include "s2/s2shape.h"
+#include "s2/s2shape_index.h"
+
+namespace s2testing {
+
+// Verifies that all methods of the two S2Shapes return identical results,
+// except for id() and type_tag().
+void ExpectEqual(const S2Shape& a, const S2Shape& b);
+
+// Verifies that two S2ShapeIndexes have identical contents (including all the
+// S2Shapes in both indexes).
+void ExpectEqual(const S2ShapeIndex& a, const S2ShapeIndex& b);
+
+}  // namespace s2testing
+
+#endif  // S2_S2SHAPEUTIL_TESTING_H_
diff --git a/src/s2/s2shapeutil_visit_crossing_edge_pairs.cc b/src/s2/s2shapeutil_visit_crossing_edge_pairs.cc
new file mode 100644 (file)
index 0000000..ebf1a5d
--- /dev/null
@@ -0,0 +1,440 @@
+// Copyright 2013 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// Author: ericv@google.com (Eric Veach)
+
+#include "s2/s2shapeutil_visit_crossing_edge_pairs.h"
+
+#include "s2/s2crossing_edge_query.h"
+#include "s2/s2edge_crosser.h"
+#include "s2/s2error.h"
+#include "s2/s2shapeutil_range_iterator.h"
+#include "s2/s2wedge_relations.h"
+
+using std::vector;
+using ChainPosition = S2Shape::ChainPosition;
+
+namespace s2shapeutil {
+
+// Ensure that we don't usually need to allocate memory when collecting the
+// edges in an S2ShapeIndex cell (which by default have about 10 edges).
+using ShapeEdgeVector = absl::InlinedVector<ShapeEdge, 16>;
+
+// Appends all edges in the given S2ShapeIndexCell to the given vector.
+static void AppendShapeEdges(const S2ShapeIndex& index,
+                             const S2ShapeIndexCell& cell,
+                             ShapeEdgeVector* shape_edges) {
+  for (int s = 0; s < cell.num_clipped(); ++s) {
+    const S2ClippedShape& clipped = cell.clipped(s);
+    const S2Shape& shape = *index.shape(clipped.shape_id());
+    int num_edges = clipped.num_edges();
+    for (int i = 0; i < num_edges; ++i) {
+      shape_edges->push_back(ShapeEdge(shape, clipped.edge(i)));
+    }
+  }
+}
+
+// Returns a vector containing all edges in the given S2ShapeIndexCell.
+// (The result is returned as an output parameter so that the same storage can
+// be reused, rather than allocating a new temporary vector each time.)
+inline static void GetShapeEdges(const S2ShapeIndex& index,
+                                 const S2ShapeIndexCell& cell,
+                                 ShapeEdgeVector* shape_edges) {
+  shape_edges->clear();
+  AppendShapeEdges(index, cell, shape_edges);
+}
+
+// Returns a vector containing all edges in the given S2ShapeIndexCell vector.
+// (The result is returned as an output parameter so that the same storage can
+// be reused, rather than allocating a new temporary vector each time.)
+inline static void GetShapeEdges(const S2ShapeIndex& index,
+                                 const vector<const S2ShapeIndexCell*>& cells,
+                                 ShapeEdgeVector* shape_edges) {
+  shape_edges->clear();
+  for (auto cell : cells) {
+    AppendShapeEdges(index, *cell, shape_edges);
+  }
+}
+
+// Given a vector of edges within an S2ShapeIndexCell, visit all pairs of
+// crossing edges (of the given CrossingType).
+static bool VisitCrossings(const ShapeEdgeVector& shape_edges,
+                           CrossingType type, bool need_adjacent,
+                           const EdgePairVisitor& visitor) {
+  const int min_crossing_sign = (type == CrossingType::INTERIOR) ? 1 : 0;
+  int num_edges = shape_edges.size();
+  for (int i = 0; i + 1 < num_edges; ++i) {
+    const ShapeEdge& a = shape_edges[i];
+    int j = i + 1;
+    // A common situation is that an edge AB is followed by an edge BC.  We
+    // only need to visit such crossings if "need_adjacent" is true (even if
+    // AB and BC belong to different edge chains).
+    if (!need_adjacent && a.v1() == shape_edges[j].v0()) {
+      if (++j >= num_edges) break;
+    }
+    S2EdgeCrosser crosser(&a.v0(), &a.v1());
+    for (; j < num_edges; ++j) {
+      const ShapeEdge& b = shape_edges[j];
+      if (crosser.c() == nullptr || *crosser.c() != b.v0()) {
+        crosser.RestartAt(&b.v0());
+      }
+      int sign = crosser.CrossingSign(&b.v1());
+      if (sign >= min_crossing_sign) {
+        if (!visitor(a, b, sign == 1)) return false;
+      }
+    }
+  }
+  return true;
+}
+
+// Visits all pairs of crossing edges in the given S2ShapeIndex, terminating
+// early if the given EdgePairVisitor function returns false (in which case
+// VisitCrossings returns false as well).  "type" indicates whether all
+// crossings should be visited, or only interior crossings.
+//
+// If "need_adjacent" is false, then edge pairs of the form (AB, BC) may
+// optionally be ignored (even if the two edges belong to different edge
+// chains).  This option exists for the benefit of FindSelfIntersection(),
+// which does not need such edge pairs (see below).
+static bool VisitCrossings(
+    const S2ShapeIndex& index, CrossingType type, bool need_adjacent,
+    const EdgePairVisitor& visitor) {
+  // TODO(ericv): Use brute force if the total number of edges is small enough
+  // (using a larger threshold if the S2ShapeIndex is not constructed yet).
+  ShapeEdgeVector shape_edges;
+  for (S2ShapeIndex::Iterator it(&index, S2ShapeIndex::BEGIN);
+       !it.done(); it.Next()) {
+    GetShapeEdges(index, it.cell(), &shape_edges);
+    if (!VisitCrossings(shape_edges, type, need_adjacent, visitor)) {
+      return false;
+    }
+  }
+  return true;
+}
+
+bool VisitCrossingEdgePairs(const S2ShapeIndex& index, CrossingType type,
+                            const EdgePairVisitor& visitor) {
+  const bool need_adjacent = (type == CrossingType::ALL);
+  return VisitCrossings(index, type, need_adjacent, visitor);
+}
+
+//////////////////////////////////////////////////////////////////////
+
+// IndexCrosser is a helper class for finding the edge crossings between a
+// pair of S2ShapeIndexes.  It is instantiated twice, once for the index pair
+// (A,B) and once for the index pair (B,A), in order to be able to test edge
+// crossings in the most efficient order.
+namespace {
+class IndexCrosser {
+ public:
+  // If "swapped" is true, the loops A and B have been swapped.  This affects
+  // how arguments are passed to the given loop relation, since for example
+  // A.Contains(B) is not the same as B.Contains(A).
+  IndexCrosser(const S2ShapeIndex& a_index, const S2ShapeIndex& b_index,
+               CrossingType type, const EdgePairVisitor& visitor, bool swapped)
+      : a_index_(a_index), b_index_(b_index), visitor_(visitor),
+        min_crossing_sign_(type == CrossingType::INTERIOR ? 1 : 0),
+        swapped_(swapped), b_query_(&b_index_) {
+  }
+
+  // Given two iterators positioned such that ai->id().Contains(bi->id()),
+  // visits all crossings between edges of A and B that intersect a->id().
+  // Terminates early and returns false if visitor_ returns false.
+  // Advances both iterators past ai->id().
+  bool VisitCrossings(RangeIterator* ai, RangeIterator* bi);
+
+  // Given two index cells, visits all crossings between edges of those cells.
+  // Terminates early and returns false if visitor_ returns false.
+  bool VisitCellCellCrossings(const S2ShapeIndexCell& a_cell,
+                              const S2ShapeIndexCell& b_cell);
+
+ private:
+  bool VisitEdgePair(const ShapeEdge& a, const ShapeEdge& b, bool is_interior);
+
+  // Visits all crossings of the current edge with all edges of the given index
+  // cell of B.  Terminates early and returns false if visitor_ returns false.
+  bool VisitEdgeCellCrossings(const ShapeEdge& a,
+                              const S2ShapeIndexCell& b_cell);
+
+  // Visits all crossings of any edge in "a_cell" with any index cell of B that
+  // is a descendant of "b_id".  Terminates early and returns false if
+  // visitor_ returns false.
+  bool VisitSubcellCrossings(const S2ShapeIndexCell& a_cell, S2CellId b_id);
+
+  // Visits all crossings of any edge in "a_edges" with any edge in "b_edges".
+  bool VisitEdgesEdgesCrossings(const ShapeEdgeVector& a_edges,
+                                const ShapeEdgeVector& b_edges);
+
+  const S2ShapeIndex& a_index_;
+  const S2ShapeIndex& b_index_;
+  const EdgePairVisitor& visitor_;
+  const int min_crossing_sign_;
+  const bool swapped_;
+
+  // Temporary data declared here to avoid repeated memory allocations.
+  S2CrossingEdgeQuery b_query_;
+  vector<const S2ShapeIndexCell*> b_cells_;
+  ShapeEdgeVector a_shape_edges_;
+  ShapeEdgeVector b_shape_edges_;
+};
+}  // namespace
+
+inline bool IndexCrosser::VisitEdgePair(const ShapeEdge& a, const ShapeEdge& b,
+                                        bool is_interior) {
+  if (swapped_) {
+    return visitor_(b, a, is_interior);
+  } else {
+    return visitor_(a, b, is_interior);
+  }
+}
+
+bool IndexCrosser::VisitEdgeCellCrossings(const ShapeEdge& a,
+                                          const S2ShapeIndexCell& b_cell) {
+  // Test the current edge of A against all edges of "b_cell".
+
+  // Note that we need to use a new S2EdgeCrosser (or call Init) whenever we
+  // replace the contents of b_shape_edges_, since S2EdgeCrosser requires that
+  // its S2Point arguments point to values that persist between Init() calls.
+  GetShapeEdges(b_index_, b_cell, &b_shape_edges_);
+  S2EdgeCrosser crosser(&a.v0(), &a.v1());
+  for (const ShapeEdge& b : b_shape_edges_) {
+    if (crosser.c() == nullptr || *crosser.c() != b.v0()) {
+      crosser.RestartAt(&b.v0());
+    }
+    int sign = crosser.CrossingSign(&b.v1());
+    if (sign >= min_crossing_sign_) {
+      if (!VisitEdgePair(a, b, sign == 1)) return false;
+    }
+  }
+  return true;
+}
+
+bool IndexCrosser::VisitSubcellCrossings(const S2ShapeIndexCell& a_cell,
+                                         S2CellId b_id) {
+  // Test all edges of "a_cell" against the edges contained in B index cells
+  // that are descendants of "b_id".
+  GetShapeEdges(a_index_, a_cell, &a_shape_edges_);
+  S2PaddedCell b_root(b_id, 0);
+  for (const ShapeEdge& a : a_shape_edges_) {
+    // Use an S2CrossingEdgeQuery starting at "b_root" to find the index cells
+    // of B that might contain crossing edges.
+    if (!b_query_.VisitCells(
+            a.v0(), a.v1(), b_root, [&a, this](const S2ShapeIndexCell& cell) {
+              return VisitEdgeCellCrossings(a, cell);
+            })) {
+      return false;
+    }
+  }
+  return true;
+}
+
+bool IndexCrosser::VisitEdgesEdgesCrossings(const ShapeEdgeVector& a_edges,
+                                            const ShapeEdgeVector& b_edges) {
+  // Test all edges of "a_edges" against all edges of "b_edges".
+  for (const ShapeEdge& a : a_edges) {
+    S2EdgeCrosser crosser(&a.v0(), &a.v1());
+    for (const ShapeEdge& b : b_edges) {
+      if (crosser.c() == nullptr || *crosser.c() != b.v0()) {
+        crosser.RestartAt(&b.v0());
+      }
+      int sign = crosser.CrossingSign(&b.v1());
+      if (sign >= min_crossing_sign_) {
+        if (!VisitEdgePair(a, b, sign == 1)) return false;
+      }
+    }
+  }
+  return true;
+}
+
+inline bool IndexCrosser::VisitCellCellCrossings(
+    const S2ShapeIndexCell& a_cell, const S2ShapeIndexCell& b_cell) {
+  // Test all edges of "a_cell" against all edges of "b_cell".
+  GetShapeEdges(a_index_, a_cell, &a_shape_edges_);
+  GetShapeEdges(b_index_, b_cell, &b_shape_edges_);
+  return VisitEdgesEdgesCrossings(a_shape_edges_, b_shape_edges_);
+}
+
+bool IndexCrosser::VisitCrossings(RangeIterator* ai, RangeIterator* bi) {
+  S2_DCHECK(ai->id().contains(bi->id()));
+  if (ai->cell().num_edges() == 0) {
+    // Skip over the cells of B using binary search.
+    bi->SeekBeyond(*ai);
+  } else {
+    // If ai->id() intersects many edges of B, then it is faster to use
+    // S2CrossingEdgeQuery to narrow down the candidates.  But if it
+    // intersects only a few edges, it is faster to check all the crossings
+    // directly.  We handle this by advancing "bi" and keeping track of how
+    // many edges we would need to test.
+    static const int kEdgeQueryMinEdges = 23;
+    int b_edges = 0;
+    b_cells_.clear();
+    do {
+      int cell_edges = bi->cell().num_edges();
+      if (cell_edges > 0) {
+        b_edges += cell_edges;
+        if (b_edges >= kEdgeQueryMinEdges) {
+          // There are too many edges, so use an S2CrossingEdgeQuery.
+          if (!VisitSubcellCrossings(ai->cell(), ai->id())) return false;
+          bi->SeekBeyond(*ai);
+          return true;
+        }
+        b_cells_.push_back(&bi->cell());
+      }
+      bi->Next();
+    } while (bi->id() <= ai->range_max());
+    if (!b_cells_.empty()) {
+      // Test all the edge crossings directly.
+      GetShapeEdges(a_index_, ai->cell(), &a_shape_edges_);
+      GetShapeEdges(b_index_, b_cells_, &b_shape_edges_);
+      if (!VisitEdgesEdgesCrossings(a_shape_edges_, b_shape_edges_)) {
+        return false;
+      }
+    }
+  }
+  ai->Next();
+  return true;
+}
+
+bool VisitCrossingEdgePairs(const S2ShapeIndex& a_index,
+                            const S2ShapeIndex& b_index,
+                            CrossingType type, const EdgePairVisitor& visitor) {
+  // We look for S2CellId ranges where the indexes of A and B overlap, and
+  // then test those edges for crossings.
+
+  // TODO(ericv): Use brute force if the total number of edges is small enough
+  // (using a larger threshold if the S2ShapeIndex is not constructed yet).
+  RangeIterator ai(a_index), bi(b_index);
+  IndexCrosser ab(a_index, b_index, type, visitor, false);  // Tests A against B
+  IndexCrosser ba(b_index, a_index, type, visitor, true);   // Tests B against A
+  while (!ai.done() || !bi.done()) {
+    if (ai.range_max() < bi.range_min()) {
+      // The A and B cells don't overlap, and A precedes B.
+      ai.SeekTo(bi);
+    } else if (bi.range_max() < ai.range_min()) {
+      // The A and B cells don't overlap, and B precedes A.
+      bi.SeekTo(ai);
+    } else {
+      // One cell contains the other.  Determine which cell is larger.
+      int64 ab_relation = ai.id().lsb() - bi.id().lsb();
+      if (ab_relation > 0) {
+        // A's index cell is larger.
+        if (!ab.VisitCrossings(&ai, &bi)) return false;
+      } else if (ab_relation < 0) {
+        // B's index cell is larger.
+        if (!ba.VisitCrossings(&bi, &ai)) return false;
+      } else {
+        // The A and B cells are the same.
+        if (ai.cell().num_edges() > 0 && bi.cell().num_edges() > 0) {
+          if (!ab.VisitCellCellCrossings(ai.cell(), bi.cell())) return false;
+        }
+        ai.Next();
+        bi.Next();
+      }
+    }
+  }
+  return true;
+}
+
+//////////////////////////////////////////////////////////////////////
+
+// Helper function that formats a loop error message.  If the loop belongs to
+// a multi-loop polygon, adds a prefix indicating which loop is affected.
+static void InitLoopError(S2Error::Code code, const char* format,
+                          ChainPosition ap, ChainPosition bp,
+                          bool is_polygon, S2Error* error) {
+  error->Init(code, format, ap.offset, bp.offset);
+  if (is_polygon) {
+    error->Init(code, "Loop %d: %s", ap.chain_id, error->text().c_str());
+  }
+}
+
+// Given two loop edges that cross (including at a shared vertex), return true
+// if there is a crossing error and set "error" to a human-readable message.
+static bool FindCrossingError(const S2Shape& shape,
+                              const ShapeEdge& a, const ShapeEdge& b,
+                              bool is_interior, S2Error* error) {
+  bool is_polygon = shape.num_chains() > 1;
+  S2Shape::ChainPosition ap = shape.chain_position(a.id().edge_id);
+  S2Shape::ChainPosition bp = shape.chain_position(b.id().edge_id);
+  if (is_interior) {
+    if (ap.chain_id != bp.chain_id) {
+      error->Init(S2Error::POLYGON_LOOPS_CROSS,
+                  "Loop %d edge %d crosses loop %d edge %d",
+                  ap.chain_id, ap.offset, bp.chain_id, bp.offset);
+    } else {
+      InitLoopError(S2Error::LOOP_SELF_INTERSECTION,
+                    "Edge %d crosses edge %d", ap, bp, is_polygon, error);
+    }
+    return true;
+  }
+  // Loops are not allowed to have duplicate vertices, and separate loops
+  // are not allowed to share edges or cross at vertices.  We only need to
+  // check a given vertex once, so we also require that the two edges have
+  // the same end vertex.
+  if (a.v1() != b.v1()) return false;
+  if (ap.chain_id == bp.chain_id) {
+    InitLoopError(S2Error::DUPLICATE_VERTICES,
+                  "Edge %d has duplicate vertex with edge %d",
+                  ap, bp, is_polygon, error);
+    return true;
+  }
+  int a_len = shape.chain(ap.chain_id).length;
+  int b_len = shape.chain(bp.chain_id).length;
+  int a_next = (ap.offset + 1 == a_len) ? 0 : ap.offset + 1;
+  int b_next = (bp.offset + 1 == b_len) ? 0 : bp.offset + 1;
+  S2Point a2 = shape.chain_edge(ap.chain_id, a_next).v1;
+  S2Point b2 = shape.chain_edge(bp.chain_id, b_next).v1;
+  if (a.v0() == b.v0() || a.v0() == b2) {
+    // The second edge index is sometimes off by one, hence "near".
+    error->Init(S2Error::POLYGON_LOOPS_SHARE_EDGE,
+                "Loop %d edge %d has duplicate near loop %d edge %d",
+                ap.chain_id, ap.offset, bp.chain_id, bp.offset);
+    return true;
+  }
+  // Since S2ShapeIndex loops are oriented such that the polygon interior is
+  // always on the left, we need to handle the case where one wedge contains
+  // the complement of the other wedge.  This is not specifically detected by
+  // GetWedgeRelation, so there are two cases to check for.
+  //
+  // Note that we don't need to maintain any state regarding loop crossings
+  // because duplicate edges are detected and rejected above.
+  if (S2::GetWedgeRelation(a.v0(), a.v1(), a2, b.v0(), b2) ==
+      S2::WEDGE_PROPERLY_OVERLAPS &&
+      S2::GetWedgeRelation(a.v0(), a.v1(), a2, b2, b.v0()) ==
+      S2::WEDGE_PROPERLY_OVERLAPS) {
+    error->Init(S2Error::POLYGON_LOOPS_CROSS,
+                "Loop %d edge %d crosses loop %d edge %d",
+                ap.chain_id, ap.offset, bp.chain_id, bp.offset);
+    return true;
+  }
+  return false;
+}
+
+bool FindSelfIntersection(const S2ShapeIndex& index, S2Error* error) {
+  if (index.num_shape_ids() == 0) return false;
+  S2_DCHECK_EQ(1, index.num_shape_ids());
+  const S2Shape& shape = *index.shape(0);
+
+  // Visit all crossing pairs except possibly for ones of the form (AB, BC),
+  // since such pairs are very common and FindCrossingError() only needs pairs
+  // of the form (AB, AC).
+  return !VisitCrossings(
+      index, CrossingType::ALL, false /*need_adjacent*/,
+      [&](const ShapeEdge& a, const ShapeEdge& b, bool is_interior) {
+        return !FindCrossingError(shape, a, b, is_interior, error);
+      });
+}
+
+}  // namespace s2shapeutil
diff --git a/src/s2/s2shapeutil_visit_crossing_edge_pairs.h b/src/s2/s2shapeutil_visit_crossing_edge_pairs.h
new file mode 100644 (file)
index 0000000..30430c9
--- /dev/null
@@ -0,0 +1,72 @@
+// Copyright 2013 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// Author: ericv@google.com (Eric Veach)
+
+#ifndef S2_S2SHAPEUTIL_VISIT_CROSSING_EDGE_PAIRS_H_
+#define S2_S2SHAPEUTIL_VISIT_CROSSING_EDGE_PAIRS_H_
+
+#include <functional>
+#include "s2/s2crossing_edge_query.h"
+#include "s2/s2shape_index.h"
+#include "s2/s2shapeutil_shape_edge.h"
+
+class S2Error;
+
+namespace s2shapeutil {
+
+// A function that is called with pairs of crossing edges.  The function may
+// return false in order to request that the algorithm should be terminated,
+// i.e. no further crossings are needed.
+//
+// "is_interior" indicates that the crossing is at a point interior to both
+// edges (i.e., not at a vertex).  (The calling function already has this
+// information and it is moderately expensive to recompute.)
+using EdgePairVisitor = std::function<
+  bool (const ShapeEdge& a, const ShapeEdge& b, bool is_interior)>;
+
+// Visits all pairs of crossing edges in the given S2ShapeIndex, terminating
+// early if the given EdgePairVisitor function returns false (in which case
+// VisitCrossings returns false as well).  "type" indicates whether all
+// crossings should be visited, or only interior crossings.
+//
+// CAVEAT: Crossings may be visited more than once.
+bool VisitCrossingEdgePairs(const S2ShapeIndex& index, CrossingType type,
+                            const EdgePairVisitor& visitor);
+
+// Like the above, but visits all pairs of crossing edges where one edge comes
+// from each S2ShapeIndex.
+//
+// CAVEAT: Crossings may be visited more than once.
+bool VisitCrossingEdgePairs(const S2ShapeIndex& a_index,
+                            const S2ShapeIndex& b_index,
+                            CrossingType type, const EdgePairVisitor& visitor);
+
+// Given an S2ShapeIndex containing a single polygonal shape (e.g., an
+// S2Polygon or S2Loop), return true if any loop has a self-intersection
+// (including duplicate vertices) or crosses any other loop (including vertex
+// crossings and duplicate edges) and set "error" to a human-readable error
+// message.  Otherwise return false and leave "error" unchanged.
+//
+// This method is used to implement the FindValidationError methods of S2Loop
+// and S2Polygon.
+//
+// TODO(ericv): Add an option to support S2LaxPolygonShape rules (i.e.,
+// duplicate vertices and edges are allowed, but loop crossings are not).
+bool FindSelfIntersection(const S2ShapeIndex& index, S2Error* error);
+
+}  // namespace s2shapeutil
+
+#endif  // S2_S2SHAPEUTIL_VISIT_CROSSING_EDGE_PAIRS_H_
diff --git a/src/s2/s2testing.cc b/src/s2/s2testing.cc
new file mode 100644 (file)
index 0000000..e1b431b
--- /dev/null
@@ -0,0 +1,465 @@
+#include "cpp-compat.h"
+// Copyright 2005 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// Author: ericv@google.com (Eric Veach)
+
+#include "s2/s2testing.h"
+
+#include <algorithm>
+#include <cmath>
+#include <cstddef>
+#include <cstdlib>
+#include <memory>
+#include <utility>
+#include <vector>
+
+#include "s2/base/commandlineflags.h"
+#include "s2/base/integral_types.h"
+#include "s2/base/logging.h"
+#include "s2/r1interval.h"
+#include "s2/s1angle.h"
+#include "s2/s1interval.h"
+#include "s2/s2cap.h"
+#include "s2/s2cell.h"
+#include "s2/s2cell_union.h"
+#include "s2/s2latlng.h"
+#include "s2/s2latlng_rect.h"
+#include "s2/s2loop.h"
+#include "s2/s2pointutil.h"
+#include "s2/s2polygon.h"
+#include "s2/s2polyline.h"
+#include "s2/s2region.h"
+#include "s2/s2text_format.h"
+#include "s2/strings/serialize.h"
+#include "absl/memory/memory.h"
+#include "absl/strings/str_split.h"
+#include "s2/util/math/matrix3x3.h"
+
+using absl::make_unique;
+using std::max;
+using std::unique_ptr;
+using std::vector;
+
+DEFINE_int32(s2_random_seed, 1,
+             "Seed value that can be passed to S2Testing::rnd.Reset()");
+
+const double S2Testing::kEarthRadiusKm = 6371.01;
+
+S2Testing::Random::Random() {
+  // Unfortunately we can't use FLAGS_s2_random_seed here, because the default
+  // S2Testing::Random instance is initialized before command-line flags have
+  // been parsed.
+  cpp_compat_srandom(1);
+}
+
+void S2Testing::Random::Reset(int seed) {
+  cpp_compat_srandom(seed);
+}
+
+// Return a 64-bit unsigned integer whose lowest "num_bits" are random, and
+// whose other bits are zero.
+inline uint64 GetBits(int num_bits) {
+  S2_DCHECK_GE(num_bits, 0);
+  S2_DCHECK_LE(num_bits, 64);
+
+  // This code uses random(), which returns an integer in the range
+  // from 0 to (2^31)-1 inclusive (i.e. all of the lower 31 bits are
+  // in play, and the 32nd bit and higher are 0) regardless of whether
+  // its return type (long) is larger than 32 bits.  See
+  //
+  // www.gnu.org/software/libc/manual/html_node/BSD-Random.html#BSD-Random
+  //
+  // Note that at some point the manual page in linux claimed that the range
+  // is 0 to RAND_MAX as defined in stdlib.h.  RAND_MAX however is part only
+  // of the ISO rand() interface.  At least as of glibc-2.21, rand() is
+  // simply an alias for random().  On other systems, rand() may differ,
+  // but random() should always adhere to the behavior specified in BSD.
+  static const int RAND_BITS = 31;
+
+  uint64 result = 0;
+  for (int bits = 0; bits < num_bits; bits += RAND_BITS) {
+    result = (result << RAND_BITS) + cpp_compat_random();
+  }
+  if (num_bits < 64) {  // Not legal to shift by full bitwidth of type
+    result &= ((1ULL << num_bits) - 1);
+  }
+  return result;
+}
+
+uint64 S2Testing::Random::Rand64() {
+  return GetBits(64);
+}
+
+uint32 S2Testing::Random::Rand32() {
+  return GetBits(32);
+}
+
+double S2Testing::Random::RandDouble() {
+  const int NUM_BITS = 53;
+  return ldexp((double) GetBits(NUM_BITS), -NUM_BITS);
+}
+
+int32 S2Testing::Random::Uniform(int32 n) {
+  S2_DCHECK_GT(n, 0);
+  return static_cast<uint32>(RandDouble() * n);
+}
+
+double S2Testing::Random::UniformDouble(double min, double limit) {
+  S2_DCHECK_LT(min, limit);
+  return min + RandDouble() * (limit - min);
+}
+
+bool S2Testing::Random::OneIn(int32 n) {
+  return Uniform(n) == 0;
+}
+
+int32 S2Testing::Random::Skewed(int max_log) {
+  S2_DCHECK_GE(max_log, 0);
+  S2_DCHECK_LE(max_log, 31);
+  int32 base = Uniform(max_log + 1);
+  return GetBits(31) & ((1U << base) - 1);
+}
+
+S2Testing::Random S2Testing::rnd;
+
+void S2Testing::AppendLoopVertices(const S2Loop& loop,
+                                   vector<S2Point>* vertices) {
+  int n = loop.num_vertices();
+  const S2Point* base = &loop.vertex(0);
+  S2_DCHECK_EQ(&loop.vertex(n - 1), base + n - 1);
+  vertices->insert(vertices->end(), base, base + n);
+}
+
+vector<S2Point> S2Testing::MakeRegularPoints(const S2Point& center,
+                                             S1Angle radius,
+                                             int num_vertices) {
+  unique_ptr<S2Loop> loop(
+      S2Loop::MakeRegularLoop(center, radius, num_vertices));
+  vector<S2Point> points;
+  points.reserve(loop->num_vertices());
+  for (int i = 0; i < loop->num_vertices(); i++) {
+    points.push_back(loop->vertex(i));
+  }
+  return points;
+}
+
+S1Angle S2Testing::MetersToAngle(double meters) {
+  return KmToAngle(0.001 * meters);
+}
+
+S1Angle S2Testing::KmToAngle(double km) {
+  return S1Angle::Radians(km / kEarthRadiusKm);
+}
+
+double S2Testing::AreaToMeters2(double steradians) {
+  return 1e6 * AreaToKm2(steradians);
+}
+
+double S2Testing::AreaToKm2(double steradians) {
+  return steradians * kEarthRadiusKm * kEarthRadiusKm;
+}
+
+// The overloaded Dump() function is for use within a debugger.
+void Dump(const S2Point& p) {
+  cpp_compat_cout << "S2Point: " << s2textformat::ToString(p) << std::endl;
+}
+
+void Dump(const S2Loop& loop) {
+  cpp_compat_cout << "S2Polygon: " << s2textformat::ToString(loop) << std::endl;
+}
+
+void Dump(const S2Polyline& polyline) {
+  cpp_compat_cout << "S2Polyline: " << s2textformat::ToString(polyline) << std::endl;
+}
+
+void Dump(const S2Polygon& polygon) {
+  cpp_compat_cout << "S2Polygon: " << s2textformat::ToString(polygon) << std::endl;
+}
+
+// Outputs the contents of an S2ShapeIndex in human-readable form.
+void Dump(const S2ShapeIndex& index) {
+  cpp_compat_cout << "S2ShapeIndex: " << &index << std::endl;
+  for (S2ShapeIndex::Iterator it(&index, S2ShapeIndex::BEGIN);
+       !it.done(); it.Next()) {
+    cpp_compat_cout << "  id: " << it.id().ToString() << std::endl;
+    const S2ShapeIndexCell& cell = it.cell();
+    for (int s = 0; s < cell.num_clipped(); ++s) {
+      const S2ClippedShape& clipped = cell.clipped(s);
+      cpp_compat_cout << "    shape_id " << clipped.shape_id() << ": ";
+      for (int e = 0; e < clipped.num_edges(); ++e) {
+        if (e > 0) cpp_compat_cout << ", ";
+        cpp_compat_cout << clipped.edge(e);
+      }
+      cpp_compat_cout << std::endl;
+    }
+  }
+}
+
+S2Point S2Testing::RandomPoint() {
+  // The order of evaluation of function arguments is unspecified,
+  // so we may not just call S2Point with three RandDouble-based args.
+  // Use temporaries to induce sequence points between calls.
+  double x = rnd.UniformDouble(-1, 1);
+  double y = rnd.UniformDouble(-1, 1);
+  double z = rnd.UniformDouble(-1, 1);
+  return S2Point(x, y, z).Normalize();
+}
+
+void S2Testing::GetRandomFrame(Vector3_d* x, Vector3_d* y, Vector3_d* z) {
+  *z = RandomPoint();
+  GetRandomFrameAt(*z, x, y);
+}
+
+Matrix3x3_d S2Testing::GetRandomFrame() {
+  return GetRandomFrameAt(RandomPoint());
+}
+
+void S2Testing::GetRandomFrameAt(const S2Point& z, S2Point* x, S2Point *y) {
+  *x = z.CrossProd(RandomPoint()).Normalize();
+  *y = z.CrossProd(*x).Normalize();
+}
+
+Matrix3x3_d S2Testing::GetRandomFrameAt(const S2Point& z) {
+  S2Point x, y;
+  GetRandomFrameAt(z, &x, &y);
+  return Matrix3x3_d::FromCols(x, y, z);
+}
+
+S2CellId S2Testing::GetRandomCellId(int level) {
+  int face = rnd.Uniform(S2CellId::kNumFaces);
+  uint64 pos = rnd.Rand64() & ((1ULL << S2CellId::kPosBits) - 1);
+  return S2CellId::FromFacePosLevel(face, pos, level);
+}
+
+S2CellId S2Testing::GetRandomCellId() {
+  return GetRandomCellId(rnd.Uniform(S2CellId::kMaxLevel + 1));
+}
+
+S2Cap S2Testing::GetRandomCap(double min_area, double max_area) {
+  double cap_area = max_area * pow(min_area / max_area, rnd.RandDouble());
+  S2_DCHECK_GE(cap_area, min_area);
+  S2_DCHECK_LE(cap_area, max_area);
+
+  // The surface area of a cap is 2*Pi times its height.
+  return S2Cap::FromCenterArea(RandomPoint(), cap_area);
+}
+
+void S2Testing::ConcentricLoopsPolygon(const S2Point& center,
+                                       int num_loops,
+                                       int num_vertices_per_loop,
+                                       S2Polygon* polygon) {
+  Matrix3x3_d m;
+  S2::GetFrame(center, &m);
+  vector<unique_ptr<S2Loop>> loops;
+  for (int li = 0; li < num_loops; ++li) {
+    vector<S2Point> vertices;
+    double radius = 0.005 * (li + 1) / num_loops;
+    double radian_step = 2 * M_PI / num_vertices_per_loop;
+    for (int vi = 0; vi < num_vertices_per_loop; ++vi) {
+      double angle = vi * radian_step;
+      S2Point p(radius * cos(angle), radius * sin(angle), 1);
+      vertices.push_back(S2::FromFrame(m, p.Normalize()));
+    }
+    loops.push_back(make_unique<S2Loop>(vertices));
+  }
+  polygon->InitNested(std::move(loops));
+}
+
+S2Point S2Testing::SamplePoint(const S2Cap& cap) {
+  // We consider the cap axis to be the "z" axis.  We choose two other axes to
+  // complete the coordinate frame.
+
+  Matrix3x3_d m;
+  S2::GetFrame(cap.center(), &m);
+
+  // The surface area of a spherical cap is directly proportional to its
+  // height.  First we choose a random height, and then we choose a random
+  // point along the circle at that height.
+
+  double h = rnd.RandDouble() * cap.height();
+  double theta = 2 * M_PI * rnd.RandDouble();
+  double r = sqrt(h * (2 - h));  // Radius of circle.
+
+  // The result should already be very close to unit-length, but we might as
+  // well make it accurate as possible.
+  return S2::FromFrame(m, S2Point(cos(theta) * r, sin(theta) * r, 1 - h))
+         .Normalize();
+}
+
+S2Point S2Testing::SamplePoint(const S2LatLngRect& rect) {
+  // First choose a latitude uniformly with respect to area on the sphere.
+  double sin_lo = sin(rect.lat().lo());
+  double sin_hi = sin(rect.lat().hi());
+  double lat = asin(rnd.UniformDouble(sin_lo, sin_hi));
+
+  // Now choose longitude uniformly within the given range.
+  double lng = rect.lng().lo() + rnd.RandDouble() * rect.lng().GetLength();
+  return S2LatLng::FromRadians(lat, lng).Normalized().ToPoint();
+}
+
+void S2Testing::CheckCovering(const S2Region& region,
+                              const S2CellUnion& covering,
+                              bool check_tight, S2CellId id) {
+  if (!id.is_valid()) {
+    for (int face = 0; face < 6; ++face) {
+      CheckCovering(region, covering, check_tight, S2CellId::FromFace(face));
+    }
+    return;
+  }
+
+  if (!region.MayIntersect(S2Cell(id))) {
+    // If region does not intersect id, then neither should the covering.
+    if (check_tight) S2_CHECK(!covering.Intersects(id));
+
+  } else if (!covering.Contains(id)) {
+    // The region may intersect id, but we can't assert that the covering
+    // intersects id because we may discover that the region does not actually
+    // intersect upon further subdivision.  (MayIntersect is not exact.)
+    S2_CHECK(!region.Contains(S2Cell(id)));
+    S2_CHECK(!id.is_leaf());
+    S2CellId end = id.child_end();
+    S2CellId child;
+    for (child = id.child_begin(); child != end; child = child.next()) {
+      CheckCovering(region, covering, check_tight, child);
+    }
+  }
+}
+
+S2Testing::Fractal::Fractal()
+    : max_level_(-1), min_level_arg_(-1), min_level_(-1),
+      dimension_(log(4.0)/log(3.0)), /* standard Koch curve */
+      edge_fraction_(0), offset_fraction_(0) {
+  ComputeOffsets();
+}
+
+void S2Testing::Fractal::set_max_level(int max_level) {
+  S2_DCHECK_GE(max_level, 0);
+  max_level_ = max_level;
+  ComputeMinLevel();
+}
+
+void S2Testing::Fractal::set_min_level(int min_level_arg) {
+  S2_DCHECK_GE(min_level_arg, -1);
+  min_level_arg_ = min_level_arg;
+  ComputeMinLevel();
+}
+
+void S2Testing::Fractal::ComputeMinLevel() {
+  if (min_level_arg_ >= 0 && min_level_arg_ <= max_level_) {
+    min_level_ = min_level_arg_;
+  } else {
+    min_level_ = max_level_;
+  }
+}
+
+void S2Testing::Fractal::set_fractal_dimension(double dimension) {
+  S2_DCHECK_GE(dimension, 1.0);
+  S2_DCHECK_LT(dimension, 2.0);
+  dimension_ = dimension;
+  ComputeOffsets();
+}
+
+void S2Testing::Fractal::ComputeOffsets() {
+  edge_fraction_ = pow(4.0, -1.0 / dimension_);
+  offset_fraction_ = sqrt(edge_fraction_ - 0.25);
+}
+
+void S2Testing::Fractal::SetLevelForApproxMinEdges(int min_edges) {
+  // Map values in the range [3*(4**n)/2, 3*(4**n)*2) to level n.
+  set_min_level(round(0.5 * log2(min_edges / 3)));
+}
+
+void S2Testing::Fractal::SetLevelForApproxMaxEdges(int max_edges) {
+  // Map values in the range [3*(4**n)/2, 3*(4**n)*2) to level n.
+  set_max_level(round(0.5 * log2(max_edges / 3)));
+}
+
+double S2Testing::Fractal::min_radius_factor() const {
+  // The minimum radius is attained at one of the vertices created by the
+  // first subdivision step as long as the dimension is not too small (at
+  // least kMinDimensionForMinRadiusAtLevel1, see below).  Otherwise we fall
+  // back on the incircle radius of the original triangle, which is always a
+  // lower bound (and is attained when dimension = 1).
+  //
+  // The value below was obtained by letting AE be an original triangle edge,
+  // letting ABCDE be the corresponding polyline after one subdivision step,
+  // and then letting BC be tangent to the inscribed circle at the center of
+  // the fractal O.  This gives rise to a pair of similar triangles whose edge
+  // length ratios can be used to solve for the corresponding "edge fraction".
+  // This method is slightly conservative because it is computed using planar
+  // rather than spherical geometry.  The value below is equal to
+  // -log(4)/log((2 + cbrt(2) - cbrt(4))/6).
+  const double kMinDimensionForMinRadiusAtLevel1 = 1.0852230903040407;
+  if (dimension_ >= kMinDimensionForMinRadiusAtLevel1) {
+    return sqrt(1 + 3 * edge_fraction_ * (edge_fraction_ - 1));
+  }
+  return 0.5;
+}
+
+double S2Testing::Fractal::max_radius_factor() const {
+  // The maximum radius is always attained at either an original triangle
+  // vertex or at a middle vertex from the first subdivision step.
+  return max(1.0, offset_fraction_ * sqrt(3.0) + 0.5);
+}
+
+void S2Testing::Fractal::GetR2Vertices(vector<R2Point>* vertices) const {
+  // The Koch "snowflake" consists of three Koch curves whose initial edges
+  // form an equilateral triangle.
+  R2Point v0(1.0, 0.0);
+  R2Point v1(-0.5, sqrt(3.0)/2);
+  R2Point v2(-0.5, -sqrt(3.0)/2);
+  GetR2VerticesHelper(v0, v1, 0, vertices);
+  GetR2VerticesHelper(v1, v2, 0, vertices);
+  GetR2VerticesHelper(v2, v0, 0, vertices);
+}
+
+// Given the two endpoints (v0,v4) of an edge, recursively subdivide the edge
+// to the desired level, and insert all vertices of the resulting curve up to
+// but not including the endpoint "v4".
+void S2Testing::Fractal::GetR2VerticesHelper(const R2Point& v0,
+                                             const R2Point& v4, int level,
+                                             vector<R2Point>* vertices) const {
+  if (level >= min_level_ && S2Testing::rnd.OneIn(max_level_ - level + 1)) {
+    // Stop subdivision at this level.
+    vertices->push_back(v0);
+    return;
+  }
+  // Otherwise compute the intermediate vertices v1, v2, and v3.
+  Vector2_d dir = v4 - v0;
+  R2Point v1 = v0 + edge_fraction_ * dir;
+  R2Point v2 = 0.5 * (v0 + v4) - offset_fraction_ * dir.Ortho();
+  R2Point v3 = v4 - edge_fraction_ * dir;
+
+  // And recurse on the four sub-edges.
+  GetR2VerticesHelper(v0, v1, level+1, vertices);
+  GetR2VerticesHelper(v1, v2, level+1, vertices);
+  GetR2VerticesHelper(v2, v3, level+1, vertices);
+  GetR2VerticesHelper(v3, v4, level+1, vertices);
+}
+
+std::unique_ptr<S2Loop> S2Testing::Fractal::MakeLoop(
+    const Matrix3x3_d& frame,
+    S1Angle nominal_radius) const {
+  vector<R2Point> r2vertices;
+  GetR2Vertices(&r2vertices);
+  vector<S2Point> vertices;
+  double r = nominal_radius.radians();
+  for (const R2Point& v : r2vertices) {
+    S2Point p(v[0] * r, v[1] * r, 1);
+    vertices.push_back(S2::FromFrame(frame, p).Normalize());
+  }
+  return make_unique<S2Loop>(vertices);
+}
diff --git a/src/s2/s2testing.h b/src/s2/s2testing.h
new file mode 100644 (file)
index 0000000..598fbf1
--- /dev/null
@@ -0,0 +1,386 @@
+// Copyright 2005 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// Author: ericv@google.com (Eric Veach)
+
+#ifndef S2_S2TESTING_H_
+#define S2_S2TESTING_H_
+#include "cpp-compat.h"
+
+#include <algorithm>
+#include <memory>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "s2/base/commandlineflags.h"
+#include "s2/base/integral_types.h"
+#include "s2/_fp_contract_off.h"
+#include "s2/r2.h"
+#include "s2/s1angle.h"
+#include "s2/s1chord_angle.h"
+#include "s2/s2cell_id.h"
+#include "absl/base/macros.h"
+#include "s2/util/math/matrix3x3.h"
+
+class S1Angle;
+class S2Cap;
+class S2CellUnion;
+class S2LatLng;
+class S2LatLngRect;
+class S2Loop;
+class S2Polygon;
+class S2Polyline;
+class S2Region;
+
+// You can optionally call S2Testing::rnd.Reset(FLAGS_s2_random_seed) at the
+// start of a test or benchmark to ensure that its results do not depend on
+// which other tests of benchmarks have run previously.  This can help with
+// debugging.
+//
+// This flag currently does *not* affect the initial seed value for
+// S2Testing::rnd.  TODO(user): Fix this.
+DECLARE_int32(s2_random_seed);
+
+// This class defines various static functions that are useful for writing
+// unit tests.
+class S2Testing {
+ public:
+  // Returns a vector of points shaped as a regular polygon with
+  // num_vertices vertices, all on a circle of the specified angular
+  // radius around the center.  The radius is the actual distance from
+  // the center to the circle along the sphere.
+  //
+  // If you want to construct a regular polygon, try this:
+  //   S2Polygon polygon(S2Loop::MakeRegularLoop(center, radius, num_vertices));
+  static std::vector<S2Point> MakeRegularPoints(const S2Point& center,
+                                           S1Angle radius,
+                                           int num_vertices);
+
+  // Append the vertices of "loop" to "vertices".
+  static void AppendLoopVertices(const S2Loop& loop,
+                                 std::vector<S2Point>* vertices);
+
+  // A simple class that generates "Koch snowflake" fractals (see Wikipedia
+  // for an introduction).  There is an option to control the fractal
+  // dimension (between 1.0 and 2.0); values between 1.02 and 1.50 are
+  // reasonable simulations of various coastlines.  The default dimension
+  // (about 1.26) corresponds to the standard Koch snowflake.  (The west coast
+  // of Britain has a fractal dimension of approximately 1.25.)
+  //
+  // The fractal is obtained by starting with an equilateral triangle and
+  // recursively subdividing each edge into four segments of equal length.
+  // Therefore the shape at level "n" consists of 3*(4**n) edges.  Multi-level
+  // fractals are also supported: if you set min_level() to a non-negative
+  // value, then the recursive subdivision has an equal probability of
+  // stopping at any of the levels between the given min and max (inclusive).
+  // This yields a fractal where the perimeter of the original triangle is
+  // approximately equally divided between fractals at the various possible
+  // levels.  If there are k distinct levels {min,..,max}, the expected number
+  // of edges at each level "i" is approximately 3*(4**i)/k.
+  class Fractal {
+   public:
+    // You must call set_max_level() or SetLevelForApproxMaxEdges() before
+    // calling MakeLoop().
+    Fractal();
+
+    // Set the maximum subdivision level for the fractal (see above).
+    // REQUIRES: max_level >= 0
+    void set_max_level(int max_level);
+    int max_level() const { return max_level_; }
+
+    // Set the minimum subdivision level for the fractal (see above).  The
+    // default value of -1 causes the min and max levels to be the same.  A
+    // min_level of 0 should be avoided since this creates a significant
+    // chance that none of the three original edges will be subdivided at all.
+    //
+    // DEFAULT: max_level()
+    void set_min_level(int min_level_arg);
+    int min_level() const { return min_level_arg_; }
+
+    // Set the min and/or max level to produce approximately the given number
+    // of edges.  (The values are rounded to a nearby value of 3*(4**n).)
+    void SetLevelForApproxMinEdges(int min_edges);
+    void SetLevelForApproxMaxEdges(int max_edges);
+
+    // Set the fractal dimension.  The default value of approximately 1.26
+    // corresponds to the stardard Koch curve.  The value must lie in the
+    // range [1.0, 2.0).
+    //
+    // DEFAULT: log(4) / log(3) ~= 1.26
+    void set_fractal_dimension(double dimension);
+    double fractal_dimension() const { return dimension_; }
+
+    // Return a lower bound on ratio (Rmin / R), where "R" is the radius
+    // passed to MakeLoop() and "Rmin" is the minimum distance from the
+    // fractal boundary to its center, where all distances are measured in the
+    // tangent plane at the fractal's center.  This can be used to inscribe
+    // another geometric figure within the fractal without intersection.
+    double min_radius_factor() const;
+
+    // Return the ratio (Rmax / R), where "R" is the radius passed to
+    // MakeLoop() and "Rmax" is the maximum distance from the fractal boundary
+    // to its center, where all distances are measured in the tangent plane at
+    // the fractal's center.  This can be used to inscribe the fractal within
+    // some other geometric figure without intersection.
+    double max_radius_factor() const;
+
+    // Return a fractal loop centered around the z-axis of the given
+    // coordinate frame, with the first vertex in the direction of the
+    // positive x-axis.  In order to avoid self-intersections, the fractal is
+    // generated by first drawing it in a 2D tangent plane to the unit sphere
+    // (touching at the fractal's center point) and then projecting the edges
+    // onto the sphere.  This has the side effect of shrinking the fractal
+    // slightly compared to its nominal radius.
+    std::unique_ptr<S2Loop> MakeLoop(const Matrix3x3_d& frame,
+                                     S1Angle nominal_radius) const;
+
+   private:
+    void ComputeMinLevel();
+    void ComputeOffsets();
+    void GetR2Vertices(std::vector<R2Point>* vertices) const;
+    void GetR2VerticesHelper(const R2Point& v0, const R2Point& v4, int level,
+                             std::vector<R2Point>* vertices) const;
+
+    int max_level_;
+    int min_level_arg_;  // Value set by user
+    int min_level_;      // Actual min level (depends on max_level_)
+    double dimension_;
+
+    // The ratio of the sub-edge length to the original edge length at each
+    // subdivision step.
+    double edge_fraction_;
+
+    // The distance from the original edge to the middle vertex at each
+    // subdivision step, as a fraction of the original edge length.
+    double offset_fraction_;
+
+    Fractal(const Fractal&) = delete;
+    void operator=(const Fractal&) = delete;
+  };
+
+  // Convert a distance on the Earth's surface to an angle.
+  // Do not use these methods in non-testing code; use s2earth.h instead.
+  static S1Angle MetersToAngle(double meters);
+  static S1Angle KmToAngle(double km);
+
+  // Convert an area in steradians (as returned by the S2 area methods) to
+  // square meters or square kilometers.
+  static double AreaToMeters2(double steradians);
+  static double AreaToKm2(double steradians);
+
+  // The Earth's mean radius in kilometers (according to NASA).
+  static const double kEarthRadiusKm;
+
+  // A deterministically-seeded random number generator.
+  class Random;
+
+  static Random rnd;
+
+  // Return a random unit-length vector.
+  static S2Point RandomPoint();
+
+  // Return a right-handed coordinate frame (three orthonormal vectors).
+  static void GetRandomFrame(S2Point* x, S2Point* y, S2Point* z);
+  static Matrix3x3_d GetRandomFrame();
+
+  // Given a unit-length z-axis, compute x- and y-axes such that (x,y,z) is a
+  // right-handed coordinate frame (three orthonormal vectors).
+  static void GetRandomFrameAt(const S2Point& z, S2Point* x, S2Point *y);
+  static Matrix3x3_d GetRandomFrameAt(const S2Point& z);
+
+  // Return a cap with a random axis such that the log of its area is
+  // uniformly distributed between the logs of the two given values.
+  // (The log of the cap angle is also approximately uniformly distributed.)
+  static S2Cap GetRandomCap(double min_area, double max_area);
+
+  // Return a point chosen uniformly at random (with respect to area)
+  // from the given cap.
+  static S2Point SamplePoint(const S2Cap& cap);
+
+  // Return a point chosen uniformly at random (with respect to area on the
+  // sphere) from the given latitude-longitude rectangle.
+  static S2Point SamplePoint(const S2LatLngRect& rect);
+
+  // Return a random cell id at the given level or at a randomly chosen
+  // level.  The distribution is uniform over the space of cell ids,
+  // but only approximately uniform over the surface of the sphere.
+  static S2CellId GetRandomCellId(int level);
+  static S2CellId GetRandomCellId();
+
+  // Return a polygon with the specified center, number of concentric loops
+  // and vertices per loop.
+  static void ConcentricLoopsPolygon(const S2Point& center,
+                                     int num_loops,
+                                     int num_vertices_per_loop,
+                                     S2Polygon* polygon);
+
+  // Checks that "covering" completely covers the given region.  If
+  // "check_tight" is true, also checks that it does not contain any cells
+  // that do not intersect the given region.  ("id" is only used internally.)
+  static void CheckCovering(const S2Region& region,
+                            const S2CellUnion& covering,
+                            bool check_tight,
+                            S2CellId id = S2CellId());
+
+ private:
+  // Contains static methods
+  S2Testing() = delete;
+  S2Testing(const S2Testing&) = delete;
+  void operator=(const S2Testing&) = delete;
+};
+
+// Functions in this class return random numbers that are as good as random()
+// is.  The results are reproducible since the seed is deterministic.  This
+// class is *NOT* thread-safe; it is only intended for testing purposes.
+class S2Testing::Random {
+ public:
+  // Initialize using a deterministic seed.
+  Random();
+
+  // Reset the generator state using the given seed.
+  void Reset(int32 seed);
+
+  // Return a uniformly distributed 64-bit unsigned integer.
+  uint64 Rand64();
+
+  // Return a uniformly distributed 32-bit unsigned integer.
+  uint32 Rand32();
+
+  // Return a uniformly distributed "double" in the range [0,1).  Note that
+  // the values returned are all multiples of 2**-53, which means that not all
+  // possible values in this range are returned.
+  double RandDouble();
+
+  // Return a uniformly distributed integer in the range [0,n).
+  int32 Uniform(int32 n);
+
+  // Return a uniformly distributed "double" in the range [min, limit).
+  double UniformDouble(double min, double limit);
+
+  // A functor-style version of Uniform, so that this class can be used with
+  // STL functions that require a RandomNumberGenerator concept.
+  int32 operator() (int32 n) {
+    return Uniform(n);
+  }
+
+  // Return true with probability 1 in n.
+  bool OneIn(int32 n);
+
+  // Skewed: pick "base" uniformly from range [0,max_log] and then
+  // return "base" random bits.  The effect is to pick a number in the
+  // range [0,2^max_log-1] with bias towards smaller numbers.
+  int32 Skewed(int max_log);
+
+ private:
+  // Currently this class is based on random(), therefore it makes no sense to
+  // make a copy.
+  Random(const Random&) = delete;
+  void operator=(const Random&) = delete;
+};
+
+// Compare two sets of "closest" items, where "expected" is computed via brute
+// force (i.e., considering every possible candidate) and "actual" is computed
+// using a spatial data structure.  Here "max_size" is a bound on the maximum
+// number of items, "max_distance" is a limit on the distance to any item, and
+// "max_error" is the maximum error allowed when selecting which items are
+// closest (see S2ClosestEdgeQuery::Options::max_error).
+template <typename Id, typename Distance>
+bool CheckDistanceResults(
+    const std::vector<std::pair<Distance, Id>>& expected,
+    const std::vector<std::pair<Distance, Id>>& actual,
+    int max_size, Distance max_distance, typename Distance::Delta max_error);
+
+
+//////////////////// Implementation Details Follow ////////////////////////
+
+
+namespace S2 {
+namespace internal {
+
+// Check that result set "x" contains all the expected results from "y", and
+// does not include any duplicate results.
+template <typename Id, typename Distance>
+bool CheckResultSet(const std::vector<std::pair<Distance, Id>>& x,
+                    const std::vector<std::pair<Distance, Id>>& y,
+                    int max_size, Distance max_distance,
+                    typename Distance::Delta max_error,
+                    typename Distance::Delta max_pruning_error,
+                    const std::string& label) {
+  using Result = std::pair<Distance, Id>;
+  // Results should be sorted by distance, but not necessarily then by Id.
+  EXPECT_TRUE(std::is_sorted(x.begin(), x.end(),
+                             [](const Result& x, const Result& y) {
+                               return x.first < y.first;
+                             }));
+
+  // Result set X should contain all the items from Y whose distance is less
+  // than "limit" computed below.
+  Distance limit = Distance::Zero();
+  if (x.size() < max_size) {
+    // Result set X was not limited by "max_size", so it should contain all
+    // the items up to "max_distance", except that a few items right near the
+    // distance limit may be missed because the distance measurements used for
+    // pruning S2Cells are not conservative.
+    if (max_distance == Distance::Infinity()) {
+      limit = max_distance;
+    } else {
+      limit = max_distance - max_pruning_error;
+    }
+  } else if (!x.empty()) {
+    // Result set X contains only the closest "max_size" items, to within a
+    // tolerance of "max_error + max_pruning_error".
+    limit = (x.back().first - max_error) - max_pruning_error;
+  }
+
+  bool result = true;
+  for (const auto& yp : y) {
+    // Note that this test also catches duplicate values.
+    int count = std::count_if(x.begin(), x.end(), [&yp](const Result& xp) {
+        return xp.second == yp.second;
+      });
+    if (yp.first < limit && count != 1) {
+      result = false;
+      cpp_compat_cout << (count > 1 ? "Duplicate" : label) << " distance = "
+                << S1ChordAngle(yp.first) << ", id = " << yp.second
+                << std::endl;
+    }
+  }
+
+  return result;
+}
+
+}  // namespace internal
+}  // namespace S2
+
+template <typename Id, typename Distance>
+bool CheckDistanceResults(
+    const std::vector<std::pair<Distance, Id>>& expected,
+    const std::vector<std::pair<Distance, Id>>& actual,
+    int max_size, Distance max_distance, typename Distance::Delta max_error) {
+  // This is a conservative bound on the error in computing the distance from
+  // the target geometry to an S2Cell.  Such errors can cause candidates to be
+  // pruned from the result set even though they may be slightly closer.
+  static const typename Distance::Delta kMaxPruningError(
+      S1ChordAngle::Radians(1e-15));
+  return (S2::internal::CheckResultSet(
+              actual, expected, max_size, max_distance, max_error,
+              kMaxPruningError, "Missing") & /*not &&*/
+          S2::internal::CheckResultSet(
+              expected, actual, max_size, max_distance, max_error,
+              Distance::Delta::Zero(), "Extra"));
+}
+
+#endif  // S2_S2TESTING_H_
diff --git a/src/s2/s2text_format.cc b/src/s2/s2text_format.cc
new file mode 100644 (file)
index 0000000..36c1f9b
--- /dev/null
@@ -0,0 +1,506 @@
+// Copyright Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#include "s2/s2text_format.h"
+
+#include <string>
+#include <vector>
+
+#include "s2/base/logging.h"
+#include "s2/base/stringprintf.h"
+#include "s2/strings/serialize.h"
+#include "absl/memory/memory.h"
+#include "absl/strings/str_split.h"
+#include "absl/strings/string_view.h"
+#include "absl/strings/strip.h"
+#include "s2/mutable_s2shape_index.h"
+#include "s2/s2latlng.h"
+#include "s2/s2lax_polygon_shape.h"
+#include "s2/s2lax_polyline_shape.h"
+#include "s2/s2loop.h"
+#include "s2/s2point_vector_shape.h"
+#include "s2/s2polygon.h"
+#include "s2/s2polyline.h"
+
+using absl::make_unique;
+using absl::string_view;
+using std::pair;
+using std::unique_ptr;
+using std::vector;
+
+namespace s2textformat {
+
+static vector<string_view> SplitString(string_view str, char separator) {
+  vector<string_view> result =
+      absl::StrSplit(str, separator, absl::SkipWhitespace());
+  for (auto& e : result) {
+    e = absl::StripAsciiWhitespace(e);
+  }
+  return result;
+}
+
+static bool ParseDouble(const std::string& str, double* value) {
+  char* end_ptr = nullptr;
+  *value = strtod(str.c_str(), &end_ptr);
+  return end_ptr && *end_ptr == 0;
+}
+
+vector<S2LatLng> ParseLatLngsOrDie(string_view str) {
+  vector<S2LatLng> latlngs;
+  S2_CHECK(ParseLatLngs(str, &latlngs)) << ": str == \"" << str << "\"";
+  return latlngs;
+}
+
+bool ParseLatLngs(string_view str, vector<S2LatLng>* latlngs) {
+  vector<pair<std::string, std::string>> ps;
+  if (!strings::DictionaryParse(str, &ps)) return false;
+  for (const auto& p : ps) {
+    double lat;
+    if (!ParseDouble(p.first, &lat)) return false;
+    double lng;
+    if (!ParseDouble(p.second, &lng)) return false;
+    latlngs->push_back(S2LatLng::FromDegrees(lat, lng));
+  }
+  return true;
+}
+
+vector<S2Point> ParsePointsOrDie(string_view str) {
+  vector<S2Point> vertices;
+  S2_CHECK(ParsePoints(str, &vertices)) << ": str == \"" << str << "\"";
+  return vertices;
+}
+
+bool ParsePoints(string_view str, vector<S2Point>* vertices) {
+  vector<S2LatLng> latlngs;
+  if (!ParseLatLngs(str, &latlngs)) return false;
+  for (const auto& latlng : latlngs) {
+    vertices->push_back(latlng.ToPoint());
+  }
+  return true;
+}
+
+S2Point MakePointOrDie(string_view str) {
+  S2Point point;
+  S2_CHECK(MakePoint(str, &point)) << ": str == \"" << str << "\"";
+  return point;
+}
+
+bool MakePoint(string_view str, S2Point* point) {
+  vector<S2Point> vertices;
+  if (!ParsePoints(str, &vertices) || vertices.size() != 1) return false;
+  *point = vertices[0];
+  return true;
+}
+
+bool MakeLatLng(string_view str, S2LatLng* latlng) {
+  std::vector<S2LatLng> latlngs;
+  if (!ParseLatLngs(str, &latlngs) || latlngs.size() != 1) return false;
+  *latlng = latlngs[0];
+  return true;
+}
+
+S2LatLng MakeLatLngOrDie(string_view str) {
+  S2LatLng latlng;
+  S2_CHECK(MakeLatLng(str, &latlng)) << ": str == \"" << str << "\"";
+  return latlng;
+}
+
+S2LatLngRect MakeLatLngRectOrDie(string_view str) {
+  S2LatLngRect rect;
+  S2_CHECK(MakeLatLngRect(str, &rect)) << ": str == \"" << str << "\"";
+  return rect;
+}
+
+bool MakeLatLngRect(string_view str, S2LatLngRect* rect) {
+  vector<S2LatLng> latlngs;
+  if (!ParseLatLngs(str, &latlngs) || latlngs.empty()) return false;
+  *rect = S2LatLngRect::FromPoint(latlngs[0]);
+  for (int i = 1; i < latlngs.size(); ++i) {
+    rect->AddPoint(latlngs[i]);
+  }
+  return rect;
+}
+
+bool MakeCellId(string_view str, S2CellId* cell_id) {
+  *cell_id = S2CellId::FromDebugString(str);
+  return *cell_id != S2CellId::None();
+}
+
+S2CellId MakeCellIdOrDie(string_view str) {
+  S2CellId cell_id;
+  S2_CHECK(MakeCellId(str, &cell_id)) << ": str == \"" << str << "\"";
+  return cell_id;
+}
+
+bool MakeCellUnion(string_view str, S2CellUnion* cell_union) {
+  vector<S2CellId> cell_ids;
+  for (const auto& cell_str : SplitString(str, ',')) {
+    S2CellId cell_id;
+    if (!MakeCellId(cell_str, &cell_id)) return false;
+    cell_ids.push_back(cell_id);
+  }
+  *cell_union = S2CellUnion(std::move(cell_ids));
+  return true;
+}
+
+S2CellUnion MakeCellUnionOrDie(string_view str) {
+  S2CellUnion cell_union;
+  S2_CHECK(MakeCellUnion(str, &cell_union)) << ": str == \"" << str << "\"";
+  return cell_union;
+}
+
+unique_ptr<S2Loop> MakeLoopOrDie(string_view str, S2Debug debug_override) {
+  unique_ptr<S2Loop> loop;
+  S2_CHECK(MakeLoop(str, &loop, debug_override)) << ": str == \"" << str << "\"";
+  return loop;
+}
+
+bool MakeLoop(string_view str, unique_ptr<S2Loop>* loop,
+              S2Debug debug_override) {
+  if (str == "empty") {
+    *loop = make_unique<S2Loop>(S2Loop::kEmpty());
+    return true;
+  }
+  if (str == "full") {
+    *loop = make_unique<S2Loop>(S2Loop::kFull());
+    return true;
+  }
+  vector<S2Point> vertices;
+  if (!ParsePoints(str, &vertices)) return false;
+  *loop = make_unique<S2Loop>(vertices, debug_override);
+  return true;
+}
+
+std::unique_ptr<S2Loop> MakeLoop(string_view str, S2Debug debug_override) {
+  return MakeLoopOrDie(str, debug_override);
+}
+
+unique_ptr<S2Polyline> MakePolylineOrDie(string_view str,
+                                         S2Debug debug_override) {
+  unique_ptr<S2Polyline> polyline;
+  S2_CHECK(MakePolyline(str, &polyline, debug_override))
+      << ": str == \"" << str << "\"";
+  return polyline;
+}
+
+bool MakePolyline(string_view str, unique_ptr<S2Polyline>* polyline,
+                  S2Debug debug_override) {
+  vector<S2Point> vertices;
+  if (!ParsePoints(str, &vertices)) return false;
+  *polyline = make_unique<S2Polyline>(vertices, debug_override);
+  return true;
+}
+
+std::unique_ptr<S2Polyline> MakePolyline(string_view str,
+                                         S2Debug debug_override) {
+  return MakePolylineOrDie(str, debug_override);
+}
+
+unique_ptr<S2LaxPolylineShape> MakeLaxPolylineOrDie(string_view str) {
+  unique_ptr<S2LaxPolylineShape> lax_polyline;
+  S2_CHECK(MakeLaxPolyline(str, &lax_polyline)) << ": str == \"" << str << "\"";
+  return lax_polyline;
+}
+
+bool MakeLaxPolyline(string_view str,
+                     unique_ptr<S2LaxPolylineShape>* lax_polyline) {
+  vector<S2Point> vertices;
+  if (!ParsePoints(str, &vertices)) return false;
+  *lax_polyline = make_unique<S2LaxPolylineShape>(vertices);
+  return true;
+}
+
+std::unique_ptr<S2LaxPolylineShape> MakeLaxPolyline(string_view str) {
+  return MakeLaxPolylineOrDie(str);
+}
+
+static bool InternalMakePolygon(string_view str,
+                                S2Debug debug_override,
+                                bool normalize_loops,
+                                unique_ptr<S2Polygon>* polygon) {
+  if (str == "empty") str = "";
+  vector<string_view> loop_strs = SplitString(str, ';');
+  vector<unique_ptr<S2Loop>> loops;
+  for (const auto& loop_str : loop_strs) {
+    std::unique_ptr<S2Loop> loop;
+    if (!MakeLoop(loop_str, &loop, debug_override)) return false;
+    // Don't normalize loops that were explicitly specified as "full".
+    if (normalize_loops && !loop->is_full()) loop->Normalize();
+    loops.push_back(std::move(loop));
+  }
+  *polygon = make_unique<S2Polygon>(std::move(loops), debug_override);
+  return true;
+}
+
+unique_ptr<S2Polygon> MakePolygonOrDie(string_view str,
+                                       S2Debug debug_override) {
+  unique_ptr<S2Polygon> polygon;
+  S2_CHECK(MakePolygon(str, &polygon, debug_override))
+      << ": str == \"" << str << "\"";
+  return polygon;
+}
+
+bool MakePolygon(string_view str, unique_ptr<S2Polygon>* polygon,
+                 S2Debug debug_override) {
+  return InternalMakePolygon(str, debug_override, true, polygon);
+}
+
+std::unique_ptr<S2Polygon> MakePolygon(string_view str,
+                                       S2Debug debug_override) {
+  return MakePolygonOrDie(str, debug_override);
+}
+
+unique_ptr<S2Polygon> MakeVerbatimPolygonOrDie(string_view str) {
+  unique_ptr<S2Polygon> polygon;
+  S2_CHECK(MakeVerbatimPolygon(str, &polygon)) << ": str == \"" << str << "\"";
+  return polygon;
+}
+
+bool MakeVerbatimPolygon(string_view str, unique_ptr<S2Polygon>* polygon) {
+  return InternalMakePolygon(str, S2Debug::ALLOW, false, polygon);
+}
+
+std::unique_ptr<S2Polygon> MakeVerbatimPolygon(string_view str) {
+  return MakeVerbatimPolygonOrDie(str);
+}
+
+unique_ptr<S2LaxPolygonShape> MakeLaxPolygonOrDie(string_view str) {
+  unique_ptr<S2LaxPolygonShape> lax_polygon;
+  S2_CHECK(MakeLaxPolygon(str, &lax_polygon)) << ": str == \"" << str << "\"";
+  return lax_polygon;
+}
+
+bool MakeLaxPolygon(string_view str,
+                    unique_ptr<S2LaxPolygonShape>* lax_polygon) {
+  vector<string_view> loop_strs = SplitString(str, ';');
+  vector<vector<S2Point>> loops;
+  for (const auto& loop_str : loop_strs) {
+    if (loop_str == "full") {
+      loops.push_back(vector<S2Point>());
+    } else if (loop_str != "empty") {
+      vector<S2Point> points;
+      if (!ParsePoints(loop_str, &points)) return false;
+      loops.push_back(points);
+    }
+  }
+  *lax_polygon = make_unique<S2LaxPolygonShape>(loops);
+  return true;
+}
+
+std::unique_ptr<S2LaxPolygonShape> MakeLaxPolygon(string_view str) {
+  return MakeLaxPolygonOrDie(str);
+}
+
+unique_ptr<MutableS2ShapeIndex> MakeIndexOrDie(string_view str) {
+  auto index = make_unique<MutableS2ShapeIndex>();
+  S2_CHECK(MakeIndex(str, &index)) << ": str == \"" << str << "\"";
+  return index;
+}
+
+bool MakeIndex(string_view str, std::unique_ptr<MutableS2ShapeIndex>* index) {
+  vector<string_view> strs = absl::StrSplit(str, '#');
+  S2_DCHECK_EQ(3, strs.size()) << "Must contain two # characters: " << str;
+
+  vector<S2Point> points;
+  for (const auto& point_str : SplitString(strs[0], '|')) {
+    S2Point point;
+    if (!MakePoint(point_str, &point)) return false;
+    points.push_back(point);
+  }
+  if (!points.empty()) {
+    (*index)->Add(make_unique<S2PointVectorShape>(std::move(points)));
+  }
+  for (const auto& line_str : SplitString(strs[1], '|')) {
+    std::unique_ptr<S2LaxPolylineShape> lax_polyline;
+    if (!MakeLaxPolyline(line_str, &lax_polyline)) return false;
+    (*index)->Add(unique_ptr<S2Shape>(lax_polyline.release()));
+  }
+  for (const auto& polygon_str : SplitString(strs[2], '|')) {
+    std::unique_ptr<S2LaxPolygonShape> lax_polygon;
+    if (!MakeLaxPolygon(polygon_str, &lax_polygon)) return false;
+    (*index)->Add(unique_ptr<S2Shape>(lax_polygon.release()));
+  }
+  return true;
+}
+
+std::unique_ptr<MutableS2ShapeIndex> MakeIndex(string_view str) {
+  return MakeIndexOrDie(str);
+}
+
+static void AppendVertex(const S2LatLng& ll, std::string* out) {
+  StringAppendF(out, "%.15g:%.15g", ll.lat().degrees(), ll.lng().degrees());
+}
+
+static void AppendVertex(const S2Point& p, std::string* out) {
+  S2LatLng ll(p);
+  return AppendVertex(ll, out);
+}
+
+static void AppendVertices(const S2Point* v, int n, std::string* out) {
+  for (int i = 0; i < n; ++i) {
+    if (i > 0) *out += ", ";
+    AppendVertex(v[i], out);
+  }
+}
+
+std::string ToString(const S2Point& point) {
+  std::string out;
+  AppendVertex(point, &out);
+  return out;
+}
+
+std::string ToString(const S2LatLng& latlng) {
+  std::string out;
+  AppendVertex(latlng, &out);
+  return out;
+}
+
+std::string ToString(const S2LatLngRect& rect) {
+  std::string out;
+  AppendVertex(rect.lo(), &out);
+  out += ", ";
+  AppendVertex(rect.hi(), &out);
+  return out;
+}
+
+std::string ToString(const S2CellId& cell_id) {
+  return cell_id.ToString();
+}
+
+std::string ToString(const S2CellUnion& cell_union) {
+  std::string out;
+  for (S2CellId cell_id : cell_union) {
+    if (!out.empty()) out += ", ";
+    out += cell_id.ToString();
+  }
+  return out;
+}
+
+std::string ToString(const S2Loop& loop) {
+  if (loop.is_empty()) {
+    return "empty";
+  } else if (loop.is_full()) {
+    return "full";
+  }
+  std::string out;
+  if (loop.num_vertices() > 0) {
+    AppendVertices(&loop.vertex(0), loop.num_vertices(), &out);
+  }
+  return out;
+}
+
+std::string ToString(S2PointLoopSpan loop) {
+  // S2Shape represents the full loop as a loop with no vertices.
+  // There is no representation of the empty loop.
+  if (loop.empty()) {
+    return "full";
+  }
+  std::string out;
+  AppendVertices(loop.data(), loop.size(), &out);
+  return out;
+}
+
+std::string ToString(const S2Polyline& polyline) {
+  std::string out;
+  if (polyline.num_vertices() > 0) {
+    AppendVertices(&polyline.vertex(0), polyline.num_vertices(), &out);
+  }
+  return out;
+}
+
+std::string ToString(const S2Polygon& polygon, const char* loop_separator) {
+  if (polygon.is_empty()) {
+    return "empty";
+  } else if (polygon.is_full()) {
+    return "full";
+  }
+  std::string out;
+  for (int i = 0; i < polygon.num_loops(); ++i) {
+    if (i > 0) out += loop_separator;
+    const S2Loop& loop = *polygon.loop(i);
+    AppendVertices(&loop.vertex(0), loop.num_vertices(), &out);
+  }
+  return out;
+}
+
+std::string ToString(const vector<S2Point>& points) {
+  std::string out;
+  AppendVertices(points.data(), points.size(), &out);
+  return out;
+}
+
+std::string ToString(const vector<S2LatLng>& latlngs) {
+  std::string out;
+  for (int i = 0; i < latlngs.size(); ++i) {
+    if (i > 0) out += ", ";
+    AppendVertex(latlngs[i], &out);
+  }
+  return out;
+}
+
+std::string ToString(const S2LaxPolylineShape& polyline) {
+  std::string out;
+  if (polyline.num_vertices() > 0) {
+    AppendVertices(&polyline.vertex(0), polyline.num_vertices(), &out);
+  }
+  return out;
+}
+
+std::string ToString(const S2LaxPolygonShape& polygon, const char* loop_separator) {
+  std::string out;
+  for (int i = 0; i < polygon.num_loops(); ++i) {
+    if (i > 0) out += loop_separator;
+    int n = polygon.num_loop_vertices(i);
+    if (n == 0) {
+      out += "full";
+    } else {
+      AppendVertices(&polygon.loop_vertex(i, 0), n, &out);
+    }
+  }
+  return out;
+}
+
+std::string ToString(const S2ShapeIndex& index) {
+  std::string out;
+  for (int dim = 0; dim < 3; ++dim) {
+    if (dim > 0) out += "#";
+    int count = 0;
+    for (S2Shape* shape : index) {
+      if (shape == nullptr || shape->dimension() != dim) continue;
+      out += (count > 0) ? " | " : (dim > 0) ? " " : "";
+      for (int i = 0; i < shape->num_chains(); ++i, ++count) {
+        if (i > 0) out += (dim == 2) ? "; " : " | ";
+        S2Shape::Chain chain = shape->chain(i);
+        if (chain.length == 0) {
+          S2_DCHECK_EQ(dim, 2);
+          out += "full";
+        } else {
+          AppendVertex(shape->edge(chain.start).v0, &out);
+        }
+        int limit = chain.start + chain.length;
+        if (dim != 1) --limit;
+        for (int e = chain.start; e < limit; ++e) {
+          out += ", ";
+          AppendVertex(shape->edge(e).v1, &out);
+        }
+      }
+    }
+    // Example output: "# #", "0:0 # #", "# # 0:0, 0:1, 1:0"
+    if (dim == 1 || (dim == 0 && count > 0)) out += " ";
+  }
+  return out;
+}
+
+}  // namespace s2textformat
diff --git a/src/s2/s2text_format.h b/src/s2/s2text_format.h
new file mode 100644 (file)
index 0000000..f092613
--- /dev/null
@@ -0,0 +1,289 @@
+// Copyright Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#ifndef S2_S2TEXT_FORMAT_H_
+#define S2_S2TEXT_FORMAT_H_
+
+// s2text_format contains a collection of functions for converting
+// geometry to and from a human-readable format.  It is mainly
+// intended for testing and debugging.  Be aware that the
+// human-readable format is *not* designed to preserve the full
+// precision of the original object, so it should not be used
+// for data storage.
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "absl/base/attributes.h"
+#include "absl/strings/string_view.h"
+#include "s2/s2cell_id.h"
+#include "s2/s2cell_union.h"
+#include "s2/s2debug.h"
+#include "s2/s2latlng_rect.h"
+#include "s2/s2point_span.h"
+
+class MutableS2ShapeIndex;
+class S2LaxPolygonShape;
+class S2LaxPolylineShape;
+class S2Loop;
+class S2Polygon;
+class S2Polyline;
+class S2ShapeIndex;
+
+namespace s2textformat {
+
+// Returns an S2Point corresponding to the given a latitude-longitude
+// coordinate in degrees.  Example of the input format:
+//     "-20:150"
+S2Point MakePointOrDie(absl::string_view str);
+
+// As above, but do not S2_CHECK-fail on invalid input. Returns true if conversion
+// is successful.
+ABSL_MUST_USE_RESULT bool MakePoint(absl::string_view str, S2Point* point);
+
+ABSL_DEPRECATED("Use MakePointOrDie.")
+inline S2Point MakePoint(absl::string_view str) { return MakePointOrDie(str); }
+
+// Parses a string of one or more latitude-longitude coordinates in degrees,
+// and return the corresponding vector of S2LatLng points.
+// Examples of the input format:
+//     ""                            // no points
+//     "-20:150"                     // one point
+//     "-20:150, -20:151, -19:150"   // three points
+std::vector<S2LatLng> ParseLatLngsOrDie(absl::string_view str);
+
+// As above, but does not S2_CHECK-fail on invalid input. Returns true if
+// conversion is successful.
+ABSL_MUST_USE_RESULT bool ParseLatLngs(absl::string_view str,
+                                       std::vector<S2LatLng>* latlngs);
+
+ABSL_DEPRECATED("Use ParseLatLngsOrDie.")
+inline std::vector<S2LatLng> ParseLatLngs(absl::string_view str) {
+  return ParseLatLngsOrDie(str);
+}
+
+// Parses a string in the same format as ParseLatLngs, and return the
+// corresponding vector of S2Point values.
+std::vector<S2Point> ParsePointsOrDie(absl::string_view str);
+
+// As above, but does not S2_CHECK-fail on invalid input. Returns true if
+// conversion is successful.
+ABSL_MUST_USE_RESULT bool ParsePoints(absl::string_view str,
+                                      std::vector<S2Point>* vertices);
+
+ABSL_DEPRECATED("Use ParsePointsOrDie.")
+inline std::vector<S2Point> ParsePoints(absl::string_view str) {
+  return ParsePointsOrDie(str);
+}
+
+// Given a string in the same format as ParseLatLngs, returns a single S2LatLng.
+S2LatLng MakeLatLngOrDie(absl::string_view str);
+
+// As above, but does not S2_CHECK-fail on invalid input. Returns true if
+// conversion is successful.
+ABSL_MUST_USE_RESULT bool MakeLatLng(absl::string_view str, S2LatLng* latlng);
+
+// Given a string in the same format as ParseLatLngs, returns the minimal
+// bounding S2LatLngRect that contains the coordinates.
+S2LatLngRect MakeLatLngRectOrDie(absl::string_view str);
+
+// As above, but does not S2_CHECK-fail on invalid input. Returns true if
+// conversion is successful.
+ABSL_MUST_USE_RESULT bool MakeLatLngRect(absl::string_view str,
+                                         S2LatLngRect* rect);
+
+ABSL_DEPRECATED("Use MakeLatLngRectOrDie.")
+inline S2LatLngRect MakeLatLngRect(absl::string_view str) {
+  return MakeLatLngRectOrDie(str);
+}
+
+// Parses an S2CellId in the format "f/dd..d" where "f" is a digit in the
+// range [0-5] representing the S2CellId face, and "dd..d" is a string of
+// digits in the range [0-3] representing each child's position with respect
+// to its parent.  (Note that the latter string may be empty.)
+//
+// For example "4/" represents S2CellId::FromFace(4), and "3/02" represents
+// S2CellId::FromFace(3).child(0).child(2).
+//
+// This function is a wrapper for S2CellId::FromDebugString().
+S2CellId MakeCellIdOrDie(absl::string_view str);
+
+// As above, but does not S2_CHECK-fail on invalid input. Returns true if
+// conversion is successful.
+ABSL_MUST_USE_RESULT bool MakeCellId(absl::string_view str, S2CellId* cell_id);
+
+// Parses a comma-separated list of S2CellIds in the format above, and returns
+// the corresponding S2CellUnion.  (Note that S2CellUnions are automatically
+// normalized by sorting, removing duplicates, and replacing groups of 4 child
+// cells by their parent cell.)
+S2CellUnion MakeCellUnionOrDie(absl::string_view str);
+
+// As above, but does not S2_CHECK-fail on invalid input. Returns true if
+// conversion is successful.
+ABSL_MUST_USE_RESULT bool MakeCellUnion(absl::string_view str,
+                                        S2CellUnion* cell_union);
+
+// Given a string of latitude-longitude coordinates in degrees,
+// returns a newly allocated loop.  Example of the input format:
+//     "-20:150, 10:-120, 0.123:-170.652"
+// The strings "empty" or "full" create an empty or full loop respectively.
+std::unique_ptr<S2Loop> MakeLoopOrDie(absl::string_view str,
+                                      S2Debug debug_override = S2Debug::ALLOW);
+
+// As above, but does not S2_CHECK-fail on invalid input. Returns true if
+// conversion is successful.
+ABSL_MUST_USE_RESULT bool MakeLoop(absl::string_view str,
+                                   std::unique_ptr<S2Loop>* loop,
+                                   S2Debug debug_override = S2Debug::ALLOW);
+
+ABSL_DEPRECATED("Use MakeLoopOrDie.")
+std::unique_ptr<S2Loop> MakeLoop(absl::string_view str,
+                                 S2Debug debug_override = S2Debug::ALLOW);
+
+// Similar to MakeLoop(), but returns an S2Polyline rather than an S2Loop.
+std::unique_ptr<S2Polyline> MakePolylineOrDie(
+    absl::string_view str,
+    S2Debug debug_override = S2Debug::ALLOW);
+
+// As above, but does not S2_CHECK-fail on invalid input. Returns true if
+// conversion is successful.
+ABSL_MUST_USE_RESULT bool MakePolyline(absl::string_view str,
+                                       std::unique_ptr<S2Polyline>* polyline,
+                                       S2Debug debug_override = S2Debug::ALLOW);
+
+ABSL_DEPRECATED("Use MakePolylineOrDie.")
+std::unique_ptr<S2Polyline> MakePolyline(
+    absl::string_view str,
+    S2Debug debug_override = S2Debug::ALLOW);
+
+// Like MakePolyline, but returns an S2LaxPolylineShape instead.
+std::unique_ptr<S2LaxPolylineShape> MakeLaxPolylineOrDie(absl::string_view str);
+
+// As above, but does not S2_CHECK-fail on invalid input. Returns true if
+// conversion is successful.
+ABSL_MUST_USE_RESULT bool MakeLaxPolyline(
+    absl::string_view str, std::unique_ptr<S2LaxPolylineShape>* lax_polyline);
+
+ABSL_DEPRECATED("Use MakeLaxPolylineOrDie.")
+std::unique_ptr<S2LaxPolylineShape> MakeLaxPolyline(absl::string_view str);
+
+// Given a sequence of loops separated by semicolons, returns a newly
+// allocated polygon.  Loops are automatically normalized by inverting them
+// if necessary so that they enclose at most half of the unit sphere.
+// (Historically this was once a requirement of polygon loops.  It also
+// hides the problem that if the user thinks of the coordinates as X:Y
+// rather than LAT:LNG, it yields a loop with the opposite orientation.)
+//
+// Examples of the input format:
+//     "10:20, 90:0, 20:30"                                  // one loop
+//     "10:20, 90:0, 20:30; 5.5:6.5, -90:-180, -15.2:20.3"   // two loops
+//     ""       // the empty polygon (consisting of no loops)
+//     "empty"  // the empty polygon (consisting of no loops)
+//     "full"   // the full polygon (consisting of one full loop).
+std::unique_ptr<S2Polygon> MakePolygonOrDie(
+    absl::string_view str,
+    S2Debug debug_override = S2Debug::ALLOW);
+
+// As above, but does not S2_CHECK-fail on invalid input. Returns true if
+// conversion is successful.
+ABSL_MUST_USE_RESULT bool MakePolygon(absl::string_view str,
+                                      std::unique_ptr<S2Polygon>* polygon,
+                                      S2Debug debug_override = S2Debug::ALLOW);
+
+ABSL_DEPRECATED("Use MakePolygonOrDie.")
+std::unique_ptr<S2Polygon> MakePolygon(absl::string_view str,
+                                       S2Debug debug_override = S2Debug::ALLOW);
+
+// Like MakePolygon(), except that it does not normalize loops (i.e., it
+// gives you exactly what you asked for).
+std::unique_ptr<S2Polygon> MakeVerbatimPolygonOrDie(absl::string_view str);
+
+// As above, but does not S2_CHECK-fail on invalid input. Returns true if
+// conversion is successful.
+ABSL_MUST_USE_RESULT bool MakeVerbatimPolygon(
+    absl::string_view str, std::unique_ptr<S2Polygon>* polygon);
+
+ABSL_DEPRECATED("Use MakeVerbatimPolygonOrDie.")
+std::unique_ptr<S2Polygon> MakeVerbatimPolygon(absl::string_view str);
+
+// Parses a string in the same format as MakePolygon, except that loops must
+// be oriented so that the interior of the loop is always on the left, and
+// polygons with degeneracies are supported.  As with MakePolygon, "full" and
+// denotes the full polygon and "" or "empty" denote the empty polygon.
+std::unique_ptr<S2LaxPolygonShape> MakeLaxPolygonOrDie(absl::string_view str);
+
+// As above, but does not S2_CHECK-fail on invalid input. Returns true if
+// conversion is successful.
+ABSL_MUST_USE_RESULT bool MakeLaxPolygon(
+    absl::string_view str, std::unique_ptr<S2LaxPolygonShape>* lax_polygon);
+
+ABSL_DEPRECATED("Use MakeLaxPolygonOrDie.")
+std::unique_ptr<S2LaxPolygonShape> MakeLaxPolygon(absl::string_view str);
+
+// Returns a MutableS2ShapeIndex containing the points, polylines, and loops
+// (in the form of a single polygon) described by the following format:
+//
+//   point1|point2|... # line1|line2|... # polygon1|polygon2|...
+//
+// Examples:
+//   1:2 | 2:3 # #                     // Two points
+//   # 0:0, 1:1, 2:2 | 3:3, 4:4 #      // Two polylines
+//   # # 0:0, 0:3, 3:0; 1:1, 2:1, 1:2  // Two nested loops (one polygon)
+//   5:5 # 6:6, 7:7 # 0:0, 0:1, 1:0    // One of each
+//   # # empty                         // One empty polygon
+//   # # empty | full                  // One empty polygon, one full polygon
+//
+// Loops should be directed so that the region's interior is on the left.
+// Loops can be degenerate (they do not need to meet S2Loop requirements).
+//
+// CAVEAT: Because whitespace is ignored, empty polygons must be specified
+//         as the string "empty" rather than as the empty string ("").
+std::unique_ptr<MutableS2ShapeIndex> MakeIndexOrDie(absl::string_view str);
+
+// As above, but does not S2_CHECK-fail on invalid input. Returns true if
+// conversion is successful.
+ABSL_MUST_USE_RESULT bool MakeIndex(
+    absl::string_view str, std::unique_ptr<MutableS2ShapeIndex>* index);
+
+ABSL_DEPRECATED("Use MakeIndexOrDie.")
+std::unique_ptr<MutableS2ShapeIndex> MakeIndex(absl::string_view str);
+
+// Convert an S2Point, S2LatLng, S2LatLngRect, S2CellId, S2CellUnion, loop,
+// polyline, or polygon to the string format above.
+std::string ToString(const S2Point& point);
+std::string ToString(const S2LatLng& latlng);
+std::string ToString(const S2LatLngRect& rect);
+std::string ToString(const S2CellId& cell_id);
+std::string ToString(const S2CellUnion& cell_union);
+std::string ToString(const S2Loop& loop);
+std::string ToString(S2PointLoopSpan loop);
+std::string ToString(const S2Polyline& polyline);
+std::string ToString(const S2Polygon& polygon, const char* loop_separator = ";\n");
+std::string ToString(const std::vector<S2Point>& points);
+std::string ToString(const std::vector<S2LatLng>& points);
+std::string ToString(const S2LaxPolylineShape& polyline);
+std::string ToString(const S2LaxPolygonShape& polygon,
+                const char* loop_separator = ";\n");
+
+// Convert the contents of an S2ShapeIndex to the format above.  The index may
+// contain S2Shapes of any type.  Shapes are reordered if necessary so that
+// all point geometry (shapes of dimension 0) are first, followed by all
+// polyline geometry, followed by all polygon geometry.
+std::string ToString(const S2ShapeIndex& index);
+
+}  // namespace s2textformat
+
+#endif  // S2_S2TEXT_FORMAT_H_
diff --git a/src/s2/s2wedge_relations.cc b/src/s2/s2wedge_relations.cc
new file mode 100644 (file)
index 0000000..85ec777
--- /dev/null
@@ -0,0 +1,80 @@
+// Copyright 2005 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// Author: ericv@google.com (Eric Veach)
+
+#include "s2/s2wedge_relations.h"
+
+#include "s2/s2predicates.h"
+
+namespace S2 {
+
+bool WedgeContains(
+    const S2Point& a0, const S2Point& ab1, const S2Point& a2,
+    const S2Point& b0, const S2Point& b2) {
+  // For A to contain B (where each loop interior is defined to be its left
+  // side), the CCW edge order around ab1 must be a2 b2 b0 a0.  We split
+  // this test into two parts that test three vertices each.
+  return (s2pred::OrderedCCW(a2, b2, b0, ab1) &&
+          s2pred::OrderedCCW(b0, a0, a2, ab1));
+}
+
+bool WedgeIntersects(
+    const S2Point& a0, const S2Point& ab1, const S2Point& a2,
+    const S2Point& b0, const S2Point& b2) {
+  // For A not to intersect B (where each loop interior is defined to be
+  // its left side), the CCW edge order around ab1 must be a0 b2 b0 a2.
+  // Note that it's important to write these conditions as negatives
+  // (!OrderedCCW(a,b,c,o) rather than Ordered(c,b,a,o)) to get correct
+  // results when two vertices are the same.
+  return !(s2pred::OrderedCCW(a0, b2, b0, ab1) &&
+           s2pred::OrderedCCW(b0, a2, a0, ab1));
+}
+
+WedgeRelation GetWedgeRelation(
+    const S2Point& a0, const S2Point& ab1, const S2Point& a2,
+    const S2Point& b0, const S2Point& b2) {
+  // There are 6 possible edge orderings at a shared vertex (all
+  // of these orderings are circular, i.e. abcd == bcda):
+  //
+  //  (1) a2 b2 b0 a0: A contains B
+  //  (2) a2 a0 b0 b2: B contains A
+  //  (3) a2 a0 b2 b0: A and B are disjoint
+  //  (4) a2 b0 a0 b2: A and B intersect in one wedge
+  //  (5) a2 b2 a0 b0: A and B intersect in one wedge
+  //  (6) a2 b0 b2 a0: A and B intersect in two wedges
+  //
+  // We do not distinguish between 4, 5, and 6.
+  // We pay extra attention when some of the edges overlap.  When edges
+  // overlap, several of these orderings can be satisfied, and we take
+  // the most specific.
+  if (a0 == b0 && a2 == b2) return WEDGE_EQUALS;
+
+  if (s2pred::OrderedCCW(a0, a2, b2, ab1)) {
+    // The cases with this vertex ordering are 1, 5, and 6,
+    // although case 2 is also possible if a2 == b2.
+    if (s2pred::OrderedCCW(b2, b0, a0, ab1)) return WEDGE_PROPERLY_CONTAINS;
+
+    // We are in case 5 or 6, or case 2 if a2 == b2.
+    return (a2 == b2) ? WEDGE_IS_PROPERLY_CONTAINED : WEDGE_PROPERLY_OVERLAPS;
+  }
+
+  // We are in case 2, 3, or 4.
+  if (s2pred::OrderedCCW(a0, b0, b2, ab1)) return WEDGE_IS_PROPERLY_CONTAINED;
+  return s2pred::OrderedCCW(a0, b0, a2, ab1) ?
+      WEDGE_IS_DISJOINT : WEDGE_PROPERLY_OVERLAPS;
+}
+
+}  // namespace S2
diff --git a/src/s2/s2wedge_relations.h b/src/s2/s2wedge_relations.h
new file mode 100644 (file)
index 0000000..8254b08
--- /dev/null
@@ -0,0 +1,64 @@
+// Copyright 2005 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// Author: ericv@google.com (Eric Veach)
+//
+// Defines functions for determining the relationship between two angles
+// ("wedges") that share a common vertex.
+
+#ifndef S2_S2WEDGE_RELATIONS_H_
+#define S2_S2WEDGE_RELATIONS_H_
+
+#include "s2/s2point.h"
+
+namespace S2 {
+
+// Given an edge chain (x0, x1, x2), the wedge at x1 is the region to the
+// left of the edges.  More precisely, it is the set of all rays from x1x0
+// (inclusive) to x1x2 (exclusive) in the *clockwise* direction.
+//
+// The following functions compare two *non-empty* wedges that share the
+// same middle vertex: A=(a0, ab1, a2) and B=(b0, ab1, b2).
+
+// Detailed relation from one wedge A to another wedge B.
+enum WedgeRelation {
+  WEDGE_EQUALS,                 // A and B are equal.
+  WEDGE_PROPERLY_CONTAINS,      // A is a strict superset of B.
+  WEDGE_IS_PROPERLY_CONTAINED,  // A is a strict subset of B.
+  WEDGE_PROPERLY_OVERLAPS,      // A-B, B-A, and A intersect B are non-empty.
+  WEDGE_IS_DISJOINT,            // A and B are disjoint.
+};
+
+// Returns the relation from wedge A to B.
+// REQUIRES: A and B are non-empty.
+WedgeRelation GetWedgeRelation(
+    const S2Point& a0, const S2Point& ab1, const S2Point& a2,
+    const S2Point& b0, const S2Point& b2);
+
+// Returns true if wedge A contains wedge B.  Equivalent to but faster than
+// GetWedgeRelation() == WEDGE_PROPERLY_CONTAINS || WEDGE_EQUALS.
+// REQUIRES: A and B are non-empty.
+bool WedgeContains(const S2Point& a0, const S2Point& ab1, const S2Point& a2,
+                   const S2Point& b0, const S2Point& b2);
+
+// Returns true if wedge A intersects wedge B.  Equivalent to but faster
+// than GetWedgeRelation() != WEDGE_IS_DISJOINT.
+// REQUIRES: A and B are non-empty.
+bool WedgeIntersects(const S2Point& a0, const S2Point& ab1, const S2Point& a2,
+                     const S2Point& b0, const S2Point& b2);
+
+}  // namespace S2
+
+#endif  // S2_S2WEDGE_RELATIONS_H_
diff --git a/src/s2/sequence_lexicon.h b/src/s2/sequence_lexicon.h
new file mode 100644 (file)
index 0000000..7c3aed7
--- /dev/null
@@ -0,0 +1,296 @@
+// Copyright 2016 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// Author: ericv@google.com (Eric Veach)
+
+#ifndef S2_SEQUENCE_LEXICON_H_
+#define S2_SEQUENCE_LEXICON_H_
+
+#include <functional>
+#include <limits>
+#include <vector>
+
+#include "s2/base/integral_types.h"
+#include "s2/util/gtl/dense_hash_set.h"
+#include "s2/util/hash/mix.h"
+
+// SequenceLexicon is a class for compactly representing sequences of values
+// (e.g., tuples).  It automatically eliminates duplicates, and maps the
+// remaining sequences to sequentially increasing integer ids.  See also
+// ValueLexicon and IdSetLexicon.
+//
+// Each distinct sequence is mapped to a 32-bit integer.  The space used for
+// each sequence is approximately 11 bytes plus the memory needed to represent
+// the sequence elements.  For example, a sequence of three "double"s would
+// need about 11 + 3*8 = 35 bytes.  Note also that sequences are referred to
+// using 32-bit ids rather than 64-bit pointers.
+//
+// This class has the same thread-safety properties as "string": const methods
+// are thread safe, and non-const methods are not thread safe.
+//
+// Example usage:
+//
+//   SequenceLexicon<string> lexicon;
+//   vector<string> pets {"cat", "dog", "parrot"};
+//   uint32 pets_id = lexicon.Add(pets);
+//   S2_CHECK_EQ(pets_id, lexicon.Add(pets));
+//   string values;
+//   for (const auto& pet : lexicon.sequence(pets_id)) {
+//     values += pet;
+//   }
+//   S2_CHECK_EQ("catdogparrot", values);
+//
+template <class T,
+          class Hasher = std::hash<T>,
+          class KeyEqual = std::equal_to<T>>
+class SequenceLexicon {
+ public:
+  explicit SequenceLexicon(const Hasher& hasher = Hasher(),
+                           const KeyEqual& key_equal = KeyEqual());
+
+  // SequenceLexicon is movable and copyable.
+  SequenceLexicon(const SequenceLexicon&);
+  SequenceLexicon& operator=(const SequenceLexicon&);
+  SequenceLexicon(SequenceLexicon&&);
+  SequenceLexicon& operator=(SequenceLexicon&&);
+
+  // Clears all data from the lexicon.
+  void Clear();
+
+  // Add the given sequence of values to the lexicon if it is not already
+  // present, and return its integer id.  Ids are assigned sequentially
+  // starting from zero.  "begin" and "end" are forward iterators over a
+  // sequence of values of type T.
+  template <class FwdIterator>
+  uint32 Add(FwdIterator begin, FwdIterator end);
+
+  // Add the given sequence of values to the lexicon if it is not already
+  // present, and return its integer id.  Ids are assigned sequentially
+  // starting from zero.  This is a convenience method equivalent to
+  // Add(std::begin(container), std::end(container)).
+  template <class Container>
+  uint32 Add(const Container& container);
+
+  // Return the number of value sequences in the lexicon.
+  uint32 size() const;
+
+  // Iterator type; please treat this as an opaque forward iterator.
+  using Iterator = typename std::vector<T>::const_iterator;
+
+  // A class representing a sequence of values.
+  class Sequence {
+   public:
+    Iterator begin() const { return begin_; }
+    Iterator end() const { return end_; }
+    size_t size() const { return end_ - begin_; }
+
+   private:
+    friend class SequenceLexicon;
+    Sequence(Iterator begin, Iterator end) : begin_(begin), end_(end) {}
+    Iterator begin_, end_;
+  };
+  // Return the value sequence with the given id.  This method can be used
+  // with range-based for loops as follows:
+  //   for (const auto& value : lexicon.sequence(id)) { ... }
+  Sequence sequence(uint32 id) const;
+
+ private:
+  friend class IdKeyEqual;
+  // Choose kEmptyKey to be the last key that will ever be generated.
+  static const uint32 kEmptyKey = std::numeric_limits<uint32>::max();
+
+  class IdHasher {
+   public:
+    IdHasher(const Hasher& hasher, const SequenceLexicon* lexicon);
+    const Hasher& hasher() const;
+    size_t operator()(uint32 id) const;
+   private:
+    Hasher hasher_;
+    const SequenceLexicon* lexicon_;
+  };
+
+  class IdKeyEqual {
+   public:
+    IdKeyEqual(const KeyEqual& key_equal, const SequenceLexicon* lexicon);
+    const KeyEqual& key_equal() const;
+    bool operator()(uint32 id1, uint32 id2) const;
+   private:
+    KeyEqual key_equal_;
+    const SequenceLexicon* lexicon_;
+  };
+
+  using IdSet = gtl::dense_hash_set<uint32, IdHasher, IdKeyEqual>;
+
+  std::vector<T> values_;
+  std::vector<uint32> begins_;
+  IdSet id_set_;
+};
+
+
+//////////////////   Implementation details follow   ////////////////////
+
+
+template <class T, class Hasher, class KeyEqual>
+const uint32 SequenceLexicon<T, Hasher, KeyEqual>::kEmptyKey;
+
+template <class T, class Hasher, class KeyEqual>
+SequenceLexicon<T, Hasher, KeyEqual>::IdHasher::IdHasher(
+    const Hasher& hasher, const SequenceLexicon* lexicon)
+    : hasher_(hasher), lexicon_(lexicon) {
+}
+
+template <class T, class Hasher, class KeyEqual>
+const Hasher& SequenceLexicon<T, Hasher, KeyEqual>::IdHasher::hasher() const {
+  return hasher_;
+}
+
+template <class T, class Hasher, class KeyEqual>
+size_t SequenceLexicon<T, Hasher, KeyEqual>::IdHasher::operator()(
+    uint32 id) const {
+  HashMix mix;
+  for (const auto& value : lexicon_->sequence(id)) {
+    mix.Mix(hasher_(value));
+  }
+  return mix.get();
+}
+
+template <class T, class Hasher, class KeyEqual>
+SequenceLexicon<T, Hasher, KeyEqual>::IdKeyEqual::IdKeyEqual(
+    const KeyEqual& key_equal, const SequenceLexicon* lexicon)
+    : key_equal_(key_equal), lexicon_(lexicon) {
+}
+
+template <class T, class Hasher, class KeyEqual>
+const KeyEqual& SequenceLexicon<T, Hasher, KeyEqual>::IdKeyEqual::key_equal()
+    const {
+  return key_equal_;
+}
+
+template <class T, class Hasher, class KeyEqual>
+bool SequenceLexicon<T, Hasher, KeyEqual>::IdKeyEqual::operator()(
+    uint32 id1, uint32 id2) const {
+  if (id1 == id2) return true;
+  if (id1 == lexicon_->kEmptyKey || id2 == lexicon_->kEmptyKey) {
+    return false;
+  }
+  SequenceLexicon::Sequence seq1 = lexicon_->sequence(id1);
+  SequenceLexicon::Sequence seq2 = lexicon_->sequence(id2);
+  return (seq1.size() == seq2.size() &&
+          std::equal(seq1.begin(), seq1.end(), seq2.begin(), key_equal_));
+}
+
+template <class T, class Hasher, class KeyEqual>
+SequenceLexicon<T, Hasher, KeyEqual>::SequenceLexicon(const Hasher& hasher,
+                                                      const KeyEqual& key_equal)
+    : id_set_(0, IdHasher(hasher, this),
+              IdKeyEqual(key_equal, this)) {
+  id_set_.set_empty_key(kEmptyKey);
+  begins_.push_back(0);
+}
+
+template <class T, class Hasher, class KeyEqual>
+SequenceLexicon<T, Hasher, KeyEqual>::SequenceLexicon(const SequenceLexicon& x)
+    : values_(x.values_), begins_(x.begins_),
+      // Unfortunately we can't copy "id_set_" because we need to change the
+      // "this" pointers associated with hasher() and key_equal().
+      id_set_(x.id_set_.begin(), x.id_set_.end(), kEmptyKey, 0,
+              IdHasher(x.id_set_.hash_funct().hasher(), this),
+              IdKeyEqual(x.id_set_.key_eq().key_equal(), this)) {
+}
+
+template <class T, class Hasher, class KeyEqual>
+SequenceLexicon<T, Hasher, KeyEqual>::SequenceLexicon(SequenceLexicon&& x)
+    : values_(std::move(x.values_)), begins_(std::move(x.begins_)),
+      // Unfortunately we can't move "id_set_" because we need to change the
+      // "this" pointers associated with hasher() and key_equal().
+      id_set_(x.id_set_.begin(), x.id_set_.end(), kEmptyKey, 0,
+              IdHasher(x.id_set_.hash_funct().hasher(), this),
+              IdKeyEqual(x.id_set_.key_eq().key_equal(), this)) {
+}
+
+template <class T, class Hasher, class KeyEqual>
+SequenceLexicon<T, Hasher, KeyEqual>&
+SequenceLexicon<T, Hasher, KeyEqual>::operator=(const SequenceLexicon& x) {
+  // Note that self-assignment is handled correctly by this code.
+  values_ = x.values_;
+  begins_ = x.begins_;
+  // Unfortunately we can't copy-assign "id_set_" because we need to change
+  // the "this" pointers associated with hasher() and key_equal().
+  id_set_ = IdSet(x.id_set_.begin(), x.id_set_.end(), kEmptyKey, 0,
+                  IdHasher(x.id_set_.hash_funct().hasher(), this),
+                  IdKeyEqual(x.id_set_.key_eq().key_equal(), this));
+  return *this;
+}
+
+template <class T, class Hasher, class KeyEqual>
+SequenceLexicon<T, Hasher, KeyEqual>&
+SequenceLexicon<T, Hasher, KeyEqual>::operator=(SequenceLexicon&& x) {
+  // Note that move self-assignment has undefined behavior.
+  values_ = std::move(x.values_);
+  begins_ = std::move(x.begins_);
+  // Unfortunately we can't move-assign "id_set_" because we need to change
+  // the "this" pointers associated with hasher() and key_equal().
+  id_set_ = IdSet(x.id_set_.begin(), x.id_set_.end(), kEmptyKey, 0,
+                  IdHasher(x.id_set_.hash_funct().hasher(), this),
+                  IdKeyEqual(x.id_set_.key_eq().key_equal(), this));
+  return *this;
+}
+
+template <class T, class Hasher, class KeyEqual>
+void SequenceLexicon<T, Hasher, KeyEqual>::Clear() {
+  values_.clear();
+  begins_.clear();
+  id_set_.clear();
+  begins_.push_back(0);
+}
+
+template <class T, class Hasher, class KeyEqual>
+template <class FwdIterator>
+uint32 SequenceLexicon<T, Hasher, KeyEqual>::Add(FwdIterator begin,
+                                                 FwdIterator end) {
+  for (; begin != end; ++begin) {
+    values_.push_back(*begin);
+  }
+  begins_.push_back(values_.size());
+  uint32 id = begins_.size() - 2;
+  auto result = id_set_.insert(id);
+  if (result.second) {
+    return id;
+  } else {
+    begins_.pop_back();
+    values_.resize(begins_.back());
+    return *result.first;
+  }
+}
+
+template <class T, class Hasher, class KeyEqual>
+template <class Container>
+uint32 SequenceLexicon<T, Hasher, KeyEqual>::Add(const Container& container) {
+  return Add(std::begin(container), std::end(container));
+}
+
+template <class T, class Hasher, class KeyEqual>
+inline uint32 SequenceLexicon<T, Hasher, KeyEqual>::size() const {
+  return begins_.size() - 1;
+}
+
+template <class T, class Hasher, class KeyEqual>
+inline typename SequenceLexicon<T, Hasher, KeyEqual>::Sequence
+SequenceLexicon<T, Hasher, KeyEqual>::sequence(uint32 id) const {
+  return Sequence(values_.begin() + begins_[id],
+                  values_.begin() + begins_[id + 1]);
+}
+
+#endif  // S2_SEQUENCE_LEXICON_H_
diff --git a/src/s2/strings/ostringstream.cc b/src/s2/strings/ostringstream.cc
new file mode 100644 (file)
index 0000000..51751e5
--- /dev/null
@@ -0,0 +1,35 @@
+// Copyright Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#include <cassert>
+
+#include "s2/strings/ostringstream.h"
+
+namespace strings {
+
+OStringStream::Buf::int_type OStringStream::overflow(int c) {
+  assert(s_);
+  if (!Buf::traits_type::eq_int_type(c, Buf::traits_type::eof()))
+    s_->push_back(static_cast<char>(c));
+  return 1;
+}
+
+std::streamsize OStringStream::xsputn(const char* s, std::streamsize n) {
+  assert(s_);
+  s_->append(s, n);
+  return n;
+}
+
+}  // namespace strings
diff --git a/src/s2/strings/ostringstream.h b/src/s2/strings/ostringstream.h
new file mode 100644 (file)
index 0000000..a6c2fb3
--- /dev/null
@@ -0,0 +1,105 @@
+// Copyright Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+
+
+#ifndef S2_STRINGS_OSTRINGSTREAM_H_
+#define S2_STRINGS_OSTRINGSTREAM_H_
+
+#include <ostream>
+#include <streambuf>
+#include <string>
+
+#include "absl/base/port.h"
+
+namespace strings {
+
+// The same as std::ostringstream but appends to a user-specified string,
+// and is faster. It is ~70% faster to create, ~50% faster to write to, and
+// completely free to extract the result string.
+//
+//   std::string s;
+//   OStringStream strm(&s);
+//   strm << 42 << ' ' << 3.14;  // appends to `s`
+//
+// The stream object doesn't have to be named. Starting from C++11 operator<<
+// works with rvalues of std::ostream.
+//
+//   std::string s;
+//   OStringStream(&s) << 42 << ' ' << 3.14;  // appends to `s`
+//
+// OStringStream is faster to create than std::ostringstream but it's still
+// relatively slow. Avoid creating multiple streams where a single stream will
+// do.
+//
+// Creates unnecessary instances of OStringStream: slow.
+//
+//   std::string s;
+//   OStringStream(&s) << 42;
+//   OStringStream(&s) << ' ';
+//   OStringStream(&s) << 3.14;
+//
+// Creates a single instance of OStringStream and reuses it: fast.
+//
+//   std::string s;
+//   OStringStream strm(&s);
+//   strm << 42;
+//   strm << ' ';
+//   strm << 3.14;
+//
+// Note: flush() has no effect. No reason to call it.
+class OStringStream : private std::basic_streambuf<char>, public std::ostream {
+ public:
+  // Export the same types as ostringstream does; for use info, see
+  // http://en.cppreference.com/w/cpp/io/basic_ostringstream
+  typedef std::string::allocator_type allocator_type;
+
+  // These types are defined in both basic_streambuf and ostream, and although
+  // they are identical, they cause compiler ambiguities, so we define them to
+  // avoid that.
+  using std::ostream::char_type;
+  using std::ostream::int_type;
+  using std::ostream::off_type;
+  using std::ostream::pos_type;
+  using std::ostream::traits_type;
+
+  // The argument can be null, in which case you'll need to call str(p) with a
+  // non-null argument before you can write to the stream.
+  //
+  // The destructor of OStringStream doesn't use the string. It's OK to destroy
+  // the string before the stream.
+  explicit OStringStream(std::string* s) : std::ostream(this), s_(s) {}
+
+  std::string* str() { return s_; }
+  const std::string* str() const { return s_; }
+  void str(std::string* s) { s_ = s; }
+
+  // These functions are defined in both basic_streambuf and ostream, but it's
+  // ostream definition that affects the strings produced.
+  using std::ostream::getloc;
+  using std::ostream::imbue;
+
+ private:
+  using Buf = std::basic_streambuf<char>;
+
+  Buf::int_type overflow(int c) override;
+  std::streamsize xsputn(const char* s, std::streamsize n) override;
+
+  std::string* s_;
+};
+
+}  // namespace strings
+
+#endif  // S2_STRINGS_OSTRINGSTREAM_H_
diff --git a/src/s2/strings/serialize.cc b/src/s2/strings/serialize.cc
new file mode 100644 (file)
index 0000000..ba7f382
--- /dev/null
@@ -0,0 +1,46 @@
+// Copyright Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#include "s2/strings/serialize.h"
+
+#include <string>
+#include <vector>
+
+#include "absl/strings/str_split.h"
+#include "absl/strings/string_view.h"
+
+using absl::StrSplit;
+using absl::string_view;
+using std::pair;
+using std::string;
+using std::vector;
+
+namespace strings {
+
+bool DictionaryParse(string_view encoded_str,
+                     vector<pair<string, string>>* items) {
+  if (encoded_str.empty())
+    return true;
+  vector<string_view> const entries = StrSplit(encoded_str, ',');
+  for (int i = 0; i < entries.size(); ++i) {
+    vector<string_view> const fields = StrSplit(entries[i], ':');
+    if (fields.size() != 2)  // parsing error
+      return false;
+    items->push_back(std::make_pair(string(fields[0]), string(fields[1])));
+  }
+  return true;
+}
+
+}  // namespace strings
diff --git a/src/s2/strings/serialize.h b/src/s2/strings/serialize.h
new file mode 100644 (file)
index 0000000..2498de6
--- /dev/null
@@ -0,0 +1,40 @@
+// Copyright Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#ifndef S2_STRINGS_SERIALIZE_H_
+#define S2_STRINGS_SERIALIZE_H_
+
+#include <string>
+#include <vector>
+
+#include "absl/strings/string_view.h"
+
+namespace strings {
+
+// -------------------------------------------------------------------------
+// DictionaryParse
+//   This routine parses a common dictionary format (key and value separated
+//   by ':', entries separated by commas). This format is used for many
+//   complex commandline flags. It is also used to encode dictionaries for
+//   exporting them or writing them to a checkpoint. Returns a vector of
+//   <key, value> pairs. Returns true if there if no error in parsing, false
+//   otherwise.
+// -------------------------------------------------------------------------
+bool DictionaryParse(absl::string_view encoded_str,
+                     std::vector<std::pair<std::string, std::string>>* items);
+
+}  // namespace strings
+
+#endif  // S2_STRINGS_SERIALIZE_H_
diff --git a/src/s2/util/bits/bit-interleave.cc b/src/s2/util/bits/bit-interleave.cc
new file mode 100644 (file)
index 0000000..413336d
--- /dev/null
@@ -0,0 +1,274 @@
+// Copyright 2009 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// Author: jyrki@google.com (Jyrki Alakuijala)
+//
+// Performance notes:
+//   2009-01-16: hendrie@google.com microbenchmarked InterleaveUint32 against
+//     two table-free implementations from "Hacker's Delight" section 7-2.
+//     This implementation was substantially faster: 8 ns vs 17 ns, even
+//     without subtracting the time taken in the test harness itself.
+//     Test environment: workstation w/ 2.4 GHz Core 2 Duo, compiler target
+//       gcc-4.3.1-glibc-2.3.6-grte-k8.
+//     TODO(user): Inlining InterleaveUint32 yields a measurable speedup (5
+//     ns vs. 8 ns). Consider cost/benefit of moving implementations inline.
+
+#include "s2/util/bits/bit-interleave.h"
+
+#include "s2/base/integral_types.h"
+
+namespace util_bits {
+
+static const uint16 kInterleaveLut[256] = {
+  0x0000, 0x0001, 0x0004, 0x0005, 0x0010, 0x0011, 0x0014, 0x0015,
+  0x0040, 0x0041, 0x0044, 0x0045, 0x0050, 0x0051, 0x0054, 0x0055,
+  0x0100, 0x0101, 0x0104, 0x0105, 0x0110, 0x0111, 0x0114, 0x0115,
+  0x0140, 0x0141, 0x0144, 0x0145, 0x0150, 0x0151, 0x0154, 0x0155,
+  0x0400, 0x0401, 0x0404, 0x0405, 0x0410, 0x0411, 0x0414, 0x0415,
+  0x0440, 0x0441, 0x0444, 0x0445, 0x0450, 0x0451, 0x0454, 0x0455,
+  0x0500, 0x0501, 0x0504, 0x0505, 0x0510, 0x0511, 0x0514, 0x0515,
+  0x0540, 0x0541, 0x0544, 0x0545, 0x0550, 0x0551, 0x0554, 0x0555,
+
+  0x1000, 0x1001, 0x1004, 0x1005, 0x1010, 0x1011, 0x1014, 0x1015,
+  0x1040, 0x1041, 0x1044, 0x1045, 0x1050, 0x1051, 0x1054, 0x1055,
+  0x1100, 0x1101, 0x1104, 0x1105, 0x1110, 0x1111, 0x1114, 0x1115,
+  0x1140, 0x1141, 0x1144, 0x1145, 0x1150, 0x1151, 0x1154, 0x1155,
+  0x1400, 0x1401, 0x1404, 0x1405, 0x1410, 0x1411, 0x1414, 0x1415,
+  0x1440, 0x1441, 0x1444, 0x1445, 0x1450, 0x1451, 0x1454, 0x1455,
+  0x1500, 0x1501, 0x1504, 0x1505, 0x1510, 0x1511, 0x1514, 0x1515,
+  0x1540, 0x1541, 0x1544, 0x1545, 0x1550, 0x1551, 0x1554, 0x1555,
+
+  0x4000, 0x4001, 0x4004, 0x4005, 0x4010, 0x4011, 0x4014, 0x4015,
+  0x4040, 0x4041, 0x4044, 0x4045, 0x4050, 0x4051, 0x4054, 0x4055,
+  0x4100, 0x4101, 0x4104, 0x4105, 0x4110, 0x4111, 0x4114, 0x4115,
+  0x4140, 0x4141, 0x4144, 0x4145, 0x4150, 0x4151, 0x4154, 0x4155,
+  0x4400, 0x4401, 0x4404, 0x4405, 0x4410, 0x4411, 0x4414, 0x4415,
+  0x4440, 0x4441, 0x4444, 0x4445, 0x4450, 0x4451, 0x4454, 0x4455,
+  0x4500, 0x4501, 0x4504, 0x4505, 0x4510, 0x4511, 0x4514, 0x4515,
+  0x4540, 0x4541, 0x4544, 0x4545, 0x4550, 0x4551, 0x4554, 0x4555,
+
+  0x5000, 0x5001, 0x5004, 0x5005, 0x5010, 0x5011, 0x5014, 0x5015,
+  0x5040, 0x5041, 0x5044, 0x5045, 0x5050, 0x5051, 0x5054, 0x5055,
+  0x5100, 0x5101, 0x5104, 0x5105, 0x5110, 0x5111, 0x5114, 0x5115,
+  0x5140, 0x5141, 0x5144, 0x5145, 0x5150, 0x5151, 0x5154, 0x5155,
+  0x5400, 0x5401, 0x5404, 0x5405, 0x5410, 0x5411, 0x5414, 0x5415,
+  0x5440, 0x5441, 0x5444, 0x5445, 0x5450, 0x5451, 0x5454, 0x5455,
+  0x5500, 0x5501, 0x5504, 0x5505, 0x5510, 0x5511, 0x5514, 0x5515,
+  0x5540, 0x5541, 0x5544, 0x5545, 0x5550, 0x5551, 0x5554, 0x5555,
+};
+
+uint16 InterleaveUint8(const uint8 val0, const uint8 val1) {
+  return kInterleaveLut[val0] | (kInterleaveLut[val1] << 1);
+}
+
+uint32 InterleaveUint16(const uint16 val0, const uint16 val1) {
+  return kInterleaveLut[val0 & 0xff] |
+      (kInterleaveLut[val0 >> 8] << 16) |
+      (kInterleaveLut[val1 & 0xff] << 1) |
+      (kInterleaveLut[val1 >> 8] << 17);
+}
+
+uint64 InterleaveUint32(const uint32 val0, const uint32 val1) {
+  return
+      (static_cast<uint64>(kInterleaveLut[val0 & 0xff])) |
+      (static_cast<uint64>(kInterleaveLut[(val0 >> 8) & 0xff]) << 16) |
+      (static_cast<uint64>(kInterleaveLut[(val0 >> 16) & 0xff]) << 32) |
+      (static_cast<uint64>(kInterleaveLut[val0 >> 24]) << 48) |
+      (static_cast<uint64>(kInterleaveLut[val1 & 0xff]) << 1) |
+      (static_cast<uint64>(kInterleaveLut[(val1 >> 8) & 0xff]) << 17) |
+      (static_cast<uint64>(kInterleaveLut[(val1 >> 16) & 0xff]) << 33) |
+      (static_cast<uint64>(kInterleaveLut[val1 >> 24]) << 49);
+}
+
+// The lookup table below can convert a sequence of interleaved 8 bits into
+// non-interleaved 4 bits. The table can convert both odd and even bits at the
+// same time, and lut[x & 0x55] converts the even bits (bits 0, 2, 4 and 6),
+// while lut[x & 0xaa] converts the odd bits (bits 1, 3, 5 and 7).
+//
+// The lookup table below was generated using the following python code:
+//
+// def deinterleave(bits):
+//   if bits == 0: return 0
+//   if bits < 4: return 1
+//   return deinterleave(bits / 4) * 2 + deinterleave(bits & 3)
+//
+// for i in range(256): print "0x%x," % deinterleave(i),
+//
+static const uint8 kDeinterleaveLut[256] = {
+  0x0, 0x1, 0x1, 0x1, 0x2, 0x3, 0x3, 0x3,
+  0x2, 0x3, 0x3, 0x3, 0x2, 0x3, 0x3, 0x3,
+  0x4, 0x5, 0x5, 0x5, 0x6, 0x7, 0x7, 0x7,
+  0x6, 0x7, 0x7, 0x7, 0x6, 0x7, 0x7, 0x7,
+  0x4, 0x5, 0x5, 0x5, 0x6, 0x7, 0x7, 0x7,
+  0x6, 0x7, 0x7, 0x7, 0x6, 0x7, 0x7, 0x7,
+  0x4, 0x5, 0x5, 0x5, 0x6, 0x7, 0x7, 0x7,
+  0x6, 0x7, 0x7, 0x7, 0x6, 0x7, 0x7, 0x7,
+
+  0x8, 0x9, 0x9, 0x9, 0xa, 0xb, 0xb, 0xb,
+  0xa, 0xb, 0xb, 0xb, 0xa, 0xb, 0xb, 0xb,
+  0xc, 0xd, 0xd, 0xd, 0xe, 0xf, 0xf, 0xf,
+  0xe, 0xf, 0xf, 0xf, 0xe, 0xf, 0xf, 0xf,
+  0xc, 0xd, 0xd, 0xd, 0xe, 0xf, 0xf, 0xf,
+  0xe, 0xf, 0xf, 0xf, 0xe, 0xf, 0xf, 0xf,
+  0xc, 0xd, 0xd, 0xd, 0xe, 0xf, 0xf, 0xf,
+  0xe, 0xf, 0xf, 0xf, 0xe, 0xf, 0xf, 0xf,
+
+  0x8, 0x9, 0x9, 0x9, 0xa, 0xb, 0xb, 0xb,
+  0xa, 0xb, 0xb, 0xb, 0xa, 0xb, 0xb, 0xb,
+  0xc, 0xd, 0xd, 0xd, 0xe, 0xf, 0xf, 0xf,
+  0xe, 0xf, 0xf, 0xf, 0xe, 0xf, 0xf, 0xf,
+  0xc, 0xd, 0xd, 0xd, 0xe, 0xf, 0xf, 0xf,
+  0xe, 0xf, 0xf, 0xf, 0xe, 0xf, 0xf, 0xf,
+  0xc, 0xd, 0xd, 0xd, 0xe, 0xf, 0xf, 0xf,
+  0xe, 0xf, 0xf, 0xf, 0xe, 0xf, 0xf, 0xf,
+
+  0x8, 0x9, 0x9, 0x9, 0xa, 0xb, 0xb, 0xb,
+  0xa, 0xb, 0xb, 0xb, 0xa, 0xb, 0xb, 0xb,
+  0xc, 0xd, 0xd, 0xd, 0xe, 0xf, 0xf, 0xf,
+  0xe, 0xf, 0xf, 0xf, 0xe, 0xf, 0xf, 0xf,
+  0xc, 0xd, 0xd, 0xd, 0xe, 0xf, 0xf, 0xf,
+  0xe, 0xf, 0xf, 0xf, 0xe, 0xf, 0xf, 0xf,
+  0xc, 0xd, 0xd, 0xd, 0xe, 0xf, 0xf, 0xf,
+  0xe, 0xf, 0xf, 0xf, 0xe, 0xf, 0xf, 0xf,
+};
+
+void DeinterleaveUint8(uint16 val, uint8 *val0, uint8 *val1) {
+  *val0 = ((kDeinterleaveLut[val & 0x55]) |
+           (kDeinterleaveLut[(val >> 8) & 0x55] << 4));
+  *val1 = ((kDeinterleaveLut[val & 0xaa]) |
+           (kDeinterleaveLut[(val >> 8) & 0xaa] << 4));
+}
+
+void DeinterleaveUint16(uint32 code, uint16 *val0, uint16 *val1) {
+  *val0 = ((kDeinterleaveLut[code & 0x55]) |
+           (kDeinterleaveLut[(code >> 8) & 0x55] << 4) |
+           (kDeinterleaveLut[(code >> 16) & 0x55] << 8) |
+           (kDeinterleaveLut[(code >> 24) & 0x55] << 12));
+  *val1 = ((kDeinterleaveLut[code & 0xaa]) |
+           (kDeinterleaveLut[(code >> 8) & 0xaa] << 4) |
+           (kDeinterleaveLut[(code >> 16) & 0xaa] << 8) |
+           (kDeinterleaveLut[(code >> 24) & 0xaa] << 12));
+}
+
+void DeinterleaveUint32(uint64 code, uint32 *val0, uint32 *val1) {
+  *val0 = ((kDeinterleaveLut[code & 0x55]) |
+           (kDeinterleaveLut[(code >> 8) & 0x55] << 4) |
+           (kDeinterleaveLut[(code >> 16) & 0x55] << 8) |
+           (kDeinterleaveLut[(code >> 24) & 0x55] << 12) |
+           (kDeinterleaveLut[(code >> 32) & 0x55] << 16) |
+           (kDeinterleaveLut[(code >> 40) & 0x55] << 20) |
+           (kDeinterleaveLut[(code >> 48) & 0x55] << 24) |
+           (kDeinterleaveLut[(code >> 56) & 0x55] << 28));
+  *val1 = ((kDeinterleaveLut[code & 0xaa]) |
+           (kDeinterleaveLut[(code >> 8) & 0xaa] << 4) |
+           (kDeinterleaveLut[(code >> 16) & 0xaa] << 8) |
+           (kDeinterleaveLut[(code >> 24) & 0xaa] << 12) |
+           (kDeinterleaveLut[(code >> 32) & 0xaa] << 16) |
+           (kDeinterleaveLut[(code >> 40) & 0xaa] << 20) |
+           (kDeinterleaveLut[(code >> 48) & 0xaa] << 24) |
+           (kDeinterleaveLut[(code >> 56) & 0xaa] << 28));
+}
+
+// Derivation of the multiplication based interleave algorithm:
+// 1. Original value, bit positions shown:
+//    x = --------------------------------------------------------87654321
+// 2. Replicate the byte and select the bits we want:
+//    * 0b0000000100000001000000010000000100000001000000010000000100000001
+//      0x   0   1   0   1   0   1   0   1   0   1   0   1   0   1   0   1
+//   =>   8765432187654321876543218765432187654321876543218765432187654321
+//    & 0b0000000000000000000000001100000000001100000000000011000000000011
+//      0x   0   0   0   0   0   0   C   0   0   C   0   0   3   0   0   3
+//   =>   ------------------------87----------43------------65----------21
+// 3. Use multiplication to perform additions at different offsets:
+//    * 0b0000000000000000000000000000000000000000010100000000000000000101
+//      0x   0   0   0   0   0   0   0   0   0   0   5   0   0   0   0   5
+//   =>
+//        ------------------------87----------43------------65----------21
+//      + ----------------------87----------43------------65----------21
+//      + ----87----------43------------65----------21
+//      + --87----------43------------65----------21
+//   =>   --8787--------4343----8787--6565--4343--2121----6565--------2121
+// 4. Notice the bits never collide.  Select the bits we want.
+//    & 0b0000000000000000000000100100100100100100100100000000000000000000
+//      0x   0   0   0   0   0   2   4   9   2   4   9   0   0   0   0   0
+//   =>   ----------------------8--7--6--5--4--3--2--1--------------------
+// 5. To produce the final result, we bitwise OR the 3 split integers and shift
+//    back to the LSB.  To save instructions, we use template<N> to have steps
+//    3 and 4 produce results shifted over N bits.
+// Benchmark                      Time(ns)    CPU(ns) Iterations
+// -------------------------------------------------------------
+// BM_3_InterleaveUint8                  5          5  141967960
+// BM_3_ReferenceBitInterleave3         58         58   10000000
+// BM_3_InterleaveUint8_NoTemplate      11         11   61082024
+template<int kShift>
+static uint64 SplitFor3(uint8 x) {
+  return
+      ((((x * 0x0101010101010101ULL)
+            & 0x000000C00C003003ULL)
+            * (0x0000000000500005ULL << kShift))
+            & (0x0000024924900000ULL << kShift));
+}
+
+uint32 InterleaveUint8(uint8 val0, uint8 val1, uint8 val2) {
+  return static_cast<uint32>(
+      (SplitFor3<0>(val0) | SplitFor3<1>(val1) | SplitFor3<2>(val2)) >> 20);
+}
+
+// Multiplication based de-interleave algorithm:
+// 1. Original value, bit positions shown:
+//        --------xx8xx7xx6xx5xx4xx3xx2xx1
+//    & 0x   0   0   2   4   9   2   4   9
+//   =>   ----------8--7--6--5--4--3--2--1
+// 2. Use multiplication to perform additions at different offsets:
+//    * 0b00000000000000000000000000010101
+//      0x   0   0   0   0   0   0   1   5
+//   =>
+//        ----------8--7--6--5--4--3--2--1
+//     +  --------8--7--6--5--4--3--2--1
+//     +  ------8--7--6--5--4--3--2--1
+//   =>   ------8-8787676565454343232121-1
+// 3. Select the bits we need
+//    & 0b00000000001110000001110000001100
+//      0x   0   0   3   8   1   C   0   C
+//   =>   ----------876------543------21--
+// 4. Multiply again to make the additions we need
+//    * 0b00000000000000000001000001000001
+//      0x   0   0   0   0   1   0   4   1
+//   =>
+//        ----------876------543------21--
+//     +  ----876------543------21--
+//     +  6------543------21--
+//   =>   ----------87654321--------------
+// 5. Shift down so it lives at the lower 8 bits.
+// Benchmark                         Time(ns)    CPU(ns) Iterations
+// ----------------------------------------------------------------
+// BM_3_DeinterleaveUint8                   8          8   88136788
+// BM_3_DeinterleaveUint8_Using_Template   10         10   67385445
+// BM_3_DeinterleaveUint8_Uint64_Param     10         10   70838731
+// BM_3_ReferenceDeinterleaveUint8         79         79    8712211
+static inline uint8 UnsplitFor3(uint32 x) {
+  return ((((x & 0x00249249U)
+               * 0x00000015U)
+               & 0x00381C0CU)
+               * 0x00001041U) >> 14;
+}
+
+void DeinterleaveUint8(uint32 x, uint8* a, uint8* b, uint8* c) {
+  *a = UnsplitFor3(x);
+  *b = UnsplitFor3(x >> 1);
+  *c = UnsplitFor3(x >> 2);
+}
+
+}  // namespace util_bits
diff --git a/src/s2/util/bits/bit-interleave.h b/src/s2/util/bits/bit-interleave.h
new file mode 100644 (file)
index 0000000..27cc45b
--- /dev/null
@@ -0,0 +1,53 @@
+// Copyright 2009 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// Author: jyrki@google.com (Jyrki Alakuijala)
+//
+// Interleaving bits quickly by table lookup.
+
+#ifndef S2_UTIL_BITS_BIT_INTERLEAVE_H_
+#define S2_UTIL_BITS_BIT_INTERLEAVE_H_
+
+#include "s2/base/integral_types.h"
+
+namespace util_bits {
+
+// These functions interleave the given arguments into the return value.
+//
+// The 0-bit in val0 will be the 0-bit in the return value.
+// The 0-bit in val1 will be the 1-bit in the return value.
+// The 1-bit of val0 will be the 2-bit in the return value, and so on.
+uint16 InterleaveUint8(uint8 val0, uint8 val1);
+uint32 InterleaveUint16(uint16 val0, uint16 val1);
+uint64 InterleaveUint32(uint32 val0, uint32 val1);
+
+// These functions will decode the interleaved values.
+void DeinterleaveUint8(uint16 code, uint8 *val0, uint8 *val1);
+void DeinterleaveUint16(uint32 code, uint16 *val0, uint16 *val1);
+void DeinterleaveUint32(uint64 code, uint32 *val0, uint32 *val1);
+
+// These functions interleave three arguments into the return value.
+// The 0-bit in val0 will be the 0-bit in the return value.
+// The 0-bit in val1 will be the 1-bit in the return value.
+// The 0-bit in val2 will be the 2-bit in the return value.
+// The 1-bit of val0 will be the 3-bit in the return value, and so on.
+uint32 InterleaveUint8(uint8 val0, uint8 val1, uint8 val2);
+
+// These functions will decode the interleaved values.
+void DeinterleaveUint8(uint32 code, uint8 *val0, uint8* val1, uint8* val2);
+
+}  // namespace util_bits
+
+#endif  // S2_UTIL_BITS_BIT_INTERLEAVE_H_
diff --git a/src/s2/util/bits/bits.cc b/src/s2/util/bits/bits.cc
new file mode 100644 (file)
index 0000000..cc6da30
--- /dev/null
@@ -0,0 +1,155 @@
+// Copyright 2002 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+//
+// Derived from code by Moses Charikar
+
+#include "s2/util/bits/bits.h"
+
+#include <cassert>
+#include "absl/numeric/int128.h"
+
+using absl::uint128;
+
+// this array gives the number of bits for any number from 0 to 255
+// (We could make these ints.  The tradeoff is size (eg does it overwhelm
+// the cache?) vs efficiency in referencing sub-word-sized array elements)
+const char Bits::num_bits[] = {
+  0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4,
+  1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
+  1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
+  2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
+  1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
+  2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
+  2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
+  3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
+  1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
+  2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
+  2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
+  3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
+  2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
+  3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
+  3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
+  4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8 };
+
+int Bits::Count(const void *m, int num_bytes) {
+  int nbits = 0;
+  const uint8 *s = (const uint8 *) m;
+  for (int i = 0; i < num_bytes; i++)
+    nbits += num_bits[*s++];
+  return nbits;
+}
+
+int Bits::Difference(const void *m1, const void *m2, int num_bytes) {
+  int nbits = 0;
+  const uint8 *s1 = (const uint8 *) m1;
+  const uint8 *s2 = (const uint8 *) m2;
+  for (int i = 0; i < num_bytes; i++)
+    nbits += num_bits[(*s1++) ^ (*s2++)];
+  return nbits;
+}
+
+int Bits::CappedDifference(const void *m1, const void *m2,
+                           int num_bytes, int cap) {
+  int nbits = 0;
+  const uint8 *s1 = (const uint8 *) m1;
+  const uint8 *s2 = (const uint8 *) m2;
+  for (int i = 0; i < num_bytes && nbits <= cap; i++)
+    nbits += num_bits[(*s1++) ^ (*s2++)];
+  return nbits;
+}
+
+int Bits::Log2Floor_Portable(uint32 n) {
+  if (n == 0)
+    return -1;
+  int log = 0;
+  uint32 value = n;
+  for (int i = 4; i >= 0; --i) {
+    int shift = (1 << i);
+    uint32 x = value >> shift;
+    if (x != 0) {
+      value = x;
+      log += shift;
+    }
+  }
+  assert(value == 1);
+  return log;
+}
+
+int Bits::Log2Ceiling(uint32 n) {
+  int floor = Log2Floor(n);
+  if ((n & (n - 1)) == 0)              // zero or a power of two
+    return floor;
+  else
+    return floor + 1;
+}
+
+int Bits::Log2Ceiling64(uint64 n) {
+  int floor = Log2Floor64(n);
+  if ((n & (n - 1)) == 0)              // zero or a power of two
+    return floor;
+  else
+    return floor + 1;
+}
+
+int Bits::Log2Ceiling128(absl::uint128 n) {
+  int floor = Log2Floor128(n);
+  if ((n & (n - 1)) == 0)              // zero or a power of two
+    return floor;
+  else
+    return floor + 1;
+}
+
+int Bits::FindLSBSetNonZero_Portable(uint32 n) {
+  int rc = 31;
+  for (int i = 4, shift = 1 << 4; i >= 0; --i) {
+    const uint32 x = n << shift;
+    if (x != 0) {
+      n = x;
+      rc -= shift;
+    }
+    shift >>= 1;
+  }
+  return rc;
+}
+
+int Bits::CountLeadingZeros32_Portable(uint32 n) {
+  int bits = 1;
+  if (n == 0)
+    return 32;
+  if ((n >> 16) == 0) {
+    bits += 16;
+    n <<= 16;
+  }
+  if ((n >> 24) == 0) {
+    bits += 8;
+    n <<= 8;
+  }
+  if ((n >> 28) == 0) {
+    bits += 4;
+    n <<= 4;
+  }
+  if ((n >> 30) == 0) {
+    bits += 2;
+    n <<= 2;
+  }
+  return bits - (n >> 31);
+}
+
+int Bits::CountLeadingZeros64_Portable(uint64 n) {
+  return ((n >> 32)
+           ? Bits::CountLeadingZeros32_Portable(n >> 32)
+           : 32 +  Bits::CountLeadingZeros32_Portable(n));
+}
diff --git a/src/s2/util/bits/bits.h b/src/s2/util/bits/bits.h
new file mode 100644 (file)
index 0000000..59cb8cd
--- /dev/null
@@ -0,0 +1,745 @@
+// Copyright 2002 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#ifndef S2_UTIL_BITS_BITS_H_
+#define S2_UTIL_BITS_BITS_H_
+
+//
+// Various bit-twiddling functions, all of which are static members of the Bits
+// class (making it effectively a namespace). Operands are unsigned integers.
+// Munging bits in _signed_ integers is fraught with peril! For example,
+// -5 << n has undefined behavior (for some values of n).
+//
+// Bits provide the following:
+//
+//   * Count(Ones.*|LeadingZeros.*)? . In a similar vein, there's also the
+//     Find[LM]SBSetNonZero.* family of functions. You can think of them as
+//     (trailing|leading) zero bit count + 1. Also in a similar vein,
+//     (Capped)?Difference, which count the number of one bits in foo ^ bar.
+//
+//   * ReverseBits${power_of_two}
+//
+//   * Log2(Floor|Ceiling)(NonZero)?.* - The NonZero variants have undefined
+//     behavior if argument is 0.
+//
+//   * Bytes(ContainByte(LessThan)?|AllInRange) - These scan a sequence of bytes
+//     looking for one with(out)? some property.
+//
+//   * (Get|Set|Copy)Bits
+//
+//   * GetLowBits - Extract N lowest bits from value.
+//
+// The only other thing is BitPattern, which is a trait class template (not in
+// Bits) containing a few bit patterns (which vary based on value of template
+// parameter).
+
+#include "absl/base/casts.h"
+#include "absl/numeric/int128.h"
+#if defined(__i386__) || defined(__x86_64__)
+#include <x86intrin.h>
+#endif
+
+#include <type_traits>
+
+#include "s2/base/integral_types.h"
+#include "s2/base/logging.h"
+#include "s2/base/port.h"
+#include "absl/base/macros.h"
+
+class Bits {
+ public:
+  // A traits class template for unsigned integer type sizes. Primary
+  // information contained herein is corresponding (unsigned) integer type.
+  // E.g. UnsignedTypeBySize<32>::Type is uint32. Used by UnsignedType.
+  template<int size /* in bytes */>
+  struct UnsignedTypeBySize;
+
+  // Auxiliary struct for figuring out an unsigned type for a given type.
+  template<typename T> struct UnsignedType {
+    typedef typename UnsignedTypeBySize<sizeof(T)>::Type Type;
+  };
+
+  // Return the number of one bits in the given integer.
+  static int CountOnesInByte(unsigned char n);
+
+  static int CountOnes(uint32 n) {
+#if defined(__powerpc64__) && defined(__GNUC__)
+    // Use popcount builtin if we know it is inlined and fast.
+    return PopcountWithBuiltin(n);
+#elif (defined(__i386__) || defined(__x86_64__)) && defined(__POPCNT__) && \
+    defined(__GNUC__)
+    return PopcountWithBuiltin(n);
+#else
+    n -= ((n >> 1) & 0x55555555);
+    n = ((n >> 2) & 0x33333333) + (n & 0x33333333);
+    return static_cast<int>((((n + (n >> 4)) & 0xF0F0F0F) * 0x1010101) >> 24);
+#endif
+  }
+
+  // Count bits using sideways addition [WWG'57]. See Knuth TAOCP v4 7.1.3(59)
+  static inline int CountOnes64(uint64 n) {
+#if defined(__powerpc64__) && defined(__GNUC__)
+    return PopcountWithBuiltin(n);
+#elif defined(__x86_64__) && defined(__POPCNT__) && defined(__GNUC__)
+    return PopcountWithBuiltin(n);
+#elif defined(_LP64)
+    n -= (n >> 1) & 0x5555555555555555ULL;
+    n = ((n >> 2) & 0x3333333333333333ULL) + (n & 0x3333333333333333ULL);
+    return static_cast<int>(
+        (((n + (n >> 4)) & 0xF0F0F0F0F0F0F0FULL) * 0x101010101010101ULL) >> 56);
+#else
+    return CountOnes(n >> 32) + CountOnes(n & 0xffffffff);
+#endif
+  }
+
+  // Count bits in uint128
+  static inline int CountOnes128(absl::uint128 n) {
+    return Bits::CountOnes64(absl::Uint128High64(n)) +
+           Bits::CountOnes64(absl::Uint128Low64(n));
+  }
+
+  // Count leading zeroes.  This is similar to wordsize - 1 - floor(log2(n)).
+  // Returns number of bits if n is 0.
+  static inline int CountLeadingZeros32(uint32 n) {
+    // Instead of using __builtin_clz(), we explicitly write target specific
+    // assembly because we want to handle n == 0.  If we used __builtin_clz(),
+    // we would need to use something like "n ? __builtin_clz(n) : 32".  The
+    // check is not necessary on POWER and aarch64 but we cannot depend on
+    // that because __builtin_clz(0) is documented to be undefined.
+#if defined(__aarch64__) && defined(__GNUC__)
+    int32 count;
+    asm("clz %w0,%w1" : "=r"(count) : "r"(n));
+    return count;
+#elif (defined(__i386__) || defined(__x86_64__)) && defined(__LZCNT__) && \
+    defined(__GNUC__)
+    return __lzcnt32(n);
+#elif (defined(__i386__) || defined(__x86_64__)) && defined(__GNUC__)
+    if (n == 0) return 32;
+    int32 idx;
+    asm("bsr %1, %0"
+        : "=r"(idx)
+        : "ro"(n)
+        : "cc");              // bsr writes Z flag
+    return 31 ^ idx;
+#elif defined(__powerpc64__) && defined(__GNUC__)
+    int32 count;
+    asm("cntlzw %0,%1" : "=r"(count) : "r"(n));
+    return count;
+#elif defined(__GNUC__)
+    return CountLeadingZerosWithBuiltin(n);
+#else
+    return CountLeadingZeros32_Portable(n);
+#endif
+  }
+
+  static inline int CountLeadingZeros64(uint64 n) {
+#if defined(__aarch64__) && defined(__GNUC__)
+    int64 count;
+    asm("clz %0,%1" : "=r"(count) : "r"(n));
+    return static_cast<int>(count);
+#elif defined(__powerpc64__) && defined(__GNUC__)
+    int64 count;
+    asm("cntlzd %0,%1" : "=r"(count) : "r"(n));
+    return static_cast<int>(count);
+#elif (defined(__i386__) || defined(__x86_64__)) && defined(__LZCNT__) && \
+    defined(__GNUC__)
+    return __lzcnt64(n);
+#elif defined(__x86_64__) && defined(__GNUC__)
+    if (n == 0) return 64;
+    int64 idx;
+    asm ("bsr %1, %0"
+         : "=r"(idx)
+         : "ro"(n)
+         : "cc");              // bsr writes Z flag
+    return static_cast<int>(63 ^ idx);
+#elif defined(__GNUC__)
+    return CountLeadingZerosWithBuiltin(n);
+#else
+    return CountLeadingZeros64_Portable(n);
+#endif
+  }
+
+  static inline int CountLeadingZeros128(absl::uint128 n) {
+    if (uint64 hi = absl::Uint128High64(n))
+      return Bits::CountLeadingZeros64(hi);
+    return Bits::CountLeadingZeros64(absl::Uint128Low64(n)) + 64;
+  }
+
+  // Reverse the bits in the given integer.
+  static uint8 ReverseBits8(uint8 n);
+  static uint32 ReverseBits32(uint32 n);
+  static uint64 ReverseBits64(uint64 n);
+  static absl::uint128 ReverseBits128(absl::uint128 n);
+
+  // Return the number of one bits in the byte sequence.
+  static int Count(const void *m, int num_bytes);
+
+  // Return the number of different bits in the given byte sequences.
+  // (i.e., the Hamming distance)
+  static int Difference(const void *m1, const void *m2, int num_bytes);
+
+  // Return the number of different bits in the given byte sequences,
+  // up to a maximum.  Values larger than the maximum may be returned
+  // (because multiple bits are checked at a time), but the function
+  // may exit early if the cap is exceeded.
+  static int CappedDifference(const void *m1, const void *m2,
+                              int num_bytes, int cap);
+
+  // Return floor(log2(n)) for positive integer n.  Returns -1 iff n == 0.
+  static int Log2Floor(uint32 n);
+  static int Log2Floor64(uint64 n);
+  static int Log2Floor128(absl::uint128 n);
+
+  // Potentially faster version of Log2Floor() that returns an
+  // undefined value if n == 0
+  static int Log2FloorNonZero(uint32 n);
+  static int Log2FloorNonZero64(uint64 n);
+  static int Log2FloorNonZero128(absl::uint128 n);
+
+  // Return ceiling(log2(n)) for positive integer n.  Returns -1 iff n == 0.
+  static int Log2Ceiling(uint32 n);
+  static int Log2Ceiling64(uint64 n);
+  static int Log2Ceiling128(absl::uint128 n);
+
+  // Return the first set least / most significant bit, 0-indexed.  Returns an
+  // undefined value if n == 0.  FindLSBSetNonZero() is similar to ffs() except
+  // that it's 0-indexed, while FindMSBSetNonZero() is the same as
+  // Log2FloorNonZero().
+  static int FindLSBSetNonZero(uint32 n);
+  static int FindLSBSetNonZero64(uint64 n);
+  static int FindLSBSetNonZero128(absl::uint128 n);
+  static int FindMSBSetNonZero(uint32 n) { return Log2FloorNonZero(n); }
+  static int FindMSBSetNonZero64(uint64 n) { return Log2FloorNonZero64(n); }
+  static int FindMSBSetNonZero128(absl::uint128 n) {
+    return Log2FloorNonZero128(n);
+  }
+
+  // Viewing bytes as a stream of unsigned bytes, does that stream
+  // contain any byte equal to c?
+  template <class T> static bool BytesContainByte(T bytes, uint8 c);
+
+  // Viewing bytes as a stream of unsigned bytes, does that stream
+  // contain any byte b < c?
+  template <class T> static bool BytesContainByteLessThan(T bytes, uint8 c);
+
+  // Viewing bytes as a stream of unsigned bytes, are all elements of that
+  // stream in [lo, hi]?
+  template <class T> static bool BytesAllInRange(T bytes, uint8 lo, uint8 hi);
+
+  // Extract 'nbits' consecutive bits from 'src'.  Position of bits are
+  // specified by 'offset' from the LSB.  'T' is a scalar type (integral,
+  // float or pointer) whose size is the same as one of the unsigned types.
+  // The return type is an unsigned type having the same size as T.
+  template<typename T>
+  static typename UnsignedType<T>::Type GetBits(const T src,
+                                                const int offset,
+                                                const int nbits) {
+    typedef typename UnsignedType<T>::Type UnsignedT;
+    const UnsignedT unsigned_src = absl::bit_cast<UnsignedT>(src);
+    S2_DCHECK_GT(sizeof(UnsignedT) * 8, offset);
+    S2_DCHECK_GE(sizeof(UnsignedT) * 8, offset + nbits);
+    return GetBitsImpl(unsigned_src, offset, nbits);
+  }
+
+  // Overwrite 'nbits' consecutive bits of 'dest.'.  Position of bits are
+  // specified by an offset from the LSB.  'T' is a scalar type (integral,
+  // float or pointer) whose size is the same as one of the unsigned types.
+  template<typename T>
+  static void SetBits(const typename UnsignedType<T>::Type value,
+                      const int offset,
+                      const int nbits,
+                      T* const dest) {
+    typedef typename UnsignedType<T>::Type UnsignedT;
+    const UnsignedT unsigned_dest = absl::bit_cast<UnsignedT>(*dest);
+    S2_DCHECK_GT(sizeof(UnsignedT) * 8, offset);
+    S2_DCHECK_GE(sizeof(UnsignedT) * 8, offset + nbits);
+    const UnsignedT mask = NBitsFromLSB<UnsignedT>(nbits);
+    const UnsignedT unsigned_result =
+        (unsigned_dest & ~(mask << offset)) | ((value & mask) << offset);
+    *dest = absl::bit_cast<T>(unsigned_result);
+  }
+
+  // Combine SetBits and GetBits for convenience.  This is meant to be a
+  // replacement for BitCopy() for some use cases.  Unlike BitCopy(),
+  // Bits::CopyBits() operating on multibyte types has the same behavior on
+  // big-endian and little-endian machines. Sample usage:
+  //
+  // uint32 a, b;
+  // Bits::CopyBits(&a, 0, b, 12, 3);
+  template<typename DestType, typename SrcType>
+  static void CopyBits(DestType* const dest,
+                       const int dest_offset,
+                       const SrcType src,
+                       const int src_offset,
+                       const int nbits) {
+    const typename UnsignedType<SrcType>::Type value =
+        GetBits(src, src_offset, nbits);
+    SetBits(value, dest_offset, nbits, dest);
+  }
+
+  // Extract the lowest 'nbits' consecutive bits from 'src'.
+  // Bits::GetLowBits(13, 3); /* = 5 (0b1101 => 0b101) */
+  template<typename T>
+  static typename UnsignedType<T>::Type GetLowBits(const T src,
+                                                   const int nbits) {
+    typedef typename UnsignedType<T>::Type UnsignedT;
+    const UnsignedT unsigned_src = absl::bit_cast<UnsignedT>(src);
+    S2_DCHECK_GE(sizeof(UnsignedT) * 8, nbits);
+    return GetLowBitsImpl(unsigned_src, nbits);
+  }
+
+ private:
+  // We only use this for unsigned types and for 0 <= n <= sizeof(UnsignedT).
+  template<typename UnsignedT>
+  static UnsignedT NBitsFromLSB(const int nbits) {
+    const UnsignedT all_ones = ~static_cast<UnsignedT>(0);
+    return nbits == 0 ? static_cast<UnsignedT>(0)
+                      : all_ones >> (sizeof(UnsignedT) * 8 - nbits);
+  }
+
+  template<typename UnsignedT>
+  static inline UnsignedT GetBitsImpl(const UnsignedT src,
+                                      const int offset,
+                                      const int nbits);
+  template <typename UnsignedT>
+  static inline UnsignedT GetLowBitsImpl(const UnsignedT src, const int nbits);
+
+#ifdef __GNUC__
+  static int CountLeadingZerosWithBuiltin(unsigned n);
+  // NOLINTNEXTLINE(runtime/int)
+  static int CountLeadingZerosWithBuiltin(unsigned long n);
+  // NOLINTNEXTLINE(runtime/int)
+  static int CountLeadingZerosWithBuiltin(unsigned long long n);
+  static int PopcountWithBuiltin(unsigned n);
+  static int PopcountWithBuiltin(unsigned long n);       // NOLINT(runtime/int)
+  static int PopcountWithBuiltin(unsigned long long n);  // NOLINT(runtime/int)
+#if defined(__BMI__) && (defined(__i386__) || defined(__x86_64__))
+  static inline uint32 GetBitsImpl(const uint32 src,
+                                   const int offset,
+                                   const int nbits);
+#endif
+#if defined(__BMI__) && defined(__x86_64__)
+  static inline uint64 GetBitsImpl(const uint64 src,
+                                   const int offset,
+                                   const int nbits);
+#endif
+#if defined(__BMI2__) && (defined(__i386__) || defined(__x86_64__))
+  static inline uint32 GetLowBitsImpl(const uint32 src, const int nbits);
+#endif
+#if defined(__BMI2__) && defined(__x86_64__)
+  static inline uint64 GetLowBitsImpl(const uint64 src, const int nbits);
+#endif
+#endif  // __GNUC__
+
+  // Portable implementations.
+  static int Log2Floor_Portable(uint32 n);
+  static int Log2Floor64_Portable(uint64 n);
+  static int Log2FloorNonZero_Portable(uint32 n);
+  static int Log2FloorNonZero64_Portable(uint64 n);
+  static int CountLeadingZeros32_Portable(uint32 n);
+  static int CountLeadingZeros64_Portable(uint64 n);
+  static int FindLSBSetNonZero_Portable(uint32 n);
+  static int FindLSBSetNonZero64_Portable(uint64 n);
+
+  static const char num_bits[];
+  Bits(Bits const&) = delete;
+  void operator=(Bits const&) = delete;
+};
+
+// A utility class for some handy bit patterns.  The names l and h
+// were chosen to match Knuth Volume 4: l is 0x010101... and h is 0x808080...;
+// half_ones is ones in the lower half only.  We assume sizeof(T) is 1 or even.
+template <class T> struct BitPattern {
+  typedef typename std::make_unsigned<T>::type U;
+  static const U half_ones = (static_cast<U>(1) << (sizeof(U) * 4)) - 1;
+  static const U l =
+      (sizeof(U) == 1) ? 1 : (half_ones / 0xff * (half_ones + 2));
+  static const U h = ~(l * 0x7f);
+};
+
+// ------------------------------------------------------------------------
+// Implementation details follow
+// ------------------------------------------------------------------------
+
+#if defined(__GNUC__)
+
+inline int Bits::Log2Floor(uint32 n) {
+  return n == 0 ? -1 : 31 ^ __builtin_clz(n);
+}
+
+inline int Bits::Log2FloorNonZero(uint32 n) {
+  return 31 ^ __builtin_clz(n);
+}
+
+inline int Bits::FindLSBSetNonZero(uint32 n) {
+  return __builtin_ctz(n);
+}
+
+inline int Bits::Log2Floor64(uint64 n) {
+  return n == 0 ? -1 : 63 ^ __builtin_clzll(n);
+}
+
+inline int Bits::Log2FloorNonZero64(uint64 n) {
+  return 63 ^ __builtin_clzll(n);
+}
+
+inline int Bits::FindLSBSetNonZero64(uint64 n) {
+  return __builtin_ctzll(n);
+}
+
+#elif defined(_MSC_VER)
+
+inline int Bits::FindLSBSetNonZero(uint32 n) {
+  return Bits::FindLSBSetNonZero_Portable(n);
+}
+
+inline int Bits::FindLSBSetNonZero64(uint64 n) {
+  return Bits::FindLSBSetNonZero64_Portable(n);
+}
+
+inline int Bits::Log2FloorNonZero(uint32 n) {
+#ifdef _M_IX86
+  _asm {
+    bsr ebx, n
+    mov n, ebx
+  }
+  return n;
+#else
+  return Bits::Log2FloorNonZero_Portable(n);
+#endif
+}
+
+inline int Bits::Log2Floor(uint32 n) {
+#ifdef _M_IX86
+  _asm {
+    xor ebx, ebx
+    mov eax, n
+    and eax, eax
+    jz return_ebx
+    bsr ebx, eax
+return_ebx:
+    mov n, ebx
+  }
+  return n;
+#else
+  return Bits::Log2Floor_Portable(n);
+#endif
+}
+
+inline int Bits::Log2Floor64(uint64 n) {
+  return Bits::Log2Floor64_Portable(n);
+}
+
+inline int Bits::Log2FloorNonZero64(uint64 n) {
+  return Bits::Log2FloorNonZero64_Portable(n);
+}
+
+#else  // !__GNUC__ && !_MSC_VER
+
+inline int Bits::Log2Floor(uint32 n) {
+  return Bits::Log2Floor_Portable(n);
+}
+
+inline int Bits::Log2FloorNonZero(uint32 n) {
+  return Bits::Log2FloorNonZero_Portable(n);
+}
+
+inline int Bits::FindLSBSetNonZero(uint32 n) {
+  return Bits::FindLSBSetNonZero_Portable(n);
+}
+
+inline int Bits::Log2Floor64(uint64 n) {
+  return Bits::Log2Floor64_Portable(n);
+}
+
+inline int Bits::Log2FloorNonZero64(uint64 n) {
+  return Bits::Log2FloorNonZero64_Portable(n);
+}
+
+inline int Bits::FindLSBSetNonZero64(uint64 n) {
+  return Bits::FindLSBSetNonZero64_Portable(n);
+}
+
+#endif
+
+inline int Bits::Log2Floor128(absl::uint128 n) {
+  if (uint64 hi = absl::Uint128High64(n)) return 64 + Log2FloorNonZero64(hi);
+  return Log2Floor64(absl::Uint128Low64(n));
+}
+
+inline int Bits::Log2FloorNonZero128(absl::uint128 n) {
+  if (uint64 hi = absl::Uint128High64(n)) return 64 + Log2FloorNonZero64(hi);
+  return Log2FloorNonZero64(absl::Uint128Low64(n));
+}
+
+inline int Bits::FindLSBSetNonZero128(absl::uint128 n) {
+  if (uint64 lo = absl::Uint128Low64(n)) return Bits::FindLSBSetNonZero64(lo);
+  return 64 + Bits::FindLSBSetNonZero64(absl::Uint128High64(n));
+}
+
+inline int Bits::CountOnesInByte(unsigned char n) {
+  return num_bits[n];
+}
+
+inline uint8 Bits::ReverseBits8(unsigned char n) {
+#if defined(__aarch64__) && defined(__GNUC__)
+  // aarch64 has a reverse bits instruction but there is no gcc builtin.
+  uint32 result;
+  const uint32 n_shifted = static_cast<uint32>(n) << 24;
+  asm("rbit %w0, %w1" : "=r"(result) : "r"(n_shifted));
+  return static_cast<uint8>(result);
+#elif defined (__powerpc64__)
+  uint64 temp = n;
+  // bpermd selects a byte's worth of bits from its second input. Grab one byte
+  // at a time, in reversed order. 0x3f is the lowest order bit of a 64-bit int.
+  // Bits 0x0 through 0x37 will all be zero, and bits 0x38 through 0x3f will
+  // hold the 8 bits from `n`.
+  uint64 result = __builtin_bpermd(0x3f3e3d3c3b3a3938, temp);
+  return static_cast<unsigned char>(result);
+#else
+  n = static_cast<unsigned char>(((n >> 1) & 0x55) | ((n & 0x55) << 1));
+  n = static_cast<unsigned char>(((n >> 2) & 0x33) | ((n & 0x33) << 2));
+  return static_cast<unsigned char>(((n >> 4) & 0x0f)  | ((n & 0x0f) << 4));
+#endif
+}
+
+inline uint32 Bits::ReverseBits32(uint32 n) {
+#if defined(__aarch64__) && defined(__GNUC__)
+  uint32 result;
+  asm("rbit %w0, %w1" : "=r"(result) : "r"(n));
+  return result;
+#elif defined(__powerpc64__)
+  uint64 temp = n;
+  uint64 result_0 = __builtin_bpermd(0x3f3e3d3c3b3a3938, temp) << 24;
+  uint64 result_1 = __builtin_bpermd(0x3736353433323130, temp) << 16;
+  uint64 result_2 = __builtin_bpermd(0x2f2e2d2c2b2a2928, temp) << 8;
+  uint64 result_3 = __builtin_bpermd(0x2726252423222120, temp);
+  return static_cast<uint32>(result_0 | result_1 | result_2 | result_3);
+#else
+  n = ((n >> 1) & 0x55555555) | ((n & 0x55555555) << 1);
+  n = ((n >> 2) & 0x33333333) | ((n & 0x33333333) << 2);
+  n = ((n >> 4) & 0x0F0F0F0F) | ((n & 0x0F0F0F0F) << 4);
+  return bswap_32(n);
+#endif
+}
+
+inline uint64 Bits::ReverseBits64(uint64 n) {
+#if defined(__aarch64__) && defined(__GNUC__)
+  uint64 result;
+  asm("rbit %0, %1" : "=r"(result) : "r"(n));
+  return result;
+#elif defined(__powerpc64__)
+  uint64 result_lo0 = __builtin_bpermd(0x3f3e3d3c3b3a3938, n) << 56;
+  uint64 result_lo1 = __builtin_bpermd(0x3736353433323130, n) << 48;
+  uint64 result_lo2 = __builtin_bpermd(0x2f2e2d2c2b2a2928, n) << 40;
+  uint64 result_lo3 = __builtin_bpermd(0x2726252423222120, n) << 32;
+  uint64 result_hi0 = __builtin_bpermd(0x1f1e1d1c1b1a1918, n) << 24;
+  uint64 result_hi1 = __builtin_bpermd(0x1716151413121110, n) << 16;
+  uint64 result_hi2 = __builtin_bpermd(0x0f0e0d0c0b0a0908, n) << 8;
+  uint64 result_hi3 = __builtin_bpermd(0x0706050403020100, n);
+  return (result_lo0 | result_lo1 | result_lo2 | result_lo3 |
+          result_hi0 | result_hi1 | result_hi2 | result_hi3);
+#elif defined(_LP64)
+  n = ((n >> 1) & 0x5555555555555555ULL) | ((n & 0x5555555555555555ULL) << 1);
+  n = ((n >> 2) & 0x3333333333333333ULL) | ((n & 0x3333333333333333ULL) << 2);
+  n = ((n >> 4) & 0x0F0F0F0F0F0F0F0FULL) | ((n & 0x0F0F0F0F0F0F0F0FULL) << 4);
+  return bswap_64(n);
+#else
+  return ReverseBits32( n >> 32 ) |
+         (static_cast<uint64>(ReverseBits32(n &  0xffffffff)) << 32);
+#endif
+}
+
+inline absl::uint128 Bits::ReverseBits128(absl::uint128 n) {
+  return absl::MakeUint128(ReverseBits64(absl::Uint128Low64(n)),
+                           ReverseBits64(absl::Uint128High64(n)));
+}
+
+inline int Bits::Log2FloorNonZero_Portable(uint32 n) {
+  // Just use the common routine
+  return Log2Floor(n);
+}
+
+// Log2Floor64() is defined in terms of Log2Floor32(), Log2FloorNonZero32()
+inline int Bits::Log2Floor64_Portable(uint64 n) {
+  const uint32 topbits = static_cast<uint32>(n >> 32);
+  if (topbits == 0) {
+    // Top bits are zero, so scan in bottom bits
+    return Log2Floor(static_cast<uint32>(n));
+  } else {
+    return 32 + Log2FloorNonZero(topbits);
+  }
+}
+
+// Log2FloorNonZero64() is defined in terms of Log2FloorNonZero32()
+inline int Bits::Log2FloorNonZero64_Portable(uint64 n) {
+  const uint32 topbits = static_cast<uint32>(n >> 32);
+  if (topbits == 0) {
+    // Top bits are zero, so scan in bottom bits
+    return Log2FloorNonZero(static_cast<uint32>(n));
+  } else {
+    return 32 + Log2FloorNonZero(topbits);
+  }
+}
+
+// FindLSBSetNonZero64() is defined in terms of FindLSBSetNonZero()
+inline int Bits::FindLSBSetNonZero64_Portable(uint64 n) {
+  const uint32 bottombits = static_cast<uint32>(n);
+  if (bottombits == 0) {
+    // Bottom bits are zero, so scan in top bits
+    return 32 + FindLSBSetNonZero(static_cast<uint32>(n >> 32));
+  } else {
+    return FindLSBSetNonZero(bottombits);
+  }
+}
+
+template <class T>
+inline bool Bits::BytesContainByteLessThan(T bytes, uint8 c) {
+  auto l = BitPattern<T>::l;
+  auto h = BitPattern<T>::h;
+  // The c <= 0x80 code is straight out of Knuth Volume 4.
+  // Usually c will be manifestly constant.
+  return c <= 0x80 ?
+      ((h & (bytes - l * c) & ~bytes) != 0) :
+      ((((bytes - l * c) | (bytes ^ h)) & h) != 0);
+}
+
+template <class T> inline bool Bits::BytesContainByte(T bytes, uint8 c) {
+  // Usually c will be manifestly constant.
+  return Bits::BytesContainByteLessThan<T>(bytes ^ (c * BitPattern<T>::l), 1);
+}
+
+template <class T>
+inline bool Bits::BytesAllInRange(T bytes, uint8 lo, uint8 hi) {
+  auto l = BitPattern<T>::l;
+  auto h = BitPattern<T>::h;
+  // In the common case, lo and hi are manifest constants.
+  if (lo > hi) {
+    return false;
+  }
+  if (hi - lo < 128) {
+    auto x = bytes - l * lo;
+    auto y = bytes + l * (127 - hi);
+    return ((x | y) & h) == 0;
+  }
+  return !Bits::BytesContainByteLessThan(bytes + (255 - hi) * l,
+                                         lo + (255 - hi));
+}
+
+// Specializations for Bits::UnsignedTypeBySize.  For unsupported type
+// sizes, a compile-time error will be generated.
+template<>
+struct Bits::UnsignedTypeBySize<1> {
+  typedef uint8 Type;
+};
+
+template<>
+struct Bits::UnsignedTypeBySize<2> {
+  typedef uint16 Type;
+};
+
+template<>
+struct Bits::UnsignedTypeBySize<4> {
+  typedef uint32 Type;
+};
+
+template<>
+struct Bits::UnsignedTypeBySize<8> {
+  typedef uint64 Type;
+};
+
+template<>
+struct Bits::UnsignedTypeBySize<16> {
+  typedef absl::uint128 Type;
+};
+
+#ifdef __GNUC__
+inline int Bits::CountLeadingZerosWithBuiltin(unsigned n) {
+  if (n == 0) {
+    return sizeof(n) * 8;  // __builtin_clz(0) is undefined.
+  }
+  return __builtin_clz(n);
+}
+// NOLINTNEXTLINE(runtime/int)
+inline int Bits::CountLeadingZerosWithBuiltin(unsigned long n) {
+  if (n == 0) {
+    return sizeof(n) * 8;  // __builtin_clzl(0) is undefined.
+  }
+  return __builtin_clzl(n);
+}
+// NOLINTNEXTLINE(runtime/int)
+inline int Bits::CountLeadingZerosWithBuiltin(unsigned long long n) {
+  if (n == 0) {
+    return sizeof(n) * 8;  // __builtin_clzll(0) is undefined.
+  }
+  return __builtin_clzll(n);
+}
+
+inline int Bits::PopcountWithBuiltin(unsigned n) {
+  return __builtin_popcount(n);
+}
+// NOLINTNEXTLINE(runtime/int)
+inline int Bits::PopcountWithBuiltin(unsigned long n) {
+  return __builtin_popcountl(n);
+}
+// NOLINTNEXTLINE(runtime/int)
+inline int Bits::PopcountWithBuiltin(unsigned long long n) {
+  return __builtin_popcountll(n);
+}
+
+#if defined(__BMI__) && (defined(__i386__) || defined(__x86_64__))
+inline uint32 Bits::GetBitsImpl(const uint32 src,
+                                const int offset,
+                                const int nbits) {
+  return _bextr_u32(src, offset, nbits);
+}
+#endif
+
+#if defined(__BMI__) && defined(__x86_64__)
+inline uint64 Bits::GetBitsImpl(const uint64 src,
+                                const int offset,
+                                const int nbits) {
+  return _bextr_u64(src, offset, nbits);
+}
+#endif
+
+#if defined(__BMI2__) && (defined(__i386__) || defined(__x86_64__))
+inline uint32 Bits::GetLowBitsImpl(const uint32 src, const int nbits) {
+  return _bzhi_u32(src, nbits);
+}
+#endif
+
+#if defined(__BMI2__) && defined(__x86_64__)
+inline uint64 Bits::GetLowBitsImpl(const uint64 src, const int nbits) {
+  return _bzhi_u64(src, nbits);
+}
+#endif
+
+#endif  // __GNUC__
+
+template<typename UnsignedT>
+inline UnsignedT Bits::GetBitsImpl(const UnsignedT src,
+                                   const int offset,
+                                   const int nbits) {
+  const UnsignedT result = (src >> offset) & NBitsFromLSB<UnsignedT>(nbits);
+  return result;
+}
+
+template<typename UnsignedT>
+inline UnsignedT Bits::GetLowBitsImpl(const UnsignedT src, const int nbits) {
+  return GetBitsImpl(src, 0, nbits);
+}
+
+#endif  // S2_UTIL_BITS_BITS_H_
diff --git a/src/s2/util/coding/coder.cc b/src/s2/util/coding/coder.cc
new file mode 100644 (file)
index 0000000..ef3e67b
--- /dev/null
@@ -0,0 +1,83 @@
+// Copyright 2000 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+//
+//
+
+#include "s2/util/coding/coder.h"
+
+#include <algorithm>
+#include <cassert>
+
+#include "s2/base/integral_types.h"
+#include "s2/base/logging.h"
+
+// An initialization value used when we are allowed to
+unsigned char Encoder::kEmptyBuffer = 0;
+
+Encoder::Encoder()
+  : underlying_buffer_(&kEmptyBuffer) {
+}
+
+Encoder::~Encoder() {
+  S2_CHECK_LE(buf_, limit_);  // Catch the buffer overflow.
+  if (underlying_buffer_ != &kEmptyBuffer) {
+    std::allocator<unsigned char>().deallocate(
+        underlying_buffer_, limit_ - orig_);
+  }
+}
+
+int Encoder::varint32_length(uint32 v) {
+  return Varint::Length32(v);
+}
+
+int Encoder::varint64_length(uint64 v) {
+  return Varint::Length64(v);
+}
+
+void Encoder::EnsureSlowPath(size_t N) {
+  S2_CHECK(ensure_allowed());
+  assert(avail() < N);
+  assert(length() == 0 || orig_ == underlying_buffer_);
+
+  // Double buffer size, but make sure we always have at least N extra bytes
+  const size_t current_len = length();
+  const size_t new_capacity = std::max(current_len + N, 2 * current_len);
+
+  unsigned char* new_buffer = std::allocator<unsigned char>().allocate(
+      new_capacity);
+  memcpy(new_buffer, underlying_buffer_, current_len);
+  if (underlying_buffer_ != &kEmptyBuffer) {
+    std::allocator<unsigned char>().deallocate(
+        underlying_buffer_, limit_ - orig_);
+  }
+  underlying_buffer_ = new_buffer;
+
+  orig_ = new_buffer;
+  limit_ = new_buffer + new_capacity;
+  buf_ = orig_ + current_len;
+  S2_CHECK(avail() >= N);
+}
+
+void Encoder::RemoveLast(size_t N) {
+  S2_CHECK(length() >= N);
+  buf_ -= N;
+}
+
+void Encoder::Resize(size_t N) {
+  S2_CHECK(length() >= N);
+  buf_ = orig_ + N;
+  assert(length() == N);
+}
diff --git a/src/s2/util/coding/coder.h b/src/s2/util/coding/coder.h
new file mode 100644 (file)
index 0000000..b8d77a9
--- /dev/null
@@ -0,0 +1,562 @@
+// Copyright 2000 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+//
+//
+// This holds the encoding/decoding routines that used to live in netutil
+
+#ifndef S2_UTIL_CODING_CODER_H_
+#define S2_UTIL_CODING_CODER_H_
+
+#include <cstring>
+
+// Avoid adding expensive includes here.
+#include "s2/base/casts.h"
+#include "s2/base/integral_types.h"
+#include "s2/base/logging.h"
+#include "s2/base/port.h"
+#include "absl/base/macros.h"
+#include "absl/meta/type_traits.h"
+#include "s2/util/coding/varint.h"
+#include "s2/util/endian/endian.h"
+
+/* Class for encoding data into a memory buffer */
+class Decoder;
+class Encoder {
+ public:
+  // Creates an empty Encoder with no room that is enlarged
+  // (if necessary) when "Encoder::Ensure(N)" is called.
+  Encoder();
+  ~Encoder();
+
+  // Initialize encoder to encode into "buf"
+  Encoder(void* buf, size_t maxn);
+  void reset(void* buf, size_t maxn);
+  void clear();
+
+  // Encoding routines.  Note that these do not check bounds
+  void put8(unsigned char v);
+  void put16(uint16 v);
+  void put32(uint32 v);
+  void put64(uint64 v);
+  void putn(const void* mem, size_t n);
+
+  // Put no more than n bytes, stopping when c is put.
+  void putcn(const void* mem, int c, size_t n);
+
+  void puts(const void* mem);                // put a c-string including \0
+  void puts_without_null(const char* mem);   // put a c-string without \0
+  void putfloat(float f);
+  void putdouble(double d);
+
+  // Support for variable length encoding with 7 bits per byte
+  // (these are just simple wrappers around the Varint module)
+  static const int kVarintMax32 = Varint::kMax32;
+  static const int kVarintMax64 = Varint::kMax64;
+
+  void put_varint32(uint32 v);
+  void put_varint32_inline(uint32 v);
+  void put_varint64(uint64 v);
+  static int varint32_length(uint32 v);  // Length of var encoding of "v"
+  static int varint64_length(uint64 v);  // Length of var encoding of "v"
+
+  // The fast implementation of the code below with boundary checks.
+  //   uint64 val;
+  //   if (!dec->get_varint64(&val))
+  //     return false;
+  //   enc->put_varint64(val);
+  //   return true;
+  // We assume that the encoder and decoder point to different buffers.
+  // If the decoder has invalid value, i.e., dec->get_varint64(&val)
+  // returns false, the decoder is not updated, which is different from
+  // dec->get_varint64(&val).
+  bool put_varint64_from_decoder(Decoder* dec);
+
+  // Return number of bytes encoded so far
+  size_t length() const;
+
+  // Return number of bytes of space remaining in buffer
+  size_t avail() const;
+
+  // REQUIRES: Encoder was created with the 0-argument constructor interface.
+  //
+  // This interface ensures that at least "N" more bytes are available
+  // in the underlying buffer by resizing the buffer (if necessary).
+  //
+  // Note that no bounds checking is done on any of the put routines,
+  // so it is the client's responsibility to call Ensure() at
+  // appropriate intervals to ensure that enough space is available
+  // for the data being added.
+  void Ensure(size_t N);
+
+  // Returns true if Ensure is allowed to be called on "this"
+  bool ensure_allowed() const { return underlying_buffer_ != nullptr; }
+
+  // Return ptr to start of encoded data.  This pointer remains valid
+  // until reset or Ensure is called.
+  const char* base() const { return reinterpret_cast<const char*>(orig_); }
+
+  // Advances the write pointer by "N" bytes.
+  void skip(size_t N) { buf_ += N; }
+
+  // REQUIRES: length() >= N
+  // Removes the last N bytes out of the encoded buffer
+  void RemoveLast(size_t N);
+
+  // REQUIRES: length() >= N
+  // Removes the last length()-N bytes to make the encoded buffer have length N
+  void Resize(size_t N);
+
+ private:
+  void EnsureSlowPath(size_t N);
+
+  // Puts varint64 from decoder for varint64 sizes from 3 ~ 10. This is less
+  // common cases compared to 1 - 2 byte varint64. Returns false if either the
+  // encoder or the decoder fails the boundary check, or varint64 size exceeds
+  // the maximum size (kVarintMax64).
+  bool PutVarint64FromDecoderLessCommonSizes(Decoder* dec);
+
+  // buf_ points into the orig_ buffer, just past the last encoded byte.
+  unsigned char* buf_ = nullptr;
+
+  // limits_ points just past the last allocated byte in the orig_ buffer.
+  unsigned char* limit_ = nullptr;
+
+
+  // If this Encoder owns its buffer, underlying_buffer_ is non-nullptr
+  // and the Encoder is allowed to resize it when Ensure() is called.
+  unsigned char* underlying_buffer_ = nullptr;
+
+  // orig_ points to the start of the encoding buffer,
+  // whether or not the Encoder owns it.
+  unsigned char* orig_ = nullptr;
+
+  static unsigned char kEmptyBuffer;
+
+#ifndef SWIG
+  Encoder(Encoder const&) = delete;
+  void operator=(Encoder const&) = delete;
+#endif  // SWIG
+};
+
+/* Class for decoding data from a memory buffer */
+class Decoder {
+ public:
+  // Empty constructor to create uninitialized decoder
+  inline Decoder() { }
+
+  // NOTE: for efficiency reasons, this is not virtual.  so don't add
+  // any members that really need to be destructed, and be careful about
+  // inheritance.
+  // The defaulted destructor is not explicitly written to avoid confusing SWIG.
+  // ~Decoder() = default;
+
+  // Initialize decoder to decode from "buf"
+  Decoder(const void* buf, size_t maxn);
+  void reset(const void* buf, size_t maxn);
+
+  // Decoding routines.  Note that these do not check bounds
+  unsigned char get8();
+  uint16 get16();
+  uint32 get32();
+  uint64 get64();
+  float  getfloat();
+  double getdouble();
+  void   getn(void* mem, size_t n);
+  void   getcn(void* mem, int c, size_t n);    // get no more than n bytes,
+                                               // stopping after c is got
+  void   gets(void* mem, size_t n);            // get a c-string no more than
+                                               // n bytes. always appends '\0'
+  void   skip(ptrdiff_t n);
+  unsigned char const* ptr() const;  // Return ptr to current position in buffer
+
+  // "get_varint" actually checks bounds
+  bool get_varint32(uint32* v);
+  bool get_varint64(uint64* v);
+
+  size_t pos() const;
+  // Return number of bytes decoded so far
+
+  size_t avail() const;
+  // Return number of available bytes to read
+
+ private:
+  friend class Encoder;
+  friend class IndexBlockDecoder;
+  const unsigned char* orig_;
+  const unsigned char* buf_;
+  const unsigned char* limit_;
+};
+
+// TODO(user): Remove when LLVM detects and optimizes this case.
+class DecoderExtensions {
+ private:
+  friend class Untranspose;  // In net/proto/transpose.cc.
+  friend void TestFillArray();
+  // Fills an array of num_decoders decoders with Decoder(nullptr, 0) instances.
+  // This is much more efficient than using the stl.
+  static void FillArray(Decoder* array, int num_decoders);
+};
+
+/***** Implementation details.  Clients should ignore them. *****/
+
+inline Encoder::Encoder(void* b, size_t maxn) :
+    buf_(reinterpret_cast<unsigned char*>(b)),
+    limit_(reinterpret_cast<unsigned char*>(b) + maxn),
+    orig_(reinterpret_cast<unsigned char*>(b)) { }
+
+inline void Encoder::reset(void* b, size_t maxn) {
+  orig_ = buf_ = reinterpret_cast<unsigned char*>(b);
+  limit_ = orig_ + maxn;
+  // Can't use the underlying buffer anymore
+  if (underlying_buffer_ != &kEmptyBuffer) {
+    delete[] underlying_buffer_;
+  }
+  underlying_buffer_ = nullptr;
+}
+
+inline void Encoder::clear() {
+  buf_ = orig_;
+}
+
+inline void Encoder::Ensure(size_t N) {
+  S2_DCHECK(ensure_allowed());
+  if (avail() < N) {
+    EnsureSlowPath(N);
+  }
+}
+
+inline size_t Encoder::length() const {
+  S2_DCHECK_GE(buf_, orig_);
+  S2_CHECK_LE(buf_, limit_);  // Catch the buffer overflow.
+  return buf_ - orig_;
+}
+
+inline size_t Encoder::avail() const {
+  S2_DCHECK_GE(limit_, buf_);
+  return limit_ - buf_;
+}
+
+inline void Encoder::putn(const void* src, size_t n) {
+  memcpy(buf_, src, n);
+  buf_ += n;
+}
+
+inline void Encoder::putcn(const void* src, int c, size_t n) {
+  unsigned char *old = buf_;
+  buf_ = static_cast<unsigned char *>(memccpy(buf_, src, c, n));
+  if (buf_ == nullptr)
+    buf_ = old + n;
+}
+
+inline void Encoder::puts(const void* src) {
+  putcn(src, '\0', avail());
+}
+
+inline void Encoder::puts_without_null(const char* mem) {
+  while (*mem != '\0' && buf_ < limit_) {
+    *buf_++ = *mem++;
+  }
+}
+
+inline void Encoder::put_varint32(uint32 v) {
+  buf_ = reinterpret_cast<unsigned char*>
+         (Varint::Encode32(reinterpret_cast<char*>(buf_), v));
+}
+
+inline void Encoder::put_varint32_inline(uint32 v) {
+  buf_ = reinterpret_cast<unsigned char*>
+         (Varint::Encode32Inline(reinterpret_cast<char*>(buf_), v));
+}
+
+inline void Encoder::put_varint64(uint64 v) {
+  buf_ = reinterpret_cast<unsigned char*>
+         (Varint::Encode64(reinterpret_cast<char*>(buf_), v));
+}
+
+// Copies N bytes from *src to *dst then advances both pointers by N bytes.
+// Template parameter N specifies the number of bytes to copy. Passing
+// constant size results in optimized code from memcpy for the size.
+template <size_t N>
+void CopyAndAdvance(const uint8** src, uint8** dst) {
+  memcpy(*dst, *src, N);
+  *dst += N;
+  *src += N;
+}
+
+// Tries a fast path if both the decoder and the encoder have enough room for
+// max varint64 (10 bytes). With enough room, we don't need boundary checks at
+// every iterations. Also, memcpy with known size is faster than copying a byte
+// at a time (e.g. one movq vs. eight movb's).
+//
+// If either the decoder or the encoder doesn't have enough room, it falls back
+// to previous example where copy and boundary check happen at every byte.
+inline bool Encoder::PutVarint64FromDecoderLessCommonSizes(Decoder* dec) {
+  const unsigned char* dec_ptr = dec->buf_;
+  const unsigned char* dec_limit = dec->limit_;
+
+  // Check once if both the encoder and the decoder have enough room for
+  // maximum varint64 (kVarintMax64) instead of checking at every bytes.
+  if (ABSL_PREDICT_TRUE(dec_ptr <= dec_limit - kVarintMax64 &&
+                        buf_ <= limit_ - kVarintMax64)) {
+    if (dec_ptr[2] < 128) {
+      CopyAndAdvance<3>(&dec->buf_, &buf_);
+    } else if (dec_ptr[3] < 128) {
+      CopyAndAdvance<4>(&dec->buf_, &buf_);
+    } else if (dec_ptr[4] < 128) {
+      CopyAndAdvance<5>(&dec->buf_, &buf_);
+    } else if (dec_ptr[5] < 128) {
+      CopyAndAdvance<6>(&dec->buf_, &buf_);
+    } else if (dec_ptr[6] < 128) {
+      CopyAndAdvance<7>(&dec->buf_, &buf_);
+    } else if (dec_ptr[7] < 128) {
+      CopyAndAdvance<8>(&dec->buf_, &buf_);
+    } else if (dec_ptr[8] < 128) {
+      CopyAndAdvance<9>(&dec->buf_, &buf_);
+    } else if (dec_ptr[9] < 2) {
+      // 10th byte stores at most 1 bit for varint64.
+      CopyAndAdvance<10>(&dec->buf_, &buf_);
+    } else {
+      return false;
+    }
+    return true;
+  }
+
+  unsigned char c;
+  unsigned char* enc_ptr = buf_;
+
+  // The loop executes at most (kVarintMax64 - 1) iterations because either the
+  // decoder or the encoder has less availability than kVarintMax64. We must be
+  // careful about the cost of moving any computation out of the loop.
+  // Xref cl/133546957 for more details of various implementations we explored.
+  do {
+    if (dec_ptr >= dec_limit) return false;
+    if (enc_ptr >= limit_) return false;
+    c = *dec_ptr;
+    *enc_ptr = c;
+    ++dec_ptr;
+    ++enc_ptr;
+  } while (c >= 128);
+
+  dec->buf_ = dec_ptr;
+  buf_ = enc_ptr;
+  return true;
+}
+
+// The fast implementation of the code below with boundary checks.
+//   uint64 val;
+//   if (!dec->get_varint64(&val))
+//     return false;
+//   enc->put_varint64(val);
+//   return true;
+// BM_getvarfrom* in coder_unittest.cc are the benchmarks that measure the
+// performance of different implementations.
+//
+// Handles varint64 with one to two bytes separately as a common case.
+// PutVarint64FromDecoderLessCommonSizes handles the remaining sizes. To avoid
+// over-inlining, PutVarint64FromDecoderLessCommonSizes is defined in coder.cc.
+// As Untranspose::DecodeMessage is the only caller, compiler should be able to
+// inline all if necessary.
+ABSL_ATTRIBUTE_ALWAYS_INLINE inline bool Encoder::put_varint64_from_decoder(
+    Decoder* dec) {
+  unsigned char* enc_ptr = buf_;
+  const unsigned char* dec_ptr = dec->buf_;
+
+  // Common cases to handle varint64 with one to two bytes.
+  if (ABSL_PREDICT_TRUE(dec_ptr < dec->limit_ && dec_ptr[0] < 128)) {
+    if (ABSL_PREDICT_FALSE(enc_ptr >= limit_)) {
+      return false;
+    }
+    *enc_ptr = *dec_ptr;
+    dec->buf_++;
+    buf_++;
+    return true;
+  }
+
+  if (dec_ptr < dec->limit_ - 1 && dec_ptr[1] < 128) {
+    if (ABSL_PREDICT_FALSE(enc_ptr >= limit_ - 1)) {
+      return false;
+    }
+    UNALIGNED_STORE16(enc_ptr, UNALIGNED_LOAD16(dec_ptr));
+    dec->buf_ += 2;
+    buf_ += 2;
+    return true;
+  }
+
+  // For less common sizes in [3, kVarintMax64].
+  return PutVarint64FromDecoderLessCommonSizes(dec);
+}
+
+inline Decoder::Decoder(const void* b, size_t maxn) {
+  reset(b, maxn);
+}
+
+inline void Decoder::reset(const void* b, size_t maxn) {
+  orig_ = buf_ = reinterpret_cast<const unsigned char*>(b);
+  limit_ = orig_ + maxn;
+}
+
+inline size_t Decoder::pos() const {
+  S2_DCHECK_GE(buf_, orig_);
+  return buf_ - orig_;
+}
+
+inline size_t Decoder::avail() const {
+  S2_DCHECK_GE(limit_, buf_);
+  return limit_ - buf_;
+}
+
+inline void Decoder::getn(void* dst, size_t n) {
+  memcpy(dst, buf_, n);
+  buf_ += n;
+}
+
+inline void Decoder::getcn(void* dst, int c, size_t n) {
+  void *ptr;
+  ptr = memccpy(dst, buf_, c, n);
+  if (ptr == nullptr)
+    buf_ = buf_ + n;
+  else
+    buf_ = buf_ + (reinterpret_cast<unsigned char *>(ptr) -
+                   reinterpret_cast<unsigned char *>(dst));
+}
+
+inline void Decoder::gets(void* dst, size_t n) {
+  size_t len = n - 1;
+  S2_DCHECK_GE(limit_, buf_);
+  if (n > static_cast<size_t>(1 + limit_ - buf_)) {
+    len = limit_ - buf_;
+  }
+  (reinterpret_cast<char *>(dst))[len] = '\0';
+  getcn(dst, '\0', len);
+}
+
+inline void Decoder::skip(ptrdiff_t n) {
+  buf_ += n;
+}
+
+inline unsigned char const* Decoder::ptr() const {
+  return buf_;
+}
+
+inline void DecoderExtensions::FillArray(Decoder* array, int num_decoders) {
+  // This is an optimization based on the fact that Decoder(nullptr, 0) sets all
+  // structure bytes to 0. This is valid because Decoder is TriviallyCopyable
+  // (https://en.cppreference.com/w/cpp/named_req/TriviallyCopyable).
+  static_assert(absl::is_trivially_copy_constructible<Decoder>::value,
+                "Decoder must be trivially copy-constructible");
+  static_assert(absl::is_trivially_copy_assignable<Decoder>::value,
+                "Decoder must be trivially copy-assignable");
+  static_assert(absl::is_trivially_destructible<Decoder>::value,
+                "Decoder must be trivially destructible");
+
+  // on R 4.0 on Windows, this line gives install warning
+  // warning: 'void* memset(void*, int, size_t)' clearing an object of non-trivial type 'class Decoder';
+  // use assignment or value-initialization instead [-Wclass-memaccess]
+  // std::memset(array, 0, num_decoders * sizeof(Decoder));
+  // using non-optimized version as suggested above (this is not called by R code)
+  for (int i = 0; i < num_decoders; i++) {
+    Decoder* decoder = array + i;
+    decoder->reset(nullptr, 0);
+  }
+}
+
+inline void Encoder::put8(unsigned char v) {
+  S2_DCHECK_GE(avail(), sizeof(v));
+  *buf_ = v;
+  buf_ += sizeof(v);
+}
+
+inline void Encoder::put16(uint16 v) {
+  S2_DCHECK_GE(avail(), sizeof(v));
+  LittleEndian::Store16(buf_, v);
+  buf_ += sizeof(v);
+}
+
+inline void Encoder::put32(uint32 v) {
+  S2_DCHECK_GE(avail(), sizeof(v));
+  LittleEndian::Store32(buf_, v);
+  buf_ += sizeof(v);
+}
+
+inline void Encoder::put64(uint64 v) {
+  S2_DCHECK_GE(avail(), sizeof(v));
+  LittleEndian::Store64(buf_, v);
+  buf_ += sizeof(v);
+}
+
+inline void Encoder::putfloat(float f) {
+  put32(absl::bit_cast<uint32>(f));
+}
+
+inline void Encoder::putdouble(double d) {
+  put64(absl::bit_cast<uint64>(d));
+}
+
+inline unsigned char Decoder::get8() {
+  const unsigned char v = *buf_;
+  buf_ += sizeof(v);
+  return v;
+}
+
+inline uint16 Decoder::get16() {
+  const uint16 v = LittleEndian::Load16(buf_);
+  buf_ += sizeof(v);
+  return v;
+}
+
+inline uint32 Decoder::get32() {
+  const uint32 v = LittleEndian::Load32(buf_);
+  buf_ += sizeof(v);
+  return v;
+}
+
+inline uint64 Decoder::get64() {
+  const uint64 v = LittleEndian::Load64(buf_);
+  buf_ += sizeof(v);
+  return v;
+}
+
+inline float Decoder::getfloat() {
+  return absl::bit_cast<float>(get32());
+}
+
+inline double Decoder::getdouble() {
+  return absl::bit_cast<double>(get64());
+}
+
+inline bool Decoder::get_varint32(uint32* v) {
+  const char* const r =
+      Varint::Parse32WithLimit(reinterpret_cast<const char*>(buf_),
+                               reinterpret_cast<const char*>(limit_), v);
+  if (r == nullptr) {
+    return false;
+  }
+  buf_ = reinterpret_cast<const unsigned char*>(r);
+  return true;
+}
+
+inline bool Decoder::get_varint64(uint64* v) {
+  const char* const r =
+      Varint::Parse64WithLimit(reinterpret_cast<const char*>(buf_),
+                               reinterpret_cast<const char*>(limit_), v);
+  if (r == nullptr) {
+    return false;
+  }
+  buf_ = reinterpret_cast<const unsigned char*>(r);
+  return true;
+}
+
+#endif  // S2_UTIL_CODING_CODER_H_
diff --git a/src/s2/util/coding/nth-derivative.h b/src/s2/util/coding/nth-derivative.h
new file mode 100644 (file)
index 0000000..37b52bf
--- /dev/null
@@ -0,0 +1,134 @@
+// Copyright 2005 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+//
+//   far-far-superior implementation courtesy of amc@google.com (Adam Costello)
+//
+// Nth Derivative Coding
+//   (In signal processing disciplines, this is known as N-th Delta Coding.)
+//
+// Good for varint coding integer sequences with polynomial trends.
+//
+// Instead of coding a sequence of values directly, code its nth-order discrete
+// derivative.  Overflow in integer addition and subtraction makes this a
+// lossless transform.
+//
+//                                       constant     linear      quadratic
+//                                        trend       trend         trend
+//                                      /        \  /        \  /           \_
+// input                               |0  0  0  0  1  2  3  4  9  16  25  36
+// 0th derivative(identity)            |0  0  0  0  1  2  3  4  9  16  25  36
+// 1st derivative(delta coding)        |   0  0  0  1  1  1  1  5   7   9  11
+// 2nd derivative(linear prediction)   |      0  0  1  0  0  0  4   2   2   2
+//                                      -------------------------------------
+//                                      0  1  2  3  4  5  6  7  8   9  10  11
+//                                                  n in sequence
+//
+// Higher-order codings can break even or be detrimental on other sequences.
+//
+//                                           random            oscillating
+//                                      /               \  /                  \_
+// input                               |5  9  6  1   8  8  2 -2   4  -4   6  -6
+// 0th derivative(identity)            |5  9  6  1   8  8  2 -2   4  -4   6  -6
+// 1st derivative(delta coding)        |   4 -3 -5   7  0 -6 -4   6  -8  10 -12
+// 2nd derivative(linear prediction)   |     -7 -2  12 -7 -6  2  10 -14  18 -22
+//                                      ---------------------------------------
+//                                      0  1  2  3  4   5  6  7   8   9  10  11
+//                                                  n in sequence
+//
+// Note that the nth derivative isn't available until sequence item n.  Earlier
+// values are coded at lower order.  For the above table, read 5 4 -7 -2 12 ...
+//
+// A caveat on class usage.  Encode() and Decode() share state.  Using both
+// without a Reset() in-between probably doesn't make sense.
+
+#ifndef S2_UTIL_CODING_NTH_DERIVATIVE_H_
+#define S2_UTIL_CODING_NTH_DERIVATIVE_H_
+
+#include "s2/base/integral_types.h"
+#include "s2/base/logging.h"
+
+class NthDerivativeCoder {
+ public:
+  // range of supported Ns: [ N_MIN, N_MAX ]
+  enum {
+    N_MIN = 0,
+    N_MAX = 10,
+  };
+
+  // Initialize a new NthDerivativeCoder of the given N.
+  explicit NthDerivativeCoder(int n);
+
+  // Encode the next value in the sequence.  Don't mix with Decode() calls.
+  int32 Encode(int32 k);
+
+  // Decode the next value in the sequence.  Don't mix with Encode() calls.
+  int32 Decode(int32 k);
+
+  // Reset state.
+  void Reset();
+
+  // accessors
+  int n() const { return n_; }
+
+ private:
+  int n_;  // derivative order of the coder (the N in NthDerivative)
+  int m_;  // the derivative order in which to code the next value(ramps to n_)
+  int32 memory_[N_MAX];  // value memory. [0] is oldest
+};
+
+// Implementation below.  Callers Ignore.
+//
+// Inlining the implementation roughly doubled the speed.  All other
+// optimization tricks failed miserably.
+
+#if ~0 != -1
+#error Sorry, this code needs twos complement integers.
+#endif
+
+inline NthDerivativeCoder::NthDerivativeCoder(int n) : n_(n) {
+  if (n < N_MIN || n > N_MAX) {
+    S2_LOG(ERROR) << "Unsupported N: " << n << ".  Using 0 instead.";
+    n_ = 0;
+  }
+  Reset();
+}
+
+inline int32 NthDerivativeCoder::Encode(int32 k) {
+  for (int i = 0; i < m_; ++i) {
+    uint32 delta = static_cast<uint32>(k) - memory_[i];
+    memory_[i] = k;
+    k = delta;
+  }
+  if (m_ < n_)
+    memory_[m_++] = k;
+  return k;
+}
+
+inline int32 NthDerivativeCoder::Decode(int32 k) {
+  if (m_ < n_)
+    m_++;
+  for (int i = m_ - 1; i >= 0; --i)
+    k = memory_[i] = memory_[i] + static_cast<uint32>(k);
+  return k;
+}
+
+inline void NthDerivativeCoder::Reset() {
+  for (int i = 0; i < n_; ++i)
+    memory_[i] = 0;
+  m_ = 0;
+}
+
+#endif  // S2_UTIL_CODING_NTH_DERIVATIVE_H_
diff --git a/src/s2/util/coding/transforms.h b/src/s2/util/coding/transforms.h
new file mode 100644 (file)
index 0000000..97ed2c1
--- /dev/null
@@ -0,0 +1,62 @@
+// Copyright 2005 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+//
+//
+// Data transforms that can help code more efficiently.
+
+#ifndef S2_UTIL_CODING_TRANSFORMS_H_
+#define S2_UTIL_CODING_TRANSFORMS_H_
+
+#include "s2/base/integral_types.h"
+
+// ZigZag Transform
+//
+// Good for varint coding small signed integers centered around 0.
+//
+//       int32 ->     uint32
+// -------------------------
+//           0 ->          0
+//          -1 ->          1
+//           1 ->          2
+//          -2 ->          3
+//         ... ->        ...
+//  2147483647 -> 4294967294
+// -2147483648 -> 4294967295
+//
+//        >> encode >>
+//        << decode <<
+
+static inline uint32 ZigZagEncode(int32 n) {
+  // We need the cast to avoid an arithmetic shift.
+  uint32 sign = (static_cast<uint32>(n)) >> 31;
+  return (static_cast<uint32>(n) << 1) ^ (0u - sign);
+}
+
+static inline int32 ZigZagDecode(uint32 n) {
+  return (n >> 1) ^ (0u - (n & 1));
+}
+
+static inline uint64 ZigZagEncode64(int64 n) {
+  // We need the cast to avoid an arithmetic shift.
+  uint64 sign = (static_cast<uint64>(n)) >> 63;
+  return (static_cast<uint64>(n) << 1) ^ (0u - sign);
+}
+
+static inline int64 ZigZagDecode64(uint64 n) {
+  return (n >> 1) ^ (0u - (n & 1));
+}
+
+#endif  // S2_UTIL_CODING_TRANSFORMS_H_
diff --git a/src/s2/util/coding/varint.cc b/src/s2/util/coding/varint.cc
new file mode 100644 (file)
index 0000000..7e6d96b
--- /dev/null
@@ -0,0 +1,289 @@
+// Copyright 2001 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+
+#include "s2/util/coding/varint.h"
+
+#include <string>
+
+#include "s2/base/integral_types.h"
+
+#ifndef _MSC_VER
+const int Varint::kMax32;
+const int Varint::kMax64;
+const int Varint::kSlopBytes;
+#endif
+
+char* Varint::Encode32(char* sptr, uint32 v) {
+  return Encode32Inline(sptr, v);
+}
+
+char* Varint::Encode64(char* sptr, uint64 v) {
+  if (v < (1u << 28)) {
+    return Varint::Encode32(sptr, v);
+  } else {
+    // Operate on characters as unsigneds
+    unsigned char* ptr = reinterpret_cast<unsigned char*>(sptr);
+    // Rather than computing four subresults and or'ing each with 0x80,
+    // we can do two ors now.  (Doing one now wouldn't work.)
+    const uint32 x32 = v | (1 << 7) | (1 << 21);
+    const uint32 y32 = v | (1 << 14) | (1 << 28);
+    *(ptr++) = x32;
+    *(ptr++) = y32 >> 7;
+    *(ptr++) = x32 >> 14;
+    *(ptr++) = y32 >> 21;
+    if (v < (1ull << 35)) {
+      *(ptr++) = v >> 28;
+      return reinterpret_cast<char*>(ptr);
+    } else {
+      *(ptr++) = (v >> 28) | (1 << 7);
+      return Varint::Encode32(reinterpret_cast<char*>(ptr), v >> 35);
+    }
+  }
+}
+
+const char* Varint::Parse32Fallback(const char* ptr, uint32* OUTPUT) {
+  return Parse32FallbackInline(ptr, OUTPUT);
+}
+
+const char* Varint::Parse64Fallback(const char* p, uint64* OUTPUT) {
+  const unsigned char* ptr = reinterpret_cast<const unsigned char*>(p);
+  assert(*ptr >= 128);
+#if defined(__x86_64__)
+  // This approach saves one redundant operation on the last byte (masking a
+  // byte that doesn't need it). This is conditional on x86 because:
+  // - PowerPC has specialized bit instructions that make masking and
+  //   shifting very efficient
+  // - x86 seems to be one of the few architectures that has a single
+  //   instruction to add 3 values.
+  //
+  // e.g.
+  // Input: 0xff, 0x40
+  // Mask & Or calculates: (0xff & 0x7f) | ((0x40 & 0x7f) << 7) = 0x207f
+  // Sub1 & Add calculates: 0xff         + ((0x40    - 1) << 7) = 0x207f
+  //
+  // The subtract one removes the bit set by the previous byte used to
+  // indicate that more bytes are present. It also has the potential to
+  // allow instructions like LEA to combine 2 adds into one instruction.
+  //
+  // E.g. on an x86 architecture, %rcx = %rax + (%rbx - 1) << 7 could be
+  // emitted as:
+  //   shlq $7, %rbx
+  //   leaq -0x80(%rax, %rbx), %rcx
+  //
+  // Fast path: need to accumulate data in upto three result fragments
+  //    res1    bits 0..27
+  //    res2    bits 28..55
+  //    res3    bits 56..63
+
+  uint64 byte, res1, res2 = 0, res3 = 0;
+  byte = *(ptr++); res1 = byte;
+  byte = *(ptr++); res1 += (byte - 1) <<  7; if (byte < 128) goto done1;
+  byte = *(ptr++); res1 += (byte - 1) << 14; if (byte < 128) goto done1;
+  byte = *(ptr++); res1 += (byte - 1) << 21; if (byte < 128) goto done1;
+
+  byte = *(ptr++); res2 = byte;              if (byte < 128) goto done2;
+  byte = *(ptr++); res2 += (byte - 1) <<  7; if (byte < 128) goto done2;
+  byte = *(ptr++); res2 += (byte - 1) << 14; if (byte < 128) goto done2;
+  byte = *(ptr++); res2 += (byte - 1) << 21; if (byte < 128) goto done2;
+
+  byte = *(ptr++); res3 = byte;              if (byte < 128) goto done3;
+  byte = *(ptr++); res3 += (byte - 1) <<  7; if (byte < 2) goto done3;
+
+  return nullptr;       // Value is too long to be a varint64
+
+ done1:
+  assert(res2 == 0);
+  assert(res3 == 0);
+  *OUTPUT = res1;
+  return reinterpret_cast<const char*>(ptr);
+
+ done2:
+  assert(res3 == 0);
+  *OUTPUT = res1 + ((res2 - 1) << 28);
+  return reinterpret_cast<const char*>(ptr);
+
+ done3:
+  *OUTPUT = res1 + ((res2 - 1) << 28) + ((res3 - 1) << 56);
+  return reinterpret_cast<const char*>(ptr);
+#else
+  uint32 byte, res1, res2=0, res3=0;
+  byte = *(ptr++); res1 = byte & 127;
+  byte = *(ptr++); res1 |= (byte & 127) <<  7; if (byte < 128) goto done1;
+  byte = *(ptr++); res1 |= (byte & 127) << 14; if (byte < 128) goto done1;
+  byte = *(ptr++); res1 |= (byte & 127) << 21; if (byte < 128) goto done1;
+
+  byte = *(ptr++); res2 = byte & 127;          if (byte < 128) goto done2;
+  byte = *(ptr++); res2 |= (byte & 127) <<  7; if (byte < 128) goto done2;
+  byte = *(ptr++); res2 |= (byte & 127) << 14; if (byte < 128) goto done2;
+  byte = *(ptr++); res2 |= (byte & 127) << 21; if (byte < 128) goto done2;
+
+  byte = *(ptr++); res3 = byte & 127;          if (byte < 128) goto done3;
+  byte = *(ptr++); res3 |= (byte & 127) <<  7; if (byte < 2) goto done3;
+
+  return nullptr;       // Value is too long to be a varint64
+
+ done1:
+  assert(res2 == 0);
+  assert(res3 == 0);
+  *OUTPUT = res1;
+  return reinterpret_cast<const char*>(ptr);
+
+ done2:
+  assert(res3 == 0);
+  *OUTPUT = res1 | (uint64(res2) << 28);
+  return reinterpret_cast<const char*>(ptr);
+
+ done3:
+  *OUTPUT = res1 | (uint64(res2) << 28) | (uint64(res3) << 56);
+  return reinterpret_cast<const char*>(ptr);
+#endif
+}
+
+const char* Varint::Parse32BackwardSlow(const char* ptr, const char* base,
+                                        uint32* OUTPUT) {
+  // Since this method is rarely called, for simplicity, we just skip backward
+  // and then parse forward.
+  const char* prev = Skip32BackwardSlow(ptr, base);
+  if (prev == nullptr)
+    return nullptr; // no value before 'ptr'
+
+  Parse32(prev, OUTPUT);
+  return prev;
+}
+
+const char* Varint::Parse64BackwardSlow(const char* ptr, const char* base,
+                                        uint64* OUTPUT) {
+  // Since this method is rarely called, for simplicity, we just skip backward
+  // and then parse forward.
+  const char* prev = Skip64BackwardSlow(ptr, base);
+  if (prev == nullptr)
+    return nullptr; // no value before 'ptr'
+
+  Parse64(prev, OUTPUT);
+  return prev;
+}
+
+const char* Varint::Parse64WithLimit(const char* p,
+                                     const char* l,
+                                     uint64* OUTPUT) {
+  if (p + kMax64 <= l) {
+    return Parse64(p, OUTPUT);
+  } else {
+    // See detailed comment in Varint::Parse64Fallback about this general
+    // approach.
+    const unsigned char* ptr = reinterpret_cast<const unsigned char*>(p);
+    const unsigned char* limit = reinterpret_cast<const unsigned char*>(l);
+    uint64 b, result;
+#if defined(__x86_64__)
+    if (ptr >= limit) return nullptr;
+    b = *(ptr++); result = b;              if (b < 128) goto done;
+    if (ptr >= limit) return nullptr;
+    b = *(ptr++); result += (b - 1) <<  7; if (b < 128) goto done;
+    if (ptr >= limit) return nullptr;
+    b = *(ptr++); result += (b - 1) << 14; if (b < 128) goto done;
+    if (ptr >= limit) return nullptr;
+    b = *(ptr++); result += (b - 1) << 21; if (b < 128) goto done;
+    if (ptr >= limit) return nullptr;
+    b = *(ptr++); result += (b - 1) << 28; if (b < 128) goto done;
+    if (ptr >= limit) return nullptr;
+    b = *(ptr++); result += (b - 1) << 35; if (b < 128) goto done;
+    if (ptr >= limit) return nullptr;
+    b = *(ptr++); result += (b - 1) << 42; if (b < 128) goto done;
+    if (ptr >= limit) return nullptr;
+    b = *(ptr++); result += (b - 1) << 49; if (b < 128) goto done;
+    if (ptr >= limit) return nullptr;
+    b = *(ptr++); result += (b - 1) << 56; if (b < 128) goto done;
+    if (ptr >= limit) return nullptr;
+    b = *(ptr++); result += (b - 1) << 63; if (b < 2) goto done;
+    return nullptr;       // Value is too long to be a varint64
+#else
+    if (ptr >= limit) return nullptr;
+    b = *(ptr++); result = b & 127;          if (b < 128) goto done;
+    if (ptr >= limit) return nullptr;
+    b = *(ptr++); result |= (b & 127) <<  7; if (b < 128) goto done;
+    if (ptr >= limit) return nullptr;
+    b = *(ptr++); result |= (b & 127) << 14; if (b < 128) goto done;
+    if (ptr >= limit) return nullptr;
+    b = *(ptr++); result |= (b & 127) << 21; if (b < 128) goto done;
+    if (ptr >= limit) return nullptr;
+    b = *(ptr++); result |= (b & 127) << 28; if (b < 128) goto done;
+    if (ptr >= limit) return nullptr;
+    b = *(ptr++); result |= (b & 127) << 35; if (b < 128) goto done;
+    if (ptr >= limit) return nullptr;
+    b = *(ptr++); result |= (b & 127) << 42; if (b < 128) goto done;
+    if (ptr >= limit) return nullptr;
+    b = *(ptr++); result |= (b & 127) << 49; if (b < 128) goto done;
+    if (ptr >= limit) return nullptr;
+    b = *(ptr++); result |= (b & 127) << 56; if (b < 128) goto done;
+    if (ptr >= limit) return nullptr;
+    b = *(ptr++); result |= (b & 127) << 63; if (b < 2) goto done;
+    return nullptr;       // Value is too long to be a varint64
+#endif
+   done:
+    *OUTPUT = result;
+    return reinterpret_cast<const char*>(ptr);
+  }
+}
+
+const char* Varint::Skip32BackwardSlow(const char* p, const char* b) {
+  const unsigned char* ptr = reinterpret_cast<const unsigned char*>(p);
+  const unsigned char* base = reinterpret_cast<const unsigned char*>(b);
+  assert(ptr >= base);
+
+  // If the initial pointer is at the base or if the previous byte is not
+  // the last byte of a varint, we return nullptr since there is nothing to
+  // skip.
+  if (ptr == base) return nullptr;
+  if (*(--ptr) > 127) return nullptr;
+
+  for (int i = 0; i < 5; i++) {
+    if (ptr == base)    return reinterpret_cast<const char*>(ptr);
+    if (*(--ptr) < 128) return reinterpret_cast<const char*>(ptr + 1);
+  }
+
+  return nullptr; // value is too long to be a varint32
+}
+
+const char* Varint::Skip64BackwardSlow(const char* p, const char* b) {
+  const unsigned char* ptr = reinterpret_cast<const unsigned char*>(p);
+  const unsigned char* base = reinterpret_cast<const unsigned char*>(b);
+  assert(ptr >= base);
+
+  // If the initial pointer is at the base or if the previous byte is not
+  // the last byte of a varint, we return nullptr since there is nothing to
+  // skip.
+  if (ptr == base) return nullptr;
+  if (*(--ptr) > 127) return nullptr;
+
+  for (int i = 0; i < 10; i++) {
+    if (ptr == base)    return reinterpret_cast<const char*>(ptr);
+    if (*(--ptr) < 128) return reinterpret_cast<const char*>(ptr + 1);
+  }
+
+  return nullptr; // value is too long to be a varint64
+}
+
+void Varint::Append32Slow(std::string* s, uint32 value) {
+  const size_t start = s->size();
+  s->resize(start + Varint::Length32(value));
+  Varint::Encode32(&((*s)[start]), value);
+}
+
+void Varint::Append64Slow(std::string* s, uint64 value) {
+  const size_t start = s->size();
+  s->resize(start + Varint::Length64(value));
+  Varint::Encode64(&((*s)[start]), value);
+}
diff --git a/src/s2/util/coding/varint.h b/src/s2/util/coding/varint.h
new file mode 100644 (file)
index 0000000..04726e4
--- /dev/null
@@ -0,0 +1,476 @@
+// Copyright 2001 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+//
+// Raw support for varint encoding.  Higher level interfaces are
+// provided by Encoder/Decoder/IOBuffer.  Clients should typically use
+// those interfaces, unless speed is paramount.
+//
+// If decoding speed is very important, consider using PrefixVarint instead.
+// It has the same compression ratio, but generally faster decoding.
+//
+// Provided routines:
+//      vi_parse32_unchecked
+//      vi_parse64_unchecked
+//      vi_encode32_unchecked
+//      vi_encode64_unchecked
+
+#ifndef S2_UTIL_CODING_VARINT_H_
+#define S2_UTIL_CODING_VARINT_H_
+
+// Avoid adding expensive includes here.
+#include <cassert>
+#include <cstddef>
+#include <string>
+
+#include "s2/base/integral_types.h"
+#include "s2/base/port.h"
+#include "absl/base/macros.h"
+#include "s2/util/bits/bits.h"
+
+// Just a namespace, not a real class
+class Varint {
+ public:
+  // Maximum lengths of varint encoding of uint32 and uint64
+  static const int kMax32 = 5;
+  static const int kMax64 = 10;
+
+  // The decoder does not read past the end of the encoded data.
+  static const int kSlopBytes = 0;
+
+  // REQUIRES   "ptr" points to a buffer of length at least kMaxXX
+  // EFFECTS    Scan next varint from "ptr" and store in OUTPUT.
+  //            Returns pointer just past last read byte.  Returns
+  //            nullptr if a valid varint value was not found.
+  static const char* Parse32(const char* ptr, uint32* OUTPUT);
+  static const char* Parse64(const char* ptr, uint64* OUTPUT);
+
+  // A fully inlined version of Parse32: useful in the most time critical
+  // routines, but its code size is large
+  static const char* Parse32Inline(const char* ptr, uint32* OUTPUT);
+
+  // REQUIRES   "ptr" points just past the last byte of a varint-encoded value.
+  // REQUIRES   A second varint must be encoded just before the one we parse,
+  //            OR "base" must point to the first byte of the one we parse.
+  // REQUIRES   Bytes [base, ptr-1] are readable
+  //
+  // EFFECTS    Scan backwards from "ptr" and store in OUTPUT. Stop at the last
+  //            byte of the previous varint, OR at "base", whichever one comes
+  //            first. Returns pointer to the first byte of the decoded varint
+  //            nullptr if a valid varint value was not found.
+  static const char* Parse32Backward(const char* ptr, const char* base,
+                                     uint32* OUTPUT);
+  static const char* Parse64Backward(const char* ptr, const char* base,
+                                     uint64* OUTPUT);
+
+  // Attempts to parse a varint32 from a prefix of the bytes in [ptr,limit-1].
+  // Never reads a character at or beyond limit.  If a valid/terminated varint32
+  // was found in the range, stores it in *OUTPUT and returns a pointer just
+  // past the last byte of the varint32. Else returns nullptr.  On success,
+  // "result <= limit".
+  static const char* Parse32WithLimit(const char* ptr, const char* limit,
+                                      uint32* OUTPUT);
+  static const char* Parse64WithLimit(const char* ptr, const char* limit,
+                                      uint64* OUTPUT);
+
+  // REQUIRES   "ptr" points to the first byte of a varint-encoded value.
+  // EFFECTS     Scans until the end of the varint and returns a pointer just
+  //             past the last byte. Returns nullptr if "ptr" does not point to
+  //             a valid varint value.
+  static const char* Skip32(const char* ptr);
+  static const char* Skip64(const char* ptr);
+
+  // REQUIRES   "ptr" points just past the last byte of a varint-encoded value.
+  // REQUIRES   A second varint must be encoded just before the one we parse,
+  //            OR "base" must point to the first byte of the one we parse.
+  // REQUIRES   Bytes [base, ptr-1] are readable
+  //
+  // EFFECTS    Scan backwards from "ptr" and stop at the last byte of the
+  //            previous varint, OR at "base", whichever one comes first.
+  //            Returns pointer to the first byte of the skipped varint or
+  //            nullptr if a valid varint value was not found.
+  static const char* Skip32Backward(const char* ptr, const char* base);
+  static const char* Skip64Backward(const char* ptr, const char* base);
+
+  // REQUIRES   "ptr" points to a buffer of length sufficient to hold "v".
+  // EFFECTS    Encodes "v" into "ptr" and returns a pointer to the
+  //            byte just past the last encoded byte.
+  static char* Encode32(char* ptr, uint32 v);
+  static char* Encode64(char* ptr, uint64 v);
+
+  // A fully inlined version of Encode32: useful in the most time critical
+  // routines, but its code size is large
+  static char* Encode32Inline(char* ptr, uint32 v);
+
+  // EFFECTS    Returns the encoding length of the specified value.
+  static int Length32(uint32 v);
+  static int Length64(uint64 v);
+
+  // EFFECTS    Appends the varint representation of "value" to "*s".
+  static void Append32(std::string* s, uint32 value);
+  static void Append64(std::string* s, uint64 value);
+
+  // EFFECTS    Encodes a pair of values to "*s".  The encoding
+  //            is done by weaving together 4 bit groups of
+  //            each number into a single 64 bit value, and then
+  //            encoding this value as a Varint64 value.  This means
+  //            that if both a and b are small, both values can be
+  //            encoded in a single byte.
+  ABSL_DEPRECATED("Use TwoValuesVarint::Encode32.")
+  static void EncodeTwo32Values(std::string* s, uint32 a, uint32 b);
+  ABSL_DEPRECATED("Use TwoValuesVarint::Decode32.")
+  static const char* DecodeTwo32Values(const char* ptr, uint32* a, uint32* b);
+  ABSL_DEPRECATED("Use TwoValuesVarint::Decode32WithLimit.")
+  static const char* DecodeTwo32ValuesWithLimit(const char* ptr,
+                                                const char* limit, uint32* a,
+                                                uint32* b);
+
+  // Decode and sum up a sequence of deltas until the sum >= goal.
+  // It is significantly faster than calling ParseXXInline in a loop.
+  // NOTE(user): The code does NO error checking, it assumes all the
+  // deltas are valid and the sum of deltas will never exceed
+  // numeric_limits<int64>::max(). The code works for both 32bits and
+  // 64bits varint, and on 64 bits machines, the 64 bits version is
+  // almost always faster. Thus we only have a 64 bits interface here.
+  // The interface is slightly different from the other functions in that
+  // it requires *signed* integers.
+  // REQUIRES   "ptr" points to the first byte of a varint-encoded delta.
+  //            The sum of deltas >= goal (the code does NO boundary check).
+  //            goal is positive and fit into a signed int64.
+  // EFFECTS    Returns a pointer just past last read byte.
+  //            "out" stores the actual sum.
+  static const char* FastDecodeDeltas(const char* ptr, int64 goal, int64* out);
+
+ private:
+  static const char* Parse32FallbackInline(const char* p, uint32* val);
+  static const char* Parse32Fallback(const char* p, uint32* val);
+  static const char* Parse64Fallback(const char* p, uint64* val);
+
+  static char* Encode32Fallback(char* ptr, uint32 v);
+
+  static const char* Parse32BackwardSlow(const char* ptr, const char* base,
+                                         uint32* OUTPUT);
+  static const char* Parse64BackwardSlow(const char* ptr, const char* base,
+                                         uint64* OUTPUT);
+  static const char* Skip32BackwardSlow(const char* ptr, const char* base);
+  static const char* Skip64BackwardSlow(const char* ptr, const char* base);
+
+  static void Append32Slow(std::string* s, uint32 value);
+  static void Append64Slow(std::string* s, uint64 value);
+
+};
+
+/***** Implementation details; clients should ignore *****/
+
+inline const char* Varint::Parse32FallbackInline(const char* p,
+                                                 uint32* OUTPUT) {
+  // Fast path
+  const unsigned char* ptr = reinterpret_cast<const unsigned char*>(p);
+  uint32 byte, result;
+  byte = *(ptr++); result = byte & 127;
+  assert(byte >= 128);   // Already checked in inlined prelude
+  byte = *(ptr++); result |= (byte & 127) <<  7; if (byte < 128) goto done;
+  byte = *(ptr++); result |= (byte & 127) << 14; if (byte < 128) goto done;
+  byte = *(ptr++); result |= (byte & 127) << 21; if (byte < 128) goto done;
+  byte = *(ptr++); result |= (byte & 127) << 28; if (byte < 16) goto done;
+  return nullptr;       // Value is too long to be a varint32
+ done:
+  *OUTPUT = result;
+  return reinterpret_cast<const char*>(ptr);
+}
+
+inline const char* Varint::Parse32(const char* p, uint32* OUTPUT) {
+  // Fast path for inlining
+  const unsigned char* ptr = reinterpret_cast<const unsigned char*>(p);
+  uint32 byte = *ptr;
+  if (byte < 128) {
+    *OUTPUT = byte;
+    return reinterpret_cast<const char*>(ptr) + 1;
+  } else {
+    return Parse32Fallback(p, OUTPUT);
+  }
+}
+
+inline const char* Varint::Parse32Inline(const char* p, uint32* OUTPUT) {
+  // Fast path for inlining
+  const unsigned char* ptr = reinterpret_cast<const unsigned char*>(p);
+  uint32 byte = *ptr;
+  if (byte < 128) {
+    *OUTPUT = byte;
+    return reinterpret_cast<const char*>(ptr) + 1;
+  } else {
+    return Parse32FallbackInline(p, OUTPUT);
+  }
+}
+
+inline const char* Varint::Skip32(const char* p) {
+  const unsigned char* ptr = reinterpret_cast<const unsigned char*>(p);
+  if (*ptr++ < 128) return reinterpret_cast<const char*>(ptr);
+  if (*ptr++ < 128) return reinterpret_cast<const char*>(ptr);
+  if (*ptr++ < 128) return reinterpret_cast<const char*>(ptr);
+  if (*ptr++ < 128) return reinterpret_cast<const char*>(ptr);
+  if (*ptr++ < 16) return reinterpret_cast<const char*>(ptr);
+  return nullptr; // value is too long to be a varint32
+}
+
+inline const char* Varint::Parse32Backward(const char* p, const char* base,
+                                           uint32* OUTPUT) {
+  if (p > base + kMax32) {
+    // Fast path
+    const unsigned char* ptr = reinterpret_cast<const unsigned char*>(p);
+    uint32 byte, result;
+    byte = *(--ptr); if (byte > 127) return nullptr;
+    result = byte;
+    byte = *(--ptr); if (byte < 128) goto done;
+    result <<= 7; result |= (byte & 127);
+    byte = *(--ptr); if (byte < 128) goto done;
+    result <<= 7; result |= (byte & 127);
+    byte = *(--ptr); if (byte < 128) goto done;
+    result <<= 7; result |= (byte & 127);
+    byte = *(--ptr); if (byte < 128) goto done;
+    result <<= 7; result |= (byte & 127);
+    byte = *(--ptr); if (byte < 128) goto done;
+    return nullptr; // Value is too long to be a varint32
+ done:
+    *OUTPUT = result;
+    return reinterpret_cast<const char*>(ptr+1);
+  } else {
+    return Parse32BackwardSlow(p, base, OUTPUT);
+  }
+}
+
+inline const char* Varint::Skip32Backward(const char* p, const char* base) {
+  if (p > base + kMax32) {
+    const unsigned char* ptr = reinterpret_cast<const unsigned char*>(p);
+    if (*(--ptr) > 127) return nullptr;
+    if (*(--ptr) < 128) return reinterpret_cast<const char*>(ptr+1);
+    if (*(--ptr) < 128) return reinterpret_cast<const char*>(ptr+1);
+    if (*(--ptr) < 128) return reinterpret_cast<const char*>(ptr+1);
+    if (*(--ptr) < 128) return reinterpret_cast<const char*>(ptr+1);
+    if (*(--ptr) < 128) return reinterpret_cast<const char*>(ptr+1);
+    return nullptr; // value is too long to be a varint32
+  } else {
+    return Skip32BackwardSlow(p, base);
+  }
+}
+
+inline const char* Varint::Parse32WithLimit(const char* p,
+                                            const char* l,
+                                            uint32* OUTPUT) {
+  // Version with bounds checks.
+  // This formerly had an optimization to inline the non-bounds checking Parse32
+  // but it was found to be slower than the straightforward implementation.
+  const unsigned char* ptr = reinterpret_cast<const unsigned char*>(p);
+  const unsigned char* limit = reinterpret_cast<const unsigned char*>(l);
+  uint32 b, result;
+  if (ptr >= limit) return nullptr;
+  b = *(ptr++); result = b & 127;          if (b < 128) goto done;
+  if (ptr >= limit) return nullptr;
+  b = *(ptr++); result |= (b & 127) <<  7; if (b < 128) goto done;
+  if (ptr >= limit) return nullptr;
+  b = *(ptr++); result |= (b & 127) << 14; if (b < 128) goto done;
+  if (ptr >= limit) return nullptr;
+  b = *(ptr++); result |= (b & 127) << 21; if (b < 128) goto done;
+  if (ptr >= limit) return nullptr;
+  b = *(ptr++); result |= (b & 127) << 28; if (b < 16) goto done;
+  return nullptr;       // Value is too long to be a varint32
+ done:
+  *OUTPUT = result;
+  return reinterpret_cast<const char*>(ptr);
+}
+
+inline const char* Varint::Parse64(const char* p, uint64* OUTPUT) {
+  const unsigned char* ptr = reinterpret_cast<const unsigned char*>(p);
+  uint32 byte = *ptr;
+  if (byte < 128) {
+    *OUTPUT = byte;
+    return reinterpret_cast<const char*>(ptr) + 1;
+  } else {
+    return Parse64Fallback(p, OUTPUT);
+  }
+}
+
+inline const char* Varint::Skip64(const char* p) {
+  const unsigned char* ptr = reinterpret_cast<const unsigned char*>(p);
+  if (*ptr++ < 128) return reinterpret_cast<const char*>(ptr);
+  if (*ptr++ < 128) return reinterpret_cast<const char*>(ptr);
+  if (*ptr++ < 128) return reinterpret_cast<const char*>(ptr);
+  if (*ptr++ < 128) return reinterpret_cast<const char*>(ptr);
+  if (*ptr++ < 128) return reinterpret_cast<const char*>(ptr);
+  if (*ptr++ < 128) return reinterpret_cast<const char*>(ptr);
+  if (*ptr++ < 128) return reinterpret_cast<const char*>(ptr);
+  if (*ptr++ < 128) return reinterpret_cast<const char*>(ptr);
+  if (*ptr++ < 128) return reinterpret_cast<const char*>(ptr);
+  if (*ptr++ < 2) return reinterpret_cast<const char*>(ptr);
+  return nullptr; // value is too long to be a varint64
+}
+
+inline const char* Varint::Parse64Backward(const char* p, const char* b,
+                                           uint64* OUTPUT) {
+  if (p > b + kMax64) {
+    // Fast path
+    const unsigned char* ptr = reinterpret_cast<const unsigned char*>(p);
+    uint32 byte;
+    uint64 res;
+
+    byte = *(--ptr); if (byte > 127) return nullptr;
+
+    res = byte;
+    byte = *(--ptr); if (byte < 128) goto done;
+    res <<= 7; res |= (byte & 127);
+    byte = *(--ptr); if (byte < 128) goto done;
+    res <<= 7; res |= (byte & 127);
+    byte = *(--ptr); if (byte < 128) goto done;
+    res <<= 7; res |= (byte & 127);
+    byte = *(--ptr); if (byte < 128) goto done;
+    res <<= 7; res |= (byte & 127);
+    byte = *(--ptr); if (byte < 128) goto done;
+    res <<= 7; res |= (byte & 127);
+    byte = *(--ptr); if (byte < 128) goto done;
+    res <<= 7; res |= (byte & 127);
+    byte = *(--ptr); if (byte < 128) goto done;
+    res <<= 7; res |= (byte & 127);
+    byte = *(--ptr); if (byte < 128) goto done;
+    res <<= 7; res |= (byte & 127);
+    byte = *(--ptr); if (byte < 128) goto done;
+    res <<= 7; res |= (byte & 127);
+    byte = *(--ptr); if (byte < 128) goto done;
+
+    return nullptr;       // Value is too long to be a varint64
+
+ done:
+    *OUTPUT = res;
+    return reinterpret_cast<const char*>(ptr + 1);
+  } else {
+    return Parse64BackwardSlow(p, b, OUTPUT);
+  }
+}
+
+inline const char* Varint::Skip64Backward(const char* p, const char* b) {
+  if (p > b + kMax64) {
+    // Fast path
+    const unsigned char* ptr = reinterpret_cast<const unsigned char*>(p);
+    if (*(--ptr) > 127) return nullptr;
+    if (*(--ptr) < 128) return reinterpret_cast<const char*>(ptr+1);
+    if (*(--ptr) < 128) return reinterpret_cast<const char*>(ptr+1);
+    if (*(--ptr) < 128) return reinterpret_cast<const char*>(ptr+1);
+    if (*(--ptr) < 128) return reinterpret_cast<const char*>(ptr+1);
+    if (*(--ptr) < 128) return reinterpret_cast<const char*>(ptr+1);
+    if (*(--ptr) < 128) return reinterpret_cast<const char*>(ptr+1);
+    if (*(--ptr) < 128) return reinterpret_cast<const char*>(ptr+1);
+    if (*(--ptr) < 128) return reinterpret_cast<const char*>(ptr+1);
+    if (*(--ptr) < 128) return reinterpret_cast<const char*>(ptr+1);
+    if (*(--ptr) < 128) return reinterpret_cast<const char*>(ptr+1);
+    return nullptr; // value is too long to be a varint64
+  } else {
+    return Skip64BackwardSlow(p, b);
+  }
+}
+
+inline int Varint::Length32(uint32 v) {
+  // This computes value == 0 ? 1 : floor(log2(v)) / 7 + 1
+  // Use an explicit multiplication to implement the divide of
+  // a number in the 1..31 range.
+  // Explicit OR 0x1 to handle v == 0.
+  uint32 log2value = Bits::Log2FloorNonZero(v | 0x1);
+  return static_cast<int>((log2value * 9 + 73) / 64);
+}
+
+inline int Varint::Length64(uint64 v) {
+  // This computes value == 0 ? 1 : floor(log2(v)) / 7 + 1
+  // Use an explicit multiplication to implement the divide of
+  // a number in the 1..63 range.
+  // Explicit OR 0x1 to handle v == 0.
+  uint32 log2value = Bits::Log2FloorNonZero64(v | 0x1);
+  return static_cast<int>((log2value * 9 + 73) / 64);
+}
+
+inline void Varint::Append32(std::string* s, uint32 value) {
+  // Inline the fast-path for single-character output, but fall back to the .cc
+  // file for the full version. The size<capacity check is so the compiler can
+  // optimize out the string resize code.
+  if (value < 128 && s->size() < s->capacity()) {
+    s->push_back((unsigned char)value);
+  } else {
+    Append32Slow(s, value);
+  }
+}
+
+inline void Varint::Append64(std::string* s, uint64 value) {
+  // Inline the fast-path for single-character output, but fall back to the .cc
+  // file for the full version. The size<capacity check is so the compiler can
+  // optimize out the string resize code.
+  if (value < 128 && s->size() < s->capacity()) {
+    s->push_back((unsigned char)value);
+  } else {
+    Append64Slow(s, value);
+  }
+}
+
+inline char* Varint::Encode32Inline(char* sptr, uint32 v) {
+  // Operate on characters as unsigneds
+  uint8* ptr = reinterpret_cast<uint8*>(sptr);
+  static const uint32 B = 128;
+  if (v < (1<<7)) {
+    *(ptr++) = static_cast<uint8>(v);
+  } else if (v < (1<<14)) {
+    *(ptr++) = static_cast<uint8>(v | B);
+    *(ptr++) = static_cast<uint8>(v>>7);
+  } else if (v < (1<<21)) {
+    *(ptr++) = static_cast<uint8>(v | B);
+    *(ptr++) = static_cast<uint8>((v>>7) | B);
+    *(ptr++) = static_cast<uint8>(v>>14);
+  } else if (v < (1<<28)) {
+    *(ptr++) = static_cast<uint8>(v | B);
+    *(ptr++) = static_cast<uint8>((v>>7) | B);
+    *(ptr++) = static_cast<uint8>((v>>14) | B);
+    *(ptr++) = static_cast<uint8>(v>>21);
+  } else {
+    *(ptr++) = static_cast<uint8>(v | B);
+    *(ptr++) = static_cast<uint8>((v>>7) | B);
+    *(ptr++) = static_cast<uint8>((v>>14) | B);
+    *(ptr++) = static_cast<uint8>((v>>21) | B);
+    *(ptr++) = static_cast<uint8>(v>>28);
+  }
+  return reinterpret_cast<char*>(ptr);
+}
+
+#if (-1 >> 1) != -1
+#error FastDecodeDeltas() needs right-shift to sign-extend.
+#endif
+inline const char* Varint::FastDecodeDeltas(const char* ptr,
+                                            int64 goal,
+                                            int64* out) {
+  int64 value;
+  int64 sum = - goal;
+  int64 shift = 0;
+  // Make decoding faster by eliminating unpredictable branching.
+  do {
+    value = static_cast<int8>(*ptr++);  // sign extend one byte of data
+    sum += (value & 0x7F) << shift;
+    shift += 7;
+    // (value >> 7) is either -1(continuation byte) or 0 (stop byte)
+    shift &= value >> 7;
+    // Loop if we haven't reached goal (sum < 0) or we haven't finished
+    // parsing current delta (value < 0). We write it in the form of
+    // (a | b) < 0 as opposed to (a < 0 || b < 0) as the former one is
+    // usually as fast as a test for (a < 0).
+  } while ((sum | value) < 0);
+
+  *out = goal + sum;
+  return ptr;
+}
+
+#endif  // S2_UTIL_CODING_VARINT_H_
diff --git a/src/s2/util/endian/endian.h b/src/s2/util/endian/endian.h
new file mode 100644 (file)
index 0000000..6d33851
--- /dev/null
@@ -0,0 +1,861 @@
+// Copyright 2005 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+//
+// Utility functions that depend on bytesex. We define htonll and ntohll,
+// as well as "Google" versions of all the standards: ghtonl, ghtons, and
+// so on. These functions do exactly the same as their standard variants,
+// but don't require including the dangerous netinet/in.h.
+//
+// Buffer routines will copy to and from buffers without causing
+// a bus error when the architecture requires different byte alignments.
+#ifndef S2_UTIL_ENDIAN_ENDIAN_H_
+#define S2_UTIL_ENDIAN_ENDIAN_H_
+
+#include <cassert>
+#include <type_traits>
+
+#include "s2/base/integral_types.h"
+#include "s2/base/logging.h"
+#include "s2/base/port.h"
+#include "absl/base/casts.h"
+#include "absl/base/port.h"
+#include "absl/numeric/int128.h"
+
+// Use compiler byte-swapping intrinsics if they are available.  32-bit
+// and 64-bit versions are available in Clang and GCC as of GCC 4.3.0.
+// The 16-bit version is available in Clang and GCC only as of GCC 4.8.0.
+// For simplicity, we enable them all only for GCC 4.8.0 or later.
+#if defined(__clang__) || \
+    (defined(__GNUC__) && ((__GNUC__ == 4 && __GNUC_MINOR__ >= 8) || \
+                           __GNUC__ >= 5))
+
+inline uint64 gbswap_64(uint64 host_int) {
+  return __builtin_bswap64(host_int);
+}
+inline uint32 gbswap_32(uint32 host_int) {
+  return __builtin_bswap32(host_int);
+}
+inline uint16 gbswap_16(uint16 host_int) {
+  return __builtin_bswap16(host_int);
+}
+
+#else
+
+inline uint64 gbswap_64(uint64 host_int) {
+#if defined(__GNUC__) && defined(__x86_64__) && \
+    !(defined(__APPLE__) && defined(__MACH__))
+  // Adapted from /usr/include/byteswap.h.  Not available on Mac.
+  if (__builtin_constant_p(host_int)) {
+    return __bswap_constant_64(host_int);
+  } else {
+    uint64 result;
+    __asm__("bswap %0" : "=r" (result) : "0" (host_int));
+    return result;
+  }
+#elif defined(bswap_64)
+  return bswap_64(host_int);
+#else
+  return static_cast<uint64>(bswap_32(static_cast<uint32>(host_int >> 32))) |
+    (static_cast<uint64>(bswap_32(static_cast<uint32>(host_int))) << 32);
+#endif  // bswap_64
+}
+inline uint32 gbswap_32(uint32 host_int) {
+  return bswap_32(host_int);
+}
+inline uint16 gbswap_16(uint16 host_int) {
+  return bswap_16(host_int);
+}
+
+#endif  // intrinics available
+
+inline absl::uint128 gbswap_128(absl::uint128 host_int) {
+  return absl::MakeUint128(gbswap_64(absl::Uint128Low64(host_int)),
+                           gbswap_64(absl::Uint128High64(host_int)));
+}
+
+#ifdef IS_LITTLE_ENDIAN
+
+// Definitions for ntohl etc. that don't require us to include
+// netinet/in.h. We wrap gbswap_32 and gbswap_16 in functions rather
+// than just #defining them because in debug mode, gcc doesn't
+// correctly handle the (rather involved) definitions of bswap_32.
+// gcc guarantees that inline functions are as fast as macros, so
+// this isn't a performance hit.
+inline uint16 ghtons(uint16 x) { return gbswap_16(x); }
+inline uint32 ghtonl(uint32 x) { return gbswap_32(x); }
+inline uint64 ghtonll(uint64 x) { return gbswap_64(x); }
+
+#elif defined IS_BIG_ENDIAN
+
+// These definitions are simpler on big-endian machines
+// These are functions instead of macros to avoid self-assignment warnings
+// on calls such as "i = ghtnol(i);".  This also provides type checking.
+inline uint16 ghtons(uint16 x) { return x; }
+inline uint32 ghtonl(uint32 x) { return x; }
+inline uint64 ghtonll(uint64 x) { return x; }
+
+#else
+#error "Unsupported bytesex: Either IS_BIG_ENDIAN or IS_LITTLE_ENDIAN must be defined"  // NOLINT
+#endif  // bytesex
+
+#ifndef htonll
+// With the rise of 64-bit, some systems are beginning to define this.
+#define htonll(x) ghtonll(x)
+#endif  // htonll
+
+// ntoh* and hton* are the same thing for any size and bytesex,
+// since the function is an involution, i.e., its own inverse.
+inline uint16 gntohs(uint16 x) { return ghtons(x); }
+inline uint32 gntohl(uint32 x) { return ghtonl(x); }
+inline uint64 gntohll(uint64 x) { return ghtonll(x); }
+
+#ifndef ntohll
+#define ntohll(x) htonll(x)
+#endif  // ntohll
+
+// We provide unified FromHost and ToHost APIs for all integral types and float,
+// double types. If variable v's type is known to be one of these types, the
+// client can simply call the following function without worrying about its
+// return type.
+//     LittleEndian::FromHost(v), or BigEndian::FromHost(v)
+//     LittleEndian::ToHost(v), or BigEndian::ToHost(v)
+// This unified FromHost and ToHost APIs are useful inside a template when the
+// type of v is a template parameter.
+//
+// In order to unify all "IntType FromHostxx(ValueType)" and "IntType
+// ToHostxx(ValueType)" APIs, we use the following trait class to automatically
+// find the corresponding IntType given a ValueType, where IntType is an
+// unsigned integer type with the same size of ValueType. The supported
+// ValueTypes are uint8, uint16, uint32, uint64, int8, int16, int32, int64,
+// bool, float, double.
+//
+// template <class ValueType>
+// struct tofromhost_value_type_traits {
+//   typedef ValueType value_type;
+//   typedef IntType int_type;
+// }
+//
+// We don't provide the default implementation for this trait struct.
+// So that if ValueType is not supported by the FromHost and ToHost APIs, it
+// will give a compile time error.
+template <class ValueType>
+struct tofromhost_value_type_traits;
+
+// General byte order converter class template. It provides a common
+// implementation for LittleEndian::FromHost(ValueType),
+// BigEndian::FromHost(ValueType), LittleEndian::ToHost(ValueType), and
+// BigEndian::ToHost(ValueType).
+template <class EndianClass, typename ValueType>
+class GeneralFormatConverter {
+ public:
+  static typename tofromhost_value_type_traits<ValueType>::int_type FromHost(
+      ValueType v);
+  static typename tofromhost_value_type_traits<ValueType>::int_type ToHost(
+      ValueType v);
+};
+
+// Utilities to convert numbers between the current hosts's native byte
+// order and little-endian byte order
+//
+// Load/Store methods are alignment safe
+class LittleEndian {
+ public:
+  // Conversion functions.
+#ifdef IS_LITTLE_ENDIAN
+
+  static uint16 FromHost16(uint16 x) { return x; }
+  static uint16 ToHost16(uint16 x) { return x; }
+
+  static uint32 FromHost32(uint32 x) { return x; }
+  static uint32 ToHost32(uint32 x) { return x; }
+
+  static uint64 FromHost64(uint64 x) { return x; }
+  static uint64 ToHost64(uint64 x) { return x; }
+
+  static absl::uint128 FromHost128(absl::uint128 x) { return x; }
+  static absl::uint128 ToHost128(absl::uint128 x) { return x; }
+
+  static constexpr bool IsLittleEndian() { return true; }
+
+#elif defined IS_BIG_ENDIAN
+
+  static uint16 FromHost16(uint16 x) { return gbswap_16(x); }
+  static uint16 ToHost16(uint16 x) { return gbswap_16(x); }
+
+  static uint32 FromHost32(uint32 x) { return gbswap_32(x); }
+  static uint32 ToHost32(uint32 x) { return gbswap_32(x); }
+
+  static uint64 FromHost64(uint64 x) { return gbswap_64(x); }
+  static uint64 ToHost64(uint64 x) { return gbswap_64(x); }
+
+  static absl::uint128 FromHost128(absl::uint128 x) { return gbswap_128(x); }
+  static absl::uint128 ToHost128(absl::uint128 x) { return gbswap_128(x); }
+
+  static constexpr bool IsLittleEndian() { return false; }
+
+#endif /* ENDIAN */
+
+  // Unified LittleEndian::FromHost(ValueType v) API.
+  template <class ValueType>
+  static typename tofromhost_value_type_traits<ValueType>::int_type FromHost(
+      ValueType v) {
+    return GeneralFormatConverter<LittleEndian, ValueType>::FromHost(v);
+  }
+
+  // Unified LittleEndian::ToHost(ValueType v) API.
+  template <class ValueType>
+  static typename tofromhost_value_type_traits<ValueType>::value_type ToHost(
+      ValueType v) {
+    return GeneralFormatConverter<LittleEndian, ValueType>::ToHost(v);
+  }
+
+  // Functions to do unaligned loads and stores in little-endian order.
+  static uint16 Load16(const void *p) {
+    return ToHost16(UNALIGNED_LOAD16(p));
+  }
+
+  static void Store16(void *p, uint16 v) {
+    UNALIGNED_STORE16(p, FromHost16(v));
+  }
+
+  static uint32 Load24(const void* p) {
+#ifdef IS_LITTLE_ENDIAN
+    uint32 result = 0;
+    memcpy(&result, p, 3);
+    return result;
+#else
+    const uint8* data = reinterpret_cast<const uint8*>(p);
+    return Load16(data) + (data[2] << 16);
+#endif
+  }
+
+  static void Store24(void* p, uint32 v) {
+#ifdef IS_LITTLE_ENDIAN
+    memcpy(p, &v, 3);
+#else
+    uint8* data = reinterpret_cast<uint8*>(p);
+    data[0] = v & 0xFF;
+    data[1] = (v >> 8) & 0xFF;
+    data[2] = (v >> 16) & 0xFF;
+#endif
+  }
+
+  static uint32 Load32(const void *p) {
+    return ToHost32(UNALIGNED_LOAD32(p));
+  }
+
+  static void Store32(void *p, uint32 v) {
+    UNALIGNED_STORE32(p, FromHost32(v));
+  }
+
+  static uint64 Load64(const void *p) {
+    return ToHost64(UNALIGNED_LOAD64(p));
+  }
+
+  // Build a uint64 from 1-8 bytes.
+  // 8 * len least significant bits are loaded from the memory with
+  // LittleEndian order. The 64 - 8 * len most significant bits are
+  // set all to 0.
+  // In latex-friendly words, this function returns:
+  //     $\sum_{i=0}^{len-1} p[i] 256^{i}$, where p[i] is unsigned.
+  //
+  // This function is equivalent to:
+  // uint64 val = 0;
+  // memcpy(&val, p, len);
+  // return ToHost64(val);
+  // TODO(jyrki): write a small benchmark and benchmark the speed
+  // of a memcpy based approach.
+  //
+  // For speed reasons this function does not work for len == 0.
+  // The caller needs to guarantee that 1 <= len <= 8.
+  static uint64 Load64VariableLength(const void * const p, int len) {
+    assert(len >= 1 && len <= 8);
+    const char * const buf = static_cast<const char * const>(p);
+    uint64 val = 0;
+    --len;
+    do {
+      val = (val << 8) | buf[len];
+      // (--len >= 0) is about 10 % faster than (len--) in some benchmarks.
+    } while (--len >= 0);
+    // No ToHost64(...) needed. The bytes are accessed in little-endian manner
+    // on every architecture.
+    return val;
+  }
+
+  static void Store64(void *p, uint64 v) {
+    UNALIGNED_STORE64(p, FromHost64(v));
+  }
+
+  static absl::uint128 Load128(const void* p) {
+    return absl::MakeUint128(
+        ToHost64(UNALIGNED_LOAD64(reinterpret_cast<const uint64*>(p) + 1)),
+        ToHost64(UNALIGNED_LOAD64(p)));
+  }
+
+  static void Store128(void* p, const absl::uint128 v) {
+    UNALIGNED_STORE64(p, FromHost64(absl::Uint128Low64(v)));
+    UNALIGNED_STORE64(reinterpret_cast<uint64*>(p) + 1,
+                      FromHost64(absl::Uint128High64(v)));
+  }
+
+  // Build a uint128 from 1-16 bytes.
+  // 8 * len least significant bits are loaded from the memory with
+  // LittleEndian order. The 128 - 8 * len most significant bits are
+  // set all to 0.
+  static absl::uint128 Load128VariableLength(const void* p, int len) {
+    if (len <= 8) {
+      return absl::uint128(Load64VariableLength(p, len));
+    } else {
+      return absl::MakeUint128(
+          Load64VariableLength(static_cast<const char*>(p) + 8, len - 8),
+          Load64(p));
+    }
+  }
+
+  // Load & Store in machine's word size.
+  static uword_t LoadUnsignedWord(const void *p) {
+    if (sizeof(uword_t) == 8)
+      return Load64(p);
+    else
+      return Load32(p);
+  }
+
+  static void StoreUnsignedWord(void *p, uword_t v) {
+    if (sizeof(v) == 8)
+      Store64(p, v);
+    else
+      Store32(p, v);
+  }
+
+  // Unified LittleEndian::Load/Store<T> API.
+
+  // Returns the T value encoded by the leading bytes of 'p', interpreted
+  // according to the format specified below. 'p' has no alignment restrictions.
+  //
+  // Type              Format
+  // ----------------  -------------------------------------------------------
+  // uint{8,16,32,64}  Little-endian binary representation.
+  // int{8,16,32,64}   Little-endian twos-complement binary representation.
+  // float,double      Little-endian IEEE-754 format.
+  // char              The raw byte.
+  // bool              A byte. 0 maps to false; all other values map to true.
+  template<typename T>
+  static T Load(const char* p);
+
+  // Encodes 'value' in the format corresponding to T. Supported types are
+  // described in Load<T>(). 'p' has no alignment restrictions. In-place Store
+  // is safe (that is, it is safe to call
+  // Store(x, reinterpret_cast<char*>(&x))).
+  template<typename T>
+  static void Store(T value, char* p);
+};
+
+// Utilities to convert numbers between the current hosts's native byte
+// order and big-endian byte order (same as network byte order)
+//
+// Load/Store methods are alignment safe
+class BigEndian {
+ public:
+#ifdef IS_LITTLE_ENDIAN
+
+  static uint16 FromHost16(uint16 x) { return gbswap_16(x); }
+  static uint16 ToHost16(uint16 x) { return gbswap_16(x); }
+
+  static uint32 FromHost32(uint32 x) { return gbswap_32(x); }
+  static uint32 ToHost32(uint32 x) { return gbswap_32(x); }
+
+  static uint64 FromHost64(uint64 x) { return gbswap_64(x); }
+  static uint64 ToHost64(uint64 x) { return gbswap_64(x); }
+
+  static absl::uint128 FromHost128(absl::uint128 x) { return gbswap_128(x); }
+  static absl::uint128 ToHost128(absl::uint128 x) { return gbswap_128(x); }
+
+  static constexpr bool IsLittleEndian() { return true; }
+
+#elif defined IS_BIG_ENDIAN
+
+  static uint16 FromHost16(uint16 x) { return x; }
+  static uint16 ToHost16(uint16 x) { return x; }
+
+  static uint32 FromHost32(uint32 x) { return x; }
+  static uint32 ToHost32(uint32 x) { return x; }
+
+  static uint64 FromHost64(uint64 x) { return x; }
+  static uint64 ToHost64(uint64 x) { return x; }
+
+  static absl::uint128 FromHost128(absl::uint128 x) { return x; }
+  static absl::uint128 ToHost128(absl::uint128 x) { return x; }
+
+  static constexpr bool IsLittleEndian() { return false; }
+
+#endif /* ENDIAN */
+
+  // Unified BigEndian::FromHost(ValueType v) API.
+  template <class ValueType>
+  static typename tofromhost_value_type_traits<ValueType>::int_type FromHost(
+      ValueType v) {
+    return GeneralFormatConverter<BigEndian, ValueType>::FromHost(v);
+  }
+
+  // Unified BigEndian::ToHost(ValueType v) API.
+  template <class ValueType>
+  static typename tofromhost_value_type_traits<ValueType>::value_type ToHost(
+      ValueType v) {
+    return GeneralFormatConverter<BigEndian, ValueType>::ToHost(v);
+  }
+
+  // Functions to do unaligned loads and stores in big-endian order.
+  static uint16 Load16(const void *p) {
+    return ToHost16(UNALIGNED_LOAD16(p));
+  }
+
+  static void Store16(void *p, uint16 v) {
+    UNALIGNED_STORE16(p, FromHost16(v));
+  }
+
+  static uint32 Load24(const void* p) {
+    const uint8* data = reinterpret_cast<const uint8*>(p);
+    return (data[0] << 16) + Load16(data + 1);
+  }
+
+  static void Store24(void* p, uint32 v) {
+    uint8* data = reinterpret_cast<uint8*>(p);
+    Store16(data + 1, static_cast<uint16>(v));
+    *data = static_cast<uint8>(v >> 16);
+  }
+
+  static uint32 Load32(const void *p) {
+    return ToHost32(UNALIGNED_LOAD32(p));
+  }
+
+  static void Store32(void *p, uint32 v) {
+    UNALIGNED_STORE32(p, FromHost32(v));
+  }
+
+  static uint64 Load64(const void *p) {
+    return ToHost64(UNALIGNED_LOAD64(p));
+  }
+
+  // Semantically build a uint64 from 1-8 bytes.
+  // 8 * len least significant bits are loaded from the memory with
+  // BigEndian order. The 64 - 8 * len most significant bits are
+  // set all to 0.
+  // In latex-friendly words, this function returns:
+  //     $\sum_{i=0}^{len-1} p[i] 256^{i}$, where p[i] is unsigned.
+  //
+  // This function is equivalent to:
+  // uint64 val = 0;
+  // memcpy(&val, p, len);
+  // return ToHost64(val);
+  // TODO(jyrki): write a small benchmark and benchmark the speed
+  // of a memcpy based approach.
+  //
+  // For speed reasons this function does not work for len == 0.
+  // The caller needs to guarantee that 1 <= len <= 8.
+
+  static uint64 Load64VariableLength(const void * const p, int len) {
+    //    uint64 val = LittleEndian::Load64VariableLength(p, len);
+    //    return Load64(&val) >> (8*(8-len));
+    assert(len >= 1 && len <= 8);
+    const char* buf = static_cast<const char * const>(p);
+    uint64 val = 0;
+    do {
+      val = (val << 8) | *buf;
+      ++buf;
+    } while (--len > 0);
+    return val;
+  }
+
+  static void Store64(void *p, uint64 v) {
+    UNALIGNED_STORE64(p, FromHost64(v));
+  }
+
+  static absl::uint128 Load128(const void* p) {
+    return absl::MakeUint128(
+        ToHost64(UNALIGNED_LOAD64(p)),
+        ToHost64(UNALIGNED_LOAD64(reinterpret_cast<const uint64*>(p) + 1)));
+  }
+
+  static void Store128(void* p, const absl::uint128 v) {
+    UNALIGNED_STORE64(p, FromHost64(absl::Uint128High64(v)));
+    UNALIGNED_STORE64(reinterpret_cast<uint64*>(p) + 1,
+                      FromHost64(absl::Uint128Low64(v)));
+  }
+
+  // Build a uint128 from 1-16 bytes.
+  // 8 * len least significant bits are loaded from the memory with
+  // BigEndian order. The 128 - 8 * len most significant bits are
+  // set all to 0.
+  static absl::uint128 Load128VariableLength(const void* p, int len) {
+    if (len <= 8) {
+      return absl::uint128(
+          Load64VariableLength(static_cast<const char*>(p), len));
+    } else if (len < 16) {
+      return absl::MakeUint128(Load64VariableLength(p, len - 8),
+                               Load64(static_cast<const char*>(p) + len - 8));
+    } else {
+      return absl::MakeUint128(Load64(static_cast<const char*>(p)),
+                               Load64(static_cast<const char*>(p) + 8));
+    }
+  }
+
+  // Load & Store in machine's word size.
+  static uword_t LoadUnsignedWord(const void *p) {
+    if (sizeof(uword_t) == 8)
+      return Load64(p);
+    else
+      return Load32(p);
+  }
+
+  static void StoreUnsignedWord(void *p, uword_t v) {
+    if (sizeof(uword_t) == 8)
+      Store64(p, v);
+    else
+      Store32(p, v);
+  }
+
+  // Unified BigEndian::Load/Store<T> API.
+
+  // Returns the T value encoded by the leading bytes of 'p', interpreted
+  // according to the format specified below. 'p' has no alignment restrictions.
+  //
+  // Type              Format
+  // ----------------  -------------------------------------------------------
+  // uint{8,16,32,64}  Big-endian binary representation.
+  // int{8,16,32,64}   Big-endian twos-complement binary representation.
+  // float,double      Big-endian IEEE-754 format.
+  // char              The raw byte.
+  // bool              A byte. 0 maps to false; all other values map to true.
+  template<typename T>
+  static T Load(const char* p);
+
+  // Encodes 'value' in the format corresponding to T. Supported types are
+  // described in Load<T>(). 'p' has no alignment restrictions. In-place Store
+  // is safe (that is, it is safe to call
+  // Store(x, reinterpret_cast<char*>(&x))).
+  template<typename T>
+  static void Store(T value, char* p);
+};  // BigEndian
+
+// Network byte order is big-endian
+typedef BigEndian NetworkByteOrder;
+
+//////////////////////////////////////////////////////////////////////
+// Implementation details: Clients can stop reading here.
+//
+// Define ValueType->IntType mapping for the unified
+// "IntType FromHost(ValueType)" API. The mapping is implemented via
+// tofromhost_value_type_traits trait struct. Every legal ValueType has its own
+// specialization. There is no default body for this trait struct, so that
+// any type that is not supported by the unified FromHost API
+// will trigger a compile time error.
+#define FROMHOST_TYPE_MAP(ITYPE, VTYPE)        \
+  template <>                                  \
+  struct tofromhost_value_type_traits<VTYPE> { \
+    typedef VTYPE value_type;                  \
+    typedef ITYPE int_type;                    \
+  };
+
+// dd: the extra semi-colons here made it harder to track down other errors with
+// -Wpedantic (because the semi-colon is already defined in the marcro)
+FROMHOST_TYPE_MAP(uint8, uint8)
+FROMHOST_TYPE_MAP(uint8, int8)
+FROMHOST_TYPE_MAP(uint16, uint16)
+FROMHOST_TYPE_MAP(uint16, int16)
+FROMHOST_TYPE_MAP(uint32, uint32)
+FROMHOST_TYPE_MAP(uint32, int32)
+FROMHOST_TYPE_MAP(uint64, uint64)
+FROMHOST_TYPE_MAP(uint64, int64)
+FROMHOST_TYPE_MAP(uint32, float)
+FROMHOST_TYPE_MAP(uint64, double)
+FROMHOST_TYPE_MAP(uint8, bool)
+FROMHOST_TYPE_MAP(absl::uint128, absl::uint128)
+#undef FROMHOST_TYPE_MAP
+
+// Default implementation for the unified FromHost(ValueType) API, which
+// handles all integral types (ValueType is one of uint8, int8, uint16, int16,
+// uint32, int32, uint64, int64). The compiler will remove the switch case
+// branches and unnecessary static_cast, when the template is expanded.
+template <class EndianClass, typename ValueType>
+typename tofromhost_value_type_traits<ValueType>::int_type
+GeneralFormatConverter<EndianClass, ValueType>::FromHost(ValueType v) {
+  switch (sizeof(ValueType)) {
+    case 1:
+      return static_cast<uint8>(v);
+      break;
+    case 2:
+      return EndianClass::FromHost16(static_cast<uint16>(v));
+      break;
+    case 4:
+      return EndianClass::FromHost32(static_cast<uint32>(v));
+      break;
+    case 8:
+      return EndianClass::FromHost64(static_cast<uint64>(v));
+      break;
+    default:
+      S2_LOG(FATAL) << "Unexpected value size: " << sizeof(ValueType);
+  }
+}
+
+// Default implementation for the unified ToHost(ValueType) API, which handles
+// all integral types (ValueType is one of uint8, int8, uint16, int16, uint32,
+// int32, uint64, int64). The compiler will remove the switch case branches and
+// unnecessary static_cast, when the template is expanded.
+template <class EndianClass, typename ValueType>
+typename tofromhost_value_type_traits<ValueType>::int_type
+GeneralFormatConverter<EndianClass, ValueType>::ToHost(ValueType v) {
+  switch (sizeof(ValueType)) {
+    case 1:
+      return static_cast<uint8>(v);
+      break;
+    case 2:
+      return EndianClass::ToHost16(static_cast<uint16>(v));
+      break;
+    case 4:
+      return EndianClass::ToHost32(static_cast<uint32>(v));
+      break;
+    case 8:
+      return EndianClass::ToHost64(static_cast<uint64>(v));
+      break;
+    default:
+      S2_LOG(FATAL) << "Unexpected value size: " << sizeof(ValueType);
+  }
+}
+
+// Specialization of the unified FromHost(ValueType) API, which handles
+// float types (ValueType is float).
+template <class EndianClass>
+class GeneralFormatConverter<EndianClass, float> {
+ public:
+  static typename tofromhost_value_type_traits<float>::int_type FromHost(
+      float v) {
+    return EndianClass::FromHost32(absl::bit_cast<uint32>(v));
+  }
+  static typename tofromhost_value_type_traits<float>::int_type ToHost(
+      float v) {
+    return absl::bit_cast<float>(
+        EndianClass::ToHost32(absl::bit_cast<uint32>(v)));
+  }
+};
+
+// Specialization of the unified FromHost(ValueType) API, which handles
+// double types (ValueType is double).
+template <class EndianClass>
+class GeneralFormatConverter<EndianClass, double> {
+ public:
+  static typename tofromhost_value_type_traits<double>::int_type FromHost(
+      double v) {
+    return EndianClass::FromHost64(absl::bit_cast<uint64>(v));
+  }
+  static typename tofromhost_value_type_traits<double>::int_type ToHost(
+      double v) {
+    return absl::bit_cast<double>(
+        EndianClass::ToHost64(absl::bit_cast<uint64>(v)));
+  }
+};
+
+// Specialization of the unified FromHost(ValueType) API, which handles
+// uint128 types (ValueType is uint128).
+template <class EndianClass>
+class GeneralFormatConverter<EndianClass, absl::uint128> {
+ public:
+  static typename tofromhost_value_type_traits<absl::uint128>::int_type
+  FromHost(absl::uint128 v) {
+    return EndianClass::FromHost128(v);
+  }
+  static typename tofromhost_value_type_traits<absl::uint128>::int_type ToHost(
+      absl::uint128 v) {
+    return EndianClass::ToHost128(v);
+  }
+};
+
+namespace endian_internal {
+// Integer helper methods for the unified Load/Store APIs.
+
+// Which branch of the 'case' to use is decided at compile time, so despite the
+// apparent size of this function, it compiles into efficient code.
+template<typename EndianClass, typename T>
+inline T LoadInteger(const char* p) {
+  static_assert(sizeof(T) <= 8 && std::is_integral<T>::value,
+                "T needs to be an integral type with size <= 8.");
+  switch (sizeof(T)) {
+    case 1: return *reinterpret_cast<const T*>(p);
+    case 2: return EndianClass::ToHost16(UNALIGNED_LOAD16(p));
+    case 4: return EndianClass::ToHost32(UNALIGNED_LOAD32(p));
+    case 8: return EndianClass::ToHost64(UNALIGNED_LOAD64(p));
+    default: {
+      S2_LOG(FATAL) << "Not reached!";
+      return 0;
+    }
+  }
+}
+
+// Which branch of the 'case' to use is decided at compile time, so despite the
+// apparent size of this function, it compiles into efficient code.
+template<typename EndianClass, typename T>
+inline void StoreInteger(T value, char* p) {
+  static_assert(sizeof(T) <= 8 && std::is_integral<T>::value,
+                "T needs to be an integral type with size <= 8.");
+  switch (sizeof(T)) {
+    case 1: *reinterpret_cast<T*>(p) = value; break;
+    case 2: UNALIGNED_STORE16(p, EndianClass::FromHost16(value)); break;
+    case 4: UNALIGNED_STORE32(p, EndianClass::FromHost32(value)); break;
+    case 8: UNALIGNED_STORE64(p, EndianClass::FromHost64(value)); break;
+    default: {
+      S2_LOG(FATAL) << "Not reached!";
+    }
+  }
+}
+
+// Floating point helper methods for the unified Load/Store APIs.
+
+template<typename EndianClass>
+inline float LoadFloat(const char* p) {
+  return absl::bit_cast<float>(EndianClass::ToHost32(UNALIGNED_LOAD32(p)));
+}
+
+template<typename EndianClass>
+inline void StoreFloat(float value, char* p) {
+  UNALIGNED_STORE32(p, EndianClass::FromHost32(absl::bit_cast<uint32>(value)));
+}
+
+template<typename EndianClass>
+inline double LoadDouble(const char* p) {
+  return absl::bit_cast<double>(EndianClass::ToHost64(UNALIGNED_LOAD64(p)));
+}
+
+template<typename EndianClass>
+inline void StoreDouble(double value, char* p) {
+  UNALIGNED_STORE64(p, EndianClass::FromHost64(absl::bit_cast<uint64>(value)));
+}
+
+}  // namespace endian_internal
+
+// Load/Store for integral values.
+
+template<typename T>
+inline T LittleEndian::Load(const char* p) {
+  return endian_internal::LoadInteger<LittleEndian, T>(p);
+}
+
+template<typename T>
+inline void LittleEndian::Store(T value, char* p) {
+  endian_internal::StoreInteger<LittleEndian, T>(value, p);
+}
+
+template<typename T>
+inline T BigEndian::Load(const char* p) {
+  return endian_internal::LoadInteger<BigEndian, T>(p);
+}
+
+template<typename T>
+inline void BigEndian::Store(T value, char* p) {
+  endian_internal::StoreInteger<BigEndian, T>(value, p);
+}
+
+// Load/Store for bool. Sanitizes bool on the way in for safety.
+
+template<>
+inline bool LittleEndian::Load<bool>(const char* p) {
+  static_assert(sizeof(bool) == 1, "Unexpected sizeof(bool)");
+  return *p != 0;
+}
+
+template<>
+inline void LittleEndian::Store<bool>(bool value, char* p) {
+  static_assert(sizeof(bool) == 1, "Unexpected sizeof(bool)");
+  *p = value ? 1 : 0;
+}
+
+template<>
+inline bool BigEndian::Load<bool>(const char* p) {
+  static_assert(sizeof(bool) == 1, "Unexpected sizeof(bool)");
+  return *p != 0;
+}
+
+template<>
+inline void BigEndian::Store<bool>(bool value, char* p) {
+  static_assert(sizeof(bool) == 1, "Unexpected sizeof(bool)");
+  *p = value ? 1 : 0;
+}
+
+// Load/Store for float.
+
+template<>
+inline float LittleEndian::Load<float>(const char* p) {
+  return endian_internal::LoadFloat<LittleEndian>(p);
+}
+
+template<>
+inline void LittleEndian::Store<float>(float value, char* p) {
+  endian_internal::StoreFloat<LittleEndian>(value, p);
+}
+
+template<>
+inline float BigEndian::Load<float>(const char* p) {
+  return endian_internal::LoadFloat<BigEndian>(p);
+}
+
+template<>
+inline void BigEndian::Store<float>(float value, char* p) {
+  endian_internal::StoreFloat<BigEndian>(value, p);
+}
+
+// Load/Store for double.
+
+template<>
+inline double LittleEndian::Load<double>(const char* p) {
+  return endian_internal::LoadDouble<LittleEndian>(p);
+}
+
+template<>
+inline void LittleEndian::Store<double>(double value, char* p) {
+  endian_internal::StoreDouble<LittleEndian>(value, p);
+}
+
+template<>
+inline double BigEndian::Load<double>(const char* p) {
+  return endian_internal::LoadDouble<BigEndian>(p);
+}
+
+template<>
+inline void BigEndian::Store<double>(double value, char* p) {
+  endian_internal::StoreDouble<BigEndian>(value, p);
+}
+
+// Load/Store for uint128.
+
+template <>
+inline absl::uint128 LittleEndian::Load<absl::uint128>(const char* p) {
+  return LittleEndian::Load128(p);
+}
+
+template <>
+inline void LittleEndian::Store<absl::uint128>(absl::uint128 value, char* p) {
+  LittleEndian::Store128(p, value);
+}
+
+template <>
+inline absl::uint128 BigEndian::Load<absl::uint128>(const char* p) {
+  return BigEndian::Load128(p);
+}
+
+template <>
+inline void BigEndian::Store<absl::uint128>(absl::uint128 value, char* p) {
+  BigEndian::Store128(p, value);
+}
+
+#endif  // S2_UTIL_ENDIAN_ENDIAN_H_
diff --git a/src/s2/util/gtl/btree.h b/src/s2/util/gtl/btree.h
new file mode 100644 (file)
index 0000000..e63f216
--- /dev/null
@@ -0,0 +1,2471 @@
+// Copyright 2007 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+//
+// A btree implementation of the STL set and map interfaces. A btree is smaller
+// and generally also faster than STL set/map (refer to the benchmarks below).
+// The red-black tree implementation of STL set/map has an overhead of 3
+// pointers (left, right and parent) plus the node color information for each
+// stored value. So a set<int32> consumes 40 bytes for each value stored in
+// 64-bit mode. This btree implementation stores multiple values on fixed
+// size nodes (usually 256 bytes) and doesn't store child pointers for leaf
+// nodes. The result is that a btree_set<int32> may use much less memory per
+// stored value. For the random insertion benchmark in btree_bench.cc, a
+// btree_set<int32> with node-size of 256 uses 5.1 bytes per stored value.
+//
+// The packing of multiple values on to each node of a btree has another effect
+// besides better space utilization: better cache locality due to fewer cache
+// lines being accessed. Better cache locality translates into faster
+// operations.
+//
+// CAVEATS
+//
+// Insertions and deletions on a btree can cause splitting, merging or
+// rebalancing of btree nodes. And even without these operations, insertions
+// and deletions on a btree will move values around within a node. In both
+// cases, the result is that insertions and deletions can invalidate iterators
+// pointing to values other than the one being inserted/deleted. Therefore, this
+// container does not provide pointer stability. This is notably different from
+// STL set/map which takes care to not invalidate iterators on insert/erase
+// except, of course, for iterators pointing to the value being erased.  A
+// partial workaround when erasing is available: erase() returns an iterator
+// pointing to the item just after the one that was erased (or end() if none
+// exists).
+
+// PERFORMANCE
+//
+// See the latest benchmark results at:
+// https://paste.googleplex.com/5549632792821760
+//
+
+#ifndef S2_UTIL_GTL_BTREE_H_
+#define S2_UTIL_GTL_BTREE_H_
+
+#include <cstddef>
+#include <cstring>
+#include <algorithm>
+#include <cassert>
+#include <functional>
+#include <iterator>
+#include <limits>
+#include <new>
+#include <string>
+#include <type_traits>
+#include <utility>
+
+#include "s2/base/integral_types.h"
+#include "absl/base/macros.h"
+#include "absl/container/internal/compressed_tuple.h"
+#include "absl/container/internal/container_memory.h"
+#include "absl/memory/memory.h"
+#include "absl/meta/type_traits.h"
+#include "absl/strings/string_view.h"
+#include "absl/utility/utility.h"
+#include "s2/util/gtl/layout.h"
+
+namespace gtl {
+
+// A helper type used to indicate that a key-compare-to functor has been
+// provided. A key-compare-to functor compares two arguments of type value_type
+// and returns 0 if they are equal, a negative integer when the first argument
+// should be first, and a positive integer otherwise. A user can specify a
+// key-compare-to functor by doing:
+//
+//  struct MyStringComparer
+//      : public gtl::btree_key_compare_to_tag {
+//    int operator()(const string &a, const string &b) const {
+//      return a.compare(b);
+//    }
+//  };
+//
+// Note that the return type is an int and not a bool. There is a
+// static_assert which enforces this return type.
+// TODO(user): get rid of this tag and just detect whether there is an operator
+struct btree_key_compare_to_tag {};
+
+// A helper class that indicates if the Compare parameter is derived from
+// btree_key_compare_to_tag.
+template <typename Compare>
+using btree_is_key_compare_to =
+    std::is_convertible<Compare, btree_key_compare_to_tag>;
+
+namespace internal_btree {
+// A helper class used to indicate if the comparator provided is transparent
+// and thus supports heterogeneous lookups. This is only used internally to
+// check if the Compare parameter has a valid is_transparent member.
+// A transparent comparator will see lookup keys with any type (lookup_type)
+// passed by the user to any of the lookup methods. The comparator then has a
+// chance to do the comparison without first converting the lookup key to a
+// key_type.
+//
+// For example, a comparator that is transparent may look like:
+//
+//  struct MyStringComparer {
+//    bool operator()(const string &a, const string &b) const {
+//      return a < b;
+//    }
+//    bool operator()(const string &a, const char* b) const {
+//      return strcmp(a.c_str(), b) < 0;
+//    }
+//    bool operator()(const char* a, const string& b) const {
+//      return strcmp(a, b.c_str()) < 0;
+//    }
+//    using is_transparent = void;
+//  };
+//
+// Note that we need to declare operator() for both combinations of key_type and
+// lookup_type. Also note that setting is_transparent to void is an arbitrary
+// decision; it can be std::true_type, int, or anything else, just as long as
+// the member is_transparent is defined to be something.
+template <typename, typename = void>
+struct is_comparator_transparent : std::false_type {};
+template <typename Compare>
+struct is_comparator_transparent<Compare,
+                                 absl::void_t<typename Compare::is_transparent>>
+    : std::true_type {};
+
+// A helper class to convert a boolean comparison into a three-way "compare-to"
+// comparison that returns a negative value to indicate less-than, zero to
+// indicate equality and a positive value to indicate greater-than. This helper
+// class is specialized for less<string>, greater<string>, less<string_view>,
+// and greater<string_view>. The
+// key_compare_to_adapter is provided so that btree users
+// automatically get the more efficient compare-to code when using common
+// google string types with common comparison functors.
+// TODO(user): see if we can extract this logic so that it can be used with
+template <typename Compare>
+struct key_compare_to_adapter {
+  using type = Compare;
+};
+
+template <>
+struct key_compare_to_adapter<std::less<std::string>> {
+  struct type : public btree_key_compare_to_tag {
+    type() = default;
+    explicit type(const std::less<std::string> &) {}
+    int operator()(const std::string &a, const std::string &b) const {
+      return a.compare(b);
+    }
+  };
+};
+
+template <>
+struct key_compare_to_adapter<std::greater<std::string>> {
+  struct type : public btree_key_compare_to_tag {
+    type() = default;
+    explicit type(const std::greater<std::string> &) {}
+    int operator()(const std::string &a, const std::string &b) const {
+      return b.compare(a);
+    }
+  };
+};
+
+template <>
+struct key_compare_to_adapter<std::less<absl::string_view>> {
+  struct type : public btree_key_compare_to_tag {
+    type() = default;
+    explicit type(const std::less<absl::string_view> &) {}
+    int operator()(const absl::string_view a, const absl::string_view b) const {
+      return a.compare(b);
+    }
+  };
+};
+
+template <>
+struct key_compare_to_adapter<std::greater<absl::string_view>> {
+  struct type : public btree_key_compare_to_tag {
+    type() = default;
+    explicit type(const std::greater<absl::string_view> &) {}
+    int operator()(const absl::string_view a, const absl::string_view b) const {
+      return b.compare(a);
+    }
+  };
+};
+
+
+// A helper function to do a boolean comparison of two keys given a boolean
+// or key-compare-to (three-way) comparator.
+template <typename K, typename LK, typename Compare>
+bool bool_compare_keys(const Compare &comp, const K &x, const LK &y) {
+  return btree_is_key_compare_to<Compare>::value ? comp(x, y) < 0 : comp(x, y);
+}
+
+// Detects a 'absl_btree_prefer_linear_node_search' member. This is
+// a protocol used as an opt-in or opt-out of linear search.
+//
+//  For example, this would be useful for key types that wrap an integer
+//  and define their own cheap operator<(). For example:
+//
+//   class K {
+//    public:
+//     using absl_btree_prefer_linear_node_search = std::true_type;
+//     ...
+//    private:
+//     friend bool operator<(K a, K b) { return a.k_ < b.k_; }
+//     int k_;
+//   };
+//
+//   btree_map<K, V> m;  // Uses linear search
+//   assert((btree_map<K, V>::testonly_uses_linear_node_search()));
+//
+// If T has the preference tag, then it has a preference.
+// Btree will use the tag's truth value.
+template <typename T, typename = void>
+struct has_linear_node_search_preference : std::false_type {};
+template <typename T, typename = void>
+struct prefers_linear_node_search : std::false_type {};
+template <typename T>
+struct has_linear_node_search_preference<
+    T, absl::void_t<typename T::absl_btree_prefer_linear_node_search>>
+    : std::true_type {};
+template <typename T>
+struct prefers_linear_node_search<
+    T, absl::void_t<typename T::absl_btree_prefer_linear_node_search>>
+    : T::absl_btree_prefer_linear_node_search {};
+
+template <typename Key, typename Compare, typename Alloc, int TargetNodeSize,
+          int ValueSize, bool Multi>
+struct common_params {
+  // If Compare is derived from btree_key_compare_to_tag then use it as the
+  // key_compare type. Otherwise, use key_compare_to_adapter<> which will
+  // fall-back to Compare if we don't have an appropriate specialization.
+  using key_compare =
+      absl::conditional_t<btree_is_key_compare_to<Compare>::value, Compare,
+                          typename key_compare_to_adapter<Compare>::type>;
+  // A type which indicates if we have a key-compare-to functor or a plain old
+  // key-compare functor.
+  using is_key_compare_to = btree_is_key_compare_to<key_compare>;
+
+  using allocator_type = Alloc;
+  using key_type = Key;
+  using size_type = std::make_signed<size_t>::type;
+  using difference_type = ptrdiff_t;
+
+  // True if this is a multiset or multimap.
+  using is_multi_container = std::integral_constant<bool, Multi>;
+
+  enum {
+    kTargetNodeSize = TargetNodeSize,
+
+    // Upper bound for the available space for values. This is largest for leaf
+    // nodes, which have overhead of at least a pointer + 4 bytes (for storing
+    // 3 field_types and an enum).
+    kNodeValueSpace =
+        TargetNodeSize - /*minimum overhead=*/(sizeof(void *) + 4),
+  };
+
+  // This is an integral type large enough to hold as many
+  // ValueSize-values as will fit a node of TargetNodeSize bytes.
+  using node_count_type =
+      absl::conditional_t<(kNodeValueSpace / ValueSize >
+                           std::numeric_limits<uint8>::max()),
+                          uint16, uint8>;  // NOLINT
+  static_assert(kNodeValueSpace / ValueSize <=
+                    std::numeric_limits<uint16>::max(),
+                "uint16 is not big enough for node_count_type.");
+};
+
+// A parameters structure for holding the type parameters for a btree_map.
+// Compare and Alloc should be nothrow copy-constructible.
+template <typename Key, typename Data, typename Compare, typename Alloc,
+          int TargetNodeSize, bool Multi>
+struct map_params : common_params<Key, Compare, Alloc, TargetNodeSize,
+                                  sizeof(std::pair<const Key, Data>), Multi> {
+  using mapped_type = Data;
+  // This type allows us to move keys when it is safe to do so. It is safe
+  // for maps in which value_type and mutable_value_type are layout compatible.
+  using slot_type = absl::container_internal::slot_type<Key, mapped_type>;
+  using value_type = typename slot_type::value_type;
+  using mutable_value_type = typename slot_type::mutable_value_type;
+  using pointer = value_type *;
+  using const_pointer = const value_type *;
+  using reference = value_type &;
+  using const_reference = const value_type &;
+
+  using key_compare = typename map_params::common_params::key_compare;
+  // Inherit from key_compare for empty base class optimization.
+  struct value_compare : private key_compare {
+    value_compare() = default;
+    explicit value_compare(const key_compare &cmp) : key_compare(cmp) {}
+
+    template <typename T, typename U>
+    absl::conditional_t<btree_is_key_compare_to<key_compare>::value, int, bool>
+    operator()(const T &left, const U &right) const {
+      return key_compare::operator()(left.first, right.first);
+    }
+  };
+
+  static const Key& key(const value_type &x) { return x.first; }
+  static const Key& key(const mutable_value_type &x) { return x.first; }
+};
+
+// A parameters structure for holding the type parameters for a btree_set.
+// Compare and Alloc should be nothrow copy-constructible.
+template <typename Key, typename Compare, typename Alloc, int TargetNodeSize,
+          bool Multi>
+struct set_params
+    : common_params<Key, Compare, Alloc, TargetNodeSize, sizeof(Key), Multi> {
+  using mapped_type = void;
+  using value_type = Key;
+  using mutable_value_type = Key;
+  // This type implements the necessary functions from the
+  // absl::container_internal::slot_type interface.
+  struct slot_type {
+    value_type value;
+
+    template <class... Args>
+    static void construct(Alloc *alloc, slot_type *slot, Args &&... args) {
+      absl::allocator_traits<Alloc>::construct(*alloc, &slot->value,
+                                               std::forward<Args>(args)...);
+    }
+
+    static void construct(Alloc *alloc, slot_type *slot, slot_type *other) {
+      absl::allocator_traits<Alloc>::construct(*alloc, &slot->value,
+                                               std::move(other->value));
+    }
+
+    static void destroy(Alloc *alloc, slot_type *slot) {
+      absl::allocator_traits<Alloc>::destroy(*alloc, &slot->value);
+    }
+
+    static void swap(Alloc * /*alloc*/, slot_type *a, slot_type *b) {
+      using std::swap;
+      swap(a->value, b->value);
+    }
+
+    static void move(Alloc * /*alloc*/, slot_type *src, slot_type *dest) {
+      dest->value = std::move(src->value);
+    }
+
+    static void move(Alloc *alloc, slot_type *first, slot_type *last,
+                     slot_type *result) {
+      for (slot_type *src = first, *dest = result; src != last; ++src, ++dest)
+        move(alloc, src, dest);
+    }
+  };
+  using pointer = value_type *;
+  using const_pointer = const value_type *;
+  using reference = value_type &;
+  using const_reference = const value_type &;
+  using value_compare = typename set_params::common_params::key_compare;
+
+  static const Key& key(const value_type &x) { return x; }
+};
+
+// An adapter class that converts a lower-bound compare into an upper-bound
+// compare. Note: there is no need to make a version of this adapter specialized
+// for key-compare-to functors because the upper-bound (the first value greater
+// than the input) is never an exact match.
+template <typename Compare>
+struct upper_bound_adapter {
+  explicit upper_bound_adapter(const Compare &c) : comp(c) {}
+  template <typename K, typename LK>
+  bool operator()(const K &a, const LK &b) const {
+    // Returns true when a is not greater than b.
+    return !bool_compare_keys(comp, b, a);
+  }
+
+ private:
+  Compare comp;
+};
+
+// A node in the btree holding. The same node type is used for both internal
+// and leaf nodes in the btree, though the nodes are allocated in such a way
+// that the children array is only valid in internal nodes.
+template <typename Params>
+class btree_node {
+  using is_key_compare_to = typename Params::is_key_compare_to;
+  using is_multi_container = typename Params::is_multi_container;
+  using field_type = typename Params::node_count_type;
+  using allocator_type = typename Params::allocator_type;
+  using slot_type = typename Params::slot_type;
+
+ public:
+  using params_type = Params;
+  using key_type = typename Params::key_type;
+  using value_type = typename Params::value_type;
+  using mutable_value_type = typename Params::mutable_value_type;
+  using pointer = typename Params::pointer;
+  using const_pointer = typename Params::const_pointer;
+  using reference = typename Params::reference;
+  using const_reference = typename Params::const_reference;
+  using key_compare = typename Params::key_compare;
+  using size_type = typename Params::size_type;
+  using difference_type = typename Params::difference_type;
+
+  // Btree's choice of binary search or linear search is a customization
+  // point that can be configured via the key_compare and key_type.
+  // Btree decides whether to use linear node search as follows:
+  //   - If the comparator expresses a preference, use that.
+  //   - Otherwise, if the key expresses a preference, use that.
+  //   - Otherwise, if the key is arithmetic and the comparator is std::less or
+  //     std::greater, choose linear.
+  //   - Otherwise, choose binary.
+  // See documentation for has_linear_node_search_preference and
+  // prefers_linear_node_search above.
+  // Might be wise to also configure linear search based on node-size.
+  using use_linear_search = absl::conditional_t<
+      has_linear_node_search_preference<key_compare>::value
+          ? prefers_linear_node_search<key_compare>::value
+          : has_linear_node_search_preference<key_type>::value
+                ? prefers_linear_node_search<key_type>::value
+                : std::is_arithmetic<key_type>::value &&
+                      (std::is_same<std::less<key_type>, key_compare>::value ||
+                       std::is_same<std::greater<key_type>,
+                                    key_compare>::value),
+      std::true_type, std::false_type>;
+
+  // This class is organized by gtl::Layout as if it had the following
+  // structure:
+  //   // A pointer to the node's parent.
+  //   btree_node *parent;
+  //
+  //   // The position of the node in the node's parent.
+  //   field_type position;
+  //   // The index of the first populated value in `values`.
+  //   // TODO(user): right now, `start` is always 0. Update insertion/merge
+  //   // logic to allow for floating storage within nodes.
+  //   field_type start;
+  //   // The count of the number of populated values in the node.
+  //   field_type count;
+  //   // The maximum number of values the node can hold. This is an integer in
+  //   // [1, kNodeValues] for root leaf nodes, kNodeValues for non-root leaf
+  //   // nodes, and kInternalNodeMaxCount (as a sentinel value) for internal
+  //   // nodes (even though there are still kNodeValues values in the node).
+  //   // TODO(user): make max_count use only 4 bits and record log2(capacity)
+  //   // to free extra bits for is_root, etc.
+  //   field_type max_count;
+  //
+  //   // The array of values. The capacity is `max_count` for leaf nodes and
+  //   // kNodeValues for internal nodes. Only the values in
+  //   // [start, start + count) have been initialized and are valid.
+  //   slot_type values[max_count];
+  //
+  //   // The array of child pointers. The keys in children[i] are all less
+  //   // than key(i). The keys in children[i + 1] are all greater than key(i).
+  //   // There are 0 children for leaf nodes and kNodeValues + 1 children for
+  //   // internal nodes.
+  //   btree_node *children[kNodeValues + 1];
+  //
+  // This class is never constructed or deleted. Instead, pointers to the layout
+  // above are allocated, cast to btree_node*, and de-allocated within the btree
+  // implementation.
+  btree_node() = delete;
+  ~btree_node() = delete;
+  btree_node(btree_node const &) = delete;
+  btree_node &operator=(btree_node const &) = delete;
+
+ private:
+  using layout_type = Layout<btree_node *, field_type, slot_type, btree_node *>;
+  constexpr static size_type SizeWithNValues(size_type n) {
+    return layout_type(/*parent*/ 1,
+                       /*position, start, count, max_count*/ 4,
+                       /*values*/ n,
+                       /*children*/ 0)
+        .AllocSize();
+  }
+  // A lower bound for the overhead of fields other than values in a leaf node.
+  constexpr static size_type MinimumOverhead() {
+    return SizeWithNValues(1) - sizeof(value_type);
+  }
+
+  // Compute how many values we can fit onto a leaf node taking into account
+  // padding.
+  constexpr static size_type NodeTargetValues(const int begin, const int end) {
+    return begin == end ? begin
+                        : SizeWithNValues((begin + end) / 2 + 1) >
+                                  params_type::kTargetNodeSize
+                              ? NodeTargetValues(begin, (begin + end) / 2)
+                              : NodeTargetValues((begin + end) / 2 + 1, end);
+  }
+
+  enum {
+    kTargetNodeSize = params_type::kTargetNodeSize,
+    kNodeTargetValues = NodeTargetValues(0, params_type::kTargetNodeSize),
+
+    // We need a minimum of 3 values per internal node in order to perform
+    // splitting (1 value for the two nodes involved in the split and 1 value
+    // propagated to the parent as the delimiter for the split).
+    kNodeValues = kNodeTargetValues >= 3 ? kNodeTargetValues : 3,
+
+    kExactMatch = 1 << 30,
+    kMatchMask = kExactMatch - 1,
+
+    // The node is internal (i.e. is not a leaf node) if and only if `max_count`
+    // has this value.
+    kInternalNodeMaxCount = 0,
+  };
+
+  // Leaves can have less than kNodeValues values.
+  constexpr static layout_type LeafLayout(const int max_values = kNodeValues) {
+    return layout_type(/*parent*/ 1,
+                       /*position, start, count, max_count*/ 4,
+                       /*values*/ max_values,
+                       /*children*/ 0);
+  }
+  constexpr static layout_type InternalLayout() {
+    return layout_type(/*parent*/ 1,
+                       /*position, start, count, max_count*/ 4,
+                       /*values*/ kNodeValues,
+                       /*children*/ kNodeValues + 1);
+  }
+  constexpr static size_type LeafSize(const int max_values = kNodeValues) {
+    return LeafLayout(max_values).AllocSize();
+  }
+  constexpr static size_type InternalSize() {
+    return InternalLayout().AllocSize();
+  }
+  constexpr static size_type Alignment() {
+    static_assert(LeafLayout(1).Alignment() == InternalLayout().Alignment(),
+                  "Alignment of all nodes must be equal.");
+    return InternalLayout().Alignment();
+  }
+
+  // N is the index of the type in the Layout definition.
+  // ElementType<N> is the Nth type in the Layout definition.
+  template <size_type N>
+  inline typename layout_type::template ElementType<N> *GetField() {
+    // We assert that we don't read from values that aren't there.
+    assert(N < 3 || !leaf());
+    return InternalLayout().template Pointer<N>(reinterpret_cast<char *>(this));
+  }
+  template <size_type N>
+  inline const typename layout_type::template ElementType<N> *GetField() const {
+    assert(N < 3 || !leaf());
+    return InternalLayout().template Pointer<N>(
+        reinterpret_cast<const char *>(this));
+  }
+  void set_parent(btree_node *p) { *GetField<0>() = p; }
+  field_type &mutable_count() { return GetField<1>()[2]; }
+  slot_type *slot(int i) { return &GetField<2>()[i]; }
+  const slot_type *slot(int i) const { return &GetField<2>()[i]; }
+  void set_position(field_type v) { GetField<1>()[0] = v; }
+  void set_start(field_type v) { GetField<1>()[1] = v; }
+  void set_count(field_type v) { GetField<1>()[2] = v; }
+  // This method is only called by the node init methods.
+  void set_max_count(field_type v) { GetField<1>()[3] = v; }
+
+ public:
+  // Whether this is a leaf node or not. This value doesn't change after the
+  // node is created.
+  bool leaf() const { return GetField<1>()[3] != kInternalNodeMaxCount; }
+
+  // Getter for the position of this node in its parent.
+  field_type position() const { return GetField<1>()[0]; }
+
+  // Getter for the offset of the first value in the `values` array.
+  field_type start() const { return GetField<1>()[1]; }
+
+  // Getters for the number of values stored in this node.
+  field_type count() const { return GetField<1>()[2]; }
+  field_type max_count() const {
+    // Internal nodes have max_count==kInternalNodeMaxCount.
+    // Leaf nodes have max_count in [1, kNodeValues].
+    const field_type max_count = GetField<1>()[3];
+    return max_count == kInternalNodeMaxCount ? kNodeValues : max_count;
+  }
+
+  // Getter for the parent of this node.
+  btree_node *parent() const { return *GetField<0>(); }
+  // Getter for whether the node is the root of the tree. The parent of the
+  // root of the tree is the leftmost node in the tree which is guaranteed to
+  // be a leaf.
+  bool is_root() const { return parent()->leaf(); }
+  void make_root() {
+    assert(parent()->is_root());
+    set_parent(parent()->parent());
+  }
+
+  // Getters for the key/value at position i in the node.
+  const key_type &key(int i) const { return params_type::key(slot(i)->value); }
+  reference value(int i) { return slot(i)->value; }
+  const_reference value(int i) const { return slot(i)->value; }
+
+  // Getters/setter for the child at position i in the node.
+  btree_node *child(int i) const { return GetField<3>()[i]; }
+  btree_node *&mutable_child(int i) { return GetField<3>()[i]; }
+  void clear_child(int i) {
+    absl::container_internal::SanitizerPoisonObject(&mutable_child(i));
+  }
+  void set_child(int i, btree_node *c) {
+    absl::container_internal::SanitizerUnpoisonObject(&mutable_child(i));
+    mutable_child(i) = c;
+    c->set_position(i);
+  }
+  void init_child(int i, btree_node *c) {
+    set_child(i, c);
+    c->set_parent(this);
+  }
+
+  // Returns the position of the first value whose key is not less than k.
+  template <typename K>
+  int lower_bound(const K &k, const key_compare &comp) const {
+    return use_linear_search::value ? linear_search(k, comp)
+                                    : binary_search(k, comp);
+  }
+  // Returns the position of the first value whose key is greater than k.
+  template <typename K>
+  int upper_bound(const K &k, const key_compare &comp) const {
+    auto upper_compare = upper_bound_adapter<key_compare>(comp);
+    return use_linear_search::value ? linear_search(k, upper_compare)
+                                    : binary_search(k, upper_compare);
+  }
+
+  template <typename K, typename Compare>
+  int linear_search(const K &k, const Compare &comp) const {
+    return btree_is_key_compare_to<Compare>::value
+               ? linear_search_compare_to(k, 0, count(), comp)
+               : linear_search_plain_compare(k, 0, count(), comp);
+  }
+
+  template <typename K, typename Compare>
+  int binary_search(const K &k, const Compare &comp) const {
+    return btree_is_key_compare_to<Compare>::value
+               ? binary_search_compare_to(k, 0, count(), comp)
+               : binary_search_plain_compare(k, 0, count(), comp);
+  }
+
+  // Returns the position of the first value whose key is not less than k using
+  // linear search performed using plain compare.
+  template <typename K, typename Compare>
+  int linear_search_plain_compare(const K &k, int s, const int e,
+                                  const Compare &comp) const {
+    while (s < e) {
+      if (!comp(key(s), k)) {
+        break;
+      }
+      ++s;
+    }
+    return s;
+  }
+
+  // Returns the position of the first value whose key is not less than k using
+  // linear search performed using compare-to.
+  template <typename K, typename Compare>
+  int linear_search_compare_to(const K &k, int s, const int e,
+                               const Compare &comp) const {
+    while (s < e) {
+      const int c = comp(key(s), k);
+      if (c == 0) {
+        return s | kExactMatch;
+      } else if (c > 0) {
+        break;
+      }
+      ++s;
+    }
+    return s;
+  }
+
+  // Returns the position of the first value whose key is not less than k using
+  // binary search performed using plain compare.
+  template <typename K, typename Compare>
+  int binary_search_plain_compare(const K &k, int s, int e,
+                                  const Compare &comp) const {
+    while (s != e) {
+      const int mid = (s + e) >> 1;
+      if (comp(key(mid), k)) {
+        s = mid + 1;
+      } else {
+        e = mid;
+      }
+    }
+    return s;
+  }
+
+  // Returns the position of the first value whose key is not less than k using
+  // binary search performed using compare-to.
+  template <typename K, typename CompareTo>
+  int binary_search_compare_to(
+      const K &k, int s, int e, const CompareTo &comp) const {
+    if (is_multi_container::value) {
+      int exact_match = 0;
+      while (s != e) {
+        const int mid = (s + e) >> 1;
+        const int c = comp(key(mid), k);
+        if (c < 0) {
+          s = mid + 1;
+        } else {
+          e = mid;
+          if (c == 0) {
+            // Need to return the first value whose key is not less than k,
+            // which requires continuing the binary search if this is a
+            // multi-container.
+            exact_match = kExactMatch;
+          }
+        }
+      }
+      return s | exact_match;
+    } else {  // Not a multi-container.
+      while (s != e) {
+        const int mid = (s + e) >> 1;
+        const int c = comp(key(mid), k);
+        if (c < 0) {
+          s = mid + 1;
+        } else if (c > 0) {
+          e = mid;
+        } else {
+          return mid | kExactMatch;
+        }
+      }
+      return s;
+    }
+  }
+
+  // Emplaces a value at position i, shifting all existing values and
+  // children at positions >= i to the right by 1.
+  template <typename... Args>
+  void emplace_value(size_type i, allocator_type *alloc, Args &&... args);
+
+  // Removes the value at position i, shifting all existing values and children
+  // at positions > i to the left by 1.
+  void remove_value(int i, allocator_type *alloc);
+
+  // Rebalances a node with its right sibling.
+  void rebalance_right_to_left(int to_move, btree_node *right,
+                               allocator_type *alloc);
+  void rebalance_left_to_right(int to_move, btree_node *right,
+                               allocator_type *alloc);
+
+  // Splits a node, moving a portion of the node's values to its right sibling.
+  void split(int insert_position, btree_node *dest, allocator_type *alloc);
+
+  // Merges a node with its right sibling, moving all of the values and the
+  // delimiting key in the parent node onto itself.
+  void merge(btree_node *sibling, allocator_type *alloc);
+
+  // Swap the contents of "this" and "src".
+  void swap(btree_node *src, allocator_type *alloc);
+
+  // Node allocation/deletion routines.
+  static btree_node *init_leaf(btree_node *n, btree_node *parent,
+                               int max_count) {
+    n->set_parent(parent);
+    n->set_position(0);
+    n->set_start(0);
+    n->set_count(0);
+    n->set_max_count(max_count);
+    absl::container_internal::SanitizerPoisonMemoryRegion(
+        n->slot(0), max_count * sizeof(slot_type));
+    return n;
+  }
+  static btree_node *init_internal(btree_node *n, btree_node *parent) {
+    init_leaf(n, parent, kNodeValues);
+    // Set `max_count` to a sentinel value to indicate that this node is
+    // internal.
+    n->set_max_count(kInternalNodeMaxCount);
+    absl::container_internal::SanitizerPoisonMemoryRegion(
+        &n->mutable_child(0), (kNodeValues + 1) * sizeof(btree_node *));
+    return n;
+  }
+  void destroy(allocator_type *alloc) {
+    for (int i = 0; i < count(); ++i) {
+      value_destroy(i, alloc);
+    }
+  }
+
+ public:
+  // Exposed only for tests.
+  static bool testonly_uses_linear_node_search() {
+    return use_linear_search::value;
+  }
+
+ private:
+  template <typename... Args>
+  void value_init(const size_type i, allocator_type *alloc, Args &&... args) {
+    absl::container_internal::SanitizerUnpoisonObject(slot(i));
+    slot_type::construct(alloc, slot(i), std::forward<Args>(args)...);
+  }
+  void value_destroy(const size_type i, allocator_type *alloc) {
+    slot_type::destroy(alloc, slot(i));
+    absl::container_internal::SanitizerPoisonObject(slot(i));
+  }
+
+  // Move n values starting at value i in this node into the values starting at
+  // value j in node x.
+  void uninitialized_move_n(const size_type n, const size_type i,
+                            const size_type j, btree_node *x,
+                            allocator_type *alloc) {
+    absl::container_internal::SanitizerUnpoisonMemoryRegion(
+        x->slot(j), n * sizeof(slot_type));
+    for (slot_type *src = slot(i), *end = src + n, *dest = x->slot(j);
+         src != end; ++src, ++dest) {
+      slot_type::construct(alloc, dest, src);
+    }
+  }
+
+  // Destroys a range of n values, starting at index i.
+  void value_destroy_n(const size_type i, const size_type n,
+                       allocator_type *alloc) {
+    for (int j = 0; j < n; ++j) {
+      value_destroy(i + j, alloc);
+    }
+  }
+
+  template <typename P>
+  friend class btree;
+  friend class BtreeNodePeer;
+};
+
+template <typename Node, typename Reference, typename Pointer>
+struct btree_iterator {
+ private:
+  using key_type = typename Node::key_type;
+  using size_type = typename Node::size_type;
+  using params_type = typename Node::params_type;
+
+  using node_type = Node;
+  using normal_node = typename std::remove_const<Node>::type;
+  using const_node = const Node;
+  using normal_pointer = typename params_type::pointer;
+  using normal_reference = typename params_type::reference;
+  using const_pointer = typename params_type::const_pointer;
+  using const_reference = typename params_type::const_reference;
+
+  using iterator =
+      btree_iterator<normal_node, normal_reference, normal_pointer>;
+  using const_iterator =
+      btree_iterator<const_node, const_reference, const_pointer>;
+
+ public:
+  // These aliases are public for std::iterator_traits.
+  using difference_type = typename Node::difference_type;
+  using value_type = typename params_type::value_type;
+  using pointer = Pointer;
+  using reference = Reference;
+  using iterator_category = std::bidirectional_iterator_tag;
+
+  btree_iterator() : node(nullptr), position(-1) {}
+  btree_iterator(Node *n, int p) : node(n), position(p) {}
+
+  // NOTE: this SFINAE allows for implicit conversions from iterator to
+  // const_iterator, but it specifically avoids defining copy constructors so
+  // that btree_iterator can be trivially copyable. This is for performance and
+  // binary size reasons.
+  template <
+      typename N, typename R, typename P,
+      absl::enable_if_t<
+          std::is_same<btree_iterator<N, R, P>, iterator>::value &&
+              !std::is_same<btree_iterator<N, R, P>, btree_iterator>::value,
+          int> = 0>
+  btree_iterator(const btree_iterator<N, R, P> &x)  // NOLINT
+      : node(x.node), position(x.position) {}
+
+ private:
+  // Increment/decrement the iterator.
+  void increment() {
+    if (node->leaf() && ++position < node->count()) {
+      return;
+    }
+    increment_slow();
+  }
+  void increment_slow();
+
+  void decrement() {
+    if (node->leaf() && --position >= 0) {
+      return;
+    }
+    decrement_slow();
+  }
+  void decrement_slow();
+
+ public:
+  bool operator==(const const_iterator &x) const {
+    return node == x.node && position == x.position;
+  }
+  bool operator!=(const const_iterator &x) const {
+    return node != x.node || position != x.position;
+  }
+
+  // Accessors for the key/value the iterator is pointing at.
+  reference operator*() const {
+    return node->value(position);
+  }
+  pointer operator->() const {
+    return &node->value(position);
+  }
+
+  btree_iterator& operator++() {
+    increment();
+    return *this;
+  }
+  btree_iterator& operator--() {
+    decrement();
+    return *this;
+  }
+  btree_iterator operator++(int) {
+    btree_iterator tmp = *this;
+    ++*this;
+    return tmp;
+  }
+  btree_iterator operator--(int) {
+    btree_iterator tmp = *this;
+    --*this;
+    return tmp;
+  }
+
+ private:
+  template <typename Params>
+  friend class btree;
+  template <typename N, typename R, typename P>
+  friend struct btree_iterator;
+  template <typename TreeType, typename CheckerType>
+  friend class base_checker;
+
+  const key_type &key() const { return node->key(position); }
+
+  // The node in the tree the iterator is pointing at.
+  Node *node;
+  // The position within the node of the tree the iterator is pointing at.
+  int position;
+};
+
+// Approximation of std::is_trivially_copyable (which is currently unsupported).
+template <typename T>
+using is_trivially_copyable = absl::conjunction<
+    absl::is_trivially_copy_constructible<T>,
+    absl::disjunction<absl::is_trivially_copy_assignable<T>,
+                      absl::negation<std::is_copy_assignable<T>>>,
+    absl::is_trivially_destructible<T>>;
+
+template <typename Params>
+class btree {
+  using node_type = btree_node<Params>;
+  using is_key_compare_to = typename Params::is_key_compare_to;
+
+  template <typename K>
+  using const_lookup_key_reference = absl::conditional_t<
+      is_comparator_transparent<typename Params::key_compare>::value, const K &,
+      const typename Params::key_type &>;
+
+  enum {
+    kNodeValues = node_type::kNodeValues,
+    kMinNodeValues = kNodeValues / 2,
+    kExactMatch = node_type::kExactMatch,
+    kMatchMask = node_type::kMatchMask,
+  };
+
+  struct node_stats {
+    using size_type = typename Params::size_type;
+
+    node_stats(size_type l, size_type i)
+        : leaf_nodes(l),
+          internal_nodes(i) {
+    }
+
+    node_stats& operator+=(const node_stats &x) {
+      leaf_nodes += x.leaf_nodes;
+      internal_nodes += x.internal_nodes;
+      return *this;
+    }
+
+    size_type leaf_nodes;
+    size_type internal_nodes;
+  };
+
+ public:
+  using key_type = typename Params::key_type;
+  using mapped_type = typename Params::mapped_type;
+  using value_type = typename Params::value_type;
+  using size_type = typename Params::size_type;
+  using difference_type = typename Params::difference_type;
+  using key_compare = typename Params::key_compare;
+  using value_compare = typename Params::value_compare;
+  using allocator_type = typename Params::allocator_type;
+  using reference = typename Params::reference;
+  using const_reference = typename Params::const_reference;
+  using pointer = typename Params::pointer;
+  using const_pointer = typename Params::const_pointer;
+  using iterator = btree_iterator<node_type, reference, pointer>;
+  using const_iterator = typename iterator::const_iterator;
+  using reverse_iterator = std::reverse_iterator<iterator>;
+  using const_reverse_iterator = std::reverse_iterator<const_iterator>;
+
+  // Internal types made public for use by btree_container types.
+  using params_type = Params;
+  using mutable_value_type = typename Params::mutable_value_type;
+  using slot_type = typename Params::slot_type;
+
+ private:
+  // Copies the values in x into this btree in their order in x.
+  // This btree must be empty before this method is called.
+  // This method is used in copy construction and copy assignment.
+  void copy_values_in_order(const btree &x);
+
+ public:
+  btree(const key_compare &comp, const allocator_type &alloc);
+
+  btree(const btree &x);
+  btree(btree &&x) noexcept
+      : root_(std::move(x.root_)),
+        rightmost_(absl::exchange(x.rightmost_, nullptr)),
+        size_(absl::exchange(x.size_, 0)) {
+    x.mutable_root() = nullptr;
+  }
+
+  ~btree() {
+    static_assert(std::is_nothrow_copy_constructible<key_compare>::value,
+                  "Key comparison must be nothrow copy constructible");
+    static_assert(std::is_nothrow_copy_constructible<allocator_type>::value,
+                  "Allocator must be nothrow copy constructible");
+    static_assert(is_trivially_copyable<iterator>::value,
+                  "iterator not trivially copyable.");
+    clear();
+  }
+
+  // Assign the contents of x to *this.
+  btree &operator=(const btree &x);
+
+  btree &operator=(btree &&x) noexcept {
+    clear();
+    swap(x);
+    return *this;
+  }
+
+  iterator begin() {
+    return iterator(leftmost(), 0);
+  }
+  const_iterator begin() const {
+    return const_iterator(leftmost(), 0);
+  }
+  iterator end() {
+    return iterator(rightmost_,
+                    rightmost_ != nullptr ? rightmost_->count() : 0);
+  }
+  const_iterator end() const {
+    return const_iterator(rightmost_,
+                          rightmost_ != nullptr ? rightmost_->count() : 0);
+  }
+  reverse_iterator rbegin() {
+    return reverse_iterator(end());
+  }
+  const_reverse_iterator rbegin() const {
+    return const_reverse_iterator(end());
+  }
+  reverse_iterator rend() {
+    return reverse_iterator(begin());
+  }
+  const_reverse_iterator rend() const {
+    return const_reverse_iterator(begin());
+  }
+
+  // Finds the first element whose key is not less than key.
+  template <typename K>
+  iterator lower_bound(const K &key) {
+    return internal_end(
+        internal_lower_bound(key, iterator(root(), 0)));
+  }
+  template <typename K>
+  const_iterator lower_bound(const K &key) const {
+    return internal_end(
+        internal_lower_bound(key, const_iterator(root(), 0)));
+  }
+
+  // Finds the first element whose key is greater than key.
+  template <typename K>
+  iterator upper_bound(const K &key) {
+    return internal_end(
+        internal_upper_bound(key, iterator(root(), 0)));
+  }
+  template <typename K>
+  const_iterator upper_bound(const K &key) const {
+    return internal_end(
+        internal_upper_bound(key, const_iterator(root(), 0)));
+  }
+
+  // Finds the range of values which compare equal to key. The first member of
+  // the returned pair is equal to lower_bound(key). The second member pair of
+  // the pair is equal to upper_bound(key).
+  template <typename K>
+  std::pair<iterator, iterator> equal_range(const K &key) {
+    const_lookup_key_reference<K> lookup_key(key);
+    return std::make_pair(lower_bound(lookup_key), upper_bound(lookup_key));
+  }
+  template <typename K>
+  std::pair<const_iterator, const_iterator> equal_range(const K &key) const {
+    const_lookup_key_reference<K> lookup_key(key);
+    return std::make_pair(lower_bound(lookup_key), upper_bound(lookup_key));
+  }
+
+  // Inserts a value into the btree only if it does not already exist. The
+  // boolean return value indicates whether insertion succeeded or failed.
+  template <typename... Args>
+  std::pair<iterator, bool> insert_unique(const key_type &key, Args &&... args);
+
+  // Insert with hint. Check to see if the value should be placed immediately
+  // before position in the tree. If it does, then the insertion will take
+  // amortized constant time. If not, the insertion will take amortized
+  // logarithmic time as if a call to insert_unique(v) were made.
+  template <typename... Args>
+  iterator insert_hint_unique(iterator position, const key_type &key,
+                              Args &&... args);
+
+  // Insert a range of values into the btree.
+  template <typename InputIterator>
+  void insert_iterator_unique(InputIterator b, InputIterator e);
+
+  // Inserts a value into the btree.
+  template <typename ValueType>
+  iterator insert_multi(const key_type &key, ValueType &&v);
+
+  // Inserts a value into the btree.
+  template <typename ValueType>
+  iterator insert_multi(ValueType &&v) {
+    return insert_multi(params_type::key(v), std::forward<ValueType>(v));
+  }
+
+  // Insert with hint. Check to see if the value should be placed immediately
+  // before position in the tree. If it does, then the insertion will take
+  // amortized constant time. If not, the insertion will take amortized
+  // logarithmic time as if a call to insert_multi(v) were made.
+  template <typename ValueType>
+  iterator insert_hint_multi(iterator position, ValueType &&v);
+
+  // Insert a range of values into the btree.
+  template <typename InputIterator>
+  void insert_iterator_multi(InputIterator b, InputIterator e);
+
+  // Erase the specified iterator from the btree. The iterator must be valid
+  // (i.e. not equal to end()).  Return an iterator pointing to the node after
+  // the one that was erased (or end() if none exists).
+  iterator erase(iterator iter);
+
+  // Erases range. Returns the number of keys erased.
+  int erase(iterator begin, iterator end);
+
+  // Erases the specified key from the btree. Returns 1 if an element was
+  // erased and 0 otherwise.
+  template <typename K>
+  int erase_unique(const K &key);
+
+  // Erases all of the entries matching the specified key from the
+  // btree. Returns the number of elements erased.
+  template <typename K>
+  int erase_multi(const K &key);
+
+  // Finds the iterator corresponding to a key or returns end() if the key is
+  // not present.
+  template <typename K>
+  iterator find_unique(const K &key) {
+    return internal_end(
+        internal_find_unique(key, iterator(root(), 0)));
+  }
+  template <typename K>
+  const_iterator find_unique(const K &key) const {
+    return internal_end(
+        internal_find_unique(key, const_iterator(root(), 0)));
+  }
+  template <typename K>
+  iterator find_multi(const K &key) {
+    return internal_end(
+        internal_find_multi(key, iterator(root(), 0)));
+  }
+  template <typename K>
+  const_iterator find_multi(const K &key) const {
+    return internal_end(
+        internal_find_multi(key, const_iterator(root(), 0)));
+  }
+
+  // Returns a count of the number of times the key appears in the btree.
+  template <typename K>
+  size_type count_unique(const K &key) const {
+    const_iterator begin = internal_find_unique(
+        key, const_iterator(root(), 0));
+    if (!begin.node) {
+      // The key doesn't exist in the tree.
+      return 0;
+    }
+    return 1;
+  }
+  // Returns a count of the number of times the key appears in the btree.
+  template <typename K>
+  size_type count_multi(const K &key) const {
+    const auto range = equal_range(key);
+    return std::distance(range.first, range.second);
+  }
+
+  // Clear the btree, deleting all of the values it contains.
+  void clear();
+
+  // Swap the contents of *this and x.
+  void swap(btree &x);
+
+  const key_compare &key_comp() const noexcept {
+    return root_.template get<0>();
+  }
+  template <typename K, typename LK>
+  bool compare_keys(const K &x, const LK &y) const {
+    return bool_compare_keys(key_comp(), x, y);
+  }
+
+  value_compare value_comp() const { return value_compare(key_comp()); }
+
+  // Verifies the structure of the btree.
+  void verify() const;
+
+  // Size routines.
+  size_type size() const { return size_; }
+  size_type max_size() const { return std::numeric_limits<size_type>::max(); }
+  bool empty() const { return size_ == 0; }
+
+  // The height of the btree. An empty tree will have height 0.
+  size_type height() const {
+    size_type h = 0;
+    if (root()) {
+      // Count the length of the chain from the leftmost node up to the
+      // root. We actually count from the root back around to the level below
+      // the root, but the calculation is the same because of the circularity
+      // of that traversal.
+      const node_type *n = root();
+      do {
+        ++h;
+        n = n->parent();
+      } while (n != root());
+    }
+    return h;
+  }
+
+  // The number of internal, leaf and total nodes used by the btree.
+  size_type leaf_nodes() const {
+    return internal_stats(root()).leaf_nodes;
+  }
+  size_type internal_nodes() const {
+    return internal_stats(root()).internal_nodes;
+  }
+  size_type nodes() const {
+    node_stats stats = internal_stats(root());
+    return stats.leaf_nodes + stats.internal_nodes;
+  }
+
+  // The total number of bytes used by the btree.
+  size_type bytes_used() const {
+    node_stats stats = internal_stats(root());
+    if (stats.leaf_nodes == 1 && stats.internal_nodes == 0) {
+      return sizeof(*this) +
+             node_type::LeafSize(root()->max_count());
+    } else {
+      return sizeof(*this) +
+             stats.leaf_nodes * node_type::LeafSize() +
+             stats.internal_nodes * node_type::InternalSize();
+    }
+  }
+
+  // The average number of bytes used per value stored in the btree.
+  static double average_bytes_per_value() {
+    // Returns the number of bytes per value on a leaf node that is 75%
+    // full. Experimentally, this matches up nicely with the computed number of
+    // bytes per value in trees that had their values inserted in random order.
+    return node_type::LeafSize() / (kNodeValues * 0.75);
+  }
+
+  // The fullness of the btree. Computed as the number of elements in the btree
+  // divided by the maximum number of elements a tree with the current number
+  // of nodes could hold. A value of 1 indicates perfect space
+  // utilization. Smaller values indicate space wastage.
+  double fullness() const {
+    return static_cast<double>(size()) / (nodes() * kNodeValues);
+  }
+  // The overhead of the btree structure in bytes per node. Computed as the
+  // total number of bytes used by the btree minus the number of bytes used for
+  // storing elements divided by the number of elements.
+  double overhead() const {
+    if (empty()) {
+      return 0.0;
+    }
+    return (bytes_used() - size() * sizeof(value_type)) /
+           static_cast<double>(size());
+  }
+
+  // The allocator used by the btree.
+  allocator_type get_allocator() const {
+    return allocator();
+  }
+
+ private:
+  // Internal accessor routines.
+  node_type *root() { return root_.template get<2>(); }
+  const node_type *root() const { return root_.template get<2>(); }
+  node_type *&mutable_root() noexcept { return root_.template get<2>(); }
+  key_compare *mutable_key_comp() noexcept { return &root_.template get<0>(); }
+
+  // The leftmost node is stored as the parent of the root node.
+  node_type *leftmost() { return root() ? root()->parent() : nullptr; }
+  const node_type *leftmost() const {
+    return root() ? root()->parent() : nullptr;
+  }
+
+  // Allocator routines.
+  allocator_type *mutable_allocator() noexcept {
+    return &root_.template get<1>();
+  }
+  const allocator_type &allocator() const noexcept {
+    return root_.template get<1>();
+  }
+
+  // Allocates a correctly aligned node of at least size bytes using the
+  // allocator.
+  node_type *allocate(const size_type size) {
+    return reinterpret_cast<node_type *>(
+        absl::container_internal::Allocate<node_type::Alignment()>(
+            mutable_allocator(), size));
+  }
+
+  // Node creation/deletion routines.
+  node_type* new_internal_node(node_type *parent) {
+    node_type *p = allocate(node_type::InternalSize());
+    return node_type::init_internal(p, parent);
+  }
+  node_type* new_leaf_node(node_type *parent) {
+    node_type *p = allocate(node_type::LeafSize());
+    return node_type::init_leaf(p, parent, kNodeValues);
+  }
+  node_type *new_leaf_root_node(const int max_count) {
+    node_type *p = allocate(node_type::LeafSize(max_count));
+    return node_type::init_leaf(p, p, max_count);
+  }
+
+  // Deallocates a node of a certain size in bytes using the allocator.
+  void deallocate(const size_type size, node_type *node) {
+    absl::container_internal::Deallocate<node_type::Alignment()>(
+        mutable_allocator(), node, size);
+  }
+
+  void delete_internal_node(node_type *node) {
+    node->destroy(mutable_allocator());
+    deallocate(node_type::InternalSize(), node);
+  }
+  void delete_leaf_node(node_type *node) {
+    node->destroy(mutable_allocator());
+    deallocate(node_type::LeafSize(node->max_count()), node);
+  }
+
+  // Rebalances or splits the node iter points to.
+  void rebalance_or_split(iterator *iter);
+
+  // Merges the values of left, right and the delimiting key on their parent
+  // onto left, removing the delimiting key and deleting right.
+  void merge_nodes(node_type *left, node_type *right);
+
+  // Tries to merge node with its left or right sibling, and failing that,
+  // rebalance with its left or right sibling. Returns true if a merge
+  // occurred, at which point it is no longer valid to access node. Returns
+  // false if no merging took place.
+  bool try_merge_or_rebalance(iterator *iter);
+
+  // Tries to shrink the height of the tree by 1.
+  void try_shrink();
+
+  iterator internal_end(iterator iter) {
+    return iter.node ? iter : end();
+  }
+  const_iterator internal_end(const_iterator iter) const {
+    return iter.node ? iter : end();
+  }
+
+  // Emplaces a value into the btree immediately before iter. Requires that
+  // key(v) <= iter.key() and (--iter).key() <= key(v).
+  template <typename... Args>
+  iterator internal_emplace(iterator iter, Args &&... args);
+
+  // Returns an iterator pointing to the first value >= the value "iter" is
+  // pointing at. Note that "iter" might be pointing to an invalid location as
+  // iter.position == iter.node->count(). This routine simply moves iter up in
+  // the tree to a valid location.
+  template <typename IterType>
+  static IterType internal_last(IterType iter);
+
+  // Returns an iterator pointing to the leaf position at which key would
+  // reside in the tree. We provide 2 versions of internal_locate. The first
+  // version (internal_locate_plain_compare) always returns 0 for the second
+  // field of the pair. The second version (internal_locate_compare_to) is for
+  // the key-compare-to specialization and returns either kExactMatch (if the
+  // key was found in the tree) or -kExactMatch (if it wasn't) in the second
+  // field of the pair. The compare_to specialization allows the caller to
+  // avoid a subsequent comparison to determine if an exact match was made,
+  // speeding up string, cord and string_view keys.
+  template <typename K, typename IterType>
+  std::pair<IterType, int> internal_locate(
+      const K &key, IterType iter) const;
+  template <typename K, typename IterType>
+  std::pair<IterType, int> internal_locate_plain_compare(
+      const K &key, IterType iter) const;
+  template <typename K, typename IterType>
+  std::pair<IterType, int> internal_locate_compare_to(
+      const K &key, IterType iter) const;
+
+  // Internal routine which implements lower_bound().
+  template <typename K, typename IterType>
+  IterType internal_lower_bound(
+      const K &key, IterType iter) const;
+
+  // Internal routine which implements upper_bound().
+  template <typename K, typename IterType>
+  IterType internal_upper_bound(
+      const K &key, IterType iter) const;
+
+  // Internal routine which implements find_unique().
+  template <typename K, typename IterType>
+  IterType internal_find_unique(
+      const K &key, IterType iter) const;
+
+  // Internal routine which implements find_multi().
+  template <typename K, typename IterType>
+  IterType internal_find_multi(
+      const K &key, IterType iter) const;
+
+  // Deletes a node and all of its children.
+  void internal_clear(node_type *node);
+
+  // Verifies the tree structure of node.
+  int internal_verify(const node_type *node,
+                      const key_type *lo, const key_type *hi) const;
+
+  node_stats internal_stats(const node_type *node) const {
+    if (!node) {
+      return node_stats(0, 0);
+    }
+    if (node->leaf()) {
+      return node_stats(1, 0);
+    }
+    node_stats res(0, 1);
+    for (int i = 0; i <= node->count(); ++i) {
+      res += internal_stats(node->child(i));
+    }
+    return res;
+  }
+
+ public:
+  // Exposed only for tests.
+  static bool testonly_uses_linear_node_search() {
+    return node_type::testonly_uses_linear_node_search();
+  }
+
+ private:
+  // We use compressed tuple in order to save space because key_compare and
+  // allocator_type are usually empty.
+  absl::container_internal::CompressedTuple<key_compare, allocator_type,
+                                            node_type *>
+      root_;
+
+  // A pointer to the rightmost node. Note that the leftmost node is stored as
+  // the root's parent.
+  node_type *rightmost_;
+
+  // Number of values.
+  size_type size_;
+
+  // Verify that key_compare returns an int or bool, as appropriate
+  // depending on the value of is_key_compare_to.
+  static_assert(std::is_same<absl::result_of_t<key_compare(key_type, key_type)>,
+                             absl::conditional_t<is_key_compare_to::value, int,
+                                                 bool>>::value,
+                "key comparison function must return bool");
+
+  // Note: We assert that kTargetValues, which is computed from
+  // Params::kTargetNodeSize, must fit the node_type::field_type.
+  static_assert(kNodeValues <
+                    (1 << (8 * sizeof(typename node_type::field_type))),
+                "target node size too large");
+
+  // Test the assumption made in setting kNodeValueSpace.
+  static_assert(node_type::MinimumOverhead() >= sizeof(void *) + 4,
+                "node space assumption incorrect");
+};
+
+////
+// btree_node methods
+template <typename P>
+template <typename... Args>
+inline void btree_node<P>::emplace_value(const size_type i,
+                                         allocator_type *alloc,
+                                         Args &&... args) {
+  assert(i <= count());
+  // Shift old values to create space for new value and then construct it in
+  // place.
+  if (i < count()) {
+    value_init(count(), alloc, slot(count() - 1));
+    for (size_type j = count() - 1; j > i; --j)
+      slot_type::move(alloc, slot(j - 1), slot(j));
+    value_destroy(i, alloc);
+  }
+  value_init(i, alloc, std::forward<Args>(args)...);
+  set_count(count() + 1);
+
+  if (!leaf() && count() > i + 1) {
+    for (int j = count(); j > i + 1; --j) {
+      set_child(j, child(j - 1));
+    }
+    clear_child(i + 1);
+  }
+}
+
+template <typename P>
+inline void btree_node<P>::remove_value(const int i, allocator_type *alloc) {
+  if (!leaf() && count() > i + 1) {
+    assert(child(i + 1)->count() == 0);
+    for (size_type j = i + 1; j < count(); ++j) {
+      set_child(j, child(j + 1));
+    }
+    clear_child(count());
+  }
+
+  slot_type::move(alloc, slot(i + 1), slot(count()), slot(i));
+  value_destroy(count() - 1, alloc);
+  set_count(count() - 1);
+}
+
+template <typename P>
+void btree_node<P>::rebalance_right_to_left(const int to_move,
+                                            btree_node *right,
+                                            allocator_type *alloc) {
+  assert(parent() == right->parent());
+  assert(position() + 1 == right->position());
+  assert(right->count() >= count());
+  assert(to_move >= 1);
+  assert(to_move <= right->count());
+
+  // 1) Move the delimiting value in the parent to the left node.
+  value_init(count(), alloc, parent()->slot(position()));
+
+  // 2) Move the (to_move - 1) values from the right node to the left node.
+  right->uninitialized_move_n(to_move - 1, 0, count() + 1, this, alloc);
+
+  // 3) Move the new delimiting value to the parent from the right node.
+  slot_type::move(alloc, right->slot(to_move - 1), parent()->slot(position()));
+
+  // 4) Shift the values in the right node to their correct position.
+  slot_type::move(alloc, right->slot(to_move), right->slot(right->count()),
+                  right->slot(0));
+
+  // 5) Destroy the now-empty to_move entries in the right node.
+  right->value_destroy_n(right->count() - to_move, to_move, alloc);
+
+  if (!leaf()) {
+    // Move the child pointers from the right to the left node.
+    for (int i = 0; i < to_move; ++i) {
+      init_child(count() + i + 1, right->child(i));
+    }
+    for (int i = 0; i <= right->count() - to_move; ++i) {
+      assert(i + to_move <= right->max_count());
+      right->init_child(i, right->child(i + to_move));
+      right->clear_child(i + to_move);
+    }
+  }
+
+  // Fixup the counts on the left and right nodes.
+  set_count(count() + to_move);
+  right->set_count(right->count() - to_move);
+}
+
+template <typename P>
+void btree_node<P>::rebalance_left_to_right(const int to_move,
+                                            btree_node *right,
+                                            allocator_type *alloc) {
+  assert(parent() == right->parent());
+  assert(position() + 1 == right->position());
+  assert(count() >= right->count());
+  assert(to_move >= 1);
+  assert(to_move <= count());
+
+  // Values in the right node are shifted to the right to make room for the
+  // new to_move values. Then, the delimiting value in the parent and the
+  // other (to_move - 1) values in the left node are moved into the right node.
+  // Lastly, a new delimiting value is moved from the left node into the
+  // parent, and the remaining empty left node entries are destroyed.
+
+  if (right->count() >= to_move) {
+    // The original location of the right->count() values are sufficient to hold
+    // the new to_move entries from the parent and left node.
+
+    // 1) Shift existing values in the right node to their correct positions.
+    right->uninitialized_move_n(to_move, right->count() - to_move,
+                                right->count(), right, alloc);
+    for (slot_type *src = right->slot(right->count() - to_move - 1),
+                   *dest = right->slot(right->count() - 1),
+                   *end = right->slot(0);
+         src >= end; --src, --dest) {
+      slot_type::move(alloc, src, dest);
+    }
+
+    // 2) Move the delimiting value in the parent to the right node.
+    slot_type::move(alloc, parent()->slot(position()),
+                    right->slot(to_move - 1));
+
+    // 3) Move the (to_move - 1) values from the left node to the right node.
+    slot_type::move(alloc, slot(count() - (to_move - 1)), slot(count()),
+                    right->slot(0));
+  } else {
+    // The right node does not have enough initialized space to hold the new
+    // to_move entries, so part of them will move to uninitialized space.
+
+    // 1) Shift existing values in the right node to their correct positions.
+    right->uninitialized_move_n(right->count(), 0, to_move, right, alloc);
+
+    // 2) Move the delimiting value in the parent to the right node.
+    right->value_init(to_move - 1, alloc, parent()->slot(position()));
+
+    // 3) Move the (to_move - 1) values from the left node to the right node.
+    const size_type uninitialized_remaining = to_move - right->count() - 1;
+    uninitialized_move_n(uninitialized_remaining,
+                         count() - uninitialized_remaining, right->count(),
+                         right, alloc);
+    slot_type::move(alloc, slot(count() - (to_move - 1)),
+                    slot(count() - uninitialized_remaining), right->slot(0));
+  }
+
+  // 4) Move the new delimiting value to the parent from the left node.
+  slot_type::move(alloc, slot(count() - to_move), parent()->slot(position()));
+
+  // 5) Destroy the now-empty to_move entries in the left node.
+  value_destroy_n(count() - to_move, to_move, alloc);
+
+  if (!leaf()) {
+    // Move the child pointers from the left to the right node.
+    for (int i = right->count(); i >= 0; --i) {
+      right->init_child(i + to_move, right->child(i));
+      right->clear_child(i);
+    }
+    for (int i = 1; i <= to_move; ++i) {
+      right->init_child(i - 1, child(count() - to_move + i));
+      clear_child(count() - to_move + i);
+    }
+  }
+
+  // Fixup the counts on the left and right nodes.
+  set_count(count() - to_move);
+  right->set_count(right->count() + to_move);
+}
+
+template <typename P>
+void btree_node<P>::split(const int insert_position, btree_node *dest,
+                          allocator_type *alloc) {
+  assert(dest->count() == 0);
+  assert(max_count() == kNodeValues);
+
+  // We bias the split based on the position being inserted. If we're
+  // inserting at the beginning of the left node then bias the split to put
+  // more values on the right node. If we're inserting at the end of the
+  // right node then bias the split to put more values on the left node.
+  if (insert_position == 0) {
+    dest->set_count(count() - 1);
+  } else if (insert_position == kNodeValues) {
+    dest->set_count(0);
+  } else {
+    dest->set_count(count() / 2);
+  }
+  set_count(count() - dest->count());
+  assert(count() >= 1);
+
+  // Move values from the left sibling to the right sibling.
+  uninitialized_move_n(dest->count(), count(), 0, dest, alloc);
+
+  // Destroy the now-empty entries in the left node.
+  value_destroy_n(count(), dest->count(), alloc);
+
+  // The split key is the largest value in the left sibling.
+  set_count(count() - 1);
+  parent()->emplace_value(position(), alloc, slot(count()));
+  value_destroy(count(), alloc);
+  parent()->init_child(position() + 1, dest);
+
+  if (!leaf()) {
+    for (int i = 0; i <= dest->count(); ++i) {
+      assert(child(count() + i + 1) != nullptr);
+      dest->init_child(i, child(count() + i + 1));
+      clear_child(count() + i + 1);
+    }
+  }
+}
+
+template <typename P>
+void btree_node<P>::merge(btree_node *src, allocator_type *alloc) {
+  assert(parent() == src->parent());
+  assert(position() + 1 == src->position());
+
+  // Move the delimiting value to the left node.
+  value_init(count(), alloc, parent()->slot(position()));
+
+  // Move the values from the right to the left node.
+  src->uninitialized_move_n(src->count(), 0, count() + 1, this, alloc);
+
+  // Destroy the now-empty entries in the right node.
+  src->value_destroy_n(0, src->count(), alloc);
+
+  if (!leaf()) {
+    // Move the child pointers from the right to the left node.
+    for (int i = 0; i <= src->count(); ++i) {
+      init_child(count() + i + 1, src->child(i));
+      src->clear_child(i);
+    }
+  }
+
+  // Fixup the counts on the src and dest nodes.
+  set_count(1 + count() + src->count());
+  src->set_count(0);
+
+  // Remove the value on the parent node.
+  parent()->remove_value(position(), alloc);
+}
+
+template <typename P>
+void btree_node<P>::swap(btree_node *x, allocator_type *alloc) {
+  using std::swap;
+  assert(leaf() == x->leaf());
+
+  // Determine which is the smaller/larger node.
+  btree_node *smaller = this, *larger = x;
+  if (smaller->count() > larger->count()) {
+    swap(smaller, larger);
+  }
+
+  // Swap the values.
+  for (slot_type *a = smaller->slot(0), *b = larger->slot(0),
+                 *end = a + smaller->count();
+       a != end; ++a, ++b) {
+    slot_type::swap(alloc, a, b);
+  }
+
+  // Move values that can't be swapped.
+  const size_type to_move = larger->count() - smaller->count();
+  larger->uninitialized_move_n(to_move, smaller->count(), smaller->count(),
+                               smaller, alloc);
+  larger->value_destroy_n(smaller->count(), to_move, alloc);
+
+  if (!leaf()) {
+    // Swap the child pointers.
+    std::swap_ranges(&smaller->mutable_child(0),
+                     &smaller->mutable_child(smaller->count() + 1),
+                     &larger->mutable_child(0));
+    // Update swapped children's parent pointers.
+    int i = 0;
+    for (; i <= smaller->count(); ++i) {
+      smaller->child(i)->set_parent(smaller);
+      larger->child(i)->set_parent(larger);
+    }
+    // Move the child pointers that couldn't be swapped.
+    for (; i <= larger->count(); ++i) {
+      smaller->init_child(i, larger->child(i));
+      larger->clear_child(i);
+    }
+  }
+
+  // Swap the counts.
+  swap(mutable_count(), x->mutable_count());
+}
+
+////
+// btree_iterator methods
+template <typename N, typename R, typename P>
+void btree_iterator<N, R, P>::increment_slow() {
+  if (node->leaf()) {
+    assert(position >= node->count());
+    btree_iterator save(*this);
+    while (position == node->count() && !node->is_root()) {
+      assert(node->parent()->child(node->position()) == node);
+      position = node->position();
+      node = node->parent();
+    }
+    if (position == node->count()) {
+      *this = save;
+    }
+  } else {
+    assert(position < node->count());
+    node = node->child(position + 1);
+    while (!node->leaf()) {
+      node = node->child(0);
+    }
+    position = 0;
+  }
+}
+
+template <typename N, typename R, typename P>
+void btree_iterator<N, R, P>::decrement_slow() {
+  if (node->leaf()) {
+    assert(position <= -1);
+    btree_iterator save(*this);
+    while (position < 0 && !node->is_root()) {
+      assert(node->parent()->child(node->position()) == node);
+      position = node->position() - 1;
+      node = node->parent();
+    }
+    if (position < 0) {
+      *this = save;
+    }
+  } else {
+    assert(position >= 0);
+    node = node->child(position);
+    while (!node->leaf()) {
+      node = node->child(node->count());
+    }
+    position = node->count() - 1;
+  }
+}
+
+////
+// btree methods
+template <typename P>
+void btree<P>::copy_values_in_order(const btree &x) {
+  assert(empty());
+
+  // We can avoid key comparisons because we know the order of the
+  // values is the same order we'll store them in.
+  const_iterator iter = x.begin();
+  if (iter == x.end()) return;
+  insert_multi(*iter);
+  ++iter;
+  for (; iter != x.end(); ++iter) {
+    // If the btree is not empty, we can just insert the new value at the end
+    // of the tree!
+    internal_emplace(end(), *iter);
+  }
+}
+
+template <typename P>
+btree<P>::btree(const key_compare &comp, const allocator_type &alloc)
+    : root_(comp, alloc, nullptr), rightmost_(nullptr), size_(0) {}
+
+template <typename P>
+btree<P>::btree(const btree &x) : btree(x.key_comp(), x.allocator()) {
+  copy_values_in_order(x);
+}
+
+template <typename P>
+template <typename... Args>
+auto btree<P>::insert_unique(const key_type &key, Args &&... args)
+    -> std::pair<iterator, bool> {
+  if (empty()) {
+    mutable_root() = rightmost_ = new_leaf_root_node(1);
+  }
+
+  std::pair<iterator, int> res = internal_locate(key, iterator(root(), 0));
+  iterator &iter = res.first;
+  if (res.second == kExactMatch) {
+    // The key already exists in the tree, do nothing.
+    return std::make_pair(internal_last(iter), false);
+  } else if (!res.second) {
+    iterator last = internal_last(iter);
+    if (last.node && !compare_keys(key, last.key())) {
+      // The key already exists in the tree, do nothing.
+      return std::make_pair(last, false);
+    }
+  }
+
+  return std::make_pair(internal_emplace(iter, std::forward<Args>(args)...),
+                        true);
+}
+
+template <typename P>
+template <typename... Args>
+inline auto btree<P>::insert_hint_unique(iterator position, const key_type &key,
+                                         Args &&... args) -> iterator {
+  if (!empty()) {
+    if (position == end() || compare_keys(key, position.key())) {
+      iterator prev = position;
+      if (position == begin() || compare_keys((--prev).key(), key)) {
+        // prev.key() < key < position.key()
+        return internal_emplace(position, std::forward<Args>(args)...);
+      }
+    } else if (compare_keys(position.key(), key)) {
+      iterator next = position;
+      ++next;
+      if (next == end() || compare_keys(key, next.key())) {
+        // position.key() < key < next.key()
+        return internal_emplace(next, std::forward<Args>(args)...);
+      }
+    } else {
+      // position.key() == key
+      return position;
+    }
+  }
+  return insert_unique(key, std::forward<Args>(args)...).first;
+}
+
+template <typename P>
+template <typename InputIterator>
+void btree<P>::insert_iterator_unique(InputIterator b, InputIterator e) {
+  for (; b != e; ++b) {
+    insert_hint_unique(end(), params_type::key(*b), *b);
+  }
+}
+
+template <typename P>
+template <typename ValueType>
+auto btree<P>::insert_multi(const key_type &key, ValueType &&v) -> iterator {
+  if (empty()) {
+    mutable_root() = rightmost_ = new_leaf_root_node(1);
+  }
+
+  iterator iter = internal_upper_bound(key, iterator(root(), 0));
+  if (!iter.node) {
+    iter = end();
+  }
+  return internal_emplace(iter, std::forward<ValueType>(v));
+}
+
+template <typename P>
+template <typename ValueType>
+auto btree<P>::insert_hint_multi(iterator position, ValueType &&v) -> iterator {
+  if (!empty()) {
+    const key_type &key = params_type::key(v);
+    if (position == end() || !compare_keys(position.key(), key)) {
+      iterator prev = position;
+      if (position == begin() || !compare_keys(key, (--prev).key())) {
+        // prev.key() <= key <= position.key()
+        return internal_emplace(position, std::forward<ValueType>(v));
+      }
+    } else {
+      iterator next = position;
+      ++next;
+      if (next == end() || !compare_keys(next.key(), key)) {
+        // position.key() < key <= next.key()
+        return internal_emplace(next, std::forward<ValueType>(v));
+      }
+    }
+  }
+  return insert_multi(std::forward<ValueType>(v));
+}
+
+template <typename P>
+template <typename InputIterator>
+void btree<P>::insert_iterator_multi(InputIterator b, InputIterator e) {
+  for (; b != e; ++b) {
+    insert_hint_multi(end(), *b);
+  }
+}
+
+template <typename P>
+auto btree<P>::operator=(const btree &x) -> btree & {
+  if (this != &x) {
+    clear();
+
+    *mutable_key_comp() = x.key_comp();
+    *mutable_allocator() = x.allocator();
+
+    copy_values_in_order(x);
+  }
+  return *this;
+}
+
+template <typename P>
+auto btree<P>::erase(iterator iter) -> iterator {
+  bool internal_delete = false;
+  if (!iter.node->leaf()) {
+    // Deletion of a value on an internal node. First, move the largest value
+    // from our left child here, then delete that position (in remove_value()
+    // below). We can get to the largest value from our left child by
+    // decrementing iter.
+    iterator internal_iter(iter);
+    --iter;
+    assert(iter.node->leaf());
+    assert(!compare_keys(internal_iter.key(), iter.key()));
+    slot_type::move(mutable_allocator(), iter.node->slot(iter.position),
+                    internal_iter.node->slot(internal_iter.position));
+    internal_delete = true;
+  }
+
+  // Delete the key from the leaf.
+  iter.node->remove_value(iter.position, mutable_allocator());
+  --size_;
+
+  // We want to return the next value after the one we just erased. If we
+  // erased from an internal node (internal_delete == true), then the next
+  // value is ++(++iter). If we erased from a leaf node (internal_delete ==
+  // false) then the next value is ++iter. Note that ++iter may point to an
+  // internal node and the value in the internal node may move to a leaf node
+  // (iter.node) when rebalancing is performed at the leaf level.
+
+  // Merge/rebalance as we walk back up the tree.
+  iterator res(iter);
+  for (;;) {
+    if (iter.node == root()) {
+      try_shrink();
+      if (empty()) {
+        return end();
+      }
+      break;
+    }
+    if (iter.node->count() >= kMinNodeValues) {
+      break;
+    }
+    bool merged = try_merge_or_rebalance(&iter);
+    if (iter.node->leaf()) {
+      res = iter;
+    }
+    if (!merged) {
+      break;
+    }
+    iter.node = iter.node->parent();
+  }
+
+  // Adjust our return value. If we're pointing at the end of a node, advance
+  // the iterator.
+  if (res.position == res.node->count()) {
+    res.position = res.node->count() - 1;
+    ++res;
+  }
+  // If we erased from an internal node, advance the iterator.
+  if (internal_delete) {
+    ++res;
+  }
+  return res;
+}
+
+template <typename P>
+int btree<P>::erase(iterator begin, iterator end) {
+  int count = std::distance(begin, end);
+  for (int i = 0; i < count; i++) {
+    begin = erase(begin);
+  }
+  return count;
+}
+
+template <typename P> template <typename K>
+int btree<P>::erase_unique(const K &key) {
+  iterator iter = internal_find_unique(key, iterator(root(), 0));
+  if (!iter.node) {
+    // The key doesn't exist in the tree, return nothing done.
+    return 0;
+  }
+  erase(iter);
+  return 1;
+}
+
+template <typename P> template <typename K>
+int btree<P>::erase_multi(const K &key) {
+  iterator begin = internal_lower_bound(key, iterator(root(), 0));
+  if (!begin.node) {
+    // The key doesn't exist in the tree, return nothing done.
+    return 0;
+  }
+  // Delete all of the keys between begin and upper_bound(key).
+  iterator end = internal_end(
+      internal_upper_bound(key, iterator(root(), 0)));
+  return erase(begin, end);
+}
+
+template <typename P>
+void btree<P>::clear() {
+  if (root() != nullptr) {
+    internal_clear(root());
+  }
+  mutable_root() = nullptr;
+  rightmost_ = nullptr;
+  size_ = 0;
+}
+
+template <typename P>
+void btree<P>::swap(btree &x) {
+  using std::swap;
+  swap(root_, x.root_);
+  swap(rightmost_, x.rightmost_);
+  swap(size_, x.size_);
+}
+
+template <typename P>
+void btree<P>::verify() const {
+  if (root() != nullptr) {
+    assert(size() == internal_verify(root(), nullptr, nullptr));
+    assert(leftmost() == (++const_iterator(root(), -1)).node);
+    assert(rightmost_ == (--const_iterator(root(), root()->count())).node);
+    assert(leftmost()->leaf());
+    assert(rightmost_->leaf());
+  } else {
+    assert(empty());
+    assert(leftmost() == nullptr);
+    assert(rightmost_ == nullptr);
+  }
+}
+
+template <typename P>
+void btree<P>::rebalance_or_split(iterator *iter) {
+  node_type *&node = iter->node;
+  int &insert_position = iter->position;
+  assert(node->count() == node->max_count());
+  assert(kNodeValues == node->max_count());
+
+  // First try to make room on the node by rebalancing.
+  node_type *parent = node->parent();
+  if (node != root()) {
+    if (node->position() > 0) {
+      // Try rebalancing with our left sibling.
+      node_type *left = parent->child(node->position() - 1);
+      assert(left->max_count() == kNodeValues);
+      if (left->count() < kNodeValues) {
+        // We bias rebalancing based on the position being inserted. If we're
+        // inserting at the end of the right node then we bias rebalancing to
+        // fill up the left node.
+        int to_move = (kNodeValues - left->count()) /
+                      (1 + (insert_position < kNodeValues));
+        to_move = std::max(1, to_move);
+
+        if (((insert_position - to_move) >= 0) ||
+            ((left->count() + to_move) < kNodeValues)) {
+          left->rebalance_right_to_left(to_move, node, mutable_allocator());
+
+          assert(node->max_count() - node->count() == to_move);
+          insert_position = insert_position - to_move;
+          if (insert_position < 0) {
+            insert_position = insert_position + left->count() + 1;
+            node = left;
+          }
+
+          assert(node->count() < node->max_count());
+          return;
+        }
+      }
+    }
+
+    if (node->position() < parent->count()) {
+      // Try rebalancing with our right sibling.
+      node_type *right = parent->child(node->position() + 1);
+      assert(right->max_count() == kNodeValues);
+      if (right->count() < kNodeValues) {
+        // We bias rebalancing based on the position being inserted. If we're
+        // inserting at the beginning of the left node then we bias rebalancing
+        // to fill up the right node.
+        int to_move =
+            (kNodeValues - right->count()) / (1 + (insert_position > 0));
+        to_move = std::max(1, to_move);
+
+        if ((insert_position <= (node->count() - to_move)) ||
+            ((right->count() + to_move) < kNodeValues)) {
+          node->rebalance_left_to_right(to_move, right, mutable_allocator());
+
+          if (insert_position > node->count()) {
+            insert_position = insert_position - node->count() - 1;
+            node = right;
+          }
+
+          assert(node->count() < node->max_count());
+          return;
+        }
+      }
+    }
+
+    // Rebalancing failed, make sure there is room on the parent node for a new
+    // value.
+    assert(parent->max_count() == kNodeValues);
+    if (parent->count() == kNodeValues) {
+      iterator parent_iter(node->parent(), node->position());
+      rebalance_or_split(&parent_iter);
+    }
+  } else {
+    // Rebalancing not possible because this is the root node.
+    // Create a new root node and set the current root node as the child of the
+    // new root.
+    parent = new_internal_node(parent);
+    parent->init_child(0, root());
+    mutable_root() = parent;
+    // If the former root was a leaf node, then it's now the rightmost node.
+    assert(!parent->child(0)->leaf() || parent->child(0) == rightmost_);
+  }
+
+  // Split the node.
+  node_type *split_node;
+  if (node->leaf()) {
+    split_node = new_leaf_node(parent);
+    node->split(insert_position, split_node, mutable_allocator());
+    if (rightmost_ == node) rightmost_ = split_node;
+  } else {
+    split_node = new_internal_node(parent);
+    node->split(insert_position, split_node, mutable_allocator());
+  }
+
+  if (insert_position > node->count()) {
+    insert_position = insert_position - node->count() - 1;
+    node = split_node;
+  }
+}
+
+template <typename P>
+void btree<P>::merge_nodes(node_type *left, node_type *right) {
+  left->merge(right, mutable_allocator());
+  if (right->leaf()) {
+    if (rightmost_ == right) rightmost_ = left;
+    delete_leaf_node(right);
+  } else {
+    delete_internal_node(right);
+  }
+}
+
+template <typename P>
+bool btree<P>::try_merge_or_rebalance(iterator *iter) {
+  node_type *parent = iter->node->parent();
+  if (iter->node->position() > 0) {
+    // Try merging with our left sibling.
+    node_type *left = parent->child(iter->node->position() - 1);
+    assert(left->max_count() == kNodeValues);
+    if ((1 + left->count() + iter->node->count()) <= kNodeValues) {
+      iter->position += 1 + left->count();
+      merge_nodes(left, iter->node);
+      iter->node = left;
+      return true;
+    }
+  }
+  if (iter->node->position() < parent->count()) {
+    // Try merging with our right sibling.
+    node_type *right = parent->child(iter->node->position() + 1);
+    assert(right->max_count() == kNodeValues);
+    if ((1 + iter->node->count() + right->count()) <= kNodeValues) {
+      merge_nodes(iter->node, right);
+      return true;
+    }
+    // Try rebalancing with our right sibling. We don't perform rebalancing if
+    // we deleted the first element from iter->node and the node is not
+    // empty. This is a small optimization for the common pattern of deleting
+    // from the front of the tree.
+    if ((right->count() > kMinNodeValues) &&
+        ((iter->node->count() == 0) ||
+         (iter->position > 0))) {
+      int to_move = (right->count() - iter->node->count()) / 2;
+      to_move = std::min(to_move, right->count() - 1);
+      iter->node->rebalance_right_to_left(to_move, right, mutable_allocator());
+      return false;
+    }
+  }
+  if (iter->node->position() > 0) {
+    // Try rebalancing with our left sibling. We don't perform rebalancing if
+    // we deleted the last element from iter->node and the node is not
+    // empty. This is a small optimization for the common pattern of deleting
+    // from the back of the tree.
+    node_type *left = parent->child(iter->node->position() - 1);
+    if ((left->count() > kMinNodeValues) &&
+        ((iter->node->count() == 0) ||
+         (iter->position < iter->node->count()))) {
+      int to_move = (left->count() - iter->node->count()) / 2;
+      to_move = std::min(to_move, left->count() - 1);
+      left->rebalance_left_to_right(to_move, iter->node, mutable_allocator());
+      iter->position += to_move;
+      return false;
+    }
+  }
+  return false;
+}
+
+template <typename P>
+void btree<P>::try_shrink() {
+  if (root()->count() > 0) {
+    return;
+  }
+  // Deleted the last item on the root node, shrink the height of the tree.
+  if (root()->leaf()) {
+    assert(size() == 0);
+    delete_leaf_node(root());
+    mutable_root() = nullptr;
+    rightmost_ = nullptr;
+  } else {
+    node_type *child = root()->child(0);
+    child->make_root();
+    delete_internal_node(root());
+    mutable_root() = child;
+  }
+}
+
+template <typename P> template <typename IterType>
+inline IterType btree<P>::internal_last(IterType iter) {
+  while (iter.node && iter.position == iter.node->count()) {
+    iter.position = iter.node->position();
+    iter.node = iter.node->parent();
+    if (iter.node->leaf()) {
+      iter.node = nullptr;
+    }
+  }
+  return iter;
+}
+
+template <typename P>
+template <typename... Args>
+inline auto btree<P>::internal_emplace(iterator iter, Args &&... args)
+    -> iterator {
+  if (!iter.node->leaf()) {
+    // We can't insert on an internal node. Instead, we'll insert after the
+    // previous value which is guaranteed to be on a leaf node.
+    --iter;
+    ++iter.position;
+  }
+  const int max_count = iter.node->max_count();
+  if (iter.node->count() == max_count) {
+    // Make room in the leaf for the new item.
+    if (max_count < kNodeValues) {
+      // Insertion into the root where the root is smaller than the full node
+      // size. Simply grow the size of the root node.
+      assert(iter.node == root());
+      iter.node = new_leaf_root_node(std::min<int>(kNodeValues, 2 * max_count));
+      iter.node->swap(root(), mutable_allocator());
+      delete_leaf_node(root());
+      mutable_root() = iter.node;
+      rightmost_ = iter.node;
+    } else {
+      rebalance_or_split(&iter);
+    }
+  }
+  iter.node->emplace_value(iter.position, mutable_allocator(),
+                           std::forward<Args>(args)...);
+  ++size_;
+  return iter;
+}
+
+template <typename P> template <typename K, typename IterType>
+inline std::pair<IterType, int> btree<P>::internal_locate(
+    const K &key, IterType iter) const {
+  return is_key_compare_to::value ? internal_locate_compare_to(key, iter)
+                                  : internal_locate_plain_compare(key, iter);
+}
+
+template <typename P> template <typename K, typename IterType>
+inline std::pair<IterType, int> btree<P>::internal_locate_plain_compare(
+    const K &key, IterType iter) const {
+  for (;;) {
+    iter.position = iter.node->lower_bound(key, key_comp());
+    if (iter.node->leaf()) {
+      break;
+    }
+    iter.node = iter.node->child(iter.position);
+  }
+  return std::make_pair(iter, 0);
+}
+
+template <typename P> template <typename K, typename IterType>
+inline std::pair<IterType, int> btree<P>::internal_locate_compare_to(
+    const K &key, IterType iter) const {
+  for (;;) {
+    int res = iter.node->lower_bound(key, key_comp());
+    iter.position = res & kMatchMask;
+    if (res & kExactMatch) {
+      return std::make_pair(iter, static_cast<int>(kExactMatch));
+    }
+    if (iter.node->leaf()) {
+      break;
+    }
+    iter.node = iter.node->child(iter.position);
+  }
+  return std::make_pair(iter, -kExactMatch);
+}
+
+template <typename P> template <typename K, typename IterType>
+IterType btree<P>::internal_lower_bound(
+    const K &key, IterType iter) const {
+  const_lookup_key_reference<K> lookup_key(key);
+  if (iter.node) {
+    for (;;) {
+      iter.position =
+          iter.node->lower_bound(lookup_key, key_comp()) & kMatchMask;
+      if (iter.node->leaf()) {
+        break;
+      }
+      iter.node = iter.node->child(iter.position);
+    }
+    iter = internal_last(iter);
+  }
+  return iter;
+}
+
+template <typename P> template <typename K, typename IterType>
+IterType btree<P>::internal_upper_bound(
+    const K &key, IterType iter) const {
+  const_lookup_key_reference<K> lookup_key(key);
+  if (iter.node) {
+    for (;;) {
+      iter.position = iter.node->upper_bound(lookup_key, key_comp());
+      if (iter.node->leaf()) {
+        break;
+      }
+      iter.node = iter.node->child(iter.position);
+    }
+    iter = internal_last(iter);
+  }
+  return iter;
+}
+
+template <typename P> template <typename K, typename IterType>
+IterType btree<P>::internal_find_unique(
+    const K &key, IterType iter) const {
+  const_lookup_key_reference<K> lookup_key(key);
+  if (iter.node) {
+    std::pair<IterType, int> res = internal_locate(lookup_key, iter);
+    if (res.second == kExactMatch) {
+      return res.first;
+    }
+    if (!res.second) {
+      iter = internal_last(res.first);
+      if (iter.node && !compare_keys(lookup_key, iter.key())) {
+        return iter;
+      }
+    }
+  }
+  return IterType(nullptr, 0);
+}
+
+template <typename P> template <typename K, typename IterType>
+IterType btree<P>::internal_find_multi(
+    const K &key, IterType iter) const {
+  const_lookup_key_reference<K> lookup_key(key);
+  if (iter.node) {
+    iter = internal_lower_bound(lookup_key, iter);
+    if (iter.node) {
+      iter = internal_last(iter);
+      if (iter.node && !compare_keys(lookup_key, iter.key())) {
+        return iter;
+      }
+    }
+  }
+  return IterType(nullptr, 0);
+}
+
+template <typename P>
+void btree<P>::internal_clear(node_type *node) {
+  if (!node->leaf()) {
+    for (int i = 0; i <= node->count(); ++i) {
+      internal_clear(node->child(i));
+    }
+    delete_internal_node(node);
+  } else {
+    delete_leaf_node(node);
+  }
+}
+
+template <typename P>
+int btree<P>::internal_verify(
+    const node_type *node, const key_type *lo, const key_type *hi) const {
+  assert(node->count() > 0);
+  assert(node->count() <= node->max_count());
+  if (lo) {
+    assert(!compare_keys(node->key(0), *lo));
+  }
+  if (hi) {
+    assert(!compare_keys(*hi, node->key(node->count() - 1)));
+  }
+  for (int i = 1; i < node->count(); ++i) {
+    assert(!compare_keys(node->key(i), node->key(i - 1)));
+  }
+  int count = node->count();
+  if (!node->leaf()) {
+    for (int i = 0; i <= node->count(); ++i) {
+      assert(node->child(i) != nullptr);
+      assert(node->child(i)->parent() == node);
+      assert(node->child(i)->position() == i);
+      count += internal_verify(
+          node->child(i),
+          (i == 0) ? lo : &node->key(i - 1),
+          (i == node->count()) ? hi : &node->key(i));
+    }
+  }
+  return count;
+}
+
+}  // namespace internal_btree
+}  // namespace gtl
+
+
+#endif  // S2_UTIL_GTL_BTREE_H_
diff --git a/src/s2/util/gtl/btree_container.h b/src/s2/util/gtl/btree_container.h
new file mode 100644 (file)
index 0000000..5a8b57f
--- /dev/null
@@ -0,0 +1,411 @@
+// Copyright 2007 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+//
+
+#ifndef S2_UTIL_GTL_BTREE_CONTAINER_H_
+#define S2_UTIL_GTL_BTREE_CONTAINER_H_
+
+#include <algorithm>
+#include <initializer_list>
+#include <utility>
+
+#include "absl/base/internal/throw_delegate.h"
+#include "s2/util/gtl/btree.h"  // IWYU pragma: export
+
+namespace gtl {
+namespace internal_btree {
+
+// A common base class for btree_set, btree_map, btree_multiset, and
+// btree_multimap.
+template <typename Tree>
+class btree_container {
+ public:
+  using key_type = typename Tree::key_type;
+  using value_type = typename Tree::value_type;
+  using size_type = typename Tree::size_type;
+  using difference_type = typename Tree::difference_type;
+  using key_compare = typename Tree::key_compare;
+  using value_compare = typename Tree::value_compare;
+  using allocator_type = typename Tree::allocator_type;
+  using reference = typename Tree::reference;
+  using const_reference = typename Tree::const_reference;
+  using pointer = typename Tree::pointer;
+  using const_pointer = typename Tree::const_pointer;
+  using iterator = typename Tree::iterator;
+  using const_iterator = typename Tree::const_iterator;
+  using reverse_iterator = typename Tree::reverse_iterator;
+  using const_reverse_iterator = typename Tree::const_reverse_iterator;
+
+  // Constructors/assignments.
+  btree_container() : tree_(key_compare(), allocator_type()) {}
+  explicit btree_container(const key_compare &comp,
+                           const allocator_type &alloc = allocator_type())
+      : tree_(comp, alloc) {}
+  btree_container(const btree_container &x) = default;
+  btree_container(btree_container &&x) noexcept = default;
+  btree_container &operator=(const btree_container &x) = default;
+  btree_container &operator=(btree_container &&x) noexcept(
+      std::is_nothrow_move_assignable<Tree>::value) = default;
+
+  // Iterator routines.
+  iterator begin() { return tree_.begin(); }
+  const_iterator begin() const { return tree_.begin(); }
+  const_iterator cbegin() const { return tree_.begin(); }
+  iterator end() { return tree_.end(); }
+  const_iterator end() const { return tree_.end(); }
+  const_iterator cend() const { return tree_.end(); }
+  reverse_iterator rbegin() { return tree_.rbegin(); }
+  const_reverse_iterator rbegin() const { return tree_.rbegin(); }
+  const_reverse_iterator crbegin() const { return tree_.rbegin(); }
+  reverse_iterator rend() { return tree_.rend(); }
+  const_reverse_iterator rend() const { return tree_.rend(); }
+  const_reverse_iterator crend() const { return tree_.rend(); }
+
+  // Lookup routines.
+  template <typename K>
+  iterator lower_bound(const K &key) {
+    return tree_.lower_bound(key);
+  }
+  template <typename K>
+  const_iterator lower_bound(const K &key) const {
+    return tree_.lower_bound(key);
+  }
+  template <typename K>
+  iterator upper_bound(const K &key) {
+    return tree_.upper_bound(key);
+  }
+  template <typename K>
+  const_iterator upper_bound(const K &key) const {
+    return tree_.upper_bound(key);
+  }
+  template <typename K>
+  std::pair<iterator, iterator> equal_range(const K &key) {
+    return tree_.equal_range(key);
+  }
+  template <typename K>
+  std::pair<const_iterator, const_iterator> equal_range(const K &key) const {
+    return tree_.equal_range(key);
+  }
+
+  // Utility routines.
+  void clear() { tree_.clear(); }
+  void swap(btree_container &x) { tree_.swap(x.tree_); }
+  void verify() const { tree_.verify(); }
+
+  // Size routines.
+  size_type size() const { return tree_.size(); }
+  size_type max_size() const { return tree_.max_size(); }
+  bool empty() const { return tree_.empty(); }
+  size_type height() const { return tree_.height(); }
+  size_type internal_nodes() const { return tree_.internal_nodes(); }
+  size_type leaf_nodes() const { return tree_.leaf_nodes(); }
+  size_type nodes() const { return tree_.nodes(); }
+  size_type bytes_used() const { return tree_.bytes_used(); }
+  static double average_bytes_per_value() {
+    return Tree::average_bytes_per_value();
+  }
+  double fullness() const { return tree_.fullness(); }
+  double overhead() const { return tree_.overhead(); }
+
+  friend bool operator==(const btree_container &x, const btree_container &y) {
+    if (x.size() != y.size()) return false;
+    return std::equal(x.begin(), x.end(), y.begin());
+  }
+
+  friend bool operator!=(const btree_container &x, const btree_container &y) {
+    return !(x == y);
+  }
+
+  friend bool operator<(const btree_container &x, const btree_container &y) {
+    return std::lexicographical_compare(x.begin(), x.end(), y.begin(), y.end());
+  }
+
+  friend bool operator>(const btree_container &x, const btree_container &y) {
+    return y < x;
+  }
+
+  friend bool operator<=(const btree_container &x, const btree_container &y) {
+    return !(y < x);
+  }
+
+  friend bool operator>=(const btree_container &x, const btree_container &y) {
+    return !(x < y);
+  }
+
+  // The allocator used by the btree.
+  allocator_type get_allocator() const { return tree_.get_allocator(); }
+
+  // The key comparator used by the btree.
+  key_compare key_comp() const { return tree_.key_comp(); }
+  value_compare value_comp() const { return tree_.value_comp(); }
+
+  // Support absl::Hash.
+  template <typename State>
+  friend State AbslHashValue(State h, const btree_container &b) {
+    for (const auto &v : b) {
+      h = State::combine(std::move(h), v);
+    }
+    return State::combine(std::move(h), b.size());
+  }
+
+  // Exposed only for tests.
+  static bool testonly_uses_linear_node_search() {
+    return Tree::testonly_uses_linear_node_search();
+  }
+
+ protected:
+  Tree tree_;
+};
+
+// A common base class for btree_set and btree_map.
+template <typename Tree>
+class btree_set_container : public btree_container<Tree> {
+  using super_type = btree_container<Tree>;
+  using mutable_value_type = typename Tree::mutable_value_type;
+  using params_type = typename Tree::params_type;
+  friend class BtreeNodePeer;
+
+ public:
+  using value_type = typename Tree::value_type;
+  using size_type = typename Tree::size_type;
+  using key_compare = typename Tree::key_compare;
+  using allocator_type = typename Tree::allocator_type;
+  using iterator = typename Tree::iterator;
+  using const_iterator = typename Tree::const_iterator;
+
+  // Inherit constructors.
+  using super_type::super_type;
+  btree_set_container() {}
+
+  // Range constructor.
+  template <class InputIterator>
+  btree_set_container(InputIterator b, InputIterator e,
+                      const key_compare &comp = key_compare(),
+                      const allocator_type &alloc = allocator_type())
+      : super_type(comp, alloc) {
+    insert(b, e);
+  }
+
+  // Initializer list constructor.
+  btree_set_container(std::initializer_list<value_type> init,
+                      const key_compare &comp = key_compare(),
+                      const allocator_type &alloc = allocator_type())
+      : btree_set_container(init.begin(), init.end(), comp, alloc) {}
+
+  // Lookup routines.
+  template <typename K>
+  iterator find(const K &key) {
+    return this->tree_.find_unique(key);
+  }
+  template <typename K>
+  const_iterator find(const K &key) const {
+    return this->tree_.find_unique(key);
+  }
+  template <typename K>
+  size_type count(const K &key) const {
+    return this->tree_.count_unique(key);
+  }
+
+  // Insertion routines.
+  std::pair<iterator, bool> insert(const value_type &x) {
+    return this->tree_.insert_unique(params_type::key(x), x);
+  }
+  std::pair<iterator, bool> insert(value_type &&x) {
+    return this->tree_.insert_unique(params_type::key(x), std::move(x));
+  }
+  template <typename... Args>
+  std::pair<iterator, bool> emplace(Args &&... args) {
+    mutable_value_type v(std::forward<Args>(args)...);
+    return this->tree_.insert_unique(params_type::key(v), std::move(v));
+  }
+  iterator insert(iterator position, const value_type &x) {
+    return this->tree_.insert_hint_unique(position, params_type::key(x), x);
+  }
+  iterator insert(iterator position, value_type &&x) {
+    return this->tree_.insert_hint_unique(position, params_type::key(x),
+                                          std::move(x));
+  }
+  template <typename... Args>
+  iterator emplace_hint(iterator position, Args &&... args) {
+    mutable_value_type v(std::forward<Args>(args)...);
+    return this->tree_.insert_hint_unique(position, params_type::key(v),
+                                          std::move(v));
+  }
+  template <typename InputIterator>
+  void insert(InputIterator b, InputIterator e) {
+    this->tree_.insert_iterator_unique(b, e);
+  }
+  void insert(std::initializer_list<value_type> init) {
+    this->tree_.insert_iterator_unique(init.begin(), init.end());
+  }
+
+  // Deletion routines.
+  template <typename K>
+  int erase(const K &key) {
+    return this->tree_.erase_unique(key);
+  }
+  // Erase the specified iterator from the btree. The iterator must be valid
+  // (i.e. not equal to end()).  Return an iterator pointing to the node after
+  // the one that was erased (or end() if none exists).
+  iterator erase(const iterator &iter) { return this->tree_.erase(iter); }
+  void erase(const iterator &first, const iterator &last) {
+    this->tree_.erase(first, last);
+  }
+};
+
+// Base class for btree_map.
+template <typename Tree>
+class btree_map_container : public btree_set_container<Tree> {
+  using super_type = btree_set_container<Tree>;
+
+ public:
+  using key_type = typename Tree::key_type;
+  using mapped_type = typename Tree::mapped_type;
+  using value_type = typename Tree::value_type;
+  using key_compare = typename Tree::key_compare;
+  using allocator_type = typename Tree::allocator_type;
+
+  // Inherit constructors.
+  using super_type::super_type;
+  btree_map_container() {}
+
+  // Insertion routines.
+  mapped_type &operator[](const key_type &key) {
+    return this->tree_
+        .insert_unique(key, std::piecewise_construct,
+                       std::forward_as_tuple(key), std::forward_as_tuple())
+        .first->second;
+  }
+  mapped_type &operator[](key_type &&key) {
+    return this->tree_
+        .insert_unique(key, std::piecewise_construct,
+                       std::forward_as_tuple(std::move(key)),
+                       std::forward_as_tuple())
+        .first->second;
+  }
+
+  mapped_type &at(const key_type &key) {
+    auto it = this->find(key);
+    if (it == this->end())
+      absl::base_internal::ThrowStdOutOfRange("btree_map::at");
+    return it->second;
+  }
+  const mapped_type &at(const key_type &key) const {
+    auto it = this->find(key);
+    if (it == this->end())
+      absl::base_internal::ThrowStdOutOfRange("btree_map::at");
+    return it->second;
+  }
+};
+
+// A common base class for btree_multiset and btree_multimap.
+template <typename Tree>
+class btree_multiset_container : public btree_container<Tree> {
+  using super_type = btree_container<Tree>;
+
+ public:
+  using key_type = typename Tree::key_type;
+  using value_type = typename Tree::value_type;
+  using mapped_type = typename Tree::mapped_type;
+  using size_type = typename Tree::size_type;
+  using key_compare = typename Tree::key_compare;
+  using allocator_type = typename Tree::allocator_type;
+  using iterator = typename Tree::iterator;
+  using const_iterator = typename Tree::const_iterator;
+
+  // Inherit constructors.
+  using super_type::super_type;
+  btree_multiset_container() {}
+
+  // Range constructor.
+  template <class InputIterator>
+  btree_multiset_container(InputIterator b, InputIterator e,
+                           const key_compare &comp = key_compare(),
+                           const allocator_type &alloc = allocator_type())
+      : super_type(comp, alloc) {
+    insert(b, e);
+  }
+
+  // Initializer list constructor.
+  btree_multiset_container(std::initializer_list<value_type> init,
+                           const key_compare &comp = key_compare(),
+                           const allocator_type &alloc = allocator_type())
+      : btree_multiset_container(init.begin(), init.end(), comp, alloc) {}
+
+  // Lookup routines.
+  template <typename K>
+  iterator find(const K &key) {
+    return this->tree_.find_multi(key);
+  }
+  template <typename K>
+  const_iterator find(const K &key) const {
+    return this->tree_.find_multi(key);
+  }
+  template <typename K>
+  size_type count(const K &key) const {
+    return this->tree_.count_multi(key);
+  }
+
+  // Insertion routines.
+  iterator insert(const value_type &x) { return this->tree_.insert_multi(x); }
+  iterator insert(value_type &&x) {
+    return this->tree_.insert_multi(std::move(x));
+  }
+  iterator insert(iterator position, const value_type &x) {
+    return this->tree_.insert_hint_multi(position, x);
+  }
+  iterator insert(iterator position, value_type &&x) {
+    return this->tree_.insert_hint_multi(position, std::move(x));
+  }
+  template <typename InputIterator>
+  void insert(InputIterator b, InputIterator e) {
+    this->tree_.insert_iterator_multi(b, e);
+  }
+  void insert(std::initializer_list<value_type> init) {
+    this->tree_.insert_iterator_multi(init.begin(), init.end());
+  }
+
+  // Deletion routines.
+  template <typename K>
+  int erase(const K &key) {
+    return this->tree_.erase_multi(key);
+  }
+  // Erase the specified iterator from the btree. The iterator must be valid
+  // (i.e. not equal to end()).  Return an iterator pointing to the node after
+  // the one that was erased (or end() if none exists).
+  iterator erase(const iterator &iter) { return this->tree_.erase(iter); }
+  void erase(const iterator &first, const iterator &last) {
+    this->tree_.erase(first, last);
+  }
+};
+
+// A base class for btree_multimap.
+template <typename Tree>
+class btree_multimap_container : public btree_multiset_container<Tree> {
+  using super_type = btree_multiset_container<Tree>;
+
+ public:
+  using mapped_type = typename Tree::mapped_type;
+
+  // Inherit constructors.
+  using super_type::super_type;
+  btree_multimap_container() {}
+};
+
+}  // namespace internal_btree
+}  // namespace gtl
+
+#endif  // S2_UTIL_GTL_BTREE_CONTAINER_H_
diff --git a/src/s2/util/gtl/btree_map.h b/src/s2/util/gtl/btree_map.h
new file mode 100644 (file)
index 0000000..6e9ef62
--- /dev/null
@@ -0,0 +1,79 @@
+// Copyright 2007 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+//
+// A btree_map<> implements the STL unique sorted associative container
+// interface and the pair associative container interface (a.k.a map<>) using a
+// btree. A btree_multimap<> implements the STL multiple sorted associative
+// container interface and the pair associative container interface (a.k.a
+// multimap<>) using a btree. See btree.h for details of the btree
+// implementation and caveats.
+//
+
+#ifndef S2_UTIL_GTL_BTREE_MAP_H_
+#define S2_UTIL_GTL_BTREE_MAP_H_
+
+#include <algorithm>
+#include <functional>
+#include <memory>
+#include <string>
+#include <utility>
+
+#include "s2/util/gtl/btree.h"            // IWYU pragma: export
+#include "s2/util/gtl/btree_container.h"  // IWYU pragma: export
+
+namespace gtl {
+
+template <typename Key, typename Value, typename Compare = std::less<Key>,
+          typename Alloc = std::allocator<std::pair<const Key, Value>>,
+          int TargetNodeSize = 256>
+class btree_map
+    : public internal_btree::btree_map_container<
+          internal_btree::btree<internal_btree::map_params<
+              Key, Value, Compare, Alloc, TargetNodeSize, /*Multi=*/false>>> {
+  using Base = typename btree_map::btree_map_container;
+
+ public:
+  btree_map() {}
+  using Base::Base;
+};
+
+template <typename K, typename V, typename C, typename A, int T>
+void swap(btree_map<K, V, C, A, T> &x, btree_map<K, V, C, A, T> &y) {
+  return x.swap(y);
+}
+
+template <typename Key, typename Value, typename Compare = std::less<Key>,
+          typename Alloc = std::allocator<std::pair<const Key, Value>>,
+          int TargetNodeSize = 256>
+class btree_multimap
+    : public internal_btree::btree_multimap_container<
+          internal_btree::btree<internal_btree::map_params<
+              Key, Value, Compare, Alloc, TargetNodeSize, /*Multi=*/true>>> {
+  using Base = typename btree_multimap::btree_multimap_container;
+
+ public:
+  btree_multimap() {}
+  using Base::Base;
+};
+
+template <typename K, typename V, typename C, typename A, int T>
+void swap(btree_multimap<K, V, C, A, T> &x, btree_multimap<K, V, C, A, T> &y) {
+  return x.swap(y);
+}
+
+}  // namespace gtl
+
+#endif  // S2_UTIL_GTL_BTREE_MAP_H_
diff --git a/src/s2/util/gtl/btree_set.h b/src/s2/util/gtl/btree_set.h
new file mode 100644 (file)
index 0000000..c03490e
--- /dev/null
@@ -0,0 +1,73 @@
+// Copyright 2007 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+//
+// A btree_set<> implements the STL unique sorted associative container
+// interface (a.k.a set<>) using a btree. A btree_multiset<> implements the STL
+// multiple sorted associative container interface (a.k.a multiset<>) using a
+// btree. See btree.h for details of the btree implementation and caveats.
+//
+
+#ifndef S2_UTIL_GTL_BTREE_SET_H_
+#define S2_UTIL_GTL_BTREE_SET_H_
+
+#include <functional>
+#include <memory>
+#include <string>
+
+#include "s2/util/gtl/btree.h"            // IWYU pragma: export
+#include "s2/util/gtl/btree_container.h"  // IWYU pragma: export
+
+namespace gtl {
+
+template <typename Key, typename Compare = std::less<Key>,
+          typename Alloc = std::allocator<Key>, int TargetNodeSize = 256>
+class btree_set
+    : public internal_btree::btree_set_container<
+          internal_btree::btree<internal_btree::set_params<
+              Key, Compare, Alloc, TargetNodeSize, /*Multi=*/false>>> {
+  using Base = typename btree_set::btree_set_container;
+
+ public:
+  btree_set() {}
+  using Base::Base;
+};
+
+template <typename K, typename C, typename A, int T>
+void swap(btree_set<K, C, A, T> &x, btree_set<K, C, A, T> &y) {
+  return x.swap(y);
+}
+
+template <typename Key, typename Compare = std::less<Key>,
+          typename Alloc = std::allocator<Key>, int TargetNodeSize = 256>
+class btree_multiset
+    : public internal_btree::btree_multiset_container<
+          internal_btree::btree<internal_btree::set_params<
+              Key, Compare, Alloc, TargetNodeSize, /*Multi=*/true>>> {
+  using Base = typename btree_multiset::btree_multiset_container;
+
+ public:
+  btree_multiset() {}
+  using Base::Base;
+};
+
+template <typename K, typename C, typename A, int T>
+void swap(btree_multiset<K, C, A, T> &x, btree_multiset<K, C, A, T> &y) {
+  return x.swap(y);
+}
+
+}  // namespace gtl
+
+#endif  // S2_UTIL_GTL_BTREE_SET_H_
diff --git a/src/s2/util/gtl/compact_array.h b/src/s2/util/gtl/compact_array.h
new file mode 100644 (file)
index 0000000..cf11f77
--- /dev/null
@@ -0,0 +1,661 @@
+// Copyright 2005 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+
+// compact_array is a more memory-efficient implementation of std::vector.
+// It uses a pointer with an integer that stores both size and capacity.
+//
+// Implementation details:
+//
+// compact_array is a small-overhead STL-like Collection, but can only be used
+// for types with trivial copy, assign, and destructor. It only takes 16
+// bytes for 64-bit binary (instead of the typical 24-bytes for vector).
+// Its size can grow to 2^24 (16M) elements. compact_array is memory
+// efficient when it is small, and CPU-efficient for growing a large array.
+// It does this by keeping both the size and capacity.  When the size is less
+// than 64, the capacity is exactly as reserved, and grows linearly. Once the
+// size grows bigger than 64, the capacity grows exponentially.
+//
+// IMPORTANT: compact_array_base does not support a constructor and destructor
+// because it is designed to be used in "union". The replacements are
+// Construct() and Destruct() which MUST be called explicitly. If you need
+// constructor and destructor, use compact_array instead.
+//
+
+#ifndef S2_UTIL_GTL_COMPACT_ARRAY_H_
+#define S2_UTIL_GTL_COMPACT_ARRAY_H_
+
+#include <cstddef>
+#include <cstring>
+#include <sys/types.h>
+#include <algorithm>
+#include <iterator>
+#include <memory>
+#include <ostream>  // NOLINT
+#include <stdexcept>
+#include <type_traits>
+#include <utility>
+
+#include "s2/base/integral_types.h"
+#include "s2/base/logging.h"
+#include "absl/base/macros.h"
+#include "s2/base/port.h"
+#include "absl/meta/type_traits.h"
+#include "s2/util/bits/bits.h"
+#include "s2/util/gtl/container_logging.h"
+
+namespace gtl {
+
+template <typename T, typename A = std::allocator<T> >
+class compact_array_base {
+ private:
+  // The number of bits for the variable size_ and capacity_
+  static const int kSizeNumBits = 24;
+  static const int kCapacityNumBits = 6;
+  // Where capacity_ becomes an exponent (of 2) instead of the exact value
+  static const int kExponentStart = (1 << kCapacityNumBits);
+  // kMaxSize is the maximum size this array can grow.
+  static const int kMaxSize = (1 << kSizeNumBits) - 1;
+
+#ifdef IS_LITTLE_ENDIAN
+  uint32 size_        : kSizeNumBits;      // number of valid items in the array
+  uint32 capacity_    : kCapacityNumBits;  // allocated array size
+  uint32 is_exponent_ : 1;                 // whether capacity_ is an exponent
+
+  // This object might share memory representation (ie. union) with
+  // other data structures. We reserved the DO_NOT_USE (32nd bit in
+  // little endian format) to be used as a tag.
+  uint32 DO_NOT_USE   : 1;
+#else
+  uint32 DO_NOT_USE   : 1;
+  uint32 is_exponent_ : 1;
+  uint32 capacity_    : kCapacityNumBits;
+  uint32 size_        : kSizeNumBits;
+#endif
+
+  // Opportunistically consider allowing inlined elements.
+  // dd: this has to be disabled to pass CRAN checks, since there is a
+  // (potentially) zero-length array that is not the last element of the class (so
+  // this can't be silenced using __extension__)
+#if defined(_LP64) && defined(__GNUC__) && false
+  // With 64-bit pointers, our approach is to form a 16-byte struct:
+  //   [5 bytes for size, capacity, is_exponent and is_inlined]
+  //   [3 bytes of padding or inlined elements]
+  //   [8 bytes of more inlined elements or a pointer]
+  // We require 0-length arrays to take 0 bytes, and no strict aliasing. There
+  // should be no compiler-inserted padding between any of our members.
+  enum {
+    kMaxInlinedBytes = 11,
+    kInlined = kMaxInlinedBytes / sizeof(T),
+    kActualInlinedBytes = kInlined * sizeof(T),
+    kUnusedPaddingBytes = (kMaxInlinedBytes - kActualInlinedBytes) > 3 ?
+        3 : (kMaxInlinedBytes - kActualInlinedBytes)
+  };
+
+  T* Array() { return IsInlined() ? InlinedSpace() : pointer_; }
+  void SetArray(T* p) {
+    static_assert(sizeof(*this) == 16, "size assumption");
+    static_assert(sizeof(this) == 8, "pointer size assumption");
+    is_inlined_ = false;
+    pointer_ = p;
+  }
+  void SetInlined() {
+    S2_DCHECK_LE(capacity(), kInlined);
+    is_inlined_ = true;
+  }
+  T* InlinedSpace() { return reinterpret_cast<T*>(inlined_elements_); }
+
+  bool is_inlined_;  // If false, the last 8 bytes of *this are a pointer.
+
+  // After is_inlined_, the next field may not be sufficiently aligned to store
+  // an object of type T. Pad it out with (unaligned) chars.
+  char unused_padding_[kUnusedPaddingBytes];
+
+  // inlined_elements_ stores the first N elements, potentially as few as zero.
+  __extension__ char inlined_elements_[3 - kUnusedPaddingBytes];
+
+  // compact_array_base itself is at least as aligned as a T* because of the
+  // T* member inside this union. The only reason to split inlined_elements_
+  // into two pieces is to have a place to put this T* member.
+  union {
+    T* pointer_;
+    char more_inlined_elements_[sizeof(T*)];
+  };
+#else
+  enum { kInlined = 0, is_inlined_ = false };
+  T* Array() { return first_; }
+  void SetArray(T* p) { first_ = p; }
+  void SetInlined() { S2_LOG(FATAL); }
+  T* InlinedSpace() { return nullptr; }
+
+  // The pointer to the actual data array.
+  T* first_;
+#endif
+  bool IsInlined() const { return is_inlined_; }
+  const T* ConstArray() const {
+    return const_cast<compact_array_base<T, A>*>(this)->Array();
+  }
+
+  typedef typename A::template rebind<T>::other value_allocator_type;
+
+ public:
+  typedef T                                     value_type;
+  typedef A                                     allocator_type;
+  typedef value_type*                           pointer;
+  typedef const value_type*                     const_pointer;
+  typedef value_type&                           reference;
+  typedef const value_type&                     const_reference;
+  typedef uint32                                size_type;
+  typedef ptrdiff_t                             difference_type;
+
+  typedef value_type*                           iterator;
+  typedef const value_type*                     const_iterator;
+  typedef std::reverse_iterator<iterator>       reverse_iterator;
+  typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
+
+  // Init() replace the default constructors; so it can be used in "union".
+  // This means Init() must be called for every new compact_array_base
+  void Init() noexcept { memset(this, 0, sizeof(*this)); }
+
+  // Construct an array of size n and initialize the values to v.
+  // Any old contents, if heap-allocated, will be leaked.
+  void Construct(size_type n, const value_type& v = value_type()) {
+    Init();
+    value_init(n, v);
+  }
+
+  // See 23.1.1/9 in the C++ standard for an explanation.
+  template <typename Iterator>
+  void Copy(Iterator first, Iterator last) {
+    Init();
+    typedef typename std::is_integral<Iterator>::type Int;
+    initialize(first, last, Int());
+  }
+
+  void CopyFrom(const compact_array_base& v) {
+    Init();
+    initialize(v.begin(), v.end(), std::false_type());
+  }
+
+  compact_array_base& AssignFrom(const compact_array_base& v) {
+    // Safe for self-assignment, which is rare.
+    // Optimized to use existing allocated space.
+    // Also to use assignment instead of copying where possible.
+    if (size() < v.size()) {  // grow
+      reserve(v.size());
+      std::copy(v.begin(), v.begin() + size(), begin());
+      insert(end(), v.begin() + size(), v.end());
+    } else {  // maybe shrink
+      erase(begin() + v.size(), end());
+      std::copy(v.begin(), v.end(), begin());
+    }
+    return *this;
+  }
+
+  // Deallocate the whole array.
+  void Destruct() {
+    if (!MayBeInlined() || Array() != InlinedSpace()) {
+      value_allocator_type allocator;
+      allocator.deallocate(Array(), capacity());
+    }
+    Init();
+  }
+
+  // Safe against self-swapping.
+  // copying/destruction of compact_array_base is fairly trivial as the type
+  // was designed to be useable in a C++98 union.
+  void swap(compact_array_base& v) noexcept {
+    compact_array_base tmp = *this;
+    *this = v;
+    v = tmp;
+  }
+
+  // The number of active items in the array.
+  size_type size() const { return size_; }
+  bool empty() const { return size() == 0; }
+
+  // Maximum size that this data structure can hold.
+  static size_type max_size() { return kMaxSize; }
+
+  static bool MayBeInlined() { return kInlined > 0; }
+
+ public:                                // Container interface (tables 65,66).
+  iterator begin() { return Array(); }
+  iterator end()   { return Array() + size(); }
+  const_iterator begin() const { return ConstArray(); }
+  const_iterator end() const   { return ConstArray() + size(); }
+
+  reverse_iterator rbegin() { return reverse_iterator(end()); }
+  reverse_iterator rend()   { return reverse_iterator(Array()); }
+  const_reverse_iterator rbegin() const {
+    return const_reverse_iterator(end());
+  }
+  const_reverse_iterator rend() const {
+    return const_reverse_iterator(ConstArray());
+  }
+
+ private:
+  // This Insert() is private because it might return the end().
+  iterator Insert(const_iterator p, const value_type& v) {
+    if (size() >= kMaxSize) {
+      throw std::length_error("compact_array size exceeded");
+    }
+    iterator r = make_hole(p, 1);
+    *r = v;
+    return r;
+  }
+
+ public:                                // Sequence operations, table 67.
+  iterator insert(const_iterator p, const value_type& v) {
+    return Insert(p, v);
+  }
+
+  void insert(const_iterator p, size_type n, const value_type& v) {
+    if (n + size() > kMaxSize) {
+      throw std::length_error("compact_array size exceeded");
+    }
+    value_insert(p, n, v);
+  }
+
+  // See 23.1.1/9 in the C++ standard for an explanation.
+  template <typename Iterator>
+  void insert(const_iterator p, Iterator first, Iterator last) {
+    typedef typename std::is_integral<Iterator>::type Int;
+    insert(p, first, last, Int());
+  }
+
+  iterator erase(const_iterator p) {
+    size_type index = p - begin();
+    erase_aux(p, 1);
+    return begin() + index;
+  }
+
+  iterator erase(const_iterator first, const_iterator last) {
+    size_type index = first - begin();
+    erase_aux(first, last - first);
+    return begin() + index;
+  }
+
+  // clear just resets the size to 0, without deallocating the storage.
+  // To deallocate the array, use Destruct().
+  void clear() {
+    set_size(0);
+  }
+
+  reference front() { return begin()[0]; }
+  const_reference front() const { return begin()[0]; }
+  reference back() { return end()[-1]; }
+  const_reference back() const { return end()[-1]; }
+
+  void push_back(const value_type& v) {
+    iterator p = make_hole(end(), 1);
+    *p = v;
+  }
+  void pop_back() {
+    erase_aux(end()-1, 1);
+  }
+
+  reference operator[](size_type n) {
+    S2_DCHECK_LT(n, size_);
+    return Array()[n];
+  }
+
+  const_reference operator[](size_type n) const {
+    S2_DCHECK_LT(n, size_);
+    return ConstArray()[n];
+  }
+
+  reference at(size_type n) {
+    if (n >= size_) {
+      throw std::out_of_range("compact_array index out of range");
+    }
+    return Array()[n];
+  }
+
+  const_reference at(size_type n) const {
+    if (n >= size_) {
+      throw std::out_of_range("compact_array index out of range");
+    }
+    return ConstArray()[n];
+  }
+
+  // Preallocate the array of size n. Only changes the capacity, not size.
+  void reserve(int n) {
+    reallocate(n);
+  }
+
+  size_type capacity() const {
+    return is_exponent_ ? (1 << capacity_) : capacity_;
+  }
+
+  void resize(size_type n) {
+    if (n > capacity()) reserve(n);
+    // resize(n) is the only place in the class that exposes uninitialized
+    // memory as live elements, so call a constructor for each element if
+    // needed.
+    // Destroying elements on shrinking resize isn't a concern, since the
+    // value_type must be trivially destructible.
+    if (n > size() &&
+        !absl::is_trivially_default_constructible<value_type>::value) {
+      // Increasing size would expose unconstructed elements.
+      value_type *new_end = Array() + n;
+      for (value_type *p = Array() + size(); p != new_end; ++p)
+        new (p) value_type();
+    }
+    set_size(n);
+  }
+
+ private:                               // Low-level helper functions.
+  void set_size(size_type n) {
+    S2_DCHECK_LE(n, capacity());
+    size_ = n;
+  }
+
+  void set_capacity(size_type n) {
+    S2_DCHECK_LE(size(), n);
+    is_exponent_ = (n >= kExponentStart);
+    capacity_ = is_exponent_ ? Bits::Log2Ceiling(n) : n;
+    // A tiny optimization here would be to set capacity_ to kInlined if
+    // it's currently less. We don't bother, because doing so would require
+    // changing the existing comments and unittests that say that, for small n,
+    // capacity() will be exactly n if one calls reserve(n).
+    S2_DCHECK(n == capacity() || n > kInlined);
+  }
+
+  // Make capacity n or more. Reallocate and copy data as necessary.
+  void reallocate(size_type n) {
+    size_type old_capacity = capacity();
+    if (n <= old_capacity)  return;
+    set_capacity(n);
+    if (MayBeInlined()) {
+      if (!IsInlined() && n <= kInlined) {
+        SetInlined();
+        return;
+      } else if (IsInlined()) {
+        if (n > kInlined) {
+          value_allocator_type allocator;
+          value_type* new_array = allocator.allocate(capacity());
+          memcpy(new_array, InlinedSpace(), size() * sizeof(T));
+          SetArray(new_array);
+        }
+        return;
+      }
+    }
+    value_allocator_type allocator;
+
+    T* new_ptr = allocator.allocate(capacity());
+    // dd: this modification fixes a ASAN/UBSAN error, because
+    // when old_capacity is 0, Array() is nullptr, which is UB
+    // for memcpy.
+    if (old_capacity > 0) {
+      memcpy(new_ptr, Array(), old_capacity * sizeof(T));
+      allocator.deallocate(Array(), old_capacity);
+    }
+
+    SetArray(new_ptr);
+  }
+
+  value_type* lastp() { return Array() + size(); }
+
+  void move(const value_type* first, const value_type* last, value_type* out) {
+    memmove(out, first, (last - first) * sizeof(value_type));
+  }
+
+  iterator make_hole(const_iterator p, size_type n) {
+    iterator q = const_cast<iterator>(p);
+    if (n != 0) {
+      size_type new_size = size() + n;
+      size_type index = q - Array();
+      reallocate(new_size);
+      q = Array() + index;
+      move(q, Array() + new_size - n, q + n);
+      set_size(new_size);
+    }
+    return q;
+  }
+
+  void erase_aux(const_iterator p, size_type n) {
+    iterator q = const_cast<iterator>(p);
+    size_type new_size = size() - n;
+    move(q + n, lastp(), q);
+    reallocate(new_size);
+    set_size(new_size);
+  }
+
+ private:                               // Helper functions for range/value.
+  void value_init(size_type n, const value_type& v) {
+    reserve(n);
+    set_size(n);
+    std::fill(Array(), lastp(), v);
+  }
+
+  template <typename InputIter>
+  void range_init(InputIter first, InputIter last, std::input_iterator_tag) {
+    for ( ; first != last; ++first)
+      push_back(*first);
+  }
+
+  template <typename ForwIter>
+  void range_init(ForwIter first, ForwIter last, std::forward_iterator_tag) {
+    size_type n = std::distance(first, last);
+    reserve(n);
+    set_size(n);
+    std::copy(first, last, Array());
+  }
+
+  template <typename Integer>
+  void initialize(Integer n, Integer v, std::true_type) {
+    value_init(n, v);
+  }
+
+  template <typename Iterator>
+  void initialize(Iterator first, Iterator last, std::false_type) {
+    typedef typename std::iterator_traits<Iterator>::iterator_category Cat;
+    range_init(first, last, Cat());
+  }
+
+  void value_insert(const_iterator p, size_type n, const value_type& v) {
+    if (n + size() > kMaxSize) {
+      throw std::length_error("compact_array size exceeded");
+    }
+    iterator hole = make_hole(p, n);
+    std::fill(hole, hole + n, v);
+  }
+
+  template <typename InputIter>
+  void range_insert(const_iterator p, InputIter first, InputIter last,
+                    std::input_iterator_tag) {
+    size_type pos = p - begin();
+    size_type old_size = size();
+    for (; first != last; ++first)
+      push_back(*first);
+    std::rotate(begin() + pos, begin() + old_size, end());
+  }
+
+  template <typename ForwIter>
+  void range_insert(const_iterator p, ForwIter first, ForwIter last,
+                    std::forward_iterator_tag) {
+    size_type n = std::distance(first, last);
+    if (n + size() > kMaxSize) {
+      throw std::length_error("compact_array size exceeded");
+    }
+    std::copy(first, last, make_hole(p, n));
+  }
+
+  template <typename Integer>
+  void insert(const_iterator p, Integer n, Integer v, std::true_type) {
+    value_insert(p, n, v);
+  }
+
+  template <typename Iterator>
+  void insert(const_iterator p, Iterator first, Iterator last,
+              std::false_type) {
+    typedef typename std::iterator_traits<Iterator>::iterator_category Cat;
+    range_insert(p, first, last, Cat());
+  }
+  static_assert(absl::is_trivially_copy_constructible<value_type>::value &&
+                absl::is_trivially_copy_assignable<value_type>::value &&
+                absl::is_trivially_destructible<value_type>::value,
+                "Requires trivial copy, assignment, and destructor.");
+};
+
+// Allocates storage for constants in compact_array_base<T>
+template <typename T, typename A>
+    const int compact_array_base<T, A>::kSizeNumBits;
+template <typename T, typename A>
+    const int compact_array_base<T, A>::kCapacityNumBits;
+template <typename T, typename A>
+    const int compact_array_base<T, A>::kMaxSize;
+template <typename T, typename A>
+    const int compact_array_base<T, A>::kExponentStart;
+
+// compact_array:  Wrapper for compact_array_base that provides the
+//  constructors and destructor.
+
+template <class T, class A = std::allocator<T> >
+class compact_array : public compact_array_base<T, A> {
+ private:
+  typedef compact_array_base<T, A> Base;
+
+ public:
+  typedef typename Base::value_type value_type;
+  typedef typename Base::allocator_type allocator_type;
+  typedef typename Base::pointer pointer;
+  typedef typename Base::const_pointer const_pointer;
+  typedef typename Base::reference reference;
+  typedef typename Base::const_reference const_reference;
+  typedef typename Base::size_type size_type;
+
+  typedef typename Base::iterator iterator;
+  typedef typename Base::const_iterator const_iterator;
+  typedef typename Base::reverse_iterator reverse_iterator;
+  typedef typename Base::const_reverse_iterator const_reverse_iterator;
+
+  compact_array() noexcept(noexcept(std::declval<Base&>().Init())) {
+    Base::Init();
+  }
+
+  explicit compact_array(size_type n) {
+    Base::Construct(n, value_type());
+  }
+
+  compact_array(size_type n, const value_type& v) {
+    Base::Construct(n, v);
+  }
+
+  // See 23.1.1/9 in the C++ standard for an explanation.
+  template <typename Iterator>
+  compact_array(Iterator first, Iterator last) {
+    Base::Copy(first, last);
+  }
+
+  compact_array(const compact_array& v) {
+    Base::CopyFrom(v);
+  }
+
+  compact_array(compact_array&& v) noexcept(
+      noexcept(compact_array()) && noexcept(std::declval<Base&>().swap(v)))
+      : compact_array() {
+    Base::swap(v);
+  }
+
+  compact_array& operator=(const compact_array& v) {
+    Base::AssignFrom(v);
+    return *this;
+  }
+
+  compact_array& operator=(compact_array&& v) {
+    // swap is only right here because the objects are trivially destructible
+    // and thus there are no side effects on their destructor.
+    // Otherwise we must destroy the objects on `this`.
+    Base::swap(v);
+    return *this;
+  }
+
+  ~compact_array() {
+    Base::Destruct();
+  }
+};
+
+// Comparison operators
+template <typename T, typename A>
+bool operator==(const compact_array<T, A>& x, const compact_array<T, A>& y) {
+  return x.size() == y.size() &&
+         std::equal(x.begin(), x.end(), y.begin());
+}
+
+template <typename T, typename A>
+bool operator!=(const compact_array<T, A>& x, const compact_array<T, A>& y) {
+  return !(x == y);
+}
+
+template <typename T, typename A>
+bool operator<(const compact_array<T, A>& x, const compact_array<T, A>& y) {
+  return std::lexicographical_compare(x.begin(), x.end(), y.begin(), y.end());
+}
+
+template <typename T, typename A>
+bool operator>(const compact_array<T, A>& x, const compact_array<T, A>& y) {
+  return y < x;
+}
+
+template <typename T, typename A>
+bool operator<=(const compact_array<T, A>& x, const compact_array<T, A>& y) {
+  return !(y < x);
+}
+
+template <typename T, typename A>
+bool operator>=(const compact_array<T, A>& x, const compact_array<T, A>& y) {
+  return !(x < y);
+}
+
+// Swap
+template <typename T, typename A>
+inline void swap(compact_array<T, A>& x, compact_array<T, A>& y) {
+  x.swap(y);
+}
+
+namespace compact_array_internal {
+struct LogArray : public gtl::LogLegacyUpTo100 {
+  template <typename ElementT>
+  void Log(std::ostream& out, const ElementT& element) const {  // NOLINT
+    out << element;
+  }
+  void Log(std::ostream& out, int8 c) const {  // NOLINT
+    out << static_cast<int32>(c);
+  }
+  void Log(std::ostream& out, uint8 c) const {  // NOLINT
+    out << static_cast<uint32>(c);
+  }
+
+  void LogOpening(std::ostream& out) const { out << "["; }  // NOLINT
+  void LogClosing(std::ostream& out) const { out << "]"; }  // NOLINT
+};
+}  // namespace compact_array_internal
+
+// Output operator for compact_array<T>. Requires that T has an
+// operator<< for std::ostream.  Note that
+// compact_array_internal::LogArray ensures that "signed char" and
+// "unsigned char" types print as integers.
+template <class T, class A>
+std::ostream& operator<<(std::ostream& out, const compact_array<T, A>& array) {
+  gtl::LogRangeToStream(out, array.begin(), array.end(),
+                        compact_array_internal::LogArray());
+  return out;
+}
+
+}  // namespace gtl
+
+#endif  // S2_UTIL_GTL_COMPACT_ARRAY_H_
diff --git a/src/s2/util/gtl/container_logging.h b/src/s2/util/gtl/container_logging.h
new file mode 100644 (file)
index 0000000..93d0d37
--- /dev/null
@@ -0,0 +1,291 @@
+// Copyright 2013 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// All Rights Reserved.
+//
+// Utilities for container logging.
+// TODO(user): Broaden the scope and rename to "stream_util.h"
+//
+
+#ifndef S2_UTIL_GTL_CONTAINER_LOGGING_H_
+#define S2_UTIL_GTL_CONTAINER_LOGGING_H_
+
+#include <limits>
+#include <ostream>
+#include <string>
+#include <type_traits>
+
+#include "s2/base/integral_types.h"
+#include "s2/base/port.h"
+#include "s2/strings/ostringstream.h"
+
+namespace gtl {
+
+// Several policy classes below determine how LogRangeToStream will
+// format a range of items.  A Policy class should have these methods:
+//
+// Called to print an individual container element.
+//   void Log(ostream &out, const ElementT &element) const;
+//
+// Called before printing the set of elements:
+//   void LogOpening(ostream &out) const;
+//
+// Called after printing the set of elements:
+//   void LogClosing(ostream &out) const;
+//
+// Called before printing the first element:
+//   void LogFirstSeparator(ostream &out) const;
+//
+// Called before printing the remaining elements:
+//   void LogSeparator(ostream &out) const;
+//
+// Returns the maximum number of elements to print:
+//   int64 MaxElements() const;
+//
+// Called to print an indication that MaximumElements() was reached:
+//   void LogEllipsis(ostream &out) const;
+
+namespace internal {
+
+struct LogBase {
+  template <typename ElementT>
+  void Log(std::ostream &out, const ElementT &element) const {  // NOLINT
+    out << element;
+  }
+  void LogEllipsis(std::ostream &out) const {  // NOLINT
+    out << "...";
+  }
+};
+
+struct LogShortBase : public LogBase {
+  void LogOpening(std::ostream &out) const { out << "["; }        // NOLINT
+  void LogClosing(std::ostream &out) const { out << "]"; }        // NOLINT
+  void LogFirstSeparator(std::ostream &out) const { out << ""; }  // NOLINT
+  void LogSeparator(std::ostream &out) const { out << ", "; }     // NOLINT
+};
+
+struct LogMultilineBase : public LogBase {
+  void LogOpening(std::ostream &out) const { out << "["; }          // NOLINT
+  void LogClosing(std::ostream &out) const { out << "\n]"; }        // NOLINT
+  void LogFirstSeparator(std::ostream &out) const { out << "\n"; }  // NOLINT
+  void LogSeparator(std::ostream &out) const { out << "\n"; }       // NOLINT
+};
+
+struct LogLegacyBase : public LogBase {
+  void LogOpening(std::ostream &out) const { out << ""; }         // NOLINT
+  void LogClosing(std::ostream &out) const { out << ""; }         // NOLINT
+  void LogFirstSeparator(std::ostream &out) const { out << ""; }  // NOLINT
+  void LogSeparator(std::ostream &out) const { out << " "; }      // NOLINT
+};
+
+}  // namespace internal
+
+// LogShort uses [] braces and separates items with comma-spaces.  For
+// example "[1, 2, 3]".
+struct LogShort : public internal::LogShortBase {
+  int64 MaxElements() const { return std::numeric_limits<int64>::max(); }
+};
+
+// LogShortUpToN(max_elements) formats the same as LogShort but prints no more
+// than the max_elements elements.
+class LogShortUpToN : public internal::LogShortBase {
+ public:
+  explicit LogShortUpToN(int64 max_elements) : max_elements_(max_elements) {}
+  int64 MaxElements() const { return max_elements_; }
+
+ private:
+  int64 max_elements_;
+};
+
+// LogShortUpTo100 formats the same as LogShort but prints no more
+// than 100 elements.
+struct LogShortUpTo100 : public LogShortUpToN {
+  LogShortUpTo100() : LogShortUpToN(100) {}
+};
+
+// LogMultiline uses [] braces and separates items with
+// newlines.  For example "[
+// 1
+// 2
+// 3
+// ]".
+struct LogMultiline : public internal::LogMultilineBase {
+  int64 MaxElements() const { return std::numeric_limits<int64>::max(); }
+};
+
+// LogMultilineUpToN(max_elements) formats the same as LogMultiline but
+// prints no more than max_elements elements.
+class LogMultilineUpToN : public internal::LogMultilineBase {
+ public:
+  explicit LogMultilineUpToN(int64 max_elements)
+      : max_elements_(max_elements) {}
+  int64 MaxElements() const { return max_elements_; }
+
+ private:
+  int64 max_elements_;
+};
+
+// LogMultilineUpTo100 formats the same as LogMultiline but
+// prints no more than 100 elements.
+struct LogMultilineUpTo100 : public LogMultilineUpToN {
+  LogMultilineUpTo100() : LogMultilineUpToN(100) {}
+};
+
+// The legacy behavior of LogSequence() does not use braces and
+// separates items with spaces.  For example "1 2 3".
+struct LogLegacyUpTo100 : public internal::LogLegacyBase {
+  int64 MaxElements() const { return 100; }
+};
+struct LogLegacy : public internal::LogLegacyBase {
+  int64 MaxElements() const { return std::numeric_limits<int64>::max(); }
+};
+
+// The default policy for new code.
+typedef LogShortUpTo100 LogDefault;
+
+// LogRangeToStream should be used to define operator<< for
+// STL and STL-like containers.  For example, see stl_logging.h.
+template <typename IteratorT, typename PolicyT>
+inline void LogRangeToStream(std::ostream &out,  // NOLINT
+                             IteratorT begin, IteratorT end,
+                             const PolicyT &policy) {
+  policy.LogOpening(out);
+  for (size_t i = 0; begin != end && i < policy.MaxElements(); ++i, ++begin) {
+    if (i == 0) {
+      policy.LogFirstSeparator(out);
+    } else {
+      policy.LogSeparator(out);
+    }
+    policy.Log(out, *begin);
+  }
+  if (begin != end) {
+    policy.LogSeparator(out);
+    policy.LogEllipsis(out);
+  }
+  policy.LogClosing(out);
+}
+
+namespace detail {
+
+// RangeLogger is a helper class for gtl::LogRange and
+// gtl::LogContainer; do not use it directly.  This object
+// captures iterators into the argument of the LogRange and
+// LogContainer functions, so its lifetime should be confined to a
+// single logging statement.  Objects of this type should not be
+// assigned to local variables.
+template <typename IteratorT, typename PolicyT>
+class RangeLogger {
+ public:
+  RangeLogger(const IteratorT &begin, const IteratorT &end,
+                  const PolicyT &policy)
+      : begin_(begin), end_(end), policy_(policy) { }
+
+  friend std::ostream &operator<<(std::ostream &out, const RangeLogger &range) {
+    gtl::LogRangeToStream<IteratorT, PolicyT>(out, range.begin_, range.end_,
+                                              range.policy_);
+    return out;
+  }
+
+  // operator<< above is generally recommended. However, some situations may
+  // require a string, so a convenience str() method is provided as well.
+  std::string str() const {
+    std::string s;
+    ::strings::OStringStream(&s) << *this;
+    return s;
+  }
+
+ private:
+  IteratorT begin_;
+  IteratorT end_;
+  PolicyT policy_;
+};
+
+template <typename E>
+class EnumLogger {
+ public:
+  explicit EnumLogger(E e) : e_(e) {}
+
+  friend std::ostream &operator<<(std::ostream &out, const EnumLogger &v) {
+    using I = typename std::underlying_type<E>::type;
+    return out << static_cast<I>(v.e_);
+  }
+
+ private:
+  E e_;
+};
+
+}  // namespace detail
+
+// Log a range using "policy".  For example:
+//
+//   S2_LOG(INFO) << gtl::LogRange(start_pos, end_pos, gtl::LogMultiline());
+//
+// The above example will print the range using newlines between
+// elements, enclosed in [] braces.
+template <typename IteratorT, typename PolicyT>
+detail::RangeLogger<IteratorT, PolicyT> LogRange(
+    const IteratorT &begin, const IteratorT &end, const PolicyT &policy) {
+  return gtl::detail::RangeLogger<IteratorT, PolicyT>(begin, end, policy);
+}
+
+// Log a range.  For example:
+//
+//   S2_LOG(INFO) << gtl::LogRange(start_pos, end_pos);
+//
+// By default, Range() uses the LogShortUpTo100 policy: comma-space
+// separation, no newlines, and with limit of 100 items.
+template <typename IteratorT>
+detail::RangeLogger<IteratorT, LogDefault> LogRange(
+    const IteratorT &begin, const IteratorT &end) {
+  return gtl::LogRange(begin, end, LogDefault());
+}
+
+// Log a container using "policy".  For example:
+//
+//   S2_LOG(INFO) << gtl::LogContainer(container, gtl::LogMultiline());
+//
+// The above example will print the container using newlines between
+// elements, enclosed in [] braces.
+template <typename ContainerT, typename PolicyT>
+auto LogContainer(const ContainerT &container, const PolicyT &policy)
+    -> decltype(gtl::LogRange(container.begin(), container.end(), policy)) {
+  return gtl::LogRange(container.begin(), container.end(), policy);
+}
+
+// Log a container.  For example:
+//
+//   S2_LOG(INFO) << gtl::LogContainer(container);
+//
+// By default, Container() uses the LogShortUpTo100 policy: comma-space
+// separation, no newlines, and with limit of 100 items.
+template <typename ContainerT>
+auto LogContainer(const ContainerT &container)
+    -> decltype(gtl::LogContainer(container, LogDefault())) {
+  return gtl::LogContainer(container, LogDefault());
+}
+
+// Log a (possibly scoped) enum.  For example:
+//
+//   enum class Color { kRed, kGreen, kBlue };
+//   S2_LOG(INFO) << gtl::LogEnum(kRed);
+template <typename E>
+detail::EnumLogger<E> LogEnum(E e) {
+  static_assert(std::is_enum<E>::value, "must be an enum");
+  return detail::EnumLogger<E>(e);
+}
+
+}  // namespace gtl
+
+#endif  // S2_UTIL_GTL_CONTAINER_LOGGING_H_
diff --git a/src/s2/util/gtl/dense_hash_set.h b/src/s2/util/gtl/dense_hash_set.h
new file mode 100644 (file)
index 0000000..b3b0003
--- /dev/null
@@ -0,0 +1,358 @@
+// Copyright 2005 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// ---
+//
+// This is just a very thin wrapper over densehashtable.h, just
+// like sgi stl's stl_hash_set is a very thin wrapper over
+// stl_hashtable.
+//
+// This is more different from dense_hash_map than you might think,
+// because all iterators for sets are const (you obviously can't
+// change the key, and for sets there is no value).
+//
+// NOTE: this is exactly like sparse_hash_set.h, with the word
+// "sparse" replaced by "dense", except for the addition of
+// set_empty_key().
+//
+//   YOU MUST CALL SET_EMPTY_KEY() IMMEDIATELY AFTER CONSTRUCTION.
+//
+// Otherwise your program will die in mysterious ways.  (Note if you
+// use the constructor that takes an InputIterator range, you pass in
+// the empty key in the constructor, rather than after.  As a result,
+// this constructor differs from the standard STL version.)
+//
+// In other respects, we adhere mostly to the STL semantics for
+// hash-map.  One important exception is that insert() may invalidate
+// iterators entirely -- STL semantics are that insert() may reorder
+// iterators, but they all still refer to something valid in the
+// hashtable.  Not so for us.  Likewise, insert() may invalidate
+// pointers into the hashtable.  (Whether insert invalidates iterators
+// and pointers depends on whether it results in a hashtable resize,
+// but that's an implementation detail that may change in the future.)
+// On the plus side, delete() doesn't invalidate iterators or pointers
+// at all, or even change the ordering of elements.
+//
+// Also please note:
+//
+//    1) set_deleted_key():
+//         If you want to use erase() you must call set_deleted_key(),
+//         in addition to set_empty_key(), after construction.
+//         The deleted and empty keys must differ.
+//
+//    2) Keys equal to the empty key or deleted key (if any) cannot be
+//         used as keys for find(), count(), insert(), etc.
+//
+//    3) min_load_factor():
+//         Setting the minimum load factor controls how aggressively the
+//         table is shrunk when keys are erased.  Setting it to 0.0
+//         guarantees that the hash table will never shrink.
+//
+//    4) resize(0):
+//         When an item is deleted, its memory isn't freed right
+//         away.  This allows you to iterate over a hashtable,
+//         and call erase(), without invalidating the iterator.
+//         To force the memory to be freed, call resize(0).
+//         For tr1 compatibility, this can also be called as rehash(0).
+// Roughly speaking:
+//   (1) dense_hash_set: fastest, uses the most memory unless entries are small
+//   (2) sparse_hash_set: slowest, uses the least memory
+//   (3) hash_set / unordered_set (STL): in the middle
+//
+// Typically I use sparse_hash_set when I care about space and/or when
+// I need to save the hashtable on disk.  I use hash_set otherwise.  I
+// don't personally use dense_hash_set ever; some people use it for
+// small sets with lots of lookups.
+//
+// - dense_hash_set has, typically, about 78% memory overhead (if your
+//   data takes up X bytes, the hash_set uses .78X more bytes in overhead).
+// - sparse_hash_set has about 4 bits overhead per entry.
+// - sparse_hash_set can be 3-7 times slower than the others for lookup and,
+//   especially, inserts.  See time_hash_map.cc for details.
+//
+// See /usr/(local/)?doc/sparsehash-*/dense_hash_set.html
+// for information about how to use this class.
+
+#ifndef S2_UTIL_GTL_DENSE_HASH_SET_H_
+#define S2_UTIL_GTL_DENSE_HASH_SET_H_
+
+#include <cstdio>
+#include <algorithm>
+#include <functional>
+#include <memory>
+#include <utility>
+#include <vector>
+
+#include "s2/base/port.h"
+#include "absl/base/macros.h"
+#include "s2/util/gtl/densehashtable.h"  // IWYU pragma: export
+
+// Some files test for this symbol.
+#define S2__DENSE_HASH_SET_H_
+
+namespace gtl {
+
+template <class Value,
+          class HashFcn = std::hash<Value>,
+          class EqualKey = std::equal_to<Value>,
+          class Alloc = std::allocator<Value> >
+class dense_hash_set {
+ private:
+
+  // Apparently identity is not stl-standard, so we define our own
+  struct Identity {
+    typedef const Value& result_type;
+    const Value& operator()(const Value& v) const { return v; }
+  };
+  struct SetKey {
+    void operator()(Value* value, const Value& new_key) const {
+      *value = new_key;
+    }
+  };
+
+  // The actual data
+  typedef dense_hashtable<Value, Value, HashFcn, Identity, SetKey,
+                          EqualKey, Alloc> ht;
+  ht rep;
+
+ public:
+  typedef typename ht::key_type key_type;
+  typedef typename ht::value_type value_type;
+  typedef typename ht::hasher hasher;
+  typedef typename ht::key_equal key_equal;
+  typedef Alloc allocator_type;
+
+  typedef typename ht::size_type size_type;
+  typedef typename ht::difference_type difference_type;
+  typedef typename ht::const_pointer pointer;
+  typedef typename ht::const_pointer const_pointer;
+  typedef typename ht::const_reference reference;
+  typedef typename ht::const_reference const_reference;
+
+  typedef typename ht::const_iterator iterator;
+  typedef typename ht::const_iterator const_iterator;
+  typedef typename ht::const_local_iterator local_iterator;
+  typedef typename ht::const_local_iterator const_local_iterator;
+
+
+  // Iterator functions -- recall all iterators are const
+  iterator begin() const                  { return rep.begin(); }
+  iterator end() const                    { return rep.end(); }
+
+  // These come from tr1's unordered_set. For us, a bucket has 0 or 1 elements.
+  ABSL_DEPRECATED(
+      "This method is slated for removal.  Please migrate to "
+      "absl::flat_hash_set.")
+  local_iterator begin(size_type i) const { return rep.begin(i); }
+
+  ABSL_DEPRECATED(
+      "This method is slated for removal.  Please migrate to "
+      "absl::flat_hash_set.")
+  local_iterator end(size_type i) const   { return rep.end(i); }
+
+
+  // Accessor functions
+  allocator_type get_allocator() const    { return rep.get_allocator(); }
+  hasher hash_funct() const               { return rep.hash_funct(); }
+  hasher hash_function() const            { return hash_funct(); }  // tr1 name
+  key_equal key_eq() const                { return rep.key_eq(); }
+
+
+  // Constructors
+  dense_hash_set() {}
+
+  explicit dense_hash_set(size_type expected_max_items_in_table,
+                          const hasher& hf = hasher(),
+                          const key_equal& eql = key_equal(),
+                          const allocator_type& alloc = allocator_type())
+      : rep(expected_max_items_in_table, hf, eql, Identity(), SetKey(), alloc) {
+  }
+
+  template <class InputIterator>
+  dense_hash_set(InputIterator f, InputIterator l,
+                 const key_type& empty_key_val,
+                 size_type expected_max_items_in_table = 0,
+                 const hasher& hf = hasher(),
+                 const key_equal& eql = key_equal(),
+                 const allocator_type& alloc = allocator_type())
+      : rep(expected_max_items_in_table, hf, eql, Identity(), SetKey(), alloc) {
+    set_empty_key(empty_key_val);
+    rep.insert(f, l);
+  }
+  // We use the default copy constructor
+  // We use the default operator=()
+  // We use the default destructor
+
+  void clear()                        { rep.clear(); }
+  // This clears the hash set without resizing it down to the minimum
+  // bucket count, but rather keeps the number of buckets constant
+  void clear_no_resize()              { rep.clear_no_resize(); }
+  void swap(dense_hash_set& hs)       { rep.swap(hs.rep); }
+
+
+  // Functions concerning size
+  size_type size() const              { return rep.size(); }
+  size_type max_size() const          { return rep.max_size(); }
+  bool empty() const                  { return rep.empty(); }
+  size_type bucket_count() const      { return rep.bucket_count(); }
+
+  ABSL_DEPRECATED(
+      "This method is slated for removal.  Please migrate to "
+      "absl::flat_hash_set.")
+  size_type max_bucket_count() const  { return rep.max_bucket_count(); }
+
+  // These are tr1 methods.  bucket() is the bucket the key is or would be in.
+  ABSL_DEPRECATED(
+      "This method is slated for removal.  Please migrate to "
+      "absl::flat_hash_set.")
+  size_type bucket_size(size_type i) const    { return rep.bucket_size(i); }
+  ABSL_DEPRECATED(
+      "This method is slated for removal.  Please migrate to "
+      "absl::flat_hash_set.")
+  size_type bucket(const key_type& key) const { return rep.bucket(key); }
+  float load_factor() const {
+    return size() * 1.0f / bucket_count();
+  }
+  float max_load_factor() const {
+    float shrink, grow;
+    rep.get_resizing_parameters(&shrink, &grow);
+    return grow;
+  }
+  void max_load_factor(float new_grow) {
+    float shrink, grow;
+    rep.get_resizing_parameters(&shrink, &grow);
+    rep.set_resizing_parameters(shrink, new_grow);
+  }
+  // These aren't tr1 methods but perhaps ought to be.
+  ABSL_DEPRECATED(
+      "This method is slated for removal.  Please migrate to "
+      "absl::flat_hash_set.")
+  float min_load_factor() const {
+    float shrink, grow;
+    rep.get_resizing_parameters(&shrink, &grow);
+    return shrink;
+  }
+  void min_load_factor(float new_shrink) {
+    float shrink, grow;
+    rep.get_resizing_parameters(&shrink, &grow);
+    rep.set_resizing_parameters(new_shrink, grow);
+  }
+  // Deprecated; use min_load_factor() or max_load_factor() instead.
+  void set_resizing_parameters(float shrink, float grow) {
+    rep.set_resizing_parameters(shrink, grow);
+  }
+
+  void resize(size_type hint)         { rep.resize(hint); }
+  void rehash(size_type hint)         { resize(hint); }     // the tr1 name
+
+  // Lookup routines
+  iterator find(const key_type& key) const           { return rep.find(key); }
+  size_type count(const key_type& key) const         { return rep.count(key); }
+  std::pair<iterator, iterator> equal_range(const key_type& key) const {
+    return rep.equal_range(key);
+  }
+
+
+  // Insertion routines
+  std::pair<iterator, bool> insert(const value_type& obj) {
+    std::pair<typename ht::iterator, bool> p = rep.insert(obj);
+    return std::pair<iterator, bool>(p.first, p.second);   // const to non-const
+  }
+  std::pair<iterator, bool> insert(value_type&& obj) {  // NOLINT
+    std::pair<typename ht::iterator, bool> p = rep.insert(std::move(obj));
+    return std::pair<iterator, bool>(p.first, p.second);   // const to non-const
+  }
+  template <class InputIterator> void insert(InputIterator f, InputIterator l) {
+    rep.insert(f, l);
+  }
+  void insert(const_iterator f, const_iterator l) {
+    rep.insert(f, l);
+  }
+  // Required for std::insert_iterator; the passed-in iterator is ignored.
+  iterator insert(iterator, const value_type& obj) {
+    return insert(obj).first;
+  }
+  iterator insert(iterator, value_type&& obj) {  // NOLINT
+    return insert(std::move(obj)).first;
+  }
+
+  // Unlike std::set, we cannot construct an element in place, as we do not have
+  // a layer of indirection like std::set nodes. Therefore, emplace* methods do
+  // not provide a performance advantage over insert + move.
+  template <typename... Args>
+  std::pair<iterator, bool> emplace(Args&&... args) {
+    return rep.insert(value_type(std::forward<Args>(args)...));
+  }
+  // The passed-in const_iterator is ignored.
+  template <typename... Args>
+  iterator emplace_hint(const_iterator, Args&&... args) {
+    return rep.insert(value_type(std::forward<Args>(args)...)).first;
+  }
+
+  // Deletion and empty routines
+  // THESE ARE NON-STANDARD!  I make you specify an "impossible" key
+  // value to identify deleted and empty buckets.  You can change the
+  // deleted key as time goes on, or get rid of it entirely to be insert-only.
+  void set_empty_key(const key_type& key)     { rep.set_empty_key(key); }
+  void set_deleted_key(const key_type& key)   { rep.set_deleted_key(key); }
+
+  // These are standard
+  size_type erase(const key_type& key)               { return rep.erase(key); }
+  void erase(iterator it)                            { rep.erase(it); }
+  void erase(iterator f, iterator l)                 { rep.erase(f, l); }
+
+
+  // Comparison
+  bool operator==(const dense_hash_set& hs) const    { return rep == hs.rep; }
+  bool operator!=(const dense_hash_set& hs) const    { return rep != hs.rep; }
+};
+
+template <class Val, class HashFcn, class EqualKey, class Alloc>
+inline void swap(dense_hash_set<Val, HashFcn, EqualKey, Alloc>& hs1,
+                 dense_hash_set<Val, HashFcn, EqualKey, Alloc>& hs2) {
+  hs1.swap(hs2);
+}
+
+}
+
+#endif  // S2_UTIL_GTL_DENSE_HASH_SET_H_
diff --git a/src/s2/util/gtl/densehashtable.h b/src/s2/util/gtl/densehashtable.h
new file mode 100644 (file)
index 0000000..737c307
--- /dev/null
@@ -0,0 +1,1493 @@
+// Copyright 2005 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// ---
+//
+// A dense hashtable is a particular implementation of
+// a hashtable: one that is meant to minimize memory allocation.
+// It does this by using an array to store all the data.  We
+// steal a value from the key space to indicate "empty" array
+// elements (ie indices where no item lives) and another to indicate
+// "deleted" elements.
+//
+// (Note it is possible to change the value of the delete key
+// on the fly; you can even remove it, though after that point
+// the hashtable is insert_only until you set it again.  The empty
+// value however can't be changed.)
+//
+// To minimize allocation and pointer overhead, we use internal
+// probing, in which the hashtable is a single table, and collisions
+// are resolved by trying to insert again in another bucket.  The
+// most cache-efficient internal probing schemes are linear probing
+// (which suffers, alas, from clumping) and quadratic probing, which
+// is what we implement by default.
+//
+// Type requirements: value_type is required to be Move Constructible
+// and Default Constructible. It is not required to be (and commonly
+// isn't) Assignable.
+//
+// You probably shouldn't use this code directly.  Use dense_hash_map<>
+// or dense_hash_set<> instead.
+
+// You can change the following below:
+// HT_OCCUPANCY_PCT      -- how full before we double size
+// HT_EMPTY_PCT          -- how empty before we halve size
+// HT_MIN_BUCKETS        -- default smallest bucket size
+//
+// You can also change enlarge_factor (which defaults to
+// HT_OCCUPANCY_PCT), and shrink_factor (which defaults to
+// HT_EMPTY_PCT) with set_resizing_parameters().
+//
+// How to decide what values to use?
+// shrink_factor's default of .4 * OCCUPANCY_PCT, is probably good.
+// HT_MIN_BUCKETS is probably unnecessary since you can specify
+// (indirectly) the starting number of buckets at construct-time.
+// For enlarge_factor, you can use this chart to try to trade-off
+// expected lookup time to the space taken up.  By default, this
+// code uses quadratic probing, though you can change it to linear
+// via JUMP_ below if you really want to.
+//
+// From
+// L = N / M,
+// where N is the number of data items in the table and M is the table size.
+// NUMBER OF PROBES / LOOKUP       Successful            Unsuccessful
+// Quadratic collision resolution   1 - ln(1-L) - L/2    1/(1-L) - L - ln(1-L)
+// Linear collision resolution     [1+1/(1-L)]/2         [1+1/(1-L)^2]/2
+//
+// -- enlarge_factor --           0.10  0.50  0.60  0.75  0.80  0.90  0.99
+// QUADRATIC COLLISION RES.
+//    probes/successful lookup    1.05  1.44  1.62  2.01  2.21  2.85  5.11
+//    probes/unsuccessful lookup  1.11  2.19  2.82  4.64  5.81  11.4  103.6
+// LINEAR COLLISION RES.
+//    probes/successful lookup    1.06  1.5   1.75  2.5   3.0   5.5   50.5
+//    probes/unsuccessful lookup  1.12  2.5   3.6   8.5   13.0  50.0  5000.0
+
+#ifndef S2_UTIL_GTL_DENSEHASHTABLE_H_
+#define S2_UTIL_GTL_DENSEHASHTABLE_H_
+
+#include <cassert>
+#include <cstddef>
+#include <cstdio>              // for FILE, fwrite, fread
+#include <algorithm>            // For swap(), eg
+#include <functional>
+#include <iterator>             // For iterator tags
+#include <limits>               // for numeric_limits
+#include <memory>               // For uninitialized_fill
+#include <new>
+#include <string>
+#include <utility>
+#include <vector>
+#include <type_traits>
+
+#include "s2/util/gtl/hashtable_common.h"
+#include "s2/base/port.h"
+#include <stdexcept>                 // For length_error
+
+namespace gtl {
+
+
+// Some files test for this symbol.
+#define S2__DENSEHASHTABLE_H_
+
+// The probing method
+// Linear probing
+// #define JUMP_(key, num_probes)    ( 1 )
+// Quadratic probing
+#define JUMP_(key, num_probes)    (num_probes)
+
+// The weird mod in the offset is entirely to quiet compiler warnings
+// as is the cast to int after doing the "x mod 256"
+#define PUT_(take_from, offset)  do {                                    \
+    if (putc(static_cast<int>(offset >= sizeof(take_from)*8)             \
+                              ? 0 : ((take_from) >> (offset)) % 256, fp) \
+        == EOF)                                                          \
+    return false;                                                        \
+} while (0)
+
+#define GET_(add_to, offset)  do {                                      \
+  if ((x=getc(fp)) == EOF)                                              \
+    return false;                                                       \
+  else if (offset >= sizeof(add_to) * 8)                                \
+    assert(x == 0);   /* otherwise it's too big for us to represent */  \
+  else                                                                  \
+    add_to |= (static_cast<size_type>(x) << ((offset) % (sizeof(add_to)*8))); \
+} while (0)
+
+
+// Hashtable class, used to implement the hashed associative containers
+// hash_set and hash_map.
+
+// Value: what is stored in the table (each bucket is a Value).
+// Key: something in a 1-to-1 correspondence to a Value, that can be used
+//      to search for a Value in the table (find() takes a Key).
+// HashFcn: Takes a Key and returns an integer, the more unique the better.
+// ExtractKey: given a Value, returns the unique Key associated with it.
+//             Must have a result_type enum indicating the return type of
+//             operator().
+// SetKey: given a Value* and a Key, modifies the value such that
+//         ExtractKey(value) == key.  We guarantee this is only called
+//         with key == deleted_key or key == empty_key.
+// EqualKey: Given two Keys, says whether they are the same (that is,
+//           if they are both associated with the same Value).
+// Alloc: STL allocator to use to allocate memory.
+
+template <class Value, class Key, class HashFcn,
+          class ExtractKey, class SetKey, class EqualKey, class Alloc>
+class dense_hashtable;
+
+template <class V, class K, class HF, class ExK, class SetK, class EqK, class A>
+struct dense_hashtable_const_iterator;
+
+// We're just an array, but we need to skip over empty and deleted elements
+template <class V, class K, class HF, class ExK, class SetK, class EqK, class A>
+struct dense_hashtable_iterator {
+ private:
+  typedef typename A::template rebind<V>::other value_alloc_type;
+
+ public:
+  typedef dense_hashtable_iterator<V, K, HF, ExK, SetK, EqK, A>
+      iterator;
+  typedef dense_hashtable_const_iterator<V, K, HF, ExK, SetK, EqK, A>
+      const_iterator;
+
+  typedef std::forward_iterator_tag iterator_category;  // very little defined!
+  typedef V value_type;
+  typedef typename value_alloc_type::difference_type difference_type;
+  typedef typename value_alloc_type::size_type size_type;
+  typedef typename value_alloc_type::reference reference;
+  typedef typename value_alloc_type::pointer pointer;
+
+  // "Real" constructor and default constructor
+  dense_hashtable_iterator(
+      const dense_hashtable<V, K, HF, ExK, SetK, EqK, A> *h,
+      pointer it, pointer it_end, bool advance)
+    : ht(h), pos(it), end(it_end)   {
+    if (advance)  advance_past_empty_and_deleted();
+  }
+  dense_hashtable_iterator() { }
+  // The default destructor is fine; we don't define one
+  // The default operator= is fine; we don't define one
+
+  // Happy dereferencer
+  reference operator*() const { return *pos; }
+  pointer operator->() const { return &(operator*()); }
+
+  // Arithmetic.  The only hard part is making sure that
+  // we're not on an empty or marked-deleted array element
+  void advance_past_empty_and_deleted() {
+    while (pos != end && (ht->test_empty(*this) || ht->test_deleted(*this)) )
+      ++pos;
+  }
+  iterator& operator++() {
+    assert(pos != end);
+    ++pos;
+    advance_past_empty_and_deleted();
+    return *this;
+  }
+  iterator operator++(int /*unused*/) {
+    auto tmp(*this);
+    ++*this;
+    return tmp;
+  }
+
+  // Comparison.
+  bool operator==(const iterator& it) const { return pos == it.pos; }
+  bool operator!=(const iterator& it) const { return pos != it.pos; }
+
+
+  // The actual data
+  const dense_hashtable<V, K, HF, ExK, SetK, EqK, A> *ht;
+  pointer pos, end;
+};
+
+
+// Now do it all again, but with const-ness!
+template <class V, class K, class HF, class ExK, class SetK, class EqK, class A>
+struct dense_hashtable_const_iterator {
+ private:
+  typedef typename A::template rebind<V>::other value_alloc_type;
+
+ public:
+  typedef dense_hashtable_iterator<V, K, HF, ExK, SetK, EqK, A>
+      iterator;
+  typedef dense_hashtable_const_iterator<V, K, HF, ExK, SetK, EqK, A>
+      const_iterator;
+
+  typedef std::forward_iterator_tag iterator_category;  // very little defined!
+  typedef V value_type;
+  typedef typename value_alloc_type::difference_type difference_type;
+  typedef typename value_alloc_type::size_type size_type;
+  typedef typename value_alloc_type::const_reference reference;
+  typedef typename value_alloc_type::const_pointer pointer;
+
+  // "Real" constructor and default constructor
+  dense_hashtable_const_iterator(
+      const dense_hashtable<V, K, HF, ExK, SetK, EqK, A> *h,
+      pointer it, pointer it_end, bool advance)
+    : ht(h), pos(it), end(it_end)   {
+    if (advance)  advance_past_empty_and_deleted();
+  }
+  dense_hashtable_const_iterator()
+    : ht(nullptr), pos(pointer()), end(pointer()) { }
+  // This lets us convert regular iterators to const iterators
+  dense_hashtable_const_iterator(const iterator &it)
+    : ht(it.ht), pos(it.pos), end(it.end) { }
+  // The default destructor is fine; we don't define one
+  // The default operator= is fine; we don't define one
+
+  // Happy dereferencer
+  reference operator*() const { return *pos; }
+  pointer operator->() const { return &(operator*()); }
+
+  // Arithmetic.  The only hard part is making sure that
+  // we're not on an empty or marked-deleted array element
+  void advance_past_empty_and_deleted() {
+    while (pos != end && (ht->test_empty(*this) || ht->test_deleted(*this)))
+      ++pos;
+  }
+  const_iterator& operator++()   {
+    assert(pos != end);
+    ++pos;
+    advance_past_empty_and_deleted();
+    return *this;
+  }
+  const_iterator operator++(int /*unused*/) {
+    auto tmp(*this);
+    ++*this;
+    return tmp;
+  }
+
+  // Comparison.
+  bool operator==(const const_iterator& it) const { return pos == it.pos; }
+  bool operator!=(const const_iterator& it) const { return pos != it.pos; }
+
+
+  // The actual data
+  const dense_hashtable<V, K, HF, ExK, SetK, EqK, A> *ht;
+  pointer pos, end;
+};
+
+template <class Value, class Key, class HashFcn,
+          class ExtractKey, class SetKey, class EqualKey, class Alloc>
+class dense_hashtable {
+ private:
+  typedef typename Alloc::template rebind<Value>::other value_alloc_type;
+
+
+ public:
+  typedef Key key_type;
+  typedef Value value_type;
+  typedef HashFcn hasher;
+  typedef EqualKey key_equal;
+  typedef Alloc allocator_type;
+
+  typedef typename value_alloc_type::size_type size_type;
+  typedef typename value_alloc_type::difference_type difference_type;
+  typedef typename value_alloc_type::reference reference;
+  typedef typename value_alloc_type::const_reference const_reference;
+  typedef typename value_alloc_type::pointer pointer;
+  typedef typename value_alloc_type::const_pointer const_pointer;
+  typedef dense_hashtable_iterator<Value, Key, HashFcn,
+                                   ExtractKey, SetKey, EqualKey, Alloc>
+  iterator;
+
+  typedef dense_hashtable_const_iterator<Value, Key, HashFcn,
+                                         ExtractKey, SetKey, EqualKey, Alloc>
+  const_iterator;
+
+  // These come from tr1.  For us they're the same as regular iterators.
+  typedef iterator local_iterator;
+  typedef const_iterator const_local_iterator;
+
+
+  // How full we let the table get before we resize, by default.
+  // Knuth says .8 is good -- higher causes us to probe too much,
+  // though it saves memory.
+  static const int HT_OCCUPANCY_PCT;  // defined at the bottom of this file
+
+  // How empty we let the table get before we resize lower, by default.
+  // (0.0 means never resize lower.)
+  // It should be less than OCCUPANCY_PCT / 2 or we thrash resizing
+  static const int HT_EMPTY_PCT;      // defined at the bottom of this file
+
+  // Minimum size we're willing to let hashtables be.
+  // Must be a power of two, and at least 4.
+  // Note, however, that for a given hashtable, the initial size is a
+  // function of the first constructor arg, and may be >HT_MIN_BUCKETS.
+  static const size_type HT_MIN_BUCKETS = 4;
+
+  // By default, if you don't specify a hashtable size at
+  // construction-time, we use this size.  Must be a power of two, and
+  // at least HT_MIN_BUCKETS.
+  static const size_type HT_DEFAULT_STARTING_BUCKETS = 32;
+
+  // ITERATOR FUNCTIONS
+  iterator begin() {
+    return iterator(this, table, table + num_buckets, true);
+  }
+  iterator end() {
+    return iterator(this, table + num_buckets, table + num_buckets, true);
+  }
+  const_iterator begin() const {
+    return const_iterator(this, table, table+num_buckets, true);
+  }
+  const_iterator end() const   {
+    return const_iterator(this, table + num_buckets, table+num_buckets, true);
+  }
+
+  // These come from tr1 unordered_map.  They iterate over 'bucket' n.
+  // We'll just consider bucket n to be the n-th element of the table.
+  local_iterator begin(size_type i) {
+    return local_iterator(this, table + i, table + i+1, false);
+  }
+  local_iterator end(size_type i) {
+    local_iterator it = begin(i);
+    if (!test_empty(i) && !test_deleted(i))
+      ++it;
+    return it;
+  }
+  const_local_iterator begin(size_type i) const {
+    return const_local_iterator(this, table + i, table + i+1, false);
+  }
+  const_local_iterator end(size_type i) const {
+    const_local_iterator it = begin(i);
+    if (!test_empty(i) && !test_deleted(i))
+      ++it;
+    return it;
+  }
+
+  // ACCESSOR FUNCTIONS for the things we templatize on, basically
+  hasher hash_funct() const               { return settings; }
+  key_equal key_eq() const                { return key_info; }
+  value_alloc_type get_allocator() const { return key_info; }
+
+  // Accessor function for statistics gathering.
+  int num_table_copies() const { return settings.num_ht_copies(); }
+
+ private:
+  // Annoyingly, we can't copy values around, because they might have
+  // const components (they're probably std::pair<const X, Y>).  We use
+  // explicit destructor invocation and placement new to get around
+  // this.  Arg.
+  static void set_value(pointer dst, const_reference src) {
+    dst->~value_type();   // delete the old value, if any
+    new(dst) value_type(src);
+  }
+
+  static void set_value(pointer dst, value_type&& src) {  // NOLINT
+    dst->~value_type();
+    new(dst) value_type(std::move(src));
+  }
+
+  void destroy_buckets(size_type first, size_type last) {
+    for ( ; first != last; ++first)
+      table[first].~value_type();
+  }
+
+  // DELETE HELPER FUNCTIONS
+  // This lets the user describe a key that will indicate deleted
+  // table entries.  This key should be an "impossible" entry --
+  // if you try to insert it for real, you won't be able to retrieve it!
+  // (NB: while you pass in an entire value, only the key part is looked
+  // at.  This is just because I don't know how to assign just a key.)
+ private:
+  // Gets rid of any deleted entries we have.
+  void squash_deleted() {
+    if (num_deleted > 0) {
+      rebucket(settings.min_buckets(size(), num_buckets));
+    }
+    assert(num_deleted == 0);
+  }
+
+  // Test if the given key is the deleted indicator.  Requires
+  // num_deleted > 0, for correctness of read(), and because that
+  // guarantees that key_info.delkey is valid.
+  bool test_deleted_key(const key_type& key) const {
+    assert(num_deleted > 0);
+    return equals(key_info.delkey, key);
+  }
+
+ public:
+  void set_deleted_key(const key_type &key) {
+    // the empty indicator (if specified) and the deleted indicator
+    // must be different
+    assert((!settings.use_empty() || !equals(key, key_info.empty)) &&
+           "Passed the empty-key to set_deleted_key");
+    // It's only safe to change what "deleted" means if we purge deleted guys
+    squash_deleted();
+    settings.set_use_deleted(true);
+    key_info.delkey = key;
+  }
+  key_type deleted_key() const {
+    assert(settings.use_deleted()
+           && "Must set deleted key before calling deleted_key");
+    return key_info.delkey;
+  }
+
+  // These are public so the iterators can use them
+  // True if the item at position bucknum is "deleted" marker
+  bool test_deleted(size_type bucknum) const {
+    // Invariant: !use_deleted() implies num_deleted is 0.
+    assert(settings.use_deleted() || num_deleted == 0);
+    return num_deleted > 0 && test_deleted_key(get_key(table[bucknum]));
+  }
+  bool test_deleted(const iterator &it) const {
+    // Invariant: !use_deleted() implies num_deleted is 0.
+    assert(settings.use_deleted() || num_deleted == 0);
+    return num_deleted > 0 && test_deleted_key(get_key(*it));
+  }
+  bool test_deleted(const const_iterator &it) const {
+    // Invariant: !use_deleted() implies num_deleted is 0.
+    assert(settings.use_deleted() || num_deleted == 0);
+    return num_deleted > 0 && test_deleted_key(get_key(*it));
+  }
+
+ private:
+  void check_use_deleted(const char* caller) {
+    (void)caller;    // could log it if the assert failed
+    assert(settings.use_deleted());
+  }
+
+  // Write the deleted key to the position specified.
+  // Requires: !test_deleted(it)
+  void set_deleted(iterator &it) {
+    check_use_deleted("set_deleted()");
+    assert(!test_deleted(it));
+    // &* converts from iterator to value-type.
+    set_key(&(*it), key_info.delkey);
+  }
+
+  // We also allow to set/clear the deleted bit on a const iterator.
+  // We allow a const_iterator for the same reason you can delete a
+  // const pointer: it's convenient, and semantically you can't use
+  // 'it' after it's been deleted anyway, so its const-ness doesn't
+  // really matter.
+  // Requires: !test_deleted(it)
+  void set_deleted(const_iterator &it) {
+    check_use_deleted("set_deleted()");
+    assert(!test_deleted(it));
+    set_key(const_cast<pointer>(&(*it)), key_info.delkey);
+  }
+
+  // EMPTY HELPER FUNCTIONS
+  // This lets the user describe a key that will indicate empty (unused)
+  // table entries.  This key should be an "impossible" entry --
+  // if you try to insert it for real, you won't be able to retrieve it!
+  // (NB: while you pass in an entire value, only the key part is looked
+  // at.  This is just because I don't know how to assign just a key.)
+ public:
+  // These are public so the iterators can use them
+  // True if the item at position bucknum is "empty" marker
+  bool test_empty(size_type bucknum) const {
+    assert(settings.use_empty());  // we always need to know what's empty!
+    return equals(key_info.empty, get_key(table[bucknum]));
+  }
+  bool test_empty(const iterator &it) const {
+    assert(settings.use_empty());  // we always need to know what's empty!
+    return equals(key_info.empty, get_key(*it));
+  }
+  bool test_empty(const const_iterator &it) const {
+    assert(settings.use_empty());  // we always need to know what's empty!
+    return equals(key_info.empty, get_key(*it));
+  }
+
+ private:
+  bool test_empty(size_type bucknum, const_pointer table) const {
+    assert(settings.use_empty());
+    return equals(key_info.empty, get_key(table[bucknum]));
+  }
+
+  void fill_range_with_empty(pointer table_start, pointer table_end) {
+    for (; table_start != table_end; ++table_start) {
+      new (table_start) value_type();
+      set_key(table_start, key_info.empty);
+    }
+  }
+
+ public:
+  // TODO(user): change all callers of this to pass in a key instead,
+  //                 and take a const key_type instead of const value_type.
+  void set_empty_key(const_reference val) {
+    // Once you set the empty key, you can't change it
+    assert(!settings.use_empty() && "Calling set_empty_key multiple times");
+    // The deleted indicator (if specified) and the empty indicator
+    // must be different.
+    const key_type& key = get_key(val);
+    assert((!settings.use_deleted() || !equals(key, key_info.delkey)) &&
+           "Setting the empty key the same as the deleted key");
+    settings.set_use_empty(true);
+    key_info.empty.~key_type();
+    new (&key_info.empty) key_type(key);
+
+    assert(!table);                  // must set before first use
+    // num_buckets was set in constructor even though table was nullptr
+    table = get_internal_allocator().allocate(num_buckets);
+    fill_range_with_empty(table, table + num_buckets);
+  }
+  // TODO(user): this should return the key by const reference.
+  value_type empty_key() const {
+    assert(settings.use_empty());
+    value_type ret = value_type();
+    set_key(&ret, key_info.empty);
+    return ret;
+  }
+
+  // FUNCTIONS CONCERNING SIZE
+ public:
+  size_type size() const      { return num_elements - num_deleted; }
+  size_type max_size() const { return get_allocator().max_size(); }
+  bool empty() const          { return size() == 0; }
+  size_type bucket_count() const      { return num_buckets; }
+  size_type max_bucket_count() const  { return max_size(); }
+  size_type nonempty_bucket_count() const { return num_elements; }
+  // These are tr1 methods.  Their idea of 'bucket' doesn't map well to
+  // what we do.  We just say every bucket has 0 or 1 items in it.
+  size_type bucket_size(size_type i) const {
+    return begin(i) == end(i) ? 0 : 1;
+  }
+
+ private:
+  // Because of the above, size_type(-1) is never legal; use it for errors
+  static const size_type ILLEGAL_BUCKET = size_type(-1);
+
+  // Used after a string of deletes.  Returns true if we actually shrunk.
+  // TODO(user): take a delta so we can take into account inserts
+  // done after shrinking.  Maybe make part of the Settings class?
+  bool maybe_shrink() {
+    assert(num_elements >= num_deleted);
+    assert((bucket_count() & (bucket_count()-1)) == 0);  // is a power of two
+    assert(bucket_count() >= HT_MIN_BUCKETS);
+    bool retval = false;
+
+    // If you construct a hashtable with < HT_DEFAULT_STARTING_BUCKETS,
+    // we'll never shrink until you get relatively big, and we'll never
+    // shrink below HT_DEFAULT_STARTING_BUCKETS.  Otherwise, something
+    // like "dense_hash_set<int> x; x.insert(4); x.erase(4);" will
+    // shrink us down to HT_MIN_BUCKETS buckets, which is too small.
+    const size_type num_remain = num_elements - num_deleted;
+    const size_type shrink_threshold = settings.shrink_threshold();
+    if (shrink_threshold > 0 && num_remain < shrink_threshold &&
+        bucket_count() > HT_DEFAULT_STARTING_BUCKETS) {
+      const float shrink_factor = settings.shrink_factor();
+      size_type sz = bucket_count() / 2;    // find how much we should shrink
+      while (sz > HT_DEFAULT_STARTING_BUCKETS &&
+             num_remain < sz * shrink_factor) {
+        sz /= 2;                            // stay a power of 2
+      }
+      rebucket(sz);
+      retval = true;
+    }
+    settings.set_consider_shrink(false);    // because we just considered it
+    return retval;
+  }
+
+  // We'll let you resize a hashtable -- though this makes us copy all!
+  // When you resize, you say, "make it big enough for this many more elements"
+  // Returns true if we actually resized, false if size was already ok.
+  bool resize_delta(size_type delta) {
+    bool did_resize = false;
+    if (settings.consider_shrink()) {  // see if lots of deletes happened
+      if (maybe_shrink())
+        did_resize = true;
+    }
+    if (num_elements >= std::numeric_limits<size_type>::max() - delta) {
+      throw std::length_error("resize overflow");
+    }
+
+    assert(settings.enlarge_threshold() < bucket_count());
+    // Check if our work is done.
+    if (bucket_count() >= HT_MIN_BUCKETS &&
+        num_elements + delta <= settings.enlarge_threshold()) {
+      return did_resize;
+    }
+
+    // Sometimes, we need to resize just to get rid of all the
+    // "deleted" buckets that are clogging up the hashtable.  So when
+    // deciding whether to resize, count the deleted buckets (which
+    // are currently taking up room).  But later, when we decide what
+    // size to resize to, *don't* count deleted buckets, since they
+    // get discarded during the resize.
+    const size_type needed_size = settings.min_buckets(num_elements + delta, 0);
+    if (needed_size <= bucket_count())      // we have enough buckets
+      return did_resize;
+
+    // We will rebucket.
+    size_type resize_to =
+      settings.min_buckets(num_elements - num_deleted + delta, bucket_count());
+
+    if (resize_to < needed_size) {
+      // This situation means that we have enough deleted elements,
+      // that once we purge them, we won't actually have needed to
+      // grow.  But we may want to grow anyway: if we just purge one
+      // element, say, we'll have to grow anyway next time we
+      // insert.  Might as well grow now, since we're already going
+      // through the trouble of rebucketing in order to purge the
+      // deleted elements.  (Safety note: Can resize_to * 2 overflow? No.
+      // The output of min_buckets() is always a power of two, so resize_to
+      // and needed_size are powers of two. That plus resize_to < needed_size
+      // proves that overflow isn't a concern.)
+      const size_type target =
+          static_cast<size_type>(settings.shrink_size(resize_to*2));
+      if (num_elements - num_deleted + delta >= target) {
+        // Good, we won't be below the shrink threshhold even if we double.
+        resize_to *= 2;
+      }
+    }
+    rebucket(resize_to);
+    return true;
+  }
+
+  // We require table be non-null and empty before calling this.
+  void resize_table(size_type old_size, size_type new_size) {
+    get_internal_allocator().deallocate(table, old_size);
+    table = get_internal_allocator().allocate(new_size);
+  }
+
+  // Copy (or, if Iter is a move_iterator, move) the elements from
+  // [src_first, src_last) into dest_table, which we assume has size
+  // dest_bucket_count and has been initialized to the empty key.
+  template<class Iter>
+  void copy_elements(Iter src_first, Iter src_last, pointer dest_table,
+                     size_type dest_bucket_count) {
+    assert((dest_bucket_count & (dest_bucket_count - 1)) == 0);  // a power of 2
+    // We use a normal iterator to get non-deleted bcks from ht
+    // We could use insert() here, but since we know there are
+    // no duplicates and no deleted items, we can be more efficient
+    for (; src_first != src_last; ++src_first) {
+      size_type num_probes = 0;               // how many times we've probed
+      size_type bucknum;
+      const size_type bucket_count_minus_one = dest_bucket_count - 1;
+      for (bucknum = hash(get_key(*src_first)) & bucket_count_minus_one;
+           !test_empty(bucknum, dest_table);  // not empty
+           bucknum = (bucknum +
+                      JUMP_(key, num_probes)) & bucket_count_minus_one) {
+        ++num_probes;
+        assert(num_probes < dest_bucket_count
+               && "Hashtable is full: an error in key_equal<> or hash<>");
+      }
+      // Copies or moves the value into dest_table.
+      set_value(&dest_table[bucknum], *src_first);
+    }
+  }
+
+  // Used to actually do the rehashing when we grow/shrink a hashtable
+  void copy_from(const dense_hashtable &ht, size_type min_buckets_wanted) {
+    size_type size = ht.size();  // clear_to_size() sets ht.size() to 0.
+    clear_to_size(settings.min_buckets(ht.size(), min_buckets_wanted));
+    copy_elements(ht.begin(), ht.end(), table, bucket_count());
+    num_elements = size;
+    settings.inc_num_ht_copies();
+  }
+
+  // Rebuckets and resizes the hashtable.  Gets rid of any deleted entries.
+  void rebucket(size_type new_num_buckets) {
+    if (table == nullptr) {
+      // When we eventually allocate the table, it will have this many buckets.
+      num_buckets = new_num_buckets;
+      return;
+    }
+    assert(settings.use_empty());
+    assert((new_num_buckets & (new_num_buckets - 1)) == 0);  // a power of two
+    // If settings.shrink_factor() is zero then we must not shrink.
+    assert(settings.shrink_factor() > 0 || new_num_buckets >= num_buckets);
+    pointer new_table = get_internal_allocator().allocate(new_num_buckets);
+
+    fill_range_with_empty(new_table, new_table + new_num_buckets);
+    copy_elements(std::make_move_iterator(begin()),
+                  std::make_move_iterator(end()),
+                  new_table, new_num_buckets);
+
+    destroy_buckets(0, num_buckets);  // Destroy table's elements.
+    get_internal_allocator().deallocate(table, num_buckets);
+
+    table = new_table;
+    num_buckets = new_num_buckets;
+    assert(num_elements >= num_deleted);
+    num_elements -= num_deleted;
+    num_deleted = 0;
+    settings.reset_thresholds(bucket_count());
+    settings.inc_num_ht_copies();
+  }
+
+  // Required by the spec for hashed associative container
+ public:
+  // Though the docs say this should be num_buckets, I think it's much
+  // more useful as num_elements.  As a special feature, calling with
+  // req_elements==0 will cause us to shrink if we can, saving space.
+  void resize(size_type req_elements) {       // resize to this or larger
+    if ( settings.consider_shrink() || req_elements == 0 )
+      maybe_shrink();
+    if ( req_elements > num_elements )
+      resize_delta(req_elements - num_elements);
+  }
+
+  // Get and change the value of shrink_factor and enlarge_factor.  The
+  // description at the beginning of this file explains how to choose
+  // the values.  Setting the shrink parameter to 0.0 ensures that the
+  // table never shrinks.
+  void get_resizing_parameters(float* shrink, float* grow) const {
+    *shrink = settings.shrink_factor();
+    *grow = settings.enlarge_factor();
+  }
+  void set_resizing_parameters(float shrink, float grow) {
+    settings.set_resizing_parameters(shrink, grow);
+    settings.reset_thresholds(bucket_count());
+  }
+
+  // CONSTRUCTORS -- as required by the specs, we take a size,
+  // but also let you specify a hashfunction, key comparator,
+  // and key extractor.  We also define a copy constructor and =.
+  // DESTRUCTOR -- needs to free the table
+  explicit dense_hashtable(size_type expected_max_items_in_table = 0,
+                           const HashFcn& hf = HashFcn(),
+                           const EqualKey& eql = EqualKey(),
+                           const ExtractKey& ext = ExtractKey(),
+                           const SetKey& set = SetKey(),
+                           const Alloc& alloc = Alloc())
+      : settings(hf),
+        key_info(ext, set, eql, value_alloc_type(alloc)),
+        num_deleted(0),
+        num_elements(0),
+        num_buckets(expected_max_items_in_table == 0
+                        ? HT_DEFAULT_STARTING_BUCKETS
+                        : settings.min_buckets(expected_max_items_in_table, 0)),
+        table(nullptr) {
+    // table is nullptr until the empty key is set. However, we set num_buckets
+    // here so we know how much space to allocate once the empty key is set.
+    settings.reset_thresholds(bucket_count());
+  }
+
+  // As a convenience for resize(), we allow an optional second argument
+  // which lets you make this new hashtable a different size than ht
+  dense_hashtable(const dense_hashtable& ht,
+                  size_type min_buckets_wanted = HT_DEFAULT_STARTING_BUCKETS)
+      : settings(ht.settings),
+        key_info(ht.key_info.as_extract_key(), ht.key_info.as_set_key(),
+                 ht.key_info.as_equal_key(),
+                 value_alloc_type(
+                     std::allocator_traits<value_alloc_type>::
+                         select_on_container_copy_construction(
+                             ht.key_info.as_value_alloc()))),
+        num_deleted(0),
+        num_elements(0),
+        num_buckets(0),
+        table(nullptr) {
+    key_info.delkey = ht.key_info.delkey;
+    key_info.empty = ht.key_info.empty;
+    if (!ht.settings.use_empty()) {
+      // If use_empty isn't set, copy_from will crash, so we do our own copying.
+      assert(ht.empty());
+      num_buckets = settings.min_buckets(ht.size(), min_buckets_wanted);
+      settings.reset_thresholds(bucket_count());
+      return;
+    }
+    settings.reset_thresholds(bucket_count());
+    copy_from(ht, min_buckets_wanted);   // copy_from() ignores deleted entries
+  }
+
+  dense_hashtable& operator=(const dense_hashtable& ht) {
+    if (&ht == this)  return *this;        // don't copy onto ourselves
+    settings = ht.settings;
+    key_info.as_extract_key() = ht.key_info.as_extract_key();
+    key_info.as_set_key() = ht.key_info.as_set_key();
+    key_info.as_equal_key() = ht.key_info.as_equal_key();
+    if (std::allocator_traits<
+            value_alloc_type>::propagate_on_container_copy_assignment::value) {
+      // If we're about to overwrite our allocator, we need to free all
+      // memory using our old allocator.
+      if (key_info.as_value_alloc() != ht.key_info.as_value_alloc()) {
+        destroy_table();
+      }
+      static_cast<value_alloc_type&>(key_info) =
+          static_cast<const value_alloc_type&>(ht.key_info);
+    }
+    key_info.empty = ht.key_info.empty;
+    key_info.delkey = ht.key_info.delkey;
+
+    if (ht.settings.use_empty()) {
+      // copy_from() calls clear and sets num_deleted to 0 too
+      copy_from(ht, HT_MIN_BUCKETS);
+    } else {
+      assert(ht.empty());
+      destroy_table();
+    }
+
+    // we purposefully don't copy the allocator, which may not be copyable
+    return *this;
+  }
+
+  dense_hashtable(dense_hashtable&& ht)
+      : settings(std::move(ht.settings)),
+        key_info(std::move(ht.key_info)),
+        num_deleted(ht.num_deleted),
+        num_elements(ht.num_elements),
+        num_buckets(ht.num_buckets),
+        table(ht.table) {
+    ht.num_deleted = 0;
+    ht.num_elements = 0;
+    ht.table = nullptr;
+    ht.num_buckets = HT_DEFAULT_STARTING_BUCKETS;
+    ht.settings.set_use_empty(false);
+    ht.settings.set_use_deleted(false);
+  }
+
+  dense_hashtable& operator=(dense_hashtable&& ht) {
+    if (&ht == this) return *this;        // don't move onto ourselves
+
+    const bool can_move_table =
+        std::allocator_traits<
+            Alloc>::propagate_on_container_move_assignment::value ||
+        key_info.as_value_alloc() == ht.key_info.as_value_alloc();
+
+    // First, deallocate with this's allocator.
+    destroy_table();
+
+    if (std::allocator_traits<
+            value_alloc_type>::propagate_on_container_move_assignment::value) {
+      // This moves the allocator.
+      key_info = std::move(ht.key_info);
+    } else {
+      // Move all other base classes of key_info from ht, but don't move the
+      // allocator.
+      key_info.as_extract_key() = std::move(ht.key_info.as_extract_key());
+      key_info.as_set_key() = std::move(ht.key_info.as_set_key());
+      key_info.as_equal_key() = std::move(ht.key_info.as_equal_key());
+      key_info.delkey = std::move(ht.key_info.delkey);
+      key_info.empty = std::move(ht.key_info.empty);
+    }
+
+    settings = std::move(ht.settings);
+    num_deleted = ht.num_deleted;
+    ht.num_deleted = 0;
+    num_elements = ht.num_elements;
+    ht.num_elements = 0;
+    num_buckets = ht.num_buckets;
+    ht.num_buckets = HT_DEFAULT_STARTING_BUCKETS;
+    ht.settings.set_use_empty(false);
+    ht.settings.set_use_deleted(false);
+
+    if (can_move_table) {
+      // We can transfer ownership of the table from ht to this because either
+      // we're propagating the allocator or ht's allocator is equal to this's.
+      table = ht.table;
+      ht.table = nullptr;
+    } else if (ht.table) {
+      // We can't transfer ownership of any memory from ht to this, so the
+      // best we can do is move element-by-element.
+      table = get_internal_allocator().allocate(num_buckets);
+      for (size_type i = 0; i < num_buckets; ++i) {
+        new(table + i) Value(std::move(ht.table[i]));
+      }
+      ht.destroy_table();
+    }
+
+    return *this;
+  }
+
+  ~dense_hashtable() { destroy_table(); }
+
+  // Many STL algorithms use swap instead of copy constructors
+  void swap(dense_hashtable& ht) {
+    if (this == &ht) return;  // swap with self.
+    using std::swap;
+    swap(settings, ht.settings);
+    // Swap everything in key_info but the allocator.
+    swap(key_info.as_extract_key(), ht.key_info.as_extract_key());
+    swap(key_info.as_set_key(), ht.key_info.as_set_key());
+    swap(key_info.as_equal_key(), ht.key_info.as_equal_key());
+    if (std::allocator_traits<
+            value_alloc_type>::propagate_on_container_swap::value) {
+      swap(static_cast<value_alloc_type&>(key_info),
+           static_cast<value_alloc_type&>(ht.key_info));
+    } else {
+      // Swapping when allocators are unequal and
+      // propagate_on_container_swap is false is undefined behavior.
+      S2_CHECK(key_info.as_value_alloc() == ht.key_info.as_value_alloc());
+    }
+    swap(key_info.empty, ht.key_info.empty);
+    swap(key_info.delkey, ht.key_info.delkey);
+    swap(num_deleted, ht.num_deleted);
+    swap(num_elements, ht.num_elements);
+    swap(num_buckets, ht.num_buckets);
+    swap(table, ht.table);
+  }
+
+ private:
+  void destroy_table() {
+    if (table) {
+      destroy_buckets(0, num_buckets);
+      get_internal_allocator().deallocate(table, num_buckets);
+      table = nullptr;
+    }
+  }
+
+  void clear_to_size(size_type new_num_buckets) {
+    if (!table) {
+      table = get_internal_allocator().allocate(new_num_buckets);
+    } else {
+      destroy_buckets(0, num_buckets);
+      if (new_num_buckets != num_buckets) {   // resize, if necessary
+        resize_table(num_buckets, new_num_buckets);
+      }
+    }
+    assert(table);
+    fill_range_with_empty(table, table + new_num_buckets);
+    num_elements = 0;
+    num_deleted = 0;
+    num_buckets = new_num_buckets;          // our new size
+    settings.reset_thresholds(bucket_count());
+  }
+
+ public:
+  // It's always nice to be able to clear a table without deallocating it
+  void clear() {
+    // If the table is already empty, and the number of buckets is
+    // already as we desire, there's nothing to do.
+    const size_type new_num_buckets = settings.min_buckets(0, 0);
+    if (num_elements == 0 && new_num_buckets == num_buckets) {
+      return;
+    }
+    clear_to_size(new_num_buckets);
+  }
+
+  // Clear the table without resizing it.
+  // Mimicks the stl_hashtable's behaviour when clear()-ing in that it
+  // does not modify the bucket count
+  void clear_no_resize() {
+    if (num_elements > 0) {
+      assert(table);
+      destroy_buckets(0, num_buckets);
+      fill_range_with_empty(table, table + num_buckets);
+    }
+    // don't consider to shrink before another erase()
+    settings.reset_thresholds(bucket_count());
+    num_elements = 0;
+    num_deleted = 0;
+  }
+
+  // LOOKUP ROUTINES
+ private:
+  template <class K>
+  void assert_key_is_not_empty_or_deleted(const K& key) const {
+    assert(settings.use_empty() && "set_empty_key() was not called");
+    assert(!equals(key, key_info.empty) &&
+           "Using the empty key as a regular key");
+    assert((!settings.use_deleted() || !equals(key, key_info.delkey))
+           && "Using the deleted key as a regular key");
+  }
+
+  template <class K>
+  std::pair<size_type, size_type> find_position(const K& key) const {
+    return find_position_using_hash(hash(key), key);
+  }
+
+  // Returns a pair of positions: 1st where the object is, 2nd where
+  // it would go if you wanted to insert it.  1st is ILLEGAL_BUCKET
+  // if object is not found; 2nd is ILLEGAL_BUCKET if it is.
+  // Note: because of deletions where-to-insert is not trivial: it's the
+  // first deleted bucket we see, as long as we don't find the key later
+  template <class K>
+  std::pair<size_type, size_type> find_position_using_hash(
+      const size_type key_hash, const K& key) const {
+    assert_key_is_not_empty_or_deleted(key);
+    size_type num_probes = 0;              // how many times we've probed
+    const size_type bucket_count_minus_one = bucket_count() - 1;
+    size_type bucknum = key_hash & bucket_count_minus_one;
+    size_type insert_pos = ILLEGAL_BUCKET;  // where we would insert
+    while (1) {                             // probe until something happens
+      if (test_empty(bucknum)) {            // bucket is empty
+        if (insert_pos == ILLEGAL_BUCKET)   // found no prior place to insert
+          return std::pair<size_type, size_type>(ILLEGAL_BUCKET, bucknum);
+        else
+          return std::pair<size_type, size_type>(ILLEGAL_BUCKET, insert_pos);
+
+      } else if (test_deleted(bucknum)) {
+        // keep searching, but mark to insert
+        if ( insert_pos == ILLEGAL_BUCKET )
+          insert_pos = bucknum;
+
+      } else if (equals(key, get_key(table[bucknum]))) {
+        return std::pair<size_type, size_type>(bucknum, ILLEGAL_BUCKET);
+      }
+      ++num_probes;                        // we're doing another probe
+      bucknum = (bucknum + JUMP_(key, num_probes)) & bucket_count_minus_one;
+      assert(num_probes < bucket_count()
+             && "Hashtable is full: an error in key_equal<> or hash<>");
+    }
+  }
+
+  template <class K>
+  std::pair<size_type, bool> find_if_present(const K& key) const {
+    return find_if_present_using_hash(hash(key), key);
+  }
+
+  // Return where the key is (if at all), and if it is present.  If
+  // the key isn't present then the first part of the return value is
+  // undefined.  The same information can be extracted from the result
+  // of find_position(), but that tends to be slower in practice.
+  template <class K>
+  std::pair<size_type, bool> find_if_present_using_hash(
+      const size_type key_hash, const K& key) const {
+    assert_key_is_not_empty_or_deleted(key);
+    size_type num_probes = 0;              // how many times we've probed
+    const size_type bucket_count_minus_one = bucket_count() - 1;
+    size_type bucknum = key_hash & bucket_count_minus_one;
+    while (1) {                             // probe until something happens
+      if (equals(key, get_key(table[bucknum]))) {
+        return std::pair<size_type, bool>(bucknum, true);
+      } else if (test_empty(bucknum)) {
+        return std::pair<size_type, bool>(0, false);
+      }
+      ++num_probes;                        // we're doing another probe
+      bucknum = (bucknum + JUMP_(key, num_probes)) & bucket_count_minus_one;
+      assert(num_probes < bucket_count()
+             && "Hashtable is full: an error in key_equal<> or hash<>");
+    }
+  }
+
+ private:
+  template <class K>
+  iterator find_impl(const K& key) {
+    std::pair<size_type, bool> pos = find_if_present(key);
+    return pos.second ?
+        iterator(this, table + pos.first, table + num_buckets, false) :
+        end();
+  }
+
+  template <class K>
+  const_iterator find_impl(const K& key) const {
+    std::pair<size_type, bool> pos = find_if_present(key);
+    return pos.second ?
+        const_iterator(this, table + pos.first, table + num_buckets, false) :
+        end();
+  }
+
+  template <class K>
+  size_type bucket_impl(const K& key) const {
+    std::pair<size_type, size_type> pos = find_position(key);
+    return pos.first == ILLEGAL_BUCKET ? pos.second : pos.first;
+  }
+
+  template <class K>
+  size_type count_impl(const K& key) const {
+    return find_if_present(key).second ? 1 : 0;
+  }
+
+  template <class K>
+  std::pair<iterator, iterator>
+  equal_range_impl(const K& key) {
+    iterator pos = find(key);
+    if (pos == end()) {
+      return std::pair<iterator, iterator>(pos, pos);
+    } else {
+      const iterator startpos = pos++;
+      return std::pair<iterator, iterator>(startpos, pos);
+    }
+  }
+
+  template <class K>
+  std::pair<const_iterator, const_iterator>
+  equal_range_impl(const K& key) const {
+    const_iterator pos = find(key);
+    if (pos == end()) {
+      return std::pair<const_iterator, const_iterator>(pos, pos);
+    } else {
+      const const_iterator startpos = pos++;
+      return std::pair<const_iterator, const_iterator>(startpos, pos);
+    }
+  }
+
+ public:
+  iterator find(const key_type& key) { return find_impl(key); }
+
+  const_iterator find(const key_type& key) const { return find_impl(key); }
+
+  // This is a tr1 method: the bucket a given key is in, or what bucket
+  // it would be put in, if it were to be inserted.  Shrug.
+  size_type bucket(const key_type& key) const { return bucket_impl(key); }
+
+  // Counts how many elements have key key.  For maps, it's either 0 or 1.
+  size_type count(const key_type &key) const { return count_impl(key); }
+
+  // Likewise, equal_range doesn't really make sense for us.  Oh well.
+  std::pair<iterator, iterator>
+  equal_range(const key_type& key) { return equal_range_impl(key); }
+
+  std::pair<const_iterator, const_iterator>
+  equal_range(const key_type& key) const { return equal_range_impl(key); }
+
+
+
+  // INSERTION ROUTINES
+ private:
+  // Private method used by insert_noresize and find_or_insert.
+  // 'obj' is either value_type&& or const value_type&.
+  template <typename U>
+  iterator insert_at(U&& obj, size_type pos) {
+    if (size() >= max_size()) {
+      throw std::length_error("insert overflow");
+    }
+    if ( test_deleted(pos) ) {      // just replace if it's been del.
+      assert(num_deleted > 0);
+      --num_deleted;                // used to be, now it isn't
+    } else {
+      ++num_elements;               // replacing an empty bucket
+    }
+    set_value(&table[pos], std::forward<U>(obj));
+    return iterator(this, table + pos, table + num_buckets, false);
+  }
+
+  // If you know *this is big enough to hold obj, use this routine
+  // 'obj' is value_type&& or const value_type&.
+  template <typename U>
+  std::pair<iterator, bool> insert_noresize(U&& obj) {  // NOLINT
+    return insert_noresize_using_hash(hash(get_key(obj)), std::forward<U>(obj));
+  }
+
+  // If you know *this is big enough to hold obj, use this routine
+  // 'obj' is value_type&& or const value_type&.
+  template <typename U>
+  std::pair<iterator, bool> insert_noresize_using_hash(const size_type key_hash,
+                                                       U&& obj) {
+    const std::pair<size_type, size_type> pos =
+        find_position_using_hash(key_hash, get_key(obj));
+    if (pos.first != ILLEGAL_BUCKET) {      // object was already there
+      return std::pair<iterator, bool>(iterator(this, table + pos.first,
+                                          table + num_buckets, false),
+                                 false);          // false: we didn't insert
+    } else {                                 // pos.second says where to put it
+      iterator i = insert_at(std::forward<U>(obj), pos.second);
+      return std::pair<iterator, bool>(i, true);
+    }
+  }
+
+  // Specializations of insert(it, it) depending on the power of the iterator:
+  // (1) Iterator supports operator-, resize before inserting
+  template <class ForwardIterator>
+  void insert(ForwardIterator f, ForwardIterator l, std::forward_iterator_tag) {
+    size_t dist = std::distance(f, l);
+    if (dist >= std::numeric_limits<size_type>::max()) {
+      throw std::length_error("insert-range overflow");
+    }
+    resize_delta(static_cast<size_type>(dist));
+    for ( ; dist > 0; --dist, ++f) {
+      insert_noresize(*f);
+    }
+  }
+
+  // (2) Arbitrary iterator, can't tell how much to resize
+  template <class InputIterator>
+  void insert(InputIterator f, InputIterator l, std::input_iterator_tag) {
+    for ( ; f != l; ++f)
+      insert(*f);
+  }
+
+ public:
+  // This is the normal insert routine, used by the outside world
+  std::pair<iterator, bool> insert(const value_type& obj) {
+    resize_delta(1);                      // adding an object, grow if need be
+    return insert_noresize(obj);
+  }
+
+  std::pair<iterator, bool> insert(value_type&& obj) {  // NOLINT
+    resize_delta(1);                      // adding an object, grow if need be
+    return insert_noresize(std::move(obj));
+  }
+
+  // When inserting a lot at a time, we specialize on the type of iterator
+  template <class InputIterator>
+  void insert(InputIterator f, InputIterator l) {
+    // specializes on iterator type
+    insert(f, l,
+           typename std::iterator_traits<InputIterator>::iterator_category());
+  }
+
+  template <class DefaultValue>
+  value_type& find_or_insert(const key_type& key) {
+    return find_or_insert_using_hash<DefaultValue>(hash(key), key);
+  }
+
+  // DefaultValue is a functor that takes a key and returns a value_type
+  // representing the default value to be inserted if none is found.
+  template <class DefaultValue>
+  value_type& find_or_insert_using_hash(const size_type key_hash,
+                                        const key_type& key) {
+    const std::pair<size_type, size_type> pos =
+        find_position_using_hash(key_hash, key);
+    DefaultValue default_value;
+    if (pos.first != ILLEGAL_BUCKET) {  // object was already there
+      return table[pos.first];
+    } else if (resize_delta(1)) {        // needed to rehash to make room
+      // Since we resized, we can't use pos, so recalculate where to insert.
+      return *insert_noresize(default_value(key)).first;
+    } else {                             // no need to rehash, insert right here
+      return *insert_at(default_value(key), pos.second);
+    }
+  }
+
+
+  // DELETION ROUTINES
+ private:
+  template <class K>
+  size_type erase_impl(const K& key) {
+    iterator pos = find(key);
+    if (pos != end()) {
+      assert(!test_deleted(pos));  // or find() shouldn't have returned it
+      set_deleted(pos);
+      ++num_deleted;
+      // will think about shrink after next insert
+      settings.set_consider_shrink(true);
+      return 1;                    // because we deleted one thing
+    } else {
+      return 0;                    // because we deleted nothing
+    }
+  }
+
+ public:
+  size_type erase(const key_type& key) {
+    return erase_impl(key);
+  }
+
+
+  void erase(iterator pos) {
+    if (pos == end()) return;    // sanity check
+    set_deleted(pos);
+    ++num_deleted;
+    // will think about shrink after next insert
+    settings.set_consider_shrink(true);
+  }
+
+  void erase(iterator f, iterator l) {
+    for (; f != l; ++f) {
+      set_deleted(f);
+      ++num_deleted;
+    }
+    // will think about shrink after next insert
+    settings.set_consider_shrink(true);
+  }
+
+  // We allow you to erase a const_iterator just like we allow you to
+  // erase an iterator.  This is in parallel to 'delete': you can delete
+  // a const pointer just like a non-const pointer.  The logic is that
+  // you can't use the object after it's erased anyway, so it doesn't matter
+  // if it's const or not.
+  void erase(const_iterator pos) {
+    if (pos == end()) return;    // sanity check
+    set_deleted(pos);
+    ++num_deleted;
+    // will think about shrink after next insert
+    settings.set_consider_shrink(true);
+  }
+  void erase(const_iterator f, const_iterator l) {
+    for ( ; f != l; ++f) {
+      set_deleted(f);
+      ++num_deleted;
+    }
+    // will think about shrink after next insert
+    settings.set_consider_shrink(true);
+  }
+
+
+  // COMPARISON
+  bool operator==(const dense_hashtable& ht) const {
+    if (size() != ht.size()) {
+      return false;
+    } else if (this == &ht) {
+      return true;
+    } else {
+      // Iterate through the elements in "this" and see if the
+      // corresponding element is in ht
+      for ( const_iterator it = begin(); it != end(); ++it ) {
+        const_iterator it2 = ht.find(get_key(*it));
+        if ((it2 == ht.end()) || (*it != *it2)) {
+          return false;
+        }
+      }
+      return true;
+    }
+  }
+  bool operator!=(const dense_hashtable& ht) const {
+    return !(*this == ht);
+  }
+
+
+  // I/O
+  // We support reading and writing hashtables to disk.  Alas, since
+  // I don't know how to write a hasher or key_equal, you have to make
+  // sure everything but the table is the same.  We compact before writing.
+ private:
+  // Every time the disk format changes, this should probably change too
+  typedef unsigned long MagicNumberType;
+  static const MagicNumberType MAGIC_NUMBER = 0x13578642;
+
+  // Package functors with another class to eliminate memory needed for
+  // zero-size functors.  Since ExtractKey and hasher's operator() might
+  // have the same function signature, they must be packaged in
+  // different classes.
+  struct Settings :
+      sh_hashtable_settings<key_type, hasher, size_type, HT_MIN_BUCKETS> {
+    explicit Settings(const hasher& hf)
+        : sh_hashtable_settings<key_type, hasher, size_type, HT_MIN_BUCKETS>(
+            hf, HT_OCCUPANCY_PCT / 100.0f, HT_EMPTY_PCT / 100.0f) {}
+  };
+
+  // Packages ExtractKey, SetKey, EqualKey functors, allocator and deleted and
+  // empty key values.
+  struct KeyInfo : public ExtractKey,
+                   public SetKey,
+                   public EqualKey,
+                   public value_alloc_type {
+    KeyInfo(const ExtractKey& ek, const SetKey& sk, const EqualKey& eq,
+            const value_alloc_type& a)
+        : ExtractKey(ek),
+          SetKey(sk),
+          EqualKey(eq),
+          value_alloc_type(a),
+          delkey(),
+          empty() {}
+
+    // Accessors for convenient access to base classes.
+    ExtractKey& as_extract_key() { return *this; }
+    const ExtractKey& as_extract_key() const { return *this; }
+    SetKey& as_set_key() { return *this; }
+    const SetKey& as_set_key() const { return *this; }
+    EqualKey& as_equal_key() { return *this; }
+    const EqualKey& as_equal_key() const { return *this; }
+    value_alloc_type& as_value_alloc() { return *this; }
+    const value_alloc_type& as_value_alloc() const { return *this; }
+
+    // We want to return the exact same type as ExtractKey: Key or const Key&
+    typename ExtractKey::result_type get_key(const_reference v) const {
+      return ExtractKey::operator()(v);
+    }
+    void set_key(pointer v, const key_type& k) const {
+      SetKey::operator()(v, k);
+    }
+
+    // We only ever call EqualKey::operator()(key_type, K) -- we never use the
+    // other order of args.  This allows consumers to get away with implementing
+    // only half of operator==.
+    template <class K>
+    bool equals(const key_type& a, const K& b) const {
+      return EqualKey::operator()(a, b);
+    }
+
+    pointer allocate(size_type size) {
+      pointer memory = value_alloc_type::allocate(size);
+      assert(memory != nullptr);
+      return memory;
+    }
+
+    // Which key marks deleted entries.
+    // TODO(user): make a pointer, and get rid of use_deleted (benchmark!)
+    typename std::remove_const<key_type>::type delkey;
+    // Key value used to mark unused entries.
+    typename std::remove_const<key_type>::type empty;
+  };
+
+  // Returns the value_alloc_type used to allocate and deallocate
+  // the table. This can be different from the one returned by get_allocator().
+  value_alloc_type& get_internal_allocator() { return key_info; }
+
+  // Utility functions to access the templated operators
+  size_type hash(const key_type& v) const {
+    return settings.hash(v);
+  }
+  bool equals(const key_type& a, const key_type& b) const {
+    return key_info.equals(a, b);
+  }
+
+
+  typename ExtractKey::result_type get_key(const_reference v) const {
+    return key_info.get_key(v);
+  }
+  void set_key(pointer v, const key_type& k) const {
+    key_info.set_key(v, k);
+  }
+
+ private:
+  // Actual data
+  Settings settings;
+  KeyInfo key_info;
+
+  size_type num_deleted;  // how many occupied buckets are marked deleted
+  size_type num_elements;
+  size_type num_buckets;
+  pointer table;
+};
+
+
+// We need a global swap as well
+template <class V, class K, class HF, class ExK, class SetK, class EqK, class A>
+inline void swap(dense_hashtable<V, K, HF, ExK, SetK, EqK, A> &x,
+                 dense_hashtable<V, K, HF, ExK, SetK, EqK, A> &y) {
+  x.swap(y);
+}
+
+#undef JUMP_
+#undef PUT_
+#undef GET_
+
+template <class V, class K, class HF, class ExK, class SetK, class EqK, class A>
+const typename dense_hashtable<V, K, HF, ExK, SetK, EqK, A>::size_type
+  dense_hashtable<V, K, HF, ExK, SetK, EqK, A>::ILLEGAL_BUCKET;
+
+// How full we let the table get before we resize.  Knuth says .8 is
+// good -- higher causes us to probe too much, though saves memory.
+// However, we go with .5, getting better performance at the cost of
+// more space (a trade-off densehashtable explicitly chooses to make).
+// Feel free to play around with different values, though, via
+// max_load_factor() and/or set_resizing_parameters().
+template <class V, class K, class HF, class ExK, class SetK, class EqK, class A>
+const int dense_hashtable<V,K,HF,ExK,SetK,EqK,A>::HT_OCCUPANCY_PCT = 50;
+
+// How empty we let the table get before we resize lower.
+// It should be less than OCCUPANCY_PCT / 2 or we thrash resizing.
+template <class V, class K, class HF, class ExK, class SetK, class EqK, class A>
+const int dense_hashtable<V, K, HF, ExK, SetK, EqK, A>::HT_EMPTY_PCT =
+  static_cast<int>(
+      0.4 * dense_hashtable<V, K, HF, ExK, SetK, EqK, A>::HT_OCCUPANCY_PCT);
+
+}
+
+#endif  // S2_UTIL_GTL_DENSEHASHTABLE_H_
diff --git a/src/s2/util/gtl/hashtable_common.h b/src/s2/util/gtl/hashtable_common.h
new file mode 100644 (file)
index 0000000..a5ea2a0
--- /dev/null
@@ -0,0 +1,253 @@
+// Copyright 2010 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// ---
+
+#ifndef S2_UTIL_GTL_HASHTABLE_COMMON_H_
+#define S2_UTIL_GTL_HASHTABLE_COMMON_H_
+
+#include <cassert>
+#include <cstddef>
+#include <algorithm>
+
+#include <stdexcept>                 // For length_error
+
+// Settings contains parameters for growing and shrinking the table.
+// It also packages zero-size functor (ie. hasher).  One invariant
+// enforced in enlarge_size() is that we never allow all slots
+// occupied.  (This is unlikely to matter to users, because using
+// a load near 1 is slow and not recommended.  It allows other code
+// to assume there is at least one empty bucket.)
+//
+// It does some munging of the hash value in cases where we think
+// (fear) the original hash function might not be very good.  In
+// particular, the default hash of pointers is the identity hash,
+// so probably all the low bits are 0.  We identify when we think
+// we're hashing a pointer, and chop off the low bits.  Note this
+// isn't perfect: even when the key is a pointer, we can't tell
+// for sure that the hash is the identity hash.  If it's not, this
+// is needless work (and possibly, though not likely, harmful).
+
+template<typename Key, typename HashFunc,
+         typename SizeType, int HT_MIN_BUCKETS>
+class sh_hashtable_settings : public HashFunc {
+ public:
+  typedef Key key_type;
+  typedef HashFunc hasher;
+  typedef SizeType size_type;
+
+ public:
+  sh_hashtable_settings(const hasher& hf,
+                        const float ht_occupancy_flt,
+                        const float ht_empty_flt)
+      : hasher(hf),
+        enlarge_threshold_(0),
+        shrink_threshold_(0),
+        consider_shrink_(false),
+        use_empty_(false),
+        use_deleted_(false),
+        num_ht_copies_(0) {
+    set_enlarge_factor(ht_occupancy_flt);
+    set_shrink_factor(ht_empty_flt);
+  }
+
+  template<class K>
+  size_type hash(const K& v) const {
+    // We munge the hash value when we don't trust hasher::operator().  It is
+    // very important that we use hash_munger<Key> instead of hash_munger<K>.
+    // Within a given hashtable, all hash values must be munged in the same way.
+    return hash_munger<Key>::MungedHash(hasher::operator()(v));
+  }
+
+  float enlarge_factor() const {
+    return enlarge_factor_;
+  }
+  void set_enlarge_factor(float f) {
+    enlarge_factor_ = f;
+  }
+  float shrink_factor() const {
+    return shrink_factor_;
+  }
+  void set_shrink_factor(float f) {
+    shrink_factor_ = f;
+  }
+
+  size_type enlarge_threshold() const {
+    return enlarge_threshold_;
+  }
+  void set_enlarge_threshold(size_type t) {
+    enlarge_threshold_ = t;
+  }
+  size_type shrink_threshold() const {
+    return shrink_threshold_;
+  }
+  void set_shrink_threshold(size_type t) {
+    shrink_threshold_ = t;
+  }
+
+  size_type enlarge_size(size_type x) const {
+    return std::min<size_type>(x - 1, x * enlarge_factor_);
+  }
+  size_type shrink_size(size_type x) const {
+    return static_cast<size_type>(x * shrink_factor_);
+  }
+
+  bool consider_shrink() const {
+    return consider_shrink_;
+  }
+  void set_consider_shrink(bool t) {
+    consider_shrink_ = t;
+  }
+
+  bool use_empty() const {
+    return use_empty_;
+  }
+  void set_use_empty(bool t) {
+    use_empty_ = t;
+  }
+
+  bool use_deleted() const {
+    return use_deleted_;
+  }
+  void set_use_deleted(bool t) {
+    use_deleted_ = t;
+  }
+
+  size_type num_ht_copies() const {
+    return static_cast<size_type>(num_ht_copies_);
+  }
+  void inc_num_ht_copies() {
+    ++num_ht_copies_;
+  }
+
+  // Reset the enlarge and shrink thresholds
+  void reset_thresholds(size_type num_buckets) {
+    set_enlarge_threshold(enlarge_size(num_buckets));
+    set_shrink_threshold(shrink_size(num_buckets));
+    // whatever caused us to reset already considered
+    set_consider_shrink(false);
+  }
+
+  // Caller is resposible for calling reset_threshold right after
+  // set_resizing_parameters.
+  void set_resizing_parameters(float shrink, float grow) {
+    assert(shrink >= 0.0);
+    assert(grow <= 1.0);
+    if (shrink > grow/2.0f)
+      shrink = grow / 2.0f;     // otherwise we thrash hashtable size
+    set_shrink_factor(shrink);
+    set_enlarge_factor(grow);
+  }
+
+  // This is the smallest size a hashtable can be without being too crowded.
+  // If you like, you can give a min #buckets as well as a min #elts.
+  // This is guaranteed to return a power of two.
+  size_type min_buckets(size_type num_elts, size_type min_buckets_wanted) {
+    float enlarge = enlarge_factor();
+    size_type sz = HT_MIN_BUCKETS;             // min buckets allowed
+    while ( sz < min_buckets_wanted ||
+            num_elts >= static_cast<size_type>(sz * enlarge) ) {
+      // This just prevents overflowing size_type, since sz can exceed
+      // max_size() here.
+      if (static_cast<size_type>(sz * 2) < sz) {
+        throw std::length_error("resize overflow");  // protect against overflow
+      }
+      sz *= 2;
+    }
+    return sz;
+  }
+
+ private:
+  template<class HashKey> class hash_munger {
+   public:
+    static size_t MungedHash(size_t hash) {
+      return hash;
+    }
+  };
+  // This matches when the hashtable key is a pointer.
+  template<class HashKey> class hash_munger<HashKey*> {
+   public:
+    static size_t MungedHash(size_t hash) {
+      // TODO(user): consider rotating instead:
+      //    static const int shift = (sizeof(void *) == 4) ? 2 : 3;
+      //    return (hash << (sizeof(hash) * 8) - shift)) | (hash >> shift);
+      // This matters if we ever change sparse/dense_hash_* to compare
+      // hashes before comparing actual values.  It's speedy on x86.
+      return hash / sizeof(void*);   // get rid of known-0 bits
+    }
+  };
+
+  size_type enlarge_threshold_;  // table.size() * enlarge_factor
+  size_type shrink_threshold_;   // table.size() * shrink_factor
+  float enlarge_factor_;         // how full before resize
+  float shrink_factor_;          // how empty before resize
+  // consider_shrink=true if we should try to shrink before next insert
+  bool consider_shrink_;
+  bool use_empty_;    // used only by densehashtable, not sparsehashtable
+  bool use_deleted_;  // false until delkey has been set
+  // num_ht_copies is a counter incremented every Copy/Move
+  unsigned int num_ht_copies_;
+};
+
+// This traits class checks whether T::is_transparent exists and names a type.
+//
+//   struct Foo { using is_transparent = void; };
+//   struct Bar {};
+//   static_assert(sh_is_transparent<Foo>::value, "Foo is transparent.");
+//   staitc_assert(!sh_is_transparent<Bar>::value, "Bar is not transparent.");
+template<class T>
+struct sh_is_transparent {
+ private:
+  struct No { char x; };
+  struct Yes { No x[2]; };
+
+  template <class U>
+  static Yes Test(typename U::is_transparent*);
+  template<class U> static No Test(...);
+
+ public:
+  enum { value = sizeof(Test<T>(nullptr)) == sizeof(Yes) };
+};
+
+
+#endif  // S2_UTIL_GTL_HASHTABLE_COMMON_H_
diff --git a/src/s2/util/gtl/layout.h b/src/s2/util/gtl/layout.h
new file mode 100644 (file)
index 0000000..fafb6ab
--- /dev/null
@@ -0,0 +1,28 @@
+// Copyright Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#ifndef S2_UTIL_GTL_LAYOUT_H_
+#define S2_UTIL_GTL_LAYOUT_H_
+
+#include "absl/container/internal/layout.h"
+
+namespace gtl {
+
+using absl::container_internal::Aligned;
+using absl::container_internal::Layout;
+
+}  // namespace gtl
+
+#endif  // S2_UTIL_GTL_LAYOUT_H_
diff --git a/src/s2/util/gtl/legacy_random_shuffle.h b/src/s2/util/gtl/legacy_random_shuffle.h
new file mode 100644 (file)
index 0000000..72a47dc
--- /dev/null
@@ -0,0 +1,77 @@
+// Copyright Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// gtl::legacy_random_shuffle is similar in API and behavior to
+// std::random_shuffle, which was removed in C++17.
+//
+// When built for Linux production targets using crosstool 18,
+// these APIs produce the same results as std::random_shuffle.
+//
+// Otherwise, the specification for these functions reverts to that
+// of std::random_shuffle as specified in C++11. In particular,
+// these functions do not promise to produce the same shuffle
+// sequences forever.
+//
+// These are deprecated, and intended to be used only for legacy
+// code that must move off std::random_shuffle simply because the
+// function is not part of C++17.
+#ifndef S2_UTIL_GTL_LEGACY_RANDOM_SHUFFLE_H_
+#define S2_UTIL_GTL_LEGACY_RANDOM_SHUFFLE_H_
+
+#include <algorithm>
+#include <cstdlib>
+#include <iterator>
+
+#include "absl/base/macros.h"
+
+namespace gtl {
+
+// Reorders the elements in the range `[begin, last)` randomly.  The
+// random number generator `rnd` must be a function object returning a
+// randomly chosen value of type convertible to and from
+// `std::iterator_traits<RandomIt>::difference_type` in the interval
+// `[0,n)` if invoked as `r(n)`.
+//
+// This function is deprecated.  See the file comment above for
+// additional details.
+template <class RandomIt, class RandomFunc>
+ABSL_DEPRECATED("Use std::shuffle instead; see go/nors-legacy-api")
+void legacy_random_shuffle(const RandomIt begin, const RandomIt end,
+                           RandomFunc&& rnd) {
+  auto size = std::distance(begin, end);
+  for (decltype(size) i = 1; i < size; ++i) {
+    // Loop invariant: elements below i are uniformly shuffled.
+    std::iter_swap(begin + i, begin + rnd(i + 1));
+  }
+}
+
+// Reorders the elements in the range `[begin, last)` randomly.  The
+// random number generator is `std::rand()`.
+//
+// This function is deprecated.  See the file comment above for
+// additional details.
+template <class RandomIt>
+ABSL_DEPRECATED("Use std::shuffle instead; see go/nors-legacy-api")
+void legacy_random_shuffle(RandomIt begin, RandomIt end) {
+  legacy_random_shuffle(
+      begin, end,
+      [](typename std::iterator_traits<RandomIt>::difference_type i) {
+        return std::rand() % i;
+      });
+}
+
+}  // namespace gtl
+
+#endif  // S2_UTIL_GTL_LEGACY_RANDOM_SHUFFLE_H_
diff --git a/src/s2/util/hash/mix.h b/src/s2/util/hash/mix.h
new file mode 100644 (file)
index 0000000..65f7bfa
--- /dev/null
@@ -0,0 +1,76 @@
+// Copyright 2013 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// Author: jyrki@google.com (Jyrki Alakuijala)
+//
+// This file contains routines for mixing hashes.
+
+#ifndef S2_UTIL_HASH_MIX_H_
+#define S2_UTIL_HASH_MIX_H_
+
+#include <cstddef>
+#include <limits>
+
+// Fast mixing of hash values -- not strong enough for fingerprinting.
+// May change from time to time.
+//
+// Values given are expected to be hashes from good hash functions.
+// What constitutes a good hash may depend on your application. As a rule of
+// thumb, if std::hash<int> is strong enough for your hashing need if
+// your data were just ints, it will most likely be the correct choice
+// for a mixed hash of data members. HashMix does one round of multiply and
+// rotate mixing, so you get some additional collision avoidance guarantees
+// compared to just using std::hash<int> directly.
+//
+// Possible use:
+//
+// struct Xyzzy {
+//   int x;
+//   int y;
+//   string id;
+// };
+//
+// #ifndef SWIG
+// template<> struct XyzzyHash<Xyzzy> {
+//   size_t operator()(const Xyzzy& c) const {
+//     HashMix mix(hash<int>()(c.x));
+//     mix.Mix(hash<int>()(c.y));
+//     mix.Mix(GoodFastHash<string>()(c.id));
+//     return mix.get();
+//   }
+// }
+// #endif
+//
+// HashMix is a lower level interface than std::hash<std::tuple<>>.
+// Use std::hash<std::tuple<>> instead of HashMix where appropriate.
+
+class HashMix {
+ public:
+  HashMix() : hash_(1) {}
+  explicit HashMix(size_t val) : hash_(val + 83) {}
+  void Mix(size_t val) {
+    static const size_t kMul = static_cast<size_t>(0xdc3eb94af8ab4c93ULL);
+    // Multiplicative hashing will mix bits better in the msb end ...
+    hash_ *= kMul;
+    // ... and rotating will move the better mixed msb-bits to lsb-bits.
+    hash_ = ((hash_ << 19) |
+             (hash_ >> (std::numeric_limits<size_t>::digits - 19))) + val;
+  }
+  size_t get() const { return hash_; }
+ private:
+  size_t hash_;
+};
+
+#endif  // S2_UTIL_HASH_MIX_H_
diff --git a/src/s2/util/math/exactfloat/exactfloat.cc b/src/s2/util/math/exactfloat/exactfloat.cc
new file mode 100644 (file)
index 0000000..2300ea0
--- /dev/null
@@ -0,0 +1,832 @@
+// Copyright 2009 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// Author: ericv@google.com (Eric Veach)
+
+#include "s2/util/math/exactfloat/exactfloat.h"
+
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
+#include <algorithm>
+#include <cmath>
+#include <limits>
+
+#include <openssl/bn.h>
+#include <openssl/crypto.h>  // for OPENSSL_free
+
+#include "s2/base/integral_types.h"
+#include "s2/base/logging.h"
+#include "absl/base/macros.h"
+#include "absl/container/fixed_array.h"
+
+using std::max;
+using std::min;
+
+// Define storage for constants.
+const int ExactFloat::kMinExp;
+const int ExactFloat::kMaxExp;
+const int ExactFloat::kMaxPrec;
+const int32 ExactFloat::kExpNaN;
+const int32 ExactFloat::kExpInfinity;
+const int32 ExactFloat::kExpZero;
+const int ExactFloat::kDoubleMantissaBits;
+
+// To simplify the overflow/underflow logic, we limit the exponent and
+// precision range so that (2 * bn_exp_) does not overflow an "int".  We take
+// advantage of this, for example, by only checking for overflow/underflow
+// *after* multiplying two numbers.
+static_assert(
+    ExactFloat::kMaxExp <= INT_MAX / 2 &&
+    ExactFloat::kMinExp - ExactFloat::kMaxPrec >= INT_MIN / 2,
+    "exactfloat exponent might overflow");
+
+// We define a few simple extensions to the OpenSSL's BIGNUM interface.
+// In some cases these depend on BIGNUM internal fields, so they might
+// require tweaking if the BIGNUM implementation changes significantly.
+// These are just thin wrappers for BoringSSL.
+
+#ifdef OPENSSL_IS_BORINGSSL
+
+inline static void BN_ext_set_uint64(BIGNUM* bn, uint64 v) {
+  S2_CHECK(BN_set_u64(bn, v));
+}
+
+// Return the absolute value of a BIGNUM as a 64-bit unsigned integer.
+// Requires that BIGNUM fits into 64 bits.
+inline static uint64 BN_ext_get_uint64(const BIGNUM* bn) {
+  uint64_t u64;
+  if (!BN_get_u64(bn, &u64)) {
+    S2_DCHECK(false) << "BN has " << BN_num_bits(bn) << " bits";
+    return 0;
+  }
+  return u64;
+}
+
+static int BN_ext_count_low_zero_bits(const BIGNUM* bn) {
+  return BN_count_low_zero_bits(bn);
+}
+
+#else  // !defined(OPENSSL_IS_BORINGSSL)
+
+// Set a BIGNUM to the given unsigned 64-bit value.
+inline static void BN_ext_set_uint64(BIGNUM* bn, uint64 v) {
+#if BN_BITS2 == 64
+  S2_CHECK(BN_set_word(bn, v));
+#else
+  static_assert(BN_BITS2 == 32, "at least 32 bit openssl build needed");
+  S2_CHECK(BN_set_word(bn, static_cast<uint32>(v >> 32)));
+  S2_CHECK(BN_lshift(bn, bn, 32));
+  S2_CHECK(BN_add_word(bn, static_cast<uint32>(v)));
+#endif
+}
+
+// Return the absolute value of a BIGNUM as a 64-bit unsigned integer.
+// Requires that BIGNUM fits into 64 bits.
+inline static uint64 BN_ext_get_uint64(const BIGNUM* bn) {
+  S2_DCHECK_LE(BN_num_bytes(bn), sizeof(uint64));
+#if BN_BITS2 == 64
+  return BN_get_word(bn);
+#else
+  static_assert(BN_BITS2 == 32, "at least 32 bit openssl build needed");
+  if (bn->top == 0) return 0;
+  if (bn->top == 1) return BN_get_word(bn);
+  S2_DCHECK_EQ(bn->top, 2);
+  return (static_cast<uint64>(bn->d[1]) << 32) + bn->d[0];
+#endif
+}
+
+#if OPENSSL_VERSION_NUMBER < 0x10100000L
+
+// Count the number of low-order zero bits in the given BIGNUM (ignoring its
+// sign).  Returns 0 if the argument is zero.
+static int BN_ext_count_low_zero_bits(const BIGNUM* bn) {
+  int count = 0;
+  for (int i = 0; i < bn->top; ++i) {
+    BN_ULONG w = bn->d[i];
+    if (w == 0) {
+      count += 8 * sizeof(BN_ULONG);
+    } else {
+      for (; (w & 1) == 0; w >>= 1) {
+        ++count;
+      }
+      break;
+    }
+  }
+  return count;
+}
+
+#else  // OPENSSL_VERSION_NUMBER >= 0x10100000L
+
+static int BN_ext_count_low_zero_bits(const BIGNUM* bn) {
+  // In OpenSSL >= 1.1, BIGNUM is an opaque type, so d and top
+  // cannot be accessed.  The bytes must be copied out at a ~25%
+  // performance penalty.
+  absl::FixedArray<unsigned char> bytes(BN_num_bytes(bn));
+  // "le" indicates little endian.
+  S2_CHECK_EQ(BN_bn2lebinpad(bn, bytes.data(), bytes.size()), bytes.size());
+
+  int count = 0;
+  for (unsigned char c : bytes) {
+    if (c == 0) {
+      count += 8;
+    } else {
+      for (; (c & 1) == 0; c >>= 1) {
+        ++count;
+      }
+      break;
+    }
+  }
+  return count;
+}
+
+#endif  // OPENSSL_VERSION_NUMBER >= 0x10100000L
+
+#endif  // !defined(OPENSSL_IS_BORINGSSL)
+
+ExactFloat::ExactFloat(double v) {
+  sign_ = std::signbit(v) ? -1 : 1;
+  if (std::isnan(v)) {
+    set_nan();
+  } else if (std::isinf(v)) {
+    set_inf(sign_);
+  } else {
+    // The following code is much simpler than messing about with bit masks,
+    // has the advantage of handling denormalized numbers and zero correctly,
+    // and is actually quite efficient (at least compared to the rest of this
+    // code).  "f" is a fraction in the range [0.5, 1), so if we shift it left
+    // by the number of mantissa bits in a double (53, including the leading
+    // "1") then the result is always an integer.
+    int exp;
+    double f = frexp(fabs(v), &exp);
+    uint64 m = static_cast<uint64>(ldexp(f, kDoubleMantissaBits));
+    BN_ext_set_uint64(bn_.get(), m);
+    bn_exp_ = exp - kDoubleMantissaBits;
+    Canonicalize();
+  }
+}
+
+ExactFloat::ExactFloat(int v) {
+  sign_ = (v >= 0) ? 1 : -1;
+  // Note that this works even for INT_MIN because the parameter type for
+  // BN_set_word() is unsigned.
+  S2_CHECK(BN_set_word(bn_.get(), abs(v)));
+  bn_exp_ = 0;
+  Canonicalize();
+}
+
+ExactFloat::ExactFloat(const ExactFloat& b)
+    : sign_(b.sign_),
+      bn_exp_(b.bn_exp_) {
+  BN_copy(bn_.get(), b.bn_.get());
+}
+
+ExactFloat ExactFloat::SignedZero(int sign) {
+  ExactFloat r;
+  r.set_zero(sign);
+  return r;
+}
+
+ExactFloat ExactFloat::Infinity(int sign) {
+  ExactFloat r;
+  r.set_inf(sign);
+  return r;
+}
+
+ExactFloat ExactFloat::NaN() {
+  ExactFloat r;
+  r.set_nan();
+  return r;
+}
+
+int ExactFloat::prec() const {
+  return BN_num_bits(bn_.get());
+}
+
+int ExactFloat::exp() const {
+  S2_DCHECK(is_normal());
+  return bn_exp_ + BN_num_bits(bn_.get());
+}
+
+void ExactFloat::set_zero(int sign) {
+  sign_ = sign;
+  bn_exp_ = kExpZero;
+  if (!BN_is_zero(bn_.get())) BN_zero(bn_.get());
+}
+
+void ExactFloat::set_inf(int sign) {
+  sign_ = sign;
+  bn_exp_ = kExpInfinity;
+  if (!BN_is_zero(bn_.get())) BN_zero(bn_.get());
+}
+
+void ExactFloat::set_nan() {
+  sign_ = 1;
+  bn_exp_ = kExpNaN;
+  if (!BN_is_zero(bn_.get())) BN_zero(bn_.get());
+}
+
+double ExactFloat::ToDouble() const {
+  // If the mantissa has too many bits, we need to round it.
+  if (prec() <= kDoubleMantissaBits) {
+    return ToDoubleHelper();
+  } else {
+    ExactFloat r = RoundToMaxPrec(kDoubleMantissaBits, kRoundTiesToEven);
+    return r.ToDoubleHelper();
+  }
+}
+
+double ExactFloat::ToDoubleHelper() const {
+  S2_DCHECK_LE(BN_num_bits(bn_.get()), kDoubleMantissaBits);
+  if (!is_normal()) {
+    if (is_zero()) return copysign(0, sign_);
+    if (is_inf()) {
+      return std::copysign(std::numeric_limits<double>::infinity(), sign_);
+    }
+    return std::copysign(std::numeric_limits<double>::quiet_NaN(), sign_);
+  }
+  uint64 d_mantissa = BN_ext_get_uint64(bn_.get());
+  // We rely on ldexp() to handle overflow and underflow.  (It will return a
+  // signed zero or infinity if the result is too small or too large.)
+  return sign_ * ldexp(static_cast<double>(d_mantissa), bn_exp_);
+}
+
+ExactFloat ExactFloat::RoundToMaxPrec(int max_prec, RoundingMode mode) const {
+  // The "kRoundTiesToEven" mode requires at least 2 bits of precision
+  // (otherwise both adjacent representable values may be odd).
+  S2_DCHECK_GE(max_prec, 2);
+  S2_DCHECK_LE(max_prec, kMaxPrec);
+
+  // The following test also catches zero, infinity, and NaN.
+  int shift = prec() - max_prec;
+  if (shift <= 0) return *this;
+
+  // Round by removing the appropriate number of bits from the mantissa.  Note
+  // that if the value is rounded up to a power of 2, the high-order bit
+  // position may increase, but in that case Canonicalize() will remove at
+  // least one zero bit and so the output will still have prec() <= max_prec.
+  return RoundToPowerOf2(bn_exp_ + shift, mode);
+}
+
+ExactFloat ExactFloat::RoundToPowerOf2(int bit_exp, RoundingMode mode) const {
+  S2_DCHECK_GE(bit_exp, kMinExp - kMaxPrec);
+  S2_DCHECK_LE(bit_exp, kMaxExp);
+
+  // If the exponent is already large enough, or the value is zero, infinity,
+  // or NaN, then there is nothing to do.
+  int shift = bit_exp - bn_exp_;
+  if (shift <= 0) return *this;
+  S2_DCHECK(is_normal());
+
+  // Convert rounding up/down to toward/away from zero, so that we don't need
+  // to consider the sign of the number from this point onward.
+  if (mode == kRoundTowardPositive) {
+    mode = (sign_ > 0) ? kRoundAwayFromZero : kRoundTowardZero;
+  } else if (mode == kRoundTowardNegative) {
+    mode = (sign_ > 0) ? kRoundTowardZero : kRoundAwayFromZero;
+  }
+
+  // Rounding consists of right-shifting the mantissa by "shift", and then
+  // possibly incrementing the result (depending on the rounding mode, the
+  // bits that were discarded, and sometimes the lowest kept bit).  The
+  // following code figures out whether we need to increment.
+  ExactFloat r;
+  bool increment = false;
+  if (mode == kRoundTowardZero) {
+    // Never increment.
+  } else if (mode == kRoundTiesAwayFromZero) {
+    // Increment if the highest discarded bit is 1.
+    if (BN_is_bit_set(bn_.get(), shift - 1))
+      increment = true;
+  } else if (mode == kRoundAwayFromZero) {
+    // Increment unless all discarded bits are zero.
+    if (BN_ext_count_low_zero_bits(bn_.get()) < shift)
+      increment = true;
+  } else {
+    S2_DCHECK_EQ(mode, kRoundTiesToEven);
+    // Let "w/xyz" denote a mantissa where "w" is the lowest kept bit and
+    // "xyz" are the discarded bits.  Then using regexp notation:
+    //    ./0.*       ->    Don't increment (fraction < 1/2)
+    //    0/10*       ->    Don't increment (fraction = 1/2, kept part even)
+    //    1/10*       ->    Increment (fraction = 1/2, kept part odd)
+    //    ./1.*1.*    ->    Increment (fraction > 1/2)
+    if (BN_is_bit_set(bn_.get(), shift - 1) &&
+        ((BN_is_bit_set(bn_.get(), shift) ||
+          BN_ext_count_low_zero_bits(bn_.get()) < shift - 1))) {
+      increment = true;
+    }
+  }
+  r.bn_exp_ = bn_exp_ + shift;
+  S2_CHECK(BN_rshift(r.bn_.get(), bn_.get(), shift));
+  if (increment) {
+    S2_CHECK(BN_add_word(r.bn_.get(), 1));
+  }
+  r.sign_ = sign_;
+  r.Canonicalize();
+  return r;
+}
+
+int ExactFloat::NumSignificantDigitsForPrec(int prec) {
+  // The simplest bound is
+  //
+  //    d <= 1 + ceil(prec * log10(2))
+  //
+  // The following bound is tighter by 0.5 digits on average, but requires
+  // the exponent to be known as well:
+  //
+  //    d <= ceil(exp * log10(2)) - floor((exp - prec) * log10(2))
+  //
+  // Since either of these bounds can be too large by 0, 1, or 2 digits, we
+  // stick with the simpler first bound.
+  return static_cast<int>(1 + ceil(prec * (M_LN2 / M_LN10)));
+}
+
+// Numbers are always formatted with at least this many significant digits.
+// This prevents small integers from being formatted in exponential notation
+// (e.g. 1024 formatted as 1e+03), and also avoids the confusion of having
+// supposedly "high precision" numbers formatted with just 1 or 2 digits
+// (e.g. 1/512 == 0.001953125 formatted as 0.002).
+static const int kMinSignificantDigits = 10;
+
+std::string ExactFloat::ToString() const {
+  int max_digits = max(kMinSignificantDigits,
+                       NumSignificantDigitsForPrec(prec()));
+  return ToStringWithMaxDigits(max_digits);
+}
+
+std::string ExactFloat::ToStringWithMaxDigits(int max_digits) const {
+  S2_DCHECK_GT(max_digits, 0);
+  if (!is_normal()) {
+    if (is_nan()) return "nan";
+    if (is_zero()) return (sign_ < 0) ? "-0" : "0";
+    return (sign_ < 0) ? "-inf" : "inf";
+  }
+  std::string digits;
+  int exp10 = GetDecimalDigits(max_digits, &digits);
+  std::string str;
+  if (sign_ < 0) str.push_back('-');
+
+  // We use the standard '%g' formatting rules.  If the exponent is less than
+  // -4 or greater than or equal to the requested precision (i.e., max_digits)
+  // then we use exponential notation.
+  //
+  // But since "exp10" is the base-10 exponent corresponding to a mantissa in
+  // the range [0.1, 1), whereas the '%g' rules assume a mantissa in the range
+  // [1.0, 10), we need to adjust these parameters by 1.
+  if (exp10 <= -4 || exp10 > max_digits) {
+    // Use exponential format.
+    str.push_back(digits[0]);
+    if (digits.size() > 1) {
+      str.push_back('.');
+      str.append(digits.begin() + 1, digits.end());
+    }
+    char exp_buf[20];
+    sprintf(exp_buf, "e%+02d", exp10 - 1);
+    str += exp_buf;
+  } else {
+    // Use fixed format.  We split this into two cases depending on whether
+    // the integer portion is non-zero or not.
+    if (exp10 > 0) {
+      if (exp10 >= digits.size()) {
+        str += digits;
+        for (int i = exp10 - digits.size(); i > 0; --i) {
+          str.push_back('0');
+        }
+      } else {
+        str.append(digits.begin(), digits.begin() + exp10);
+        str.push_back('.');
+        str.append(digits.begin() + exp10, digits.end());
+      }
+    } else {
+      str += "0.";
+      for (int i = exp10; i < 0; ++i) {
+        str.push_back('0');
+      }
+      str += digits;
+    }
+  }
+  return str;
+}
+
+// Increment an unsigned integer represented as a string of ASCII digits.
+static void IncrementDecimalDigits(std::string* digits) {
+  std::string::iterator pos = digits->end();
+  while (--pos >= digits->begin()) {
+    if (*pos < '9') { ++*pos; return; }
+    *pos = '0';
+  }
+  digits->insert(0, "1");
+}
+
+int ExactFloat::GetDecimalDigits(int max_digits, std::string* digits) const {
+  S2_DCHECK(is_normal());
+  // Convert the value to the form (bn * (10 ** bn_exp10)) where "bn" is a
+  // positive integer (BIGNUM).
+  BIGNUM* bn = BN_new();
+  int bn_exp10;
+  if (bn_exp_ >= 0) {
+    // The easy case: bn = bn_ * (2 ** bn_exp_)), bn_exp10 = 0.
+    S2_CHECK(BN_lshift(bn, bn_.get(), bn_exp_));
+    bn_exp10 = 0;
+  } else {
+    // Set bn = bn_ * (5 ** -bn_exp_) and bn_exp10 = bn_exp_.  This is
+    // equivalent to the original value of (bn_ * (2 ** bn_exp_)).
+    BIGNUM* power = BN_new();
+    S2_CHECK(BN_set_word(power, -bn_exp_));
+    S2_CHECK(BN_set_word(bn, 5));
+    BN_CTX* ctx = BN_CTX_new();
+    S2_CHECK(BN_exp(bn, bn, power, ctx));
+    S2_CHECK(BN_mul(bn, bn, bn_.get(), ctx));
+    BN_CTX_free(ctx);
+    BN_free(power);
+    bn_exp10 = bn_exp_;
+  }
+  // Now convert "bn" to a decimal string.
+  char* all_digits = BN_bn2dec(bn);
+  S2_DCHECK(all_digits != nullptr);
+  BN_free(bn);
+  // Check whether we have too many digits and round if necessary.
+  int num_digits = strlen(all_digits);
+  if (num_digits <= max_digits) {
+    *digits = all_digits;
+  } else {
+    digits->assign(all_digits, max_digits);
+    // Standard "printf" formatting rounds ties to an even number.  This means
+    // that we round up (away from zero) if highest discarded digit is '5' or
+    // more, unless all other discarded digits are zero in which case we round
+    // up only if the lowest kept digit is odd.
+    if (all_digits[max_digits] >= '5' &&
+        ((all_digits[max_digits-1] & 1) == 1 ||
+         strpbrk(all_digits + max_digits + 1, "123456789") != nullptr)) {
+      // This can increase the number of digits by 1, but in that case at
+      // least one trailing zero will be stripped off below.
+      IncrementDecimalDigits(digits);
+    }
+    // Adjust the base-10 exponent to reflect the digits we have removed.
+    bn_exp10 += num_digits - max_digits;
+  }
+  OPENSSL_free(all_digits);
+
+  // Now strip any trailing zeros.
+  S2_DCHECK_NE((*digits)[0], '0');
+  std::string::iterator pos = digits->end();
+  while (pos[-1] == '0') --pos;
+  if (pos < digits->end()) {
+    bn_exp10 += digits->end() - pos;
+    digits->erase(pos, digits->end());
+  }
+  S2_DCHECK_LE(digits->size(), max_digits);
+
+  // Finally, we adjust the base-10 exponent so that the mantissa is a
+  // fraction in the range [0.1, 1) rather than an integer.
+  return bn_exp10 + digits->size();
+}
+
+std::string ExactFloat::ToUniqueString() const {
+  char prec_buf[20];
+  sprintf(prec_buf, "<%d>", prec());
+  return ToString() + prec_buf;
+}
+
+ExactFloat& ExactFloat::operator=(const ExactFloat& b) {
+  if (this != &b) {
+    sign_ = b.sign_;
+    bn_exp_ = b.bn_exp_;
+    BN_copy(bn_.get(), b.bn_.get());
+  }
+  return *this;
+}
+
+ExactFloat ExactFloat::operator-() const {
+  return CopyWithSign(-sign_);
+}
+
+ExactFloat operator+(const ExactFloat& a, const ExactFloat& b) {
+  return ExactFloat::SignedSum(a.sign_, &a, b.sign_, &b);
+}
+
+ExactFloat operator-(const ExactFloat& a, const ExactFloat& b) {
+  return ExactFloat::SignedSum(a.sign_, &a, -b.sign_, &b);
+}
+
+ExactFloat ExactFloat::SignedSum(int a_sign, const ExactFloat* a,
+                                 int b_sign, const ExactFloat* b) {
+  if (!a->is_normal() || !b->is_normal()) {
+    // Handle zero, infinity, and NaN according to IEEE 754-2008.
+    if (a->is_nan()) return *a;
+    if (b->is_nan()) return *b;
+    if (a->is_inf()) {
+      // Adding two infinities with opposite sign yields NaN.
+      if (b->is_inf() && a_sign != b_sign) return NaN();
+      return Infinity(a_sign);
+    }
+    if (b->is_inf()) return Infinity(b_sign);
+    if (a->is_zero()) {
+      if (!b->is_zero()) return b->CopyWithSign(b_sign);
+      // Adding two zeros with the same sign preserves the sign.
+      if (a_sign == b_sign) return SignedZero(a_sign);
+      // Adding two zeros of opposite sign produces +0.
+      return SignedZero(+1);
+    }
+    S2_DCHECK(b->is_zero());
+    return a->CopyWithSign(a_sign);
+  }
+  // Swap the numbers if necessary so that "a" has the larger bn_exp_.
+  if (a->bn_exp_ < b->bn_exp_) {
+    using std::swap;
+    swap(a_sign, b_sign);
+    swap(a, b);
+  }
+  // Shift "a" if necessary so that both values have the same bn_exp_.
+  ExactFloat r;
+  if (a->bn_exp_ > b->bn_exp_) {
+    S2_CHECK(BN_lshift(r.bn_.get(), a->bn_.get(), a->bn_exp_ - b->bn_exp_));
+    a = &r;  // The only field of "a" used below is bn_.
+  }
+  r.bn_exp_ = b->bn_exp_;
+  if (a_sign == b_sign) {
+    S2_CHECK(BN_add(r.bn_.get(), a->bn_.get(), b->bn_.get()));
+    r.sign_ = a_sign;
+  } else {
+    // Note that the BIGNUM documentation is out of date -- all methods now
+    // allow the result to be the same as any input argument, so it is okay if
+    // (a == &r) due to the shift above.
+    S2_CHECK(BN_sub(r.bn_.get(), a->bn_.get(), b->bn_.get()));
+    if (BN_is_zero(r.bn_.get())) {
+      r.sign_ = +1;
+    } else if (BN_is_negative(r.bn_.get())) {
+      // The magnitude of "b" was larger.
+      r.sign_ = b_sign;
+      BN_set_negative(r.bn_.get(), false);
+    } else {
+      // They were equal, or the magnitude of "a" was larger.
+      r.sign_ = a_sign;
+    }
+  }
+  r.Canonicalize();
+  return r;
+}
+
+void ExactFloat::Canonicalize() {
+  if (!is_normal()) return;
+
+  // Underflow/overflow occurs if exp() is not in [kMinExp, kMaxExp].
+  // We also convert a zero mantissa to signed zero.
+  int my_exp = exp();
+  if (my_exp < kMinExp || BN_is_zero(bn_.get())) {
+    set_zero(sign_);
+  } else if (my_exp > kMaxExp) {
+    set_inf(sign_);
+  } else if (!BN_is_odd(bn_.get())) {
+    // Remove any low-order zero bits from the mantissa.
+    S2_DCHECK(!BN_is_zero(bn_.get()));
+    int shift = BN_ext_count_low_zero_bits(bn_.get());
+    if (shift > 0) {
+      S2_CHECK(BN_rshift(bn_.get(), bn_.get(), shift));
+      bn_exp_ += shift;
+    }
+  }
+  // If the mantissa has too many bits, we replace it by NaN to indicate
+  // that an inexact calculation has occurred.
+  if (prec() > kMaxPrec) {
+    set_nan();
+  }
+}
+
+ExactFloat operator*(const ExactFloat& a, const ExactFloat& b) {
+  int result_sign = a.sign_ * b.sign_;
+  if (!a.is_normal() || !b.is_normal()) {
+    // Handle zero, infinity, and NaN according to IEEE 754-2008.
+    if (a.is_nan()) return a;
+    if (b.is_nan()) return b;
+    if (a.is_inf()) {
+      // Infinity times zero yields NaN.
+      if (b.is_zero()) return ExactFloat::NaN();
+      return ExactFloat::Infinity(result_sign);
+    }
+    if (b.is_inf()) {
+      if (a.is_zero()) return ExactFloat::NaN();
+      return ExactFloat::Infinity(result_sign);
+    }
+    S2_DCHECK(a.is_zero() || b.is_zero());
+    return ExactFloat::SignedZero(result_sign);
+  }
+  ExactFloat r;
+  r.sign_ = result_sign;
+  r.bn_exp_ = a.bn_exp_ + b.bn_exp_;
+  BN_CTX* ctx = BN_CTX_new();
+  S2_CHECK(BN_mul(r.bn_.get(), a.bn_.get(), b.bn_.get(), ctx));
+  BN_CTX_free(ctx);
+  r.Canonicalize();
+  return r;
+}
+
+bool operator==(const ExactFloat& a, const ExactFloat& b) {
+  // NaN is not equal to anything, not even itself.
+  if (a.is_nan() || b.is_nan()) return false;
+
+  // Since Canonicalize() strips low-order zero bits, all other cases
+  // (including non-normal values) require bn_exp_ to be equal.
+  if (a.bn_exp_ != b.bn_exp_) return false;
+
+  // Positive and negative zero are equal.
+  if (a.is_zero() && b.is_zero()) return true;
+
+  // Otherwise, the signs and mantissas must match.  Note that non-normal
+  // values such as infinity have a mantissa of zero.
+  return a.sign_ == b.sign_ && BN_ucmp(a.bn_.get(), b.bn_.get()) == 0;
+}
+
+int ExactFloat::ScaleAndCompare(const ExactFloat& b) const {
+  S2_DCHECK(is_normal() && b.is_normal() && bn_exp_ >= b.bn_exp_);
+  ExactFloat tmp = *this;
+  S2_CHECK(BN_lshift(tmp.bn_.get(), tmp.bn_.get(), bn_exp_ - b.bn_exp_));
+  return BN_ucmp(tmp.bn_.get(), b.bn_.get());
+}
+
+bool ExactFloat::UnsignedLess(const ExactFloat& b) const {
+  // Handle the zero/infinity cases (NaN has already been done).
+  if (is_inf() || b.is_zero()) return false;
+  if (is_zero() || b.is_inf()) return true;
+  // If the high-order bit positions differ, we are done.
+  int cmp = exp() - b.exp();
+  if (cmp != 0) return cmp < 0;
+  // Otherwise shift one of the two values so that they both have the same
+  // bn_exp_ and then compare the mantissas.
+  return (bn_exp_ >= b.bn_exp_ ?
+          ScaleAndCompare(b) < 0 : b.ScaleAndCompare(*this) > 0);
+}
+
+bool operator<(const ExactFloat& a, const ExactFloat& b) {
+  // NaN is unordered compared to everything, including itself.
+  if (a.is_nan() || b.is_nan()) return false;
+  // Positive and negative zero are equal.
+  if (a.is_zero() && b.is_zero()) return false;
+  // Otherwise, anything negative is less than anything positive.
+  if (a.sign_ != b.sign_) return a.sign_ < b.sign_;
+  // Now we just compare absolute values.
+  return (a.sign_ > 0) ? a.UnsignedLess(b) : b.UnsignedLess(a);
+}
+
+ExactFloat fabs(const ExactFloat& a) {
+  return abs(a);
+}
+
+ExactFloat abs(const ExactFloat& a) {
+  return a.CopyWithSign(+1);
+}
+
+ExactFloat fmax(const ExactFloat& a, const ExactFloat& b) {
+  // If one argument is NaN, return the other argument.
+  if (a.is_nan()) return b;
+  if (b.is_nan()) return a;
+  // Not required by IEEE 754, but we prefer +0 over -0.
+  if (a.sign_ != b.sign_) {
+    return (a.sign_ < b.sign_) ? b : a;
+  }
+  return (a < b) ? b : a;
+}
+
+ExactFloat fmin(const ExactFloat& a, const ExactFloat& b) {
+  // If one argument is NaN, return the other argument.
+  if (a.is_nan()) return b;
+  if (b.is_nan()) return a;
+  // Not required by IEEE 754, but we prefer -0 over +0.
+  if (a.sign_ != b.sign_) {
+    return (a.sign_ < b.sign_) ? a : b;
+  }
+  return (a < b) ? a : b;
+}
+
+ExactFloat fdim(const ExactFloat& a, const ExactFloat& b) {
+  // This formulation has the correct behavior for NaNs.
+  return (a <= b) ? 0 : (a - b);
+}
+
+ExactFloat ceil(const ExactFloat& a) {
+  return a.RoundToPowerOf2(0, ExactFloat::kRoundTowardPositive);
+}
+
+ExactFloat floor(const ExactFloat& a) {
+  return a.RoundToPowerOf2(0, ExactFloat::kRoundTowardNegative);
+}
+
+ExactFloat trunc(const ExactFloat& a) {
+  return a.RoundToPowerOf2(0, ExactFloat::kRoundTowardZero);
+}
+
+ExactFloat round(const ExactFloat& a) {
+  return a.RoundToPowerOf2(0, ExactFloat::kRoundTiesAwayFromZero);
+}
+
+ExactFloat rint(const ExactFloat& a) {
+  return a.RoundToPowerOf2(0, ExactFloat::kRoundTiesToEven);
+}
+
+template <class T>
+T ExactFloat::ToInteger(RoundingMode mode) const {
+  using std::numeric_limits;
+  static_assert(sizeof(T) <= sizeof(uint64), "max 64 bits supported");
+  static_assert(numeric_limits<T>::is_signed, "only signed types supported");
+  const int64 kMinValue = numeric_limits<T>::min();
+  const int64 kMaxValue = numeric_limits<T>::max();
+
+  ExactFloat r = RoundToPowerOf2(0, mode);
+  if (r.is_nan()) return kMaxValue;
+  if (r.is_zero()) return 0;
+  if (!r.is_inf()) {
+    // If the unsigned value has more than 63 bits it is always clamped.
+    if (r.exp() < 64) {
+      int64 value = BN_ext_get_uint64(r.bn_.get()) << r.bn_exp_;
+      if (r.sign_ < 0) value = -value;
+      return max(kMinValue, min(kMaxValue, value));
+    }
+  }
+  return (r.sign_ < 0) ? kMinValue : kMaxValue;
+}
+
+long lrint(const ExactFloat& a) {
+  return a.ToInteger<long>(ExactFloat::kRoundTiesToEven);
+}
+
+long long llrint(const ExactFloat& a) {
+  return a.ToInteger<long long>(ExactFloat::kRoundTiesToEven);
+}
+
+long lround(const ExactFloat& a) {
+  return a.ToInteger<long>(ExactFloat::kRoundTiesAwayFromZero);
+}
+
+long long llround(const ExactFloat& a) {
+  return a.ToInteger<long long>(ExactFloat::kRoundTiesAwayFromZero);
+}
+
+ExactFloat copysign(const ExactFloat& a, const ExactFloat& b) {
+  return a.CopyWithSign(b.sign_);
+}
+
+ExactFloat frexp(const ExactFloat& a, int* exp) {
+  if (!a.is_normal()) {
+    // If a == 0, exp should be zero.  If a.is_inf() or a.is_nan(), exp is not
+    // defined but the glibc implementation returns zero.
+    *exp = 0;
+    return a;
+  }
+  *exp = a.exp();
+  return ldexp(a, -a.exp());
+}
+
+ExactFloat ldexp(const ExactFloat& a, int exp) {
+  if (!a.is_normal()) return a;
+
+  // To prevent integer overflow, we first clamp "exp" so that
+  // (kMinExp - 1) <= (a_exp + exp) <= (kMaxExp + 1).
+  int a_exp = a.exp();
+  exp = min(ExactFloat::kMaxExp + 1 - a_exp,
+            max(ExactFloat::kMinExp - 1 + a_exp, exp));
+
+  // Now modify the exponent and check for overflow/underflow.
+  ExactFloat r = a;
+  r.bn_exp_ += exp;
+  r.Canonicalize();
+  return r;
+}
+
+ExactFloat scalbln(const ExactFloat& a, long exp) {
+  // Clamp the exponent to the range of "int" in order to avoid truncation.
+  exp = max(static_cast<long>(INT_MIN), min(static_cast<long>(INT_MAX), exp));
+  return ldexp(a, exp);
+}
+
+int ilogb(const ExactFloat& a) {
+  if (a.is_zero()) return FP_ILOGB0;
+  if (a.is_inf()) return INT_MAX;
+  if (a.is_nan()) return FP_ILOGBNAN;
+  // a.exp() assumes the significand is in the range [0.5, 1).
+  return a.exp() - 1;
+}
+
+ExactFloat logb(const ExactFloat& a) {
+  if (a.is_zero()) return ExactFloat::Infinity(-1);
+  if (a.is_inf()) return ExactFloat::Infinity(+1);  // Even if a < 0.
+  if (a.is_nan()) return a;
+  // exp() assumes the significand is in the range [0.5,1).
+  return ExactFloat(a.exp() - 1);
+}
+
+ExactFloat ExactFloat::Unimplemented() {
+  S2_LOG(FATAL) << "Unimplemented ExactFloat method called";
+  return NaN();
+}
diff --git a/src/s2/util/math/exactfloat/exactfloat.h b/src/s2/util/math/exactfloat/exactfloat.h
new file mode 100644 (file)
index 0000000..028321e
--- /dev/null
@@ -0,0 +1,646 @@
+// Copyright 2009 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// Author: ericv@google.com (Eric Veach)
+//
+// ExactFloat is a multiple-precision floating point type based on the OpenSSL
+// Bignum library.  It has the same interface as the built-in "float" and
+// "double" types, but only supports the subset of operators and intrinsics
+// where it is possible to compute the result exactly.  So for example,
+// ExactFloat supports addition and multiplication but not division (since in
+// general, the quotient of two floating-point numbers cannot be represented
+// exactly).  Exact arithmetic is useful for geometric algorithms, especially
+// for disambiguating cases where ordinary double-precision arithmetic yields
+// an uncertain result.
+//
+// ExactFloat is a subset of the faster and more capable MPFloat class (which
+// is based on the GNU MPFR library).  The main reason to use this class
+// rather than MPFloat is that it is subject to a BSD-style license rather
+// than the much more restrictive LGPL license.
+//
+// It has the following features:
+//
+//  - ExactFloat uses the same syntax as the built-in "float" and "double"
+//    types, for example: x += 4 + fabs(2*y*y - z*z).  There are a few
+//    differences (see below), but the syntax is compatible enough so that
+//    ExactFloat can be used as a template argument to templatized classes
+//    such as Vector2, VectorN, Matrix3x3, etc.
+//
+//  - Results are not rounded; instead, precision is increased so that the
+//    result can be represented exactly.  An inexact result is returned only
+//    in the case of underflow or overflow (yielding signed zero or infinity
+//    respectively), or if the maximum allowed precision is exceeded (yielding
+//    NaN).  ExactFloat uses IEEE 754-2008 rules for handling infinities, NaN,
+//    rounding to integers, etc.
+//
+//  - ExactFloat only supports calculations where the result can be
+//    represented exactly.  Therefore it supports intrinsics such as fabs()
+//    but not transcendentals such as sin(), sqrt(), etc.
+//
+// Syntax Compatibility with "float" and "double"
+// ----------------------------------------------
+//
+// ExactFloat supports a subset of the operators and intrinsics for the
+// built-in "double" type.  (Thus it supports fabs() but not fabsf(), for
+// example.)  The syntax is different only in the following cases:
+//
+//  - Casts and implicit conversions to built-in types (including "bool") are
+//    not supported.  So for example, the following will not compile:
+//
+//      ExactFloat x = 7.5;
+//      double y = x;            // ERROR: use x.ToDouble() instead
+//      long z = x;              // ERROR: use x.ToDouble() or lround(trunc(x))
+//      q = static_cast<int>(x); // ERROR: use x.ToDouble() or lround(trunc(x))
+//      if (x) { ... }           // ERROR: use (x != 0) instead
+//
+//  - The glibc floating-point classification macros (fpclassify, isfinite,
+//    isnormal, isnan, isinf) are not supported.  Instead there are
+//    zero-argument methods:
+//
+//      ExactFloat x;
+//      if (isnan(x)) { ... }  // ERROR: use (x.is_nan()) instead
+//      if (isinf(x)) { ... }  // ERROR: use (x.is_inf()) instead
+//
+// Using ExactFloat with Vector3, etc.
+// -----------------------------------
+//
+// ExactFloat can be used with templatized classes such as Vector2 and Vector3
+// (see "util/math/vector.h"), with the following limitations:
+//
+//  - Cast() can be used to convert other vector types to an ExactFloat vector
+//    type, but not the other way around.  This is because there are no
+//    implicit conversions from ExactFloat to built-in types.  You can work
+//    around this by calling an explicit conversion method such as
+//    ToDouble().  For example:
+//
+//      typedef Vector3<ExactFloat> Vector3_xf;
+//      Vector3_xf x;
+//      Vector3_d y;
+//      x = Vector3_xf::Cast(y);   // This works.
+//      y = Vector3_d::Cast(x);    // This doesn't.
+//      y = Vector3_d(x[0].ToDouble(), x[1].ToDouble(), x[2].ToDouble()); // OK
+//
+//  - IsNaN() is not supported because it calls isnan(), which is defined as a
+//    macro in <math.h> and therefore can't easily be overrided.
+//
+// Precision Semantics
+// -------------------
+//
+// Unlike MPFloat, ExactFloat does not allow a maximum precision to be
+// specified (it is always unbounded).  Therefore it does not have any of the
+// corresponding constructors.
+//
+// The current precision of an ExactFloat (i.e., the number of bits in its
+// mantissa) is returned by prec().  The precision is increased as necessary
+// so that the result of every operation can be represented exactly.
+
+#ifndef S2_UTIL_MATH_EXACTFLOAT_EXACTFLOAT_H_
+#define S2_UTIL_MATH_EXACTFLOAT_EXACTFLOAT_H_
+
+#include <algorithm>
+#include <climits>
+#include <cmath>
+#include <algorithm>
+#include <iostream>
+#include <string>
+
+#include <openssl/bn.h>
+
+#include "s2/base/integral_types.h"
+#include "s2/base/logging.h"
+#include "s2/base/port.h"
+
+class ExactFloat {
+ public:
+  // The following limits are imposed by OpenSSL.
+
+  // The maximum exponent supported.  If a value has an exponent larger than
+  // this, it is replaced by infinity (with the appropriate sign).
+  static const int kMaxExp = 200*1000*1000;  // About 10**(60 million)
+
+  // The minimum exponent supported.  If a value has an exponent less than
+  // this, it is replaced by zero (with the appropriate sign).
+  static const int kMinExp = -kMaxExp;   // About 10**(-60 million)
+
+  // The maximum number of mantissa bits supported.  If a value has more
+  // mantissa bits than this, it is replaced with NaN.  (It is expected that
+  // users of this class will never want this much precision.)
+  static const int kMaxPrec = 64 << 20;  // About 20 million digits
+
+  // Rounding modes.  kRoundTiesToEven and kRoundTiesAwayFromZero both round
+  // to the nearest representable value unless two values are equally close.
+  // In that case kRoundTiesToEven rounds to the nearest even value, while
+  // kRoundTiesAwayFromZero always rounds away from zero.
+  enum RoundingMode {
+    kRoundTiesToEven,
+    kRoundTiesAwayFromZero,
+    kRoundTowardZero,
+    kRoundAwayFromZero,
+    kRoundTowardPositive,
+    kRoundTowardNegative
+  };
+
+  /////////////////////////////////////////////////////////////////////////////
+  // Constructors
+
+  // The default constructor initializes the value to zero.  (The initial
+  // value must be zero rather than NaN for compatibility with the built-in
+  // float types.)
+  inline ExactFloat();
+
+  // Construct an ExactFloat from a "double".  The constructor is implicit so
+  // that this class can be used as a replacement for "float" or "double" in
+  // templatized libraries.  (With an explicit constructor, code such as
+  // "ExactFloat f = 2.5;" would not compile.)  All double-precision values are
+  // supported, including denormalized numbers, infinities, and NaNs.
+  ExactFloat(double v);
+
+  // Construct an ExactFloat from an "int".  Note that in general, ints are
+  // automatically converted to doubles and so would be handled by the
+  // constructor above.  However, the particular argument (0) would be
+  // ambiguous; the compiler wouldn't know whether to treat it as a "double" or
+  // "const char*" (since 0 is a valid null pointer constant).  Adding an "int"
+  // constructor solves this problem.
+  //
+  // We do not provide constructors for "unsigned", "long", "unsigned long",
+  // "long long", or "unsigned long long", since these types are not typically
+  // used in floating-point calculations and it is safer to require them to be
+  // explicitly cast.
+  ExactFloat(int v);
+
+  // Construct an ExactFloat from a string (such as "1.2e50").  Requires that
+  // the value is exactly representable as a floating-point number (so for
+  // example, "0.125" is allowed but "0.1" is not).
+  explicit ExactFloat(const char* s) { Unimplemented(); }
+
+  // Copy constructor.
+  ExactFloat(const ExactFloat& b);
+
+  // The destructor is not virtual for efficiency reasons.  Therefore no
+  // subclass should declare additional fields that require destruction.
+  inline ~ExactFloat() = default;
+
+  /////////////////////////////////////////////////////////////////////
+  // Constants
+  //
+  // As an alternative to the constants below, you can also just use the
+  // constants defined in <math.h>, for example:
+  //
+  //   ExactFloat x = NAN, y = -INFINITY;
+
+  // Return an ExactFloat equal to positive zero (if sign >= 0) or
+  // negative zero (if sign < 0).
+  static ExactFloat SignedZero(int sign);
+
+  // Return an ExactFloat equal to positive infinity (if sign >= 0) or
+  // negative infinity (if sign < 0).
+  static ExactFloat Infinity(int sign);
+
+  // Return an ExactFloat that is NaN (Not-a-Number).
+  static ExactFloat NaN();
+
+  /////////////////////////////////////////////////////////////////////////////
+  // Accessor Methods
+
+  // Return the maximum precision of the ExactFloat.  This method exists only
+  // for compatibility with MPFloat.
+  int max_prec() const { return kMaxPrec; }
+
+  // Return the actual precision of this ExactFloat (the current number of
+  // bits in its mantissa).  Returns 0 for non-normal numbers such as NaN.
+  int prec() const;
+
+  // Return the exponent of this ExactFloat given that the mantissa is in the
+  // range [0.5, 1).  It is an error to call this method if the value is zero,
+  // infinity, or NaN.
+  int exp() const;
+
+  // Set the value of the ExactFloat to +0 (if sign >= 0) or -0 (if sign < 0).
+  void set_zero(int sign);
+
+  // Set the value of the ExactFloat to positive infinity (if sign >= 0) or
+  // negative infinity (if sign < 0).
+  void set_inf(int sign);
+
+  // Set the value of the ExactFloat to NaN (Not-a-Number).
+  void set_nan();
+
+  // Unfortunately, isinf(x), isnan(x), isnormal(x), and isfinite(x) are
+  // defined as macros in <math.h>.  Therefore we can't easily extend them
+  // here.  Instead we provide methods with underscores in their names that do
+  // the same thing: x.is_inf(), etc.
+  //
+  // These macros are not implemented: signbit(x), fpclassify(x).
+
+  // Return true if this value is zero (including negative zero).
+  inline bool is_zero() const;
+
+  // Return true if this value is infinity (positive or negative).
+  inline bool is_inf() const;
+
+  // Return true if this value is NaN (Not-a-Number).
+  inline bool is_nan() const;
+
+  // Return true if this value is a normal floating-point number.  Non-normal
+  // values (zero, infinity, and NaN) often need to be handled separately
+  // because they are represented using special exponent values and their
+  // mantissa is not defined.
+  inline bool is_normal() const;
+
+  // Return true if this value is a normal floating-point number or zero,
+  // i.e. it is not infinity or NaN.
+  inline bool is_finite() const;
+
+  // Return true if the sign bit is set (this includes negative zero).
+  inline bool sign_bit() const;
+
+  // Return +1 if this ExactFloat is positive, -1 if it is negative, and 0
+  // if it is zero or NaN.  Note that unlike sign_bit(), sgn() returns 0 for
+  // both positive and negative zero.
+  inline int sgn() const;
+
+  /////////////////////////////////////////////////////////////////////////////
+  // Conversion Methods
+  //
+  // Note that some conversions are defined as functions further below,
+  // e.g. to convert to an integer you can use lround(), llrint(), etc.
+
+  // Round to double precision.  Note that since doubles have a much smaller
+  // exponent range than ExactFloats, very small values may be rounded to
+  // (positive or negative) zero, and very large values may be rounded to
+  // infinity.
+  //
+  // It is very important to make this a named method rather than an implicit
+  // conversion, because otherwise there would be a silent loss of precision
+  // whenever some desired operator or function happens not to be implemented.
+  // For example, if fabs() were not implemented and "x" and "y" were
+  // ExactFloats, then x = fabs(y) would silently convert "y" to a "double",
+  // take its absolute value, and convert it back to an ExactFloat.
+  double ToDouble() const;
+
+  // Return a human-readable string such that if two values with the same
+  // precision are different, then their string representations are different.
+  // The format is similar to printf("%g"), except that the number of
+  // significant digits depends on the precision (with a minimum of 10).
+  // Trailing zeros are stripped (just like "%g").
+  //
+  // Note that if two values have different precisions, they may have the same
+  // ToString() value even though their values are slightly different.  If you
+  // need to distinguish such values, use ToUniqueString() intead.
+  std::string ToString() const;
+
+  // Return a string formatted according to printf("%Ng") where N is the given
+  // maximum number of significant digits.
+  std::string ToStringWithMaxDigits(int max_digits) const;
+
+  // Return a human-readable string such that if two ExactFloats have different
+  // values, then their string representations are always different.  This
+  // method is useful for debugging.  The string has the form "value<prec>",
+  // where "prec" is the actual precision of the ExactFloat (e.g., "0.215<50>").
+  std::string ToUniqueString() const;
+
+  // Return an upper bound on the number of significant digits required to
+  // distinguish any two floating-point numbers with the given precision when
+  // they are formatted as decimal strings in exponential format.
+  static int NumSignificantDigitsForPrec(int prec);
+
+  // Output the ExactFloat in human-readable format, e.g. for logging.
+  friend std::ostream& operator<<(std::ostream& o, ExactFloat const& f) {
+    return o << f.ToString();
+  }
+
+  /////////////////////////////////////////////////////////////////////////////
+  // Other Methods
+
+  // Round the ExactFloat so that its mantissa has at most "max_prec" bits
+  // using the given rounding mode.  Requires "max_prec" to be at least 2
+  // (since kRoundTiesToEven doesn't make sense with fewer bits than this).
+  ExactFloat RoundToMaxPrec(int max_prec, RoundingMode mode) const;
+
+  /////////////////////////////////////////////////////////////////////////////
+  // Operators
+
+  // Assignment operator.
+  ExactFloat& operator=(const ExactFloat& b);
+
+  // Unary plus.
+  ExactFloat operator+() const { return *this; }
+
+  // Unary minus.
+  ExactFloat operator-() const;
+
+  // Addition.
+  friend ExactFloat operator+(const ExactFloat& a, const ExactFloat& b);
+
+  // Subtraction.
+  friend ExactFloat operator-(const ExactFloat& a, const ExactFloat& b);
+
+  // Multiplication.
+  friend ExactFloat operator*(const ExactFloat& a, const ExactFloat& b);
+
+  // Division is not implemented because the result cannot be represented
+  // exactly in general.  Doing this properly would require extending all the
+  // operations to support rounding to a specified precision.
+
+  // Arithmetic assignment operators (+=, -=, *=).
+  ExactFloat& operator+=(const ExactFloat& b) { return (*this = *this + b); }
+  ExactFloat& operator-=(const ExactFloat& b) { return (*this = *this - b); }
+  ExactFloat& operator*=(const ExactFloat& b) { return (*this = *this * b); }
+
+  // Comparison operators (==, !=, <, <=, >, >=).
+  friend bool operator==(const ExactFloat& a, const ExactFloat& b);
+  friend bool operator<(const ExactFloat& a, const ExactFloat& b);
+  // These don't need to be friends but are declared here for completeness.
+  inline friend bool operator!=(const ExactFloat& a, const ExactFloat& b);
+  inline friend bool operator<=(const ExactFloat& a, const ExactFloat& b);
+  inline friend bool operator>(const ExactFloat& a, const ExactFloat& b);
+  inline friend bool operator>=(const ExactFloat& a, const ExactFloat& b);
+
+  /////////////////////////////////////////////////////////////////////
+  // Math Intrinsics
+  //
+  // The math intrinsics currently supported by ExactFloat are listed below.
+  // Except as noted, they behave identically to the usual glibc intrinsics
+  // except that they have greater precision.  See the man pages for more
+  // information.
+
+  //////// Miscellaneous simple arithmetic functions.
+
+  // Absolute value.
+  friend ExactFloat fabs(const ExactFloat& a);
+  friend ExactFloat abs(const ExactFloat& a);
+
+  // Maximum of two values.
+  friend ExactFloat fmax(const ExactFloat& a, const ExactFloat& b);
+
+  // Minimum of two values.
+  friend ExactFloat fmin(const ExactFloat& a, const ExactFloat& b);
+
+  // Positive difference: max(a - b, 0).
+  friend ExactFloat fdim(const ExactFloat& a, const ExactFloat& b);
+
+  //////// Integer rounding functions that return ExactFloat values.
+
+  // Round up to the nearest integer.
+  friend ExactFloat ceil(const ExactFloat& a);
+
+  // Round down to the nearest integer.
+  friend ExactFloat floor(const ExactFloat& a);
+
+  // Round to the nearest integer not larger in absolute value.
+  // For example: f(-1.9) = -1, f(2.9) = 2.
+  friend ExactFloat trunc(const ExactFloat& a);
+
+  // Round to the nearest integer, rounding halfway cases away from zero.
+  // For example: f(-0.5) = -1, f(0.5) = 1, f(1.5) = 2, f(2.5) = 3.
+  friend ExactFloat round(const ExactFloat& a);
+
+  // Round to the nearest integer, rounding halfway cases to an even integer.
+  // For example: f(-0.5) = 0, f(0.5) = 0, f(1.5) = 2, f(2.5) = 2.
+  friend ExactFloat rint(const ExactFloat& a);
+
+  // A synonym for rint().
+  friend ExactFloat nearbyint(const ExactFloat& a) { return rint(a); }
+
+  //////// Integer rounding functions that return C++ integer types.
+
+  // Like rint(), but rounds to the nearest "long" value.  Returns the
+  // minimum/maximum possible integer if the value is out of range.
+  friend long lrint(const ExactFloat& a);
+
+  // Like rint(), but rounds to the nearest "long long" value.  Returns the
+  // minimum/maximum possible integer if the value is out of range.
+  friend long long llrint(const ExactFloat& a);
+
+  // Like round(), but rounds to the nearest "long" value.  Returns the
+  // minimum/maximum possible integer if the value is out of range.
+  friend long lround(const ExactFloat& a);
+
+  // Like round(), but rounds to the nearest "long long" value.  Returns the
+  // minimum/maximum possible integer if the value is out of range.
+  friend long long llround(const ExactFloat& a);
+
+  //////// Remainder functions.
+
+  // The remainder of dividing "a" by "b", where the quotient is rounded toward
+  // zero to the nearest integer.  Similar to (a - trunc(a / b) * b).
+  friend ExactFloat fmod(const ExactFloat& a, const ExactFloat& b) {
+    // Note that it is possible to implement this operation exactly, it just
+    // hasn't been done.
+    return Unimplemented();
+  }
+
+  // The remainder of dividing "a" by "b", where the quotient is rounded to the
+  // nearest integer, rounding halfway cases to an even integer.  Similar to
+  // (a - rint(a / b) * b).
+  friend ExactFloat remainder(const ExactFloat& a, const ExactFloat& b) {
+    // Note that it is possible to implement this operation exactly, it just
+    // hasn't been done.
+    return Unimplemented();
+  }
+
+  // A synonym for remainder().
+  friend ExactFloat drem(const ExactFloat& a, const ExactFloat& b) {
+    return remainder(a, b);
+  }
+
+  // Break the argument "a" into integer and fractional parts, each of which
+  // has the same sign as "a".  The fractional part is returned, and the
+  // integer part is stored in the output parameter "i_ptr".  Both output
+  // values are set to have the same maximum precision as "a".
+  friend ExactFloat modf(const ExactFloat& a, ExactFloat* i_ptr) {
+    // Note that it is possible to implement this operation exactly, it just
+    // hasn't been done.
+    return Unimplemented();
+  }
+
+  //////// Floating-point manipulation functions.
+
+  // Return an ExactFloat with the magnitude of "a" and the sign bit of "b".
+  // (Note that an IEEE zero can be either positive or negative.)
+  friend ExactFloat copysign(const ExactFloat& a, const ExactFloat& b);
+
+  // Convert "a" to a normalized fraction in the range [0.5, 1) times a power
+  // of two.  Return the fraction and set "exp" to the exponent.  If "a" is
+  // zero, infinity, or NaN then return "a" and set "exp" to zero.
+  friend ExactFloat frexp(const ExactFloat& a, int* exp);
+
+  // Return "a" multiplied by 2 raised to the power "exp".
+  friend ExactFloat ldexp(const ExactFloat& a, int exp);
+
+  // A synonym for ldexp().
+  friend ExactFloat scalbn(const ExactFloat& a, int exp) {
+    return ldexp(a, exp);
+  }
+
+  // A version of ldexp() where "exp" is a long integer.
+  friend ExactFloat scalbln(const ExactFloat& a, long exp);
+
+  // Convert "a" to a normalized fraction in the range [1,2) times a power of
+  // two, and return the exponent value as an integer.  This is equivalent to
+  // lrint(floor(log2(fabs(a)))) but it is computed more efficiently.  Returns
+  // the constants documented in the man page for zero, infinity, or NaN.
+  friend int ilogb(const ExactFloat& a);
+
+  // Convert "a" to a normalized fraction in the range [1,2) times a power of
+  // two, and return the exponent value as an ExactFloat.  This is equivalent to
+  // floor(log2(fabs(a))) but it is computed more efficiently.
+  friend ExactFloat logb(const ExactFloat& a);
+
+ protected:
+  // OpenSSL >= 1.1 does not have BN_init, and does not support stack-
+  // allocated BIGNUMS.  We use BN_init when possible, but BN_new otherwise.
+  // If the performance penalty is too high, an object pool can be added
+  // in the future.
+#if defined(OPENSSL_IS_BORINGSSL) || OPENSSL_VERSION_NUMBER < 0x10100000L
+  // BoringSSL and OpenSSL < 1.1 support stack allocated BIGNUMs and BN_init.
+  class BigNum {
+   public:
+    BigNum() { BN_init(&bn_); }
+    // Prevent accidental, expensive, copying.
+    BigNum(const BigNum&) = delete;
+    BigNum& operator=(const BigNum&) = delete;
+    ~BigNum() { BN_free(&bn_); }
+    BIGNUM* get() { return &bn_; }
+    const BIGNUM* get() const { return &bn_; }
+   private:
+    BIGNUM bn_;
+  };
+#else
+  class BigNum {
+   public:
+    BigNum() : bn_(BN_new()) {}
+    BigNum(const BigNum&) = delete;
+    BigNum& operator=(const BigNum&) = delete;
+    ~BigNum() { BN_free(bn_); }
+    BIGNUM* get() { return bn_; }
+    const BIGNUM* get() const { return bn_; }
+   private:
+    BIGNUM* bn_;
+  };
+#endif
+
+  // Non-normal numbers are represented using special exponent values and a
+  // mantissa of zero.  Do not change these values; methods such as
+  // is_normal() make assumptions about their ordering.  Non-normal numbers
+  // can have either a positive or negative sign (including zero and NaN).
+  static const int32 kExpNaN = INT_MAX;
+  static const int32 kExpInfinity = INT_MAX - 1;
+  static const int32 kExpZero = INT_MAX - 2;
+
+  // Normal numbers are represented as (sign_ * bn_ * (2 ** bn_exp_)), where:
+  //  - sign_ is either +1 or -1
+  //  - bn_ is a BIGNUM with a positive value
+  //  - bn_exp_ is the base-2 exponent applied to bn_.
+  int32 sign_;
+  int32 bn_exp_;
+  BigNum bn_;
+
+  // A standard IEEE "double" has a 53-bit mantissa consisting of a 52-bit
+  // fraction plus an implicit leading "1" bit.
+  static const int kDoubleMantissaBits = 53;
+
+  // Convert an ExactFloat with no more than 53 bits in its mantissa to a
+  // "double".  This method handles non-normal values (NaN, etc).
+  double ToDoubleHelper() const;
+
+  // Round an ExactFloat so that it is a multiple of (2 ** bit_exp), using the
+  // given rounding mode.
+  ExactFloat RoundToPowerOf2(int bit_exp, RoundingMode mode) const;
+
+  // Convert the ExactFloat to a decimal value of the form 0.ddd * (10 ** x),
+  // with at most "max_digits" significant digits (trailing zeros are removed).
+  // Set (*digits) to the ASCII digits and return the decimal exponent "x".
+  int GetDecimalDigits(int max_digits, std::string* digits) const;
+
+  // Return a_sign * fabs(a) + b_sign * fabs(b).  Used to implement addition
+  // and subtraction.
+  static ExactFloat SignedSum(int a_sign, const ExactFloat* a,
+                              int b_sign, const ExactFloat* b);
+
+  // Convert an ExactFloat to its canonical form.  Underflow results in signed
+  // zero, overflow results in signed infinity, and precision overflow results
+  // in NaN.  A zero mantissa is converted to the canonical zero value with
+  // the given sign; otherwise the mantissa is normalized so that its low bit
+  // is 1.  Non-normal numbers are left unchanged.
+  void Canonicalize();
+
+  // Scale the mantissa of this ExactFloat so that it has the same bn_exp_ as
+  // "b", then return -1, 0, or 1 according to whether the scaled mantissa is
+  // less, equal, or greater than the mantissa of "b".  Requires that both
+  // values are normal.
+  int ScaleAndCompare(const ExactFloat& b) const;
+
+  // Return true if the magnitude of this ExactFloat is less than the
+  // magnitude of "b".  Requires that neither value is NaN.
+  bool UnsignedLess(const ExactFloat& b) const;
+
+  // Return an ExactFloat with the magnitude of this ExactFloat and the given
+  // sign.  (Similar to copysign, except that the sign is given explicitly
+  // rather than being copied from another ExactFloat.)
+  inline ExactFloat CopyWithSign(int sign) const;
+
+  // Convert an ExactFloat to an integer of type "T" using the given rounding
+  // mode.  The type "T" must be signed.  Returns the largest possible integer
+  // for NaN, and clamps out of range values to the largest or smallest
+  // possible values.
+  template <class T> T ToInteger(RoundingMode mode) const;
+
+  // Log a fatal error message (used for unimplemented methods).
+  static ExactFloat Unimplemented();
+};
+
+/////////////////////////////////////////////////////////////////////////
+// Implementation details follow:
+
+inline ExactFloat::ExactFloat() : sign_(1), bn_exp_(kExpZero) {
+}
+
+inline bool ExactFloat::is_zero() const { return bn_exp_ == kExpZero; }
+inline bool ExactFloat::is_inf() const { return bn_exp_ == kExpInfinity; }
+inline bool ExactFloat::is_nan() const { return bn_exp_ == kExpNaN; }
+inline bool ExactFloat::is_normal() const { return bn_exp_ < kExpZero; }
+inline bool ExactFloat::is_finite() const { return bn_exp_ <= kExpZero; }
+inline bool ExactFloat::sign_bit() const { return sign_ < 0; }
+
+inline int ExactFloat::sgn() const {
+  return (is_nan() || is_zero()) ? 0 : sign_;
+}
+
+inline bool operator!=(const ExactFloat& a, const ExactFloat& b) {
+  return !(a == b);
+}
+
+inline bool operator<=(const ExactFloat& a, const ExactFloat& b) {
+  // NaN is unordered compared to everything, including itself.
+  if (a.is_nan() || b.is_nan()) return false;
+  return !(b < a);
+}
+
+inline bool operator>(const ExactFloat& a, const ExactFloat& b) {
+  return b < a;
+}
+
+inline bool operator>=(const ExactFloat& a, const ExactFloat& b) {
+  return b <= a;
+}
+
+inline ExactFloat ExactFloat::CopyWithSign(int sign) const {
+  ExactFloat r = *this;
+  r.sign_ = sign;
+  return r;
+}
+
+#endif  // S2_UTIL_MATH_EXACTFLOAT_EXACTFLOAT_H_
diff --git a/src/s2/util/math/mathutil.cc b/src/s2/util/math/mathutil.cc
new file mode 100644 (file)
index 0000000..c9bad60
--- /dev/null
@@ -0,0 +1,75 @@
+// Copyright 2008 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+
+#include "s2/util/math/mathutil.h"
+
+#include <cmath>
+#include <cstdlib>
+
+namespace {
+// Returns the sign of x:
+//   -1 if x < 0,
+//   +1 if x > 0,
+//    0 if x = 0.
+template <class T>
+inline T sgn(const T x) {
+  return (x == 0 ? 0 : (x < 0 ? -1 : 1));
+}
+}  // namespace
+
+bool MathUtil::RealRootsForCubic(long double const a,
+                                 long double const b,
+                                 long double const c,
+                                 long double *const r1,
+                                 long double *const r2,
+                                 long double *const r3) {
+  // According to Numerical Recipes (pp. 184-5), what
+  // follows is an arrangement of computations to
+  // compute the roots of a cubic that minimizes
+  // roundoff error (as pointed out by A.J. Glassman).
+
+  long double const a_squared = a * a, a_third = a / 3.0, b_tripled = 3.0 * b;
+  long double const Q = (a_squared - b_tripled) / 9.0;
+  long double const R =
+      (2.0 * a_squared * a - 3.0 * a * b_tripled + 27.0 * c) / 54.0;
+
+  long double const R_squared = R * R;
+  long double const Q_cubed = Q * Q * Q;
+
+  if (R_squared < Q_cubed) {
+    long double const root_Q = sqrt(Q);
+    long double const two_pi_third = 2.0 * M_PI / 3.0;
+    long double const theta_third = acos(R / sqrt(Q_cubed)) / 3.0;
+    long double const minus_two_root_Q = -2.0 * root_Q;
+
+    *r1 = minus_two_root_Q * cos(theta_third) - a_third;
+    *r2 = minus_two_root_Q * cos(theta_third + two_pi_third) - a_third;
+    *r3 = minus_two_root_Q * cos(theta_third - two_pi_third) - a_third;
+
+    return true;
+  }
+
+  long double const A =
+    -sgn(R) * pow(std::abs(R) + sqrt(R_squared - Q_cubed), 1.0 / 3.0L);
+
+  if (A != 0.0) {  // in which case, B from NR is zero
+    *r1 = A + Q / A - a_third;
+    return false;
+  }
+
+  *r1 = *r2 = *r3 = -a_third;
+  return true;
+}
diff --git a/src/s2/util/math/mathutil.h b/src/s2/util/math/mathutil.h
new file mode 100644 (file)
index 0000000..ac9eebf
--- /dev/null
@@ -0,0 +1,189 @@
+// Copyright 2001 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+//
+// This class is intended to contain a collection of useful (static)
+// mathematical functions, properly coded (by consulting numerical
+// recipes or another authoritative source first).
+
+#ifndef S2_UTIL_MATH_MATHUTIL_H_
+#define S2_UTIL_MATH_MATHUTIL_H_
+
+#include <type_traits>
+
+#include "s2/base/integral_types.h"
+
+class MathUtil {
+ public:
+  // Solves for the real roots of x^3+ax^2+bx+c=0, returns true iff
+  // all three are real, in which case the roots are stored (in any
+  // order) in r1, r2, r3; otherwise, exactly one real root exists and
+  // it is stored in r1.
+  static bool RealRootsForCubic(long double a,
+                                long double b,
+                                long double c,
+                                long double *r1,
+                                long double *r2,
+                                long double *r3);
+
+  // --------------------------------------------------------------------
+  // Round
+  //   This function rounds a floating-point number to an integer. It
+  //   works for positive or negative numbers.
+  //
+  //   Values that are halfway between two integers may be rounded up or
+  //   down, for example Round<int>(0.5) == 0 and Round<int>(1.5) == 2.
+  //   This allows the function to be implemented efficiently on Intel
+  //   processors (see the template specializations at the bottom of this
+  //   file).  You should not use this function if you care about which
+  //   way such half-integers are rounded.
+  //
+  //   Example usage:
+  //     double y, z;
+  //     int x = Round<int>(y + 3.7);
+  //     int64 b = Round<int64>(0.3 * z);
+  //
+  //   Note that the floating-point template parameter is typically inferred
+  //   from the argument type, i.e. there is no need to specify it explicitly.
+  // --------------------------------------------------------------------
+  template <class IntOut, class FloatIn>
+  static IntOut Round(FloatIn x) {
+    static_assert(!std::is_integral<FloatIn>::value, "FloatIn is integer");
+    static_assert(std::is_integral<IntOut>::value, "IntOut is not integer");
+
+    // We don't use sgn(x) below because there is no need to distinguish the
+    // (x == 0) case.  Also note that there are specialized faster versions
+    // of this function for Intel processors at the bottom of this file.
+    return static_cast<IntOut>(x < 0 ? (x - 0.5) : (x + 0.5));
+  }
+
+  // --------------------------------------------------------------------
+  // FastIntRound, FastInt64Round
+  //   Fast routines for converting floating-point numbers to integers.
+  //
+  //   These routines are approximately 6 times faster than the default
+  //   implementation of Round<int> on Intel processors (12 times faster on
+  //   the Pentium 3).  They are also more than 5 times faster than simply
+  //   casting a "double" to an "int" using static_cast<int>.  This is
+  //   because casts are defined to truncate towards zero, which on Intel
+  //   processors requires changing the rounding mode and flushing the
+  //   floating-point pipeline (unless programs are compiled specifically
+  //   for the Pentium 4, which has a new instruction to avoid this).
+  //
+  //   Numbers that are halfway between two integers may be rounded up or
+  //   down.  This is because the conversion is done using the default
+  //   rounding mode, which rounds towards the closest even number in case
+  //   of ties.  So for example, FastIntRound(0.5) == 0, but
+  //   FastIntRound(1.5) == 2.  These functions should only be used with
+  //   applications that don't care about which way such half-integers are
+  //   rounded.
+  //
+  //   There are template specializations of Round() which call these
+  //   functions (for "int" and "int64" only), but it's safer to call them
+  //   directly.
+  //
+  //   This functions are equivalent to lrint() and llrint() as defined in
+  //   the ISO C99 standard.  Unfortunately this standard does not seem to
+  //   widely adopted yet and these functions are not available by default.
+  //   --------------------------------------------------------------------
+
+  static int32 FastIntRound(double x) {
+    // This function is not templatized because gcc doesn't seem to be able
+    // to deal with inline assembly code in templatized functions, and there
+    // is no advantage to passing an argument type of "float" on Intel
+    // architectures anyway.
+
+#if defined __GNUC__ && (defined __i386__ || defined __SSE2__)
+#if defined __SSE2__
+    // SSE2.
+    int32 result;
+    __asm__ __volatile__
+        ("cvtsd2si %1, %0"
+         : "=r" (result)    // Output operand is a register
+         : "x" (x));        // Input operand is an xmm register
+    return result;
+#elif defined __i386__
+    // FPU stack.  Adapted from /usr/include/bits/mathinline.h.
+    int32 result;
+    __asm__ __volatile__
+        ("fistpl %0"
+         : "=m" (result)    // Output operand is a memory location
+         : "t" (x)          // Input operand is top of FP stack
+         : "st");           // Clobbers (pops) top of FP stack
+    return result;
+#endif  // if defined __x86_64__ || ...
+#else
+    return Round<int32, double>(x);
+#endif  // if defined __GNUC__ && ...
+  }
+
+  static int64 FastInt64Round(double x) {
+#if defined __GNUC__ && (defined __i386__ || defined __x86_64__)
+#if defined __x86_64__
+    // SSE2.
+    int64 result;
+    __asm__ __volatile__
+        ("cvtsd2si %1, %0"
+         : "=r" (result)    // Output operand is a register
+         : "x" (x));        // Input operand is an xmm register
+    return result;
+#elif defined __i386__
+    // There is no CVTSD2SI in i386 to produce a 64 bit int, even with SSE2.
+    // FPU stack.  Adapted from /usr/include/bits/mathinline.h.
+    int64 result;
+    __asm__ __volatile__
+        ("fistpll %0"
+         : "=m" (result)    // Output operand is a memory location
+         : "t" (x)          // Input operand is top of FP stack
+         : "st");           // Clobbers (pops) top of FP stack
+    return result;
+#endif  // if defined __i386__
+#else
+    return Round<int64, double>(x);
+#endif  // if defined __GNUC__ && ...
+  }
+};
+
+// ========================================================================= //
+
+#if (defined __i386__ || defined __x86_64__) && defined __GNUC__
+
+// We define template specializations of Round() to get the more efficient
+// Intel versions when possible.  Note that gcc does not currently support
+// partial specialization of templatized functions.
+
+template<>
+inline int32 MathUtil::Round<int32, double>(double x) {
+  return FastIntRound(x);
+}
+
+template<>
+inline int32 MathUtil::Round<int32, float>(float x) {
+  return FastIntRound(x);
+}
+
+template<>
+inline int64 MathUtil::Round<int64, double>(double x) {
+  return FastInt64Round(x);
+}
+
+template<>
+inline int64 MathUtil::Round<int64, float>(float x) {
+  return FastInt64Round(x);
+}
+
+#endif
+
+#endif  // S2_UTIL_MATH_MATHUTIL_H_
diff --git a/src/s2/util/math/matrix3x3.h b/src/s2/util/math/matrix3x3.h
new file mode 100644 (file)
index 0000000..e6b60af
--- /dev/null
@@ -0,0 +1,574 @@
+// Copyright 2003 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+//
+// A simple class to handle 3x3 matrices
+// The aim of this class is to be able to manipulate 3x3 matrices
+// and 3D vectors as naturally as possible and make calculations
+// readable.
+// For that reason, the operators +, -, * are overloaded.
+// (Reading a = a + b*2 - c is much easier to read than
+// a = Sub(Add(a, Mul(b,2)),c)   )
+//
+// Please be careful about overflows when using those matrices wth integer types
+// The calculations are carried with VType. eg : if you are using uint8 as the
+// base type, all values will be modulo 256.
+// This feature is necessary to use the class in a more general framework with
+// VType != plain old data type.
+
+#ifndef S2_UTIL_MATH_MATRIX3X3_H_
+#define S2_UTIL_MATH_MATRIX3X3_H_
+
+#include <cmath>
+#include <iosfwd>
+#include <type_traits>
+
+#include "s2/base/logging.h"
+#include "s2/util/math/mathutil.h"
+#include "s2/util/math/vector.h"
+
+template <class VType>
+class Matrix3x3 {
+ private:
+  VType m_[3][3];
+
+ public:
+  typedef Matrix3x3<VType> Self;
+  typedef VType BaseType;
+  typedef Vector3<VType> MVector;
+
+  // Initialize the matrix to 0
+  Matrix3x3() {
+    m_[0][2] = m_[0][1] = m_[0][0] = VType();
+    m_[1][2] = m_[1][1] = m_[1][0] = VType();
+    m_[2][2] = m_[2][1] = m_[2][0] = VType();
+  }
+
+  // Constructor explicitly setting the values of all the coefficient of
+  // the matrix
+  Matrix3x3(const VType &m00, const VType &m01, const VType &m02,
+            const VType &m10, const VType &m11, const VType &m12,
+            const VType &m20, const VType &m21, const VType &m22) {
+    m_[0][0] = m00;
+    m_[0][1] = m01;
+    m_[0][2] = m02;
+
+    m_[1][0] = m10;
+    m_[1][1] = m11;
+    m_[1][2] = m12;
+
+    m_[2][0] = m20;
+    m_[2][1] = m21;
+    m_[2][2] = m22;
+  }
+
+  // Casting constructor
+  template <class VType2>
+  static Matrix3x3 Cast(const Matrix3x3<VType2> &mb) {
+    return Matrix3x3(static_cast<VType>(mb(0, 0)),
+                     static_cast<VType>(mb(0, 1)),
+                     static_cast<VType>(mb(0, 2)),
+                     static_cast<VType>(mb(1, 0)),
+                     static_cast<VType>(mb(1, 1)),
+                     static_cast<VType>(mb(1, 2)),
+                     static_cast<VType>(mb(2, 0)),
+                     static_cast<VType>(mb(2, 1)),
+                     static_cast<VType>(mb(2, 2)));
+  }
+
+  // Change the value of all the coefficients of the matrix
+  inline Matrix3x3 &
+    Set(const VType &m00, const VType &m01, const VType &m02,
+        const VType &m10, const VType &m11, const VType &m12,
+        const VType &m20, const VType &m21, const VType &m22) {
+    m_[0][0] = m00;
+    m_[0][1] = m01;
+    m_[0][2] = m02;
+
+    m_[1][0] = m10;
+    m_[1][1] = m11;
+    m_[1][2] = m12;
+
+    m_[2][0] = m20;
+    m_[2][1] = m21;
+    m_[2][2] = m22;
+    return (*this);
+  }
+
+  // Matrix addition
+  inline Matrix3x3& operator+=(const Matrix3x3 &mb) {
+    m_[0][0] += mb.m_[0][0];
+    m_[0][1] += mb.m_[0][1];
+    m_[0][2] += mb.m_[0][2];
+
+    m_[1][0] += mb.m_[1][0];
+    m_[1][1] += mb.m_[1][1];
+    m_[1][2] += mb.m_[1][2];
+
+    m_[2][0] += mb.m_[2][0];
+    m_[2][1] += mb.m_[2][1];
+    m_[2][2] += mb.m_[2][2];
+    return (*this);
+  }
+
+  // Matrix subtration
+  inline Matrix3x3& operator-=(const Matrix3x3 &mb) {
+    m_[0][0] -= mb.m_[0][0];
+    m_[0][1] -= mb.m_[0][1];
+    m_[0][2] -= mb.m_[0][2];
+
+    m_[1][0] -= mb.m_[1][0];
+    m_[1][1] -= mb.m_[1][1];
+    m_[1][2] -= mb.m_[1][2];
+
+    m_[2][0] -= mb.m_[2][0];
+    m_[2][1] -= mb.m_[2][1];
+    m_[2][2] -= mb.m_[2][2];
+    return (*this);
+  }
+
+  // Matrix multiplication by a scalar
+  inline Matrix3x3& operator*=(const VType &k) {
+    m_[0][0] *= k;
+    m_[0][1] *= k;
+    m_[0][2] *= k;
+
+    m_[1][0] *= k;
+    m_[1][1] *= k;
+    m_[1][2] *= k;
+
+    m_[2][0] *= k;
+    m_[2][1] *= k;
+    m_[2][2] *= k;
+    return (*this);
+  }
+
+  // Matrix addition
+  inline Matrix3x3 operator+(const Matrix3x3 &mb) const {
+    return Matrix3x3(*this) += mb;
+  }
+
+  // Matrix subtraction
+  inline Matrix3x3 operator-(const Matrix3x3 &mb) const {
+    return Matrix3x3(*this) -= mb;
+  }
+
+  // Change the sign of all the coefficients in the matrix
+  friend inline Matrix3x3 operator-(const Matrix3x3 &vb) {
+    return Matrix3x3(-vb.m_[0][0], -vb.m_[0][1], -vb.m_[0][2],
+                     -vb.m_[1][0], -vb.m_[1][1], -vb.m_[1][2],
+                     -vb.m_[2][0], -vb.m_[2][1], -vb.m_[2][2]);
+  }
+
+  // Matrix multiplication by a scalar
+  inline Matrix3x3 operator*(const VType &k) const {
+    return Matrix3x3(*this) *= k;
+  }
+
+  friend inline Matrix3x3 operator*(const VType &k, const Matrix3x3 &mb) {
+    return Matrix3x3(mb)*k;
+  }
+
+  // Matrix multiplication
+  inline Matrix3x3 operator*(const Matrix3x3 &mb) const {
+    return Matrix3x3(
+      m_[0][0] * mb.m_[0][0] + m_[0][1] * mb.m_[1][0] + m_[0][2] * mb.m_[2][0],
+      m_[0][0] * mb.m_[0][1] + m_[0][1] * mb.m_[1][1] + m_[0][2] * mb.m_[2][1],
+      m_[0][0] * mb.m_[0][2] + m_[0][1] * mb.m_[1][2] + m_[0][2] * mb.m_[2][2],
+
+      m_[1][0] * mb.m_[0][0] + m_[1][1] * mb.m_[1][0] + m_[1][2] * mb.m_[2][0],
+      m_[1][0] * mb.m_[0][1] + m_[1][1] * mb.m_[1][1] + m_[1][2] * mb.m_[2][1],
+      m_[1][0] * mb.m_[0][2] + m_[1][1] * mb.m_[1][2] + m_[1][2] * mb.m_[2][2],
+
+      m_[2][0] * mb.m_[0][0] + m_[2][1] * mb.m_[1][0] + m_[2][2] * mb.m_[2][0],
+      m_[2][0] * mb.m_[0][1] + m_[2][1] * mb.m_[1][1] + m_[2][2] * mb.m_[2][1],
+      m_[2][0] * mb.m_[0][2] + m_[2][1] * mb.m_[1][2] + m_[2][2] * mb.m_[2][2]);
+  }
+
+  // Multiplication of a matrix by a vector
+  inline MVector operator*(const MVector &v) const {
+    return MVector(
+      m_[0][0] * v[0] + m_[0][1] * v[1] + m_[0][2] * v[2],
+      m_[1][0] * v[0] + m_[1][1] * v[1] + m_[1][2] * v[2],
+      m_[2][0] * v[0] + m_[2][1] * v[1] + m_[2][2] * v[2]);
+  }
+
+  // Return the determinant of the matrix
+  inline VType Det(void) const {
+    return m_[0][0] * m_[1][1] * m_[2][2]
+         + m_[0][1] * m_[1][2] * m_[2][0]
+         + m_[0][2] * m_[1][0] * m_[2][1]
+         - m_[2][0] * m_[1][1] * m_[0][2]
+         - m_[2][1] * m_[1][2] * m_[0][0]
+         - m_[2][2] * m_[1][0] * m_[0][1];
+  }
+
+  // Return the trace of the matrix
+  inline VType Trace(void) const {
+    return m_[0][0] + m_[1][1] + m_[2][2];
+  }
+
+  // Return a pointer to the data array for interface with other libraries
+  // like opencv
+  VType* Data() {
+    return reinterpret_cast<VType*>(m_);
+  }
+  const VType* Data() const {
+    return reinterpret_cast<const VType*>(m_);
+  }
+
+  // Return matrix element (i,j) with 0<=i<=2 0<=j<=2
+  inline VType &operator()(const int i, const int j) {
+    S2_DCHECK_GE(i, 0);
+    S2_DCHECK_LT(i, 3);
+    S2_DCHECK_GE(j, 0);
+    S2_DCHECK_LT(j, 3);
+    return m_[i][j];
+  }
+  inline VType operator()(const int i, const int j) const {
+    S2_DCHECK_GE(i, 0);
+    S2_DCHECK_LT(i, 3);
+    S2_DCHECK_GE(j, 0);
+    S2_DCHECK_LT(j, 3);
+    return m_[i][j];
+  }
+
+  // Return matrix element (i/3,i%3) with 0<=i<=8 (access concatenated rows).
+  inline VType &operator[](const int i) {
+    S2_DCHECK_GE(i, 0);
+    S2_DCHECK_LT(i, 9);
+    return reinterpret_cast<VType*>(m_)[i];
+  }
+  inline VType operator[](const int i) const {
+    S2_DCHECK_GE(i, 0);
+    S2_DCHECK_LT(i, 9);
+    return reinterpret_cast<const VType*>(m_)[i];
+  }
+
+  // Return the transposed matrix
+  inline Matrix3x3 Transpose(void) const {
+    return Matrix3x3(m_[0][0], m_[1][0], m_[2][0],
+                     m_[0][1], m_[1][1], m_[2][1],
+                     m_[0][2], m_[1][2], m_[2][2]);
+  }
+
+  // Return the transposed of the matrix of the cofactors
+  // (Useful for inversion for example)
+  inline Matrix3x3 ComatrixTransposed(void) const {
+    return Matrix3x3(
+      m_[1][1] * m_[2][2] - m_[2][1] * m_[1][2],
+      m_[2][1] * m_[0][2] - m_[0][1] * m_[2][2],
+      m_[0][1] * m_[1][2] - m_[1][1] * m_[0][2],
+
+      m_[1][2] * m_[2][0] - m_[2][2] * m_[1][0],
+      m_[2][2] * m_[0][0] - m_[0][2] * m_[2][0],
+      m_[0][2] * m_[1][0] - m_[1][2] * m_[0][0],
+
+      m_[1][0] * m_[2][1] - m_[2][0] * m_[1][1],
+      m_[2][0] * m_[0][1] - m_[0][0] * m_[2][1],
+      m_[0][0] * m_[1][1] - m_[1][0] * m_[0][1]);
+  }
+  // Matrix inversion
+  inline Matrix3x3 Inverse(void) const {
+    VType det = Det();
+    S2_CHECK_NE(det, VType(0)) << " Can't inverse. Determinant = 0.";
+    return (VType(1) / det) * ComatrixTransposed();
+  }
+
+  // Return the vector 3D at row i
+  inline MVector Row(const int i) const {
+    S2_DCHECK_GE(i, 0);
+    S2_DCHECK_LT(i, 3);
+    return MVector(m_[i][0], m_[i][1], m_[i][2]);
+  }
+
+  // Return the vector 3D at col i
+  inline MVector Col(const int i) const {
+    S2_DCHECK_GE(i, 0);
+    S2_DCHECK_LT(i, 3);
+    return MVector(m_[0][i], m_[1][i], m_[2][i]);
+  }
+
+  // Create a matrix from 3 row vectors
+  static inline Matrix3x3 FromRows(const MVector &v1,
+                              const MVector &v2,
+                              const MVector &v3) {
+    Matrix3x3 temp;
+    temp.Set(v1[0], v1[1], v1[2],
+             v2[0], v2[1], v2[2],
+             v3[0], v3[1], v3[2]);
+    return temp;
+  }
+
+  // Create a matrix from 3 column vectors
+  static inline Matrix3x3 FromCols(const MVector &v1,
+                              const MVector &v2,
+                              const MVector &v3) {
+    Matrix3x3 temp;
+    temp.Set(v1[0], v2[0], v3[0],
+             v1[1], v2[1], v3[1],
+             v1[2], v2[2], v3[2]);
+    return temp;
+  }
+
+  // Set the vector in row i to be v1
+  void SetRow(int i, const MVector &v1) {
+    S2_DCHECK_GE(i, 0);
+    S2_DCHECK_LT(i, 3);
+    m_[i][0] = v1[0];
+    m_[i][1] = v1[1];
+    m_[i][2] = v1[2];
+  }
+
+  // Set the vector in column i to be v1
+  void SetCol(int i, const MVector &v1) {
+    S2_DCHECK_GE(i, 0);
+    S2_DCHECK_LT(i, 3);
+    m_[0][i] = v1[0];
+    m_[1][i] = v1[1];
+    m_[2][i] = v1[2];
+  }
+
+  // Return a matrix M close to the original but verifying MtM = I
+  // (useful to compensate for errors in a rotation matrix)
+  Matrix3x3 Orthogonalize() const {
+    MVector r1, r2, r3;
+    r1 = Row(0).Normalize();
+    r2 = (Row(2).CrossProd(r1)).Normalize();
+    r3 = (r1.CrossProd(r2)).Normalize();
+    return FromRows(r1, r2, r3);
+  }
+
+  // Return the identity matrix
+  static inline Matrix3x3 Identity(void) {
+    Matrix3x3 temp;
+    temp.Set(VType(1), VType(0), VType(0),  //
+             VType(0), VType(1), VType(0),  //
+             VType(0), VType(0), VType(1));
+    return temp;
+  }
+
+  // Return a matrix full of zeros
+  static inline Matrix3x3 Zero(void) {
+    return Matrix3x3();
+  }
+
+  // Return a diagonal matrix with the coefficients in v
+  static inline Matrix3x3 Diagonal(const MVector &v) {
+    return Matrix3x3(v[0], VType(), VType(),
+                     VType(), v[1], VType(),
+                     VType(), VType(), v[2]);
+  }
+
+  // Return the matrix vvT
+  static Matrix3x3 Sym3(const MVector &v) {
+    return Matrix3x3(
+      v[0]*v[0], v[0]*v[1], v[0]*v[2],
+      v[1]*v[0], v[1]*v[1], v[1]*v[2],
+      v[2]*v[0], v[2]*v[1], v[2]*v[2]);
+  }
+  // Return a matrix M such that:
+  // for each u,  M * u = v.CrossProd(u)
+  static Matrix3x3 AntiSym3(const MVector &v) {
+    return Matrix3x3(VType(),    -v[2],     v[1],
+                     v[2],     VType(),    -v[0],
+                     -v[1],       v[0],   VType());
+  }
+
+  // Returns matrix that rotates |rot| radians around axis rot.
+  static Matrix3x3 Rodrigues(const MVector &rot) {
+    Matrix3x3 R;
+    VType theta = rot.Norm();
+    MVector w = rot.Normalize();
+    Matrix3x3 Wv = Matrix3x3::AntiSym3(w);
+    Matrix3x3 I = Matrix3x3::Identity();
+    Matrix3x3 A = Matrix3x3::Sym3(w);
+    R = (1 - cos(theta)) * A + sin(theta) * Wv + cos(theta) * I;
+    return R;
+  }
+
+  // Returns v.Transpose() * (*this) * u
+  VType MulBothSides(const MVector &v, const MVector &u) const {
+    return ((*this) * u).DotProd(v);
+  }
+
+  // Use the 3x3 matrix as a projective transform for 2d points
+  Vector2<VType> Project(const Vector2<VType> &v) const {
+    MVector temp = (*this) * MVector(v[0], v[1], 1);
+    return Vector2<VType>(temp[0] / temp[2], temp[1] / temp[2]);
+  }
+
+  // Return the Frobenius norm of the matrix: sqrt(sum(aij^2))
+  VType FrobeniusNorm() const {
+    VType sum = VType();
+    for (int i = 0; i < 3; i++) {
+      for (int j = 0; j < 3; j++) {
+        sum += m_[i][j] * m_[i][j];
+      }
+    }
+    return sqrt(sum);
+  }
+
+  // Finds the eigen values of the matrix. Return the number of real eigenvalues
+  // found.
+  // If the matrix is known to be symmetric due to your problem formulation,
+  // then please use SymmetricEigenSolver, since this method does not guarantee
+  // finding all 3 real eigenvalues in pathological cases.  See CL 49170250.
+  int EigenValues(MVector *eig_val) const {
+    long double r1, r2, r3;  // NOLINT
+    // characteristic polynomial
+    // x^3 + a*x^2 + b*x + c
+    VType a = -Trace();
+    VType b = m_[0][0]*m_[1][1] + m_[1][1]*m_[2][2] + m_[2][2]*m_[0][0]
+            - m_[1][0]*m_[0][1] - m_[2][1]*m_[1][2] - m_[0][2]*m_[2][0];
+    VType c = -Det();
+    bool res = MathUtil::RealRootsForCubic(a, b, c, &r1, &r2, &r3);
+    (*eig_val)[0] = r1;
+    if (res) {
+      (*eig_val)[1] = r2;
+      (*eig_val)[2] = r3;
+      return 3;
+    }
+    return 1;
+  }
+
+  // Finds the eigen values and optional associated eigen vectors of a
+  // symmetric 3x3 matrix (not necessarily positive definite).
+  // eigen values are sorted in decreasing order;
+  // eig_val corresponds to the columns of the eig_vec matrix.
+  // Note: The routine will only use the lower diagonal part
+  // of the matrix, i.e.
+  // |  a00,          |
+  // |  a10, a11,     |
+  // |  a20, a21, a22 |
+  void SymmetricEigenSolver(MVector *eig_val,
+                            Matrix3x3 *eig_vec /*nullable*/) const {
+    // Compute characteristic polynomial coefficients.
+    double c2 = -Trace();
+    double c1 = -(m_[1][0] * m_[1][0] - m_[0][0] * m_[1][1]
+                  - m_[0][0] * m_[2][2] - m_[1][1] * m_[2][2]
+                  + m_[2][0] * m_[2][0] + m_[2][1] * m_[2][1]);
+    double c0 = -(m_[0][0] * m_[1][1] * m_[2][2]    //
+                  - m_[2][0] * m_[2][0] * m_[1][1]  //
+                  - m_[1][0] * m_[1][0] * m_[2][2]  //
+                  - m_[0][0] * m_[2][1] * m_[2][1]  //
+                  + 2 * m_[1][0] * m_[2][0] * m_[2][1]);
+
+    // Root finding x^3 + c2*x^2 + c1*x + c0 = 0.
+    // NOTE: Cannot reuse general cubic solver MathUtil::RealRootsForCubic()
+    // because it doesn't guarantee finding 3 real roots, e.g. it won't always
+    // return roots {2, 2, 0} for the cubic x^3 - 4*x^2 + 4*x + epsilon = 0.
+    double q = (c2*c2-3*c1)/9.0;
+    double r = (2*c2*c2*c2-9*c2*c1+27*c0)/54.0;
+    // Assume R^2 <= Q^3 so there are three real roots.
+    // Avoid sqrt of negative q, which can only happen due to numerical error.
+    if (q < 0) q = 0;
+    double sqrt_q = -2.0 * sqrt(q);
+    double q3_r2 = q * q * q - r * r;
+    // Avoid sqrt of negative q3_r2, which can only happen due to numerical
+    // error.
+    double theta = atan2(q3_r2 <= 0 ? 0 : sqrt(q3_r2), r);
+    double c2_3 = c2 / 3;
+    (*eig_val)[0] = sqrt_q * cos(theta / 3.0) - c2_3;
+    (*eig_val)[1] = sqrt_q * cos((theta + 2.0 * M_PI)/3.0) - c2_3;
+    (*eig_val)[2] = sqrt_q * cos((theta - 2.0 * M_PI)/3.0) - c2_3;
+
+    // Sort eigen value in decreasing order
+    Vector3<int> d_order = eig_val->ComponentOrder();
+    (*eig_val) = MVector((*eig_val)[d_order[2]],
+                         (*eig_val)[d_order[1]],
+                         (*eig_val)[d_order[0]]);
+
+    // Compute eigenvectors
+    if (!eig_vec) return;
+    for (int i = 0; i < 3; ++i) {
+      MVector r1 , r2 , r3 , e1 , e2 , e3;
+      r1[0] = m_[0][0] - (*eig_val)[i];
+      r2[0] = m_[1][0];
+      r3[0] = m_[2][0];
+      r1[1] = m_[1][0];
+      r2[1] = m_[1][1] - (*eig_val)[i];
+      r3[1] = m_[2][1];
+      r1[2] = m_[2][0];
+      r2[2] = m_[2][1];
+      r3[2] = m_[2][2] - (*eig_val)[i];
+
+      e1 = r1.CrossProd(r2);
+      e2 = r2.CrossProd(r3);
+      e3 = r3.CrossProd(r1);
+
+      // Make e2 and e3 point in the same direction as e1
+      if (e2.DotProd(e1) < 0) e2 = -e2;
+      if (e3.DotProd(e1) < 0) e3 = -e3;
+      MVector e = (e1 + e2 + e3).Normalize();
+      eig_vec->SetCol(i, e);
+    }
+  }
+
+  // Return true is one of the elements of the matrix is NaN
+  bool IsNaN() const {
+    for ( int i = 0; i < 3; ++i ) {
+      for ( int j = 0; j < 3; ++j ) {
+        if ( isnan(m_[i][j]) ) {
+          return true;
+        }
+      }
+    }
+    return false;
+  }
+
+  friend bool operator==(const Matrix3x3 &a, const Matrix3x3 &b) {
+    return a.m_[0][0] == b.m_[0][0] &&
+           a.m_[0][1] == b.m_[0][1] &&
+           a.m_[0][2] == b.m_[0][2] &&
+           a.m_[1][0] == b.m_[1][0] &&
+           a.m_[1][1] == b.m_[1][1] &&
+           a.m_[1][2] == b.m_[1][2] &&
+           a.m_[2][0] == b.m_[2][0] &&
+           a.m_[2][1] == b.m_[2][1] &&
+           a.m_[2][2] == b.m_[2][2];
+  }
+
+  friend bool operator!=(const Matrix3x3 &a, const Matrix3x3 &b) {
+    return !(a == b);
+  }
+
+  friend std::ostream &operator <<(std::ostream &out, const Matrix3x3 &mb) {
+    int i, j;
+    for (i = 0; i < 3; i++) {
+      if (i ==0) {
+        out << "[";
+      } else {
+        out << " ";
+      }
+      for (j = 0; j < 3; j++) {
+        out << mb(i, j) << " ";
+      }
+      if (i == 2) {
+        out << "]";
+      } else {
+        out << std::endl;
+      }
+    }
+    return out;
+  }
+};
+
+typedef Matrix3x3<int>    Matrix3x3_i;
+typedef Matrix3x3<float>  Matrix3x3_f;
+typedef Matrix3x3<double> Matrix3x3_d;
+
+
+#endif  // S2_UTIL_MATH_MATRIX3X3_H_
diff --git a/src/s2/util/math/vector.h b/src/s2/util/math/vector.h
new file mode 100644 (file)
index 0000000..6cddc9c
--- /dev/null
@@ -0,0 +1,569 @@
+// Copyright Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// Simple classes to handle vectors in 2D, 3D, and 4D.
+//
+// Maintainers: Please be mindful of extreme degradations in unoptimized
+// performance here.
+#ifndef S2_UTIL_MATH_VECTOR_H_
+#define S2_UTIL_MATH_VECTOR_H_
+
+#include <algorithm>
+#include <cmath>
+#include <cstdlib>
+#include <iosfwd>
+#include <iostream>  // NOLINT(readability/streams)
+#include <limits>
+#include <type_traits>
+
+#include "s2/base/integral_types.h"
+#include "s2/base/logging.h"
+#include "absl/base/macros.h"
+#include "absl/utility/utility.h"
+
+template <typename T> class Vector2;
+template <typename T> class Vector3;
+template <typename T> class Vector4;
+
+namespace util {
+namespace math {
+namespace internal_vector {
+
+// CRTP base class for all Vector templates.
+template <template <typename> class VecTemplate, typename T, std::size_t N>
+class BasicVector {
+  using D = VecTemplate<T>;
+
+ protected:
+  // FloatType is the type returned by Norm() and Angle().  These methods are
+  // special because they return floating-point values even when VType is an
+  // integer.
+  typedef typename std::conditional<std::is_integral<T>::value,
+                                    double, T>::type FloatType;
+
+  using IdxSeqN = typename absl::make_index_sequence<N>;
+
+  template <std::size_t I, typename F, typename... As>
+  static auto Reduce(F f, As*... as)
+      -> decltype(f(as[I]...)) {
+    return f(as[I]...);
+  }
+
+  template <typename R = D, std::size_t... Is, typename F, typename... As>
+  static R GenerateEach(absl::index_sequence<Is...>, F f, As*... as) {
+    return R(Reduce<Is>(f, as...)...);
+  }
+
+  // Generate<R>(f,a,b,...) returns an R(...), where the constructor arguments
+  // are created as a transform. R(f(a[0],b[0],...), f(a[1],b[1],...), ...),
+  // and with a,b,...  all optional.
+  template <typename R = D, typename F, typename... As>
+  static R Generate(F f, As&&... as) {
+    return GenerateEach<R>(IdxSeqN(), f, std::forward<As>(as).Data()...);
+  }
+
+ public:
+  enum { SIZE = N };
+  static int Size() { return SIZE; }
+
+  void Clear() { AsD() = D(); }
+
+  T& operator[](int b) {
+    S2_DCHECK_GE(b, 0);
+    S2_DCHECK_LT(b, SIZE);
+    return static_cast<D&>(*this).Data()[b];
+  }
+  T operator[](int b) const {
+    S2_DCHECK_GE(b, 0);
+    S2_DCHECK_LT(b, SIZE);
+    return static_cast<const D&>(*this).Data()[b];
+  }
+
+  // TODO(user): Relationals should be nonmembers.
+  bool operator==(const D& b) const {
+    const T* ap = static_cast<const D&>(*this).Data();
+    return std::equal(ap, ap + this->Size(), b.Data());
+  }
+  bool operator!=(const D& b) const { return !(AsD() == b); }
+  bool operator<(const D& b) const {
+    const T* ap = static_cast<const D&>(*this).Data();
+    const T* bp = b.Data();
+    return std::lexicographical_compare(
+        ap, ap + this->Size(), bp, bp + b.Size());
+  }
+  bool operator>(const D& b) const { return b < AsD(); }
+  bool operator<=(const D& b) const { return !(AsD() > b); }
+  bool operator>=(const D& b) const { return !(AsD() < b); }
+
+  D& operator+=(const D& b) {
+    PlusEq(static_cast<D&>(*this).Data(), b.Data(), IdxSeqN{});
+    return static_cast<D&>(*this);
+  }
+
+  D& operator-=(const D& b) {
+    MinusEq(static_cast<D&>(*this).Data(), b.Data(), IdxSeqN{});
+    return static_cast<D&>(*this);
+  }
+
+  D& operator*=(T k) {
+    MulEq(static_cast<D&>(*this).Data(), k, IdxSeqN{});
+    return static_cast<D&>(*this);
+  }
+
+  D& operator/=(T k) {
+    DivEq(static_cast<D&>(*this).Data(), k, IdxSeqN{});
+    return static_cast<D&>(*this);
+  }
+
+  D operator+(const D& b) const { return D(AsD()) += b; }
+  D operator-(const D& b) const { return D(AsD()) -= b; }
+  D operator*(T k) const { return D(AsD()) *= k; }
+  D operator/(T k) const { return D(AsD()) /= k; }
+
+  friend D operator-(const D& a) {
+    return Generate([](const T& x) { return -x; }, a);
+  }
+
+  // Convert from another vector type
+  template <typename T2>
+  static D Cast(const VecTemplate<T2> &b) {
+    return Generate([](const T2& x) { return static_cast<T>(x); }, b);
+  }
+
+  // multiply two vectors component by component
+  D MulComponents(const D &b) const {
+    return Generate([](const T& x, const T& y) { return x * y; }, AsD(), b);
+  }
+  // divide two vectors component by component
+  D DivComponents(const D &b) const {
+    return Generate([](const T& x, const T& y) { return x / y; }, AsD(), b);
+  }
+
+  // Element-wise max.  {max(a[0],b[0]), max(a[1],b[1]), ...}
+  friend D Max(const D &a, const D &b) {
+    return Generate([](const T& x, const T& y) {
+      return std::max(x, y);
+    }, a, b);
+  }
+
+  // Element-wise min.  {min(a[0],b[0]), min(a[1],b[1]), ...}
+  friend D Min(const D &a, const D &b) {
+    return Generate([](const T& x, const T& y) {
+      return std::min(x, y);
+    }, a, b);
+  }
+
+  T DotProd(const D& b) const {
+    return Dot(static_cast<T>(0), static_cast<const D&>(*this).Data(), b.Data(),
+               IdxSeqN{});
+  }
+
+  // Squared Euclidean norm (the dot product with itself).
+  T Norm2() const { return DotProd(AsD()); }
+
+  // Euclidean norm. For integer T, correct only if Norm2 does not overflow.
+  FloatType Norm() const {
+    using std::sqrt;
+    return sqrt(Norm2());
+  }
+
+  // Normalized vector if the norm is nonzero. Not for integer types.
+  D Normalize() const {
+    static_assert(!std::is_integral<T>::value, "must be floating point");
+    T n = Norm();
+    if (n != T(0.0)) {
+      n = T(1.0) / n;
+    }
+    return D(AsD()) *= n;
+  }
+
+  // Compose a vector from the sqrt of each component.
+  D Sqrt() const {
+    return Generate([](const T& x) {
+      using std::sqrt;
+      return sqrt(x);
+    }, AsD());
+  }
+
+  // Take the floor of each component.
+  D Floor() const {
+    return Generate([](const T& x) { return floor(x); }, AsD());
+  }
+
+  // Take the ceil of each component.
+  D Ceil() const {
+    return Generate([](const T& x) { return ceil(x); }, AsD());
+  }
+
+  // Round of each component.
+  D FRound() const {
+    using std::rint;
+    return Generate([](const T& x) { return rint(x); }, AsD());
+  }
+
+  // Round of each component and return an integer vector.
+  VecTemplate<int> IRound() const {
+    using std::lrint;
+    return Generate<VecTemplate<int>>([](const T& x) { return lrint(x); },
+                                      AsD());
+  }
+
+  // True if any of the components is not a number.
+  bool IsNaN() const {
+    bool r = false;
+    const T* ap = AsD().Data();
+    for (int i = 0; i < SIZE; ++i)
+      r = r || isnan(ap[i]);
+    return r;
+  }
+
+  // A Vector populated with all NaN values.
+  static D NaN() {
+    return Generate([] { return std::numeric_limits<T>::quiet_NaN(); });
+  }
+
+  friend std::ostream& operator<<(std::ostream& out, const D& v) {
+    out << "[";
+    const char *sep = "";
+    for (int i = 0; i < SIZE; ++i) {
+      out << sep;
+      Print(out, v[i]);
+      sep = ", ";
+    }
+    return out << "]";
+  }
+
+  // These are only public for technical reasons (see cl/121145822).
+  template <typename K>
+  D MulScalarInternal(const K& k) const {
+    return Generate([k](const T& x) { return k * x; }, AsD());
+  }
+  template <typename K>
+  D DivScalarInternal(const K& k) const {
+    return Generate([k](const T& x) { return k / x; }, AsD());
+  }
+
+ private:
+  const D& AsD() const { return static_cast<const D&>(*this); }
+  D& AsD() { return static_cast<D&>(*this); }
+
+  // ostream << uint8 prints the ASCII character, which is not useful.
+  // Cast to int so that numbers will be printed instead.
+  template <typename U>
+  static void Print(std::ostream& out, const U& v) { out << v; }
+  static void Print(std::ostream& out, uint8 v) { out << static_cast<int>(v); }
+
+  // Ignores its arguments so that side-effects of variadic unpacking can occur.
+  static void Ignore(std::initializer_list<bool>) {}
+
+  template <std::size_t... Is>
+  static T Dot(T sum, const T* a, const T* b, absl::index_sequence<Is...>) {
+    Ignore({(sum += a[Is] * b[Is], true)...});
+    return sum;
+  }
+
+  template <std::size_t... Is>
+  static void PlusEq(T* a, const T* b, absl::index_sequence<Is...>) {
+    Ignore({(a[Is] += b[Is], true)...});
+  }
+
+  template <std::size_t... Is>
+  static void MinusEq(T* a, const T* b, absl::index_sequence<Is...>) {
+    Ignore({(a[Is] -= b[Is], true)...});
+  }
+
+  template <std::size_t... Is>
+  static void MulEq(T* a, T b, absl::index_sequence<Is...>) {
+    Ignore({(a[Is] *= b, true)...});
+  }
+
+  template <std::size_t... Is>
+  static void DivEq(T* a, T b, absl::index_sequence<Is...>) {
+    Ignore({(a[Is] /= b, true)...});
+  }
+};
+
+// These templates must be defined outside of BasicVector so that the
+// template specialization match algorithm must deduce 'a'. See the review
+// of cl/119944115.
+template <typename K,
+          template <typename> class VT2, typename T2, std::size_t N2>
+VT2<T2> operator*(const K& k, const BasicVector<VT2, T2, N2>& a) {
+  return a.MulScalarInternal(k);
+}
+template <typename K,
+          template <typename> class VT2, typename T2, std::size_t N2>
+VT2<T2> operator/(const K& k, const BasicVector<VT2, T2, N2>& a) {
+  return a.DivScalarInternal(k);
+}
+
+}  // namespace internal_vector
+}  // namespace math
+}  // namespace util
+
+// ======================================================================
+template <typename T>
+class Vector2
+    : public util::math::internal_vector::BasicVector<Vector2, T, 2> {
+ private:
+  using Base = util::math::internal_vector::BasicVector<::Vector2, T, 2>;
+  using VType = T;
+
+ public:
+  typedef VType BaseType;
+  using FloatType = typename Base::FloatType;
+  using Base::SIZE;
+
+  Vector2() : c_() {}
+  Vector2(T x, T y) {
+    c_[0] = x;
+    c_[1] = y;
+  }
+  explicit Vector2(const Vector3<T> &b) : Vector2(b.x(), b.y()) {}
+  explicit Vector2(const Vector4<T> &b) : Vector2(b.x(), b.y()) {}
+
+  T* Data() { return c_; }
+  const T* Data() const { return c_; }
+
+  void x(T v) { c_[0] = v; }
+  void y(T v) { c_[1] = v; }
+  T x() const { return c_[0]; }
+  T y() const { return c_[1]; }
+
+  bool aequal(const Vector2 &vb, FloatType margin) const {
+    using std::fabs;
+    return (fabs(c_[0]-vb.c_[0]) < margin) && (fabs(c_[1]-vb.c_[1]) < margin);
+  }
+
+  void Set(T x, T y) { *this = Vector2(x, y); }
+
+  // Cross product.  Be aware that if T is an integer type, the high bits
+  // of the result are silently discarded.
+  T CrossProd(const Vector2 &vb) const {
+    return c_[0] * vb.c_[1] - c_[1] * vb.c_[0];
+  }
+
+  // Returns the angle between "this" and v in radians. If either vector is
+  // zero-length, or nearly zero-length, the result will be zero, regardless of
+  // the other value.
+  FloatType Angle(const Vector2 &v) const {
+    using std::atan2;
+    return atan2(CrossProd(v), this->DotProd(v));
+  }
+
+  // return a vector orthogonal to the current one
+  // with the same norm and counterclockwise to it
+  Vector2 Ortho() const { return Vector2(-c_[1], c_[0]); }
+
+  // TODO(user): unify Fabs/Abs between all Vector classes.
+  Vector2 Fabs() const {
+    using std::fabs;
+    return Vector2(fabs(c_[0]), fabs(c_[1]));
+  }
+  Vector2 Abs() const {
+    static_assert(std::is_integral<VType>::value, "use Fabs for float_types");
+    static_assert(static_cast<VType>(-1) == -1, "type must be signed");
+    static_assert(sizeof(c_[0]) <= sizeof(int), "Abs truncates to int");
+    return Vector2(abs(c_[0]), abs(c_[1]));
+  }
+
+ private:
+  VType c_[SIZE];
+};
+
+template <typename T>
+class Vector3
+    : public util::math::internal_vector::BasicVector<Vector3, T, 3> {
+ private:
+  using Base = util::math::internal_vector::BasicVector<::Vector3, T, 3>;
+  using VType = T;
+
+ public:
+  typedef VType BaseType;
+  using FloatType = typename Base::FloatType;
+  using Base::SIZE;
+
+  Vector3() : c_() {}
+  Vector3(T x, T y, T z) {
+    c_[0] = x;
+    c_[1] = y;
+    c_[2] = z;
+  }
+  Vector3(const Vector2<T> &b, T z) : Vector3(b.x(), b.y(), z) {}
+  explicit Vector3(const Vector4<T> &b) : Vector3(b.x(), b.y(), b.z()) {}
+
+  T* Data() { return c_; }
+  const T* Data() const { return c_; }
+
+  void x(const T &v) { c_[0] = v; }
+  void y(const T &v) { c_[1] = v; }
+  void z(const T &v) { c_[2] = v; }
+  T x() const { return c_[0]; }
+  T y() const { return c_[1]; }
+  T z() const { return c_[2]; }
+
+  bool aequal(const Vector3 &vb, FloatType margin) const {
+    using std::abs;
+    return (abs(c_[0] - vb.c_[0]) < margin)
+        && (abs(c_[1] - vb.c_[1]) < margin)
+        && (abs(c_[2] - vb.c_[2]) < margin);
+  }
+
+  void Set(T x, T y, T z) { *this = Vector3(x, y, z); }
+
+  // Cross product.  Be aware that if VType is an integer type, the high bits
+  // of the result are silently discarded.
+  Vector3 CrossProd(const Vector3& vb) const {
+    return Vector3(c_[1] * vb.c_[2] - c_[2] * vb.c_[1],
+                   c_[2] * vb.c_[0] - c_[0] * vb.c_[2],
+                   c_[0] * vb.c_[1] - c_[1] * vb.c_[0]);
+  }
+
+  // Returns a unit vector orthogonal to this one.
+  Vector3 Ortho() const {
+    int k = LargestAbsComponent() - 1;
+    if (k < 0) k = 2;
+    Vector3 temp;
+    temp[k] = T(1);
+    return CrossProd(temp).Normalize();
+  }
+
+  // Returns the angle between two vectors in radians. If either vector is
+  // zero-length, or nearly zero-length, the result will be zero, regardless of
+  // the other value.
+  FloatType Angle(const Vector3 &va) const {
+    using std::atan2;
+    return atan2(CrossProd(va).Norm(), this->DotProd(va));
+  }
+
+  Vector3 Fabs() const {
+    return Abs();
+  }
+
+  Vector3 Abs() const {
+    static_assert(
+        !std::is_integral<VType>::value || static_cast<VType>(-1) == -1,
+        "type must be signed");
+    using std::abs;
+    return Vector3(abs(c_[0]), abs(c_[1]), abs(c_[2]));
+  }
+
+  // return the index of the largest component (fabs)
+  int LargestAbsComponent() const {
+    Vector3 temp = Abs();
+    return temp[0] > temp[1] ?
+             temp[0] > temp[2] ? 0 : 2 :
+             temp[1] > temp[2] ? 1 : 2;
+  }
+
+  // return the index of the smallest, median ,largest component of the vector
+  Vector3<int> ComponentOrder() const {
+    using std::swap;
+    Vector3<int> temp(0, 1, 2);
+    if (c_[temp[0]] > c_[temp[1]]) swap(temp[0], temp[1]);
+    if (c_[temp[1]] > c_[temp[2]]) swap(temp[1], temp[2]);
+    if (c_[temp[0]] > c_[temp[1]]) swap(temp[0], temp[1]);
+    return temp;
+  }
+
+ private:
+  VType c_[SIZE];
+};
+
+template <typename T>
+class Vector4
+    : public util::math::internal_vector::BasicVector<Vector4, T, 4> {
+ private:
+  using Base = util::math::internal_vector::BasicVector<::Vector4, T, 4>;
+  using VType = T;
+
+ public:
+  typedef VType BaseType;
+  using FloatType = typename Base::FloatType;
+  using Base::SIZE;
+
+  Vector4() : c_() {}
+  Vector4(T x, T y, T z, T w) {
+    c_[0] = x;
+    c_[1] = y;
+    c_[2] = z;
+    c_[3] = w;
+  }
+
+  Vector4(const Vector2<T> &b, T z, T w)
+      : Vector4(b.x(), b.y(), z, w) {}
+  Vector4(const Vector2<T> &a, const Vector2<T> &b)
+      : Vector4(a.x(), a.y(), b.x(), b.y()) {}
+  Vector4(const Vector3<T> &b, T w)
+      : Vector4(b.x(), b.y(), b.z(), w) {}
+
+  T* Data() { return c_; }
+  const T* Data() const { return c_; }
+
+  bool aequal(const Vector4 &vb, FloatType margin) const {
+    using std::fabs;
+    return (fabs(c_[0] - vb.c_[0]) < margin)
+        && (fabs(c_[1] - vb.c_[1]) < margin)
+        && (fabs(c_[2] - vb.c_[2]) < margin)
+        && (fabs(c_[3] - vb.c_[3]) < margin);
+  }
+
+  void x(const T &v) { c_[0] = v; }
+  void y(const T &v) { c_[1] = v; }
+  void z(const T &v) { c_[2] = v; }
+  void w(const T &v) { c_[3] = v; }
+  T x() const { return c_[0]; }
+  T y() const { return c_[1]; }
+  T z() const { return c_[2]; }
+  T w() const { return c_[3]; }
+
+  void Set(T x, T y, T z, T w) { *this = Vector4(x, y, z, w); }
+
+  Vector4 Fabs() const {
+    using std::fabs;
+    return Vector4(fabs(c_[0]), fabs(c_[1]), fabs(c_[2]), fabs(c_[3]));
+  }
+
+  Vector4 Abs() const {
+    static_assert(std::is_integral<VType>::value, "use Fabs for float types");
+    static_assert(static_cast<VType>(-1) == -1, "type must be signed");
+    static_assert(sizeof(c_[0]) <= sizeof(int), "Abs truncates to int");
+    return Vector4(abs(c_[0]), abs(c_[1]), abs(c_[2]), abs(c_[3]));
+  }
+
+ private:
+  VType c_[SIZE];
+};
+
+typedef Vector2<uint8>  Vector2_b;
+typedef Vector2<int16>  Vector2_s;
+typedef Vector2<int>    Vector2_i;
+typedef Vector2<float>  Vector2_f;
+typedef Vector2<double> Vector2_d;
+
+typedef Vector3<uint8>  Vector3_b;
+typedef Vector3<int16>  Vector3_s;
+typedef Vector3<int>    Vector3_i;
+typedef Vector3<float>  Vector3_f;
+typedef Vector3<double> Vector3_d;
+
+typedef Vector4<uint8>  Vector4_b;
+typedef Vector4<int16>  Vector4_s;
+typedef Vector4<int>    Vector4_i;
+typedef Vector4<float>  Vector4_f;
+typedef Vector4<double> Vector4_d;
+
+
+#endif  // S2_UTIL_MATH_VECTOR_H_
diff --git a/src/s2/util/math/vector3_hash.h b/src/s2/util/math/vector3_hash.h
new file mode 100644 (file)
index 0000000..0c212a7
--- /dev/null
@@ -0,0 +1,54 @@
+// Copyright Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#ifndef S2_UTIL_MATH_VECTOR3_HASH_H_
+#define S2_UTIL_MATH_VECTOR3_HASH_H_
+
+#include <cstddef>
+#include <functional>
+#include <type_traits>
+
+#include "s2/util/hash/mix.h"
+#include "s2/util/math/vector.h"
+
+template <class T>
+struct GoodFastHash;
+
+template <class VType>
+struct GoodFastHash<Vector2<VType>> {
+  std::size_t operator()(const Vector2<VType>& v) const {
+    static_assert(std::is_pod<VType>::value, "POD expected");
+    // std::hash collapses +/-0.
+    std::hash<VType> h;
+    HashMix mix(h(v.x()));
+    mix.Mix(h(v.y()));
+    return mix.get();
+  }
+};
+
+template <class VType>
+struct GoodFastHash<Vector3<VType>> {
+  std::size_t operator()(const Vector3<VType>& v) const {
+    static_assert(std::is_pod<VType>::value, "POD expected");
+    // std::hash collapses +/-0.
+    std::hash<VType> h;
+    HashMix mix(h(v.x()));
+    mix.Mix(h(v.y()));
+    mix.Mix(h(v.z()));
+    return mix.get();
+  }
+};
+
+#endif  // S2_UTIL_MATH_VECTOR3_HASH_H_
diff --git a/src/s2/util/units/length-units.cc b/src/s2/util/units/length-units.cc
new file mode 100644 (file)
index 0000000..c8958aa
--- /dev/null
@@ -0,0 +1,21 @@
+// Copyright 2004 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+
+// Provide definitions for length unit constants
+
+#include "s2/util/units/length-units.h"
+
+const char * const util::units::LengthBase::output_suffix = "m";
diff --git a/src/s2/util/units/length-units.h b/src/s2/util/units/length-units.h
new file mode 100644 (file)
index 0000000..00dc6b1
--- /dev/null
@@ -0,0 +1,135 @@
+// Copyright 2003 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+
+// Define common length units.  New length units can be added as needed
+// provided there is a direct, multiplicative scaling to meters.
+//
+// When adding new units, you should add an appropriate GetMyUnit accessor
+// template and (optionally) define a shorthand typedef specialization for
+// float.  Also update the physical units unittest to check the conversion
+// ratio.
+
+#ifndef S2_UTIL_UNITS_LENGTH_UNITS_H_
+#define S2_UTIL_UNITS_LENGTH_UNITS_H_
+
+#include "s2/util/units/physical-units.h"
+
+namespace util {
+
+namespace units {
+
+struct LengthBase {
+  // the base unit type is meters
+  static const char* const output_suffix;
+
+  template <typename ValueType, class Unit>
+  static ValueType GetInBaseUnit(
+      const PhysicalUnit<ValueType, LengthBase, Unit> u) {
+    return GetMeters(u);
+  }
+};
+
+template <typename Float>
+class Length {
+  typedef UnitConversion<1, 1> MetersConversion;
+  typedef UnitConversion<1, 1000> KilometersConversion;
+  typedef UnitConversion<10000, 254> InchesConversion;
+  typedef UnitConversion<10000, 3048> FeetConversion;
+  typedef UnitConversion<1000, 1609344> MilesConversion;
+  typedef UnitConversion<1000, 1> MillimetersConversion;
+  typedef UnitConversion<1, 1852> NauticalMilesConversion;
+  typedef UnitConversion<10000, 9144> YardsConversion;
+
+ public:
+  typedef PhysicalUnit<Float, LengthBase, MetersConversion> Meters;
+  typedef PhysicalUnit<Float, LengthBase, KilometersConversion> Kilometers;
+  typedef PhysicalUnit<Float, LengthBase, InchesConversion> Inches;
+  typedef PhysicalUnit<Float, LengthBase, FeetConversion> Feet;
+  typedef PhysicalUnit<Float, LengthBase, MilesConversion> Miles;
+  typedef PhysicalUnit<Float, LengthBase, MillimetersConversion> Millimeters;
+  typedef PhysicalUnit<Float, LengthBase, NauticalMilesConversion>
+      NauticalMiles;
+  typedef PhysicalUnit<Float, LengthBase, YardsConversion> Yards;
+};
+
+// Define some shorthand, standard typenames.  The standard length
+// type is chosen to be float.  If you need greater precision for
+// a specific application, either use the fully qualified typename
+// Length<double>::* or declare local typedefs.  This would be an
+// ideal place for a template typedef, if only C++ supported them.
+// Note that units with different floating-point types do not
+// support implicit conversion (use the precision_cast<...> method).
+typedef Length<float>::Meters Meters;
+typedef Length<float>::Kilometers Kilometers;
+typedef Length<float>::Inches Inches;
+typedef Length<float>::Feet Feet;
+typedef Length<float>::Miles Miles;
+typedef Length<float>::Millimeters Millimeters;
+typedef Length<float>::NauticalMiles NauticalMiles;
+typedef Length<float>::Yards Yards;
+
+// Explicit unit accessors.  In general these are safer than using
+// the value() accessor, particularly in cases where the unit type
+// may not be immediately obvious (such as function returns).
+
+template <typename ValueType, class Unit>
+inline ValueType GetMeters(const PhysicalUnit<ValueType, LengthBase, Unit> u) {
+  return typename Length<ValueType>::Meters(u).value();
+}
+
+template <typename ValueType, class Unit>
+inline ValueType GetKilometers(
+    const PhysicalUnit<ValueType, LengthBase, Unit> u) {
+  return typename Length<ValueType>::Kilometers(u).value();
+}
+
+template <typename ValueType, class Unit>
+inline ValueType GetInches(const PhysicalUnit<ValueType, LengthBase, Unit> u) {
+  return typename Length<ValueType>::Inches(u).value();
+}
+
+template <typename ValueType, class Unit>
+inline ValueType GetFeet(const PhysicalUnit<ValueType, LengthBase, Unit> u) {
+  return typename Length<ValueType>::Feet(u).value();
+}
+
+template <typename ValueType, class Unit>
+inline ValueType GetMiles(const PhysicalUnit<ValueType, LengthBase, Unit> u) {
+  return typename Length<ValueType>::Miles(u).value();
+}
+
+template <typename ValueType, class Unit>
+inline ValueType GetMillimeters(
+    const PhysicalUnit<ValueType, LengthBase, Unit> u) {
+  return typename Length<ValueType>::Millimeters(u).value();
+}
+
+template <typename ValueType, class Unit>
+inline ValueType GetNauticalMiles(
+    const PhysicalUnit<ValueType, LengthBase, Unit> u) {
+  return typename Length<ValueType>::NauticalMiles(u).value();
+}
+
+template <typename ValueType, class Unit>
+inline ValueType GetYards(const PhysicalUnit<ValueType, LengthBase, Unit> u) {
+  return typename Length<ValueType>::Yards(u).value();
+}
+
+}  // end namespace units
+
+}  // end namespace util
+
+#endif  // S2_UTIL_UNITS_LENGTH_UNITS_H_
diff --git a/src/s2/util/units/physical-units.h b/src/s2/util/units/physical-units.h
new file mode 100644 (file)
index 0000000..9d99ceb
--- /dev/null
@@ -0,0 +1,313 @@
+// Copyright 2003 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+
+// Basic physical unit classes.  These classes are not as fancy as
+// some general purpose physical unit libraries, but provide a
+// simple and efficient interface for unit tracking and conversion.
+// In particular, compound units cannot be automatically constructed
+// from or decomposed into simpler units (e.g. velocity = distance /
+// time), but can be defined explicitly as opaque types.
+//
+// These classes define overloaded operators and non-explicit single
+// argument ctors, which breaks the style guidelines, but an exception
+// has been allowed in this case.
+// - Douglas Greiman <dgreiman@google.com>
+//
+// Specific types of physical units are defined in other headers
+// (e.g. angle-units.h).  Each unit type can be specialized to either
+// float or double.  Non-floating-point types are disallowed, since
+// the implicit conversion logic generally fails for integer division.
+// Attempting to declare integer-based units results in a fairly
+// informative compiler error.
+//
+// All units share common functionality, as demonstrated in this
+// example:
+//
+//   #include "angle-units.h"
+//
+//   class Nomad {
+//     Radians latitude_;
+//     ...
+//     // With -O2 optimization, the use of Radians in this method is
+//     // completely equivalent to using float, but prevents unitless
+//     // angles from being passed.
+//     void SetLatitude(Radians angle) {
+//       S2_CHECK(angle.abs() < Degrees(90.0));
+//       latitude_ = angle;
+//       latitude_radius_ = EARTH_RADIUS * cos(angle.value());
+//     }
+//
+//     // This method contains an implicit unit conversion from degrees
+//     // to radians.  In practice it would make more sense to use
+//     // Radians as the argument type to avoid this extra work if
+//     // possible (see the two calls of this method below).
+//     void MoveNorth(Degrees angle) {
+//       SetLatitude(latitude_ + angle);
+//     }
+//   };
+//
+//   void do_tests(float degrees_to_move, float radians_to_move) {
+//     Nomad joe;
+//
+//     // The use of Degrees(30.0) to set the latitude in radians requires
+//     // no runtime conversion.
+//     joe.SetLatitude(Degrees(30.0));
+//
+//     // The Degrees(...) parameter will be converted to radians at
+//     // runtime prior to addition in Nomad::MoveNorth().
+//     joe.MoveNorth(Degrees(degrees_to_move));
+//
+//     // This is ok, but due to the poor choice of units for the MoveNorth
+//     // method's argument, incurs two pointless multiply operations to
+//     // convert from radians to degrees and back to radians.
+//     joe.MoveNorth(Radians(radians_to_move));
+//
+//     // Implicit conversions from unitless values generate errors at
+//     // compile time.
+//     // joe.MoveNorth(degrees_to_move); // compile ERROR!
+//   }
+//
+
+#ifndef S2_UTIL_UNITS_PHYSICAL_UNITS_H_
+#define S2_UTIL_UNITS_PHYSICAL_UNITS_H_
+
+#include <cmath>
+#include <iosfwd>
+#include <iostream>
+#include <string>
+#include <type_traits>
+
+#include "s2/base/integral_types.h"
+#include "absl/base/macros.h"
+
+namespace util {
+
+namespace units {
+
+// Static conversion scale and offset to convert from a standard base
+// unit to a specific unit.  The scale and offset is specified as a
+// rational number to allow static construction at compile time.
+template <int ScaleNumerator, int ScaleDenominator,
+          int OffsetNumerator = 0, int OffsetDenominator = 1>
+struct UnitConversion {
+  static const int SCALE_NUMERATOR = ScaleNumerator;
+  static const int SCALE_DENOMINATOR = ScaleDenominator;
+  static const int OFFSET_NUMERATOR = OffsetNumerator;
+  static const int OFFSET_DENOMINATOR = OffsetDenominator;
+};
+
+template <class FromUnit, class ToUnit, typename Float>
+struct UnitConverter {
+  // Linear unit conversion: A' = A * s + t, where
+  // - s is a static scale factor and
+  // - t is a static offset
+  // composed from two UnitConversion structs.
+  // Cast one multiplicand to 64 bit to ensure that the integer expression
+  // is computed in 64 bit. Otherwise Feet(Miles(x)) will overflow.
+  constexpr static inline Float Convert(Float value) {
+    // scaling and offset
+    return static_cast<Float>(
+      (static_cast<double>(value *
+         (static_cast<double>(static_cast<uint64>(ToUnit::SCALE_NUMERATOR) *
+                              FromUnit::SCALE_DENOMINATOR) /
+          static_cast<double>(static_cast<uint64>(ToUnit::SCALE_DENOMINATOR) *
+                              FromUnit::SCALE_NUMERATOR)))) -
+      (static_cast<double>(static_cast<uint64>(ToUnit::SCALE_NUMERATOR) *
+                           FromUnit::SCALE_DENOMINATOR *
+                           FromUnit::OFFSET_NUMERATOR) /
+       static_cast<double>(static_cast<uint64>(ToUnit::SCALE_DENOMINATOR) *
+                           FromUnit::SCALE_NUMERATOR *
+                           FromUnit::OFFSET_DENOMINATOR)) +
+      (static_cast<double>(ToUnit::OFFSET_NUMERATOR) /
+       static_cast<double>(ToUnit::OFFSET_DENOMINATOR)));
+  }
+};
+
+// Some unit operations are only defined for base units that have linear
+// transformations, as in T(a+b) = T(a) + T(b).   Temperatures units are
+// an example of units that do not have linear transformations.  By
+// default unit transformations are assumed to be linear; see
+// temperature-units.h for an example of how to override this default.
+template <class Base>
+struct is_linear_unit_transformation : std::true_type { };
+
+// Template class holding a single value with an associated physical
+// unit.  The unit and conversion parameters are statically defined
+// and optimized at compile time.  With optimization (-O2), use of a
+// single physical unit type is as efficient as using a native
+// floating point type.  Conversions between units are optimized to
+// (typically) a single multiplication operation.  Unit conversions
+// for constants are done at compile time and incur no runtime
+// overhead (again at -O2).
+//
+// Template parameters:
+//   Base is the base unit class, such as Angle or Length. If operator<<
+//   is used, it must have:
+//   - a public static field "output_suffix" and
+//   - a public static method Float Base::GetInBaseUnit(PhysicalUnit). An
+//     example can be found in length-units.h
+//     LengthBase::GetInBaseUnit.
+//   Unit is the UnitConversion class that defines a specific unit
+//   (such as degrees) in terms of a reference unit (such as radians).
+template <class Float, class Base, class Unit>
+class PhysicalUnit {
+ public:
+  typedef PhysicalUnit<Float, Base, Unit> Type;
+  typedef Float FloatType;
+
+  // Use 'explicit' to prevent unintentional construction from untyped (or
+  // mistyped) values.  Note that this also prevents arguably reasonable
+  // constructs such as Unit unit = 10.0; use either Unit unit(10.0) or
+  // Unit unit =  Unit(10.0) instead.
+  PhysicalUnit(): value_(static_cast<Float>(0.0)) {}
+  constexpr explicit PhysicalUnit(Float value): value_(value) {}
+
+  // Conversion from other units of the same Base type.
+  //
+  // Policy decision: not using 'explicit' allows much more natural
+  // conversions between units of a given base type.  This can result in
+  // unintended implicit type conversions, but these incur very little
+  // overhead (inlined multiply at -O2) and should be inconsequential in
+  // most circumstances.  Casts between different base types (including
+  // different underlying value types) require explicit handling. The ClangTidy
+  // warnings regarding this are therefore suppressed with NOLINT below.
+  template <class Unit2>
+  constexpr PhysicalUnit(PhysicalUnit<Float, Base, Unit2> other)  // NOLINT
+      : value_(UnitConverter<Unit2, Unit, Float>::Convert(other.value())) {}
+
+  // Copy operation from other units of the same Base type.
+  template <class Unit2>
+  Type operator = (PhysicalUnit<Float, Base, Unit2> other) {
+    value_ = UnitConverter<Unit2, Unit, Float>::Convert(other.value());
+    return *this;
+  }
+
+  // Value accessor.  Consider using an explicitly typed accessor whenever
+  // the unit type is not immediately obvious (such as function return
+  // values).  For example:
+  //   float x = myclass.GetAngle().value();           // what unit is x?
+  //   float x = GetDegrees(myclass.GetAngle());       // much clearer.
+  //   float x = Degrees(myclass.GetAngle()).value();  // ok too.
+  //   Degrees degrees = myclass.GetAngle();           // using a temporary is
+  //   float x = degrees.value();                      // also good.
+  constexpr Float value() const { return value_; }
+
+  // Trivial arithematic operator wrapping.
+  Type operator - () const {
+    return Type(-value_);
+  }
+  Type operator * (const Float scale) const {
+    return Type(value_ * scale);
+  }
+  Type operator + (const Type other) const {
+    static_assert(is_linear_unit_transformation<Base>::value,
+                  "operation not defined");
+    return Type(value_ + other.value());
+  }
+  Type operator - (const Type other) const {
+    static_assert(is_linear_unit_transformation<Base>::value,
+                  "operation not defined");
+    return Type(value_ - other.value());
+  }
+  Float operator / (const Type other) const {
+    return value_ / other.value();
+  }
+  Type operator *= (const Float scale) {
+    value_ *= scale;
+    return *this;
+  }
+  Type operator += (const Type other) {
+    static_assert(is_linear_unit_transformation<Base>::value,
+                  "operation not defined");
+    value_ += other.value();
+    return *this;
+  }
+  Type operator -= (const Type other) {
+    static_assert(is_linear_unit_transformation<Base>::value,
+                  "operation not defined");
+    value_ -= other.value();
+    return *this;
+  }
+
+  // Simple comparisons.  Overloaded equality is intentionally omitted;
+  // use equals() instead.
+  bool operator < (const Type other) const {
+    return value_ < other.value();
+  }
+  bool operator > (const Type other) const {
+    return value_ > other.value();
+  }
+  bool operator <= (const Type other) const {
+    return value_ <= other.value();
+  }
+  bool operator >= (const Type other) const {
+    return value_ >= other.value();
+  }
+
+  // Test equality to within some epsilon.  Always false for
+  // epsilon < 0.
+  bool equals(const Type other,
+              const Type epsilon) const {
+    Float delta = value_ - other.value_;
+    if (delta < static_cast<Float>(0.0)) {
+       return -delta <= epsilon.value_;
+    }
+    return delta <= epsilon.value_;
+  }
+
+  // A little more sugar.
+  Type abs() const {
+    return (value_ < static_cast<Float>(0.0)) ? -(*this) : *this;
+  }
+
+  // Explicit precision casting within a base unit class.
+  template <typename OtherFloat>
+  PhysicalUnit<OtherFloat, Base, Unit> precision_cast() const {
+    typedef PhysicalUnit<OtherFloat, Base, Unit> CastType;
+    return CastType(static_cast<OtherFloat>(value_));
+  }
+
+ private:
+  Float value_;
+  // Enforce Float to be a floating point type, since unit conversions will
+  // generally fail with integers.
+  static_assert(std::is_floating_point<Float>::value,
+                "Only_use_floating_point_types");
+};
+
+// Allow 2*u (in addition to u*2).
+template <typename Scale, typename Float, class Base, class Unit>
+inline PhysicalUnit<Float, Base, Unit> operator * (
+         const Scale scale,
+         const PhysicalUnit<Float, Base, Unit> value) {
+  return value * static_cast<Float>(scale);
+}
+
+// we'll print the current value and the value converted to the natural
+// base type
+template <typename Float, typename Base, typename Unit>
+std::ostream& operator<<(std::ostream& os,
+                         PhysicalUnit<Float, Base, Unit> value) {
+  return os << value.value()
+            << " (" << Base::GetInBaseUnit(value)
+            << Base::output_suffix << ")";
+}
+
+} // end namespace units
+
+} // end namespace util
+
+#endif  // S2_UTIL_UNITS_PHYSICAL_UNITS_H_
diff --git a/src/s2/value_lexicon.h b/src/s2/value_lexicon.h
new file mode 100644 (file)
index 0000000..668439a
--- /dev/null
@@ -0,0 +1,234 @@
+// Copyright 2016 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS-IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// Author: ericv@google.com (Eric Veach)
+
+#ifndef S2_VALUE_LEXICON_H_
+#define S2_VALUE_LEXICON_H_
+
+#include <functional>
+#include <limits>
+#include <vector>
+
+#include "s2/base/integral_types.h"
+#include "s2/util/gtl/dense_hash_set.h"
+
+// ValueLexicon is a class that maps distinct values to sequentially numbered
+// integer identifiers.  It automatically eliminates duplicates and uses a
+// compact representation.  See also SequenceLexicon.
+//
+// Each distinct value is mapped to a 32-bit integer.  The space used for each
+// value is approximately 7 bytes plus the space needed for the value itself.
+// For example, int64 values would need approximately 15 bytes each.  Note
+// also that values are referred to using 32-bit ids rather than 64-bit
+// pointers.
+//
+// This class has the same thread-safety properties as "string": const methods
+// are thread safe, and non-const methods are not thread safe.
+//
+// Example usage:
+//
+//   ValueLexicon<string> lexicon;
+//   uint32 cat_id = lexicon.Add("cat");
+//   EXPECT_EQ(cat_id, lexicon.Add("cat"));
+//   EXPECT_EQ("cat", lexicon.value(cat_id));
+//
+template <class T,
+          class Hasher = std::hash<T>,
+          class KeyEqual = std::equal_to<T>>
+class ValueLexicon {
+ public:
+  explicit ValueLexicon(const Hasher& hasher = Hasher(),
+                        const KeyEqual& key_equal = KeyEqual());
+
+  // ValueLexicon is movable and copyable.
+  ValueLexicon(const ValueLexicon&);
+  ValueLexicon& operator=(const ValueLexicon&);
+  ValueLexicon(ValueLexicon&&);
+  ValueLexicon& operator=(ValueLexicon&&);
+
+  // Clears all data from the lexicon.
+  void Clear();
+
+  // Add the given value to the lexicon if it is not already present, and
+  // return its integer id.  Ids are assigned sequentially starting from zero.
+  uint32 Add(const T& value);
+
+  // Return the number of values in the lexicon.
+  uint32 size() const;
+
+  // Return the value with the given id.
+  const T& value(uint32 id) const;
+
+ private:
+  friend class IdKeyEqual;
+  // Choose kEmptyKey to be the last key that will ever be generated.
+  static const uint32 kEmptyKey = std::numeric_limits<uint32>::max();
+
+  class IdHasher {
+   public:
+    IdHasher(const Hasher& hasher, const ValueLexicon* lexicon);
+    const Hasher& hasher() const;
+    size_t operator()(uint32 id) const;
+   private:
+    Hasher hasher_;
+    const ValueLexicon* lexicon_;
+  };
+
+  class IdKeyEqual {
+   public:
+    IdKeyEqual(const KeyEqual& key_equal, const ValueLexicon* lexicon);
+    bool operator()(uint32 id1, uint32 id2) const;
+   private:
+    KeyEqual key_equal_;
+    const ValueLexicon* lexicon_;
+  };
+
+  using IdSet = gtl::dense_hash_set<uint32, IdHasher, IdKeyEqual>;
+
+  KeyEqual key_equal_;
+  std::vector<T> values_;
+  IdSet id_set_;
+};
+
+
+//////////////////   Implementation details follow   ////////////////////
+
+
+template <class T, class Hasher, class KeyEqual>
+const uint32 ValueLexicon<T, Hasher, KeyEqual>::kEmptyKey;
+
+template <class T, class Hasher, class KeyEqual>
+ValueLexicon<T, Hasher, KeyEqual>::IdHasher::IdHasher(
+    const Hasher& hasher, const ValueLexicon* lexicon)
+    : hasher_(hasher), lexicon_(lexicon) {
+}
+
+template <class T, class Hasher, class KeyEqual>
+const Hasher& ValueLexicon<T, Hasher, KeyEqual>::IdHasher::hasher() const {
+  return hasher_;
+}
+
+template <class T, class Hasher, class KeyEqual>
+inline size_t ValueLexicon<T, Hasher, KeyEqual>::IdHasher::operator()(
+    uint32 id) const {
+  return hasher_(lexicon_->value(id));
+}
+
+template <class T, class Hasher, class KeyEqual>
+ValueLexicon<T, Hasher, KeyEqual>::IdKeyEqual::IdKeyEqual(
+    const KeyEqual& key_equal, const ValueLexicon* lexicon)
+    : key_equal_(key_equal), lexicon_(lexicon) {
+}
+
+template <class T, class Hasher, class KeyEqual>
+inline bool ValueLexicon<T, Hasher, KeyEqual>::IdKeyEqual::operator()(
+    uint32 id1, uint32 id2) const {
+  if (id1 == id2) return true;
+  if (id1 == lexicon_->kEmptyKey || id2 == lexicon_->kEmptyKey) {
+    return false;
+  }
+  return key_equal_(lexicon_->value(id1), lexicon_->value(id2));
+}
+
+template <class T, class Hasher, class KeyEqual>
+ValueLexicon<T, Hasher, KeyEqual>::ValueLexicon(const Hasher& hasher,
+                                                const KeyEqual& key_equal)
+    : key_equal_(key_equal),
+      id_set_(0, IdHasher(hasher, this),
+                 IdKeyEqual(key_equal, this)) {
+  id_set_.set_empty_key(kEmptyKey);
+}
+
+template <class T, class Hasher, class KeyEqual>
+ValueLexicon<T, Hasher, KeyEqual>::ValueLexicon(const ValueLexicon& x)
+    : key_equal_(x.key_equal_), values_(x.values_),
+      // Unfortunately we can't copy "id_set_" because we need to change the
+      // "this" pointers associated with hasher() and key_equal().
+      id_set_(x.id_set_.begin(), x.id_set_.end(), kEmptyKey, 0,
+              IdHasher(x.id_set_.hash_funct().hasher(), this),
+              IdKeyEqual(x.key_equal_, this)) {
+}
+
+template <class T, class Hasher, class KeyEqual>
+ValueLexicon<T, Hasher, KeyEqual>::ValueLexicon(ValueLexicon&& x)
+    : key_equal_(std::move(x.key_equal_)), values_(std::move(x.values_)),
+      // Unfortunately we can't move "id_set_" because we need to change the
+      // "this" pointers associated with hasher() and key_equal().
+      id_set_(x.id_set_.begin(), x.id_set_.end(), kEmptyKey, 0,
+              IdHasher(x.id_set_.hash_funct().hasher(), this),
+              IdKeyEqual(x.key_equal_, this)) {
+}
+
+template <class T, class Hasher, class KeyEqual>
+ValueLexicon<T, Hasher, KeyEqual>&
+ValueLexicon<T, Hasher, KeyEqual>::operator=(const ValueLexicon& x) {
+  // Note that self-assignment is handled correctly by this code.
+  key_equal_ = x.key_equal_;
+  values_ = x.values_;
+  // Unfortunately we can't copy-assign "id_set_" because we need to change
+  // the "this" pointers associated with hasher() and key_equal().
+  id_set_ = IdSet(x.id_set_.begin(), x.id_set_.end(), kEmptyKey, 0,
+                  IdHasher(x.id_set_.hash_funct().hasher(), this),
+                  IdKeyEqual(x.key_equal_, this));
+  return *this;
+}
+
+template <class T, class Hasher, class KeyEqual>
+ValueLexicon<T, Hasher, KeyEqual>&
+ValueLexicon<T, Hasher, KeyEqual>::operator=(ValueLexicon&& x) {
+  // Note that move self-assignment has undefined behavior.
+  key_equal_ = std::move(x.key_equal_);
+  values_ = std::move(x.values_);
+  // Unfortunately we can't move-assign "id_set_" because we need to change
+  // the "this" pointers associated with hasher() and key_equal().
+  id_set_ = IdSet(x.id_set_.begin(), x.id_set_.end(), kEmptyKey, 0,
+                  IdHasher(x.id_set_.hash_funct().hasher(), this),
+                  IdKeyEqual(x.key_equal_, this));
+  return *this;
+}
+
+template <class T, class Hasher, class KeyEqual>
+void ValueLexicon<T, Hasher, KeyEqual>::Clear() {
+  values_.clear();
+  id_set_.clear();
+}
+
+template <class T, class Hasher, class KeyEqual>
+uint32 ValueLexicon<T, Hasher, KeyEqual>::Add(const T& value) {
+  if (!values_.empty() && key_equal_(value, values_.back())) {
+    return values_.size() - 1;
+  }
+  values_.push_back(value);
+  auto result = id_set_.insert(values_.size() - 1);
+  if (result.second) {
+    return values_.size() - 1;
+  } else {
+    values_.pop_back();
+    return *result.first;
+  }
+}
+
+template <class T, class Hasher, class KeyEqual>
+inline uint32 ValueLexicon<T, Hasher, KeyEqual>::size() const {
+  return values_.size();
+}
+
+template <class T, class Hasher, class KeyEqual>
+inline const T& ValueLexicon<T, Hasher, KeyEqual>::value(uint32 id) const {
+  return values_[id];
+}
+
+#endif  // S2_VALUE_LEXICON_H_
diff --git a/src/tests/soname.h b/src/tests/soname.h
new file mode 100644 (file)
index 0000000..c6ccdd5
--- /dev/null
@@ -0,0 +1,9 @@
+#include "openssl/opensslv.h"
+
+#define XSTR(x) STR(x)
+#define STR(x) #x
+#ifdef SHLIB_VERSION_NUMBER
+echo XSTR(SHLIB_VERSION_NUMBER)
+#else
+echo XSTR(OPENSSL_SHLIB_VERSION)
+#endif
diff --git a/src/wk-c-utils.c b/src/wk-c-utils.c
new file mode 100644 (file)
index 0000000..4c24ca5
--- /dev/null
@@ -0,0 +1,371 @@
+
+#define R_NO_REMAP
+#include <R.h>
+#include <Rinternals.h>
+#include "wk-v1.h"
+
+typedef struct s2_projection_t s2_projection_t;
+typedef struct s2_tessellator_t s2_tessellator_t;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+s2_projection_t* s2_projection_create_plate_carree(double scale);
+s2_projection_t* s2_projection_create_mercator(double max_x);
+void s2_projection_destroy(s2_projection_t* projection);
+int s2_projection_project(s2_projection_t* projection, const double* coord_in, double* coord_out);
+int s2_projection_unproject(s2_projection_t* projection, const double* coord_in, double* coord_out);
+
+s2_tessellator_t* s2_tessellator_create(s2_projection_t* projection, double tolerance_radians);
+void s2_tessellator_destroy(s2_tessellator_t* tessellator);
+int s2_tessellator_reset(s2_tessellator_t* tessellator);
+int s2_tessellator_add_r2_point(s2_tessellator_t* tessellator, const double* coord);
+int s2_tessellator_add_s2_point(s2_tessellator_t* tessellator, const double* coord);
+int s2_tessellator_r2_points_size(s2_tessellator_t* tessellator);
+int s2_tessellator_s2_points_size(s2_tessellator_t* tessellator);
+int s2_tessellator_r2_point(s2_tessellator_t* tessellator, int i, double* coord);
+int s2_tessellator_s2_point(s2_tessellator_t* tessellator, int i, double* coord);
+
+#ifdef __cplusplus
+}
+#endif
+
+// Expose projections as external pointers so that they can theoretically be generated
+// by other packages.
+void s2_projection_xptr_destroy(SEXP projection_xptr) {
+  s2_projection_destroy((s2_projection_t*) R_ExternalPtrAddr(projection_xptr));
+}
+
+SEXP c_s2_projection_plate_carree() {
+  SEXP projection_xptr = PROTECT(R_MakeExternalPtr(s2_projection_create_plate_carree(180), R_NilValue, R_NilValue));
+  R_RegisterCFinalizer(projection_xptr, &s2_projection_xptr_destroy);
+  UNPROTECT(1);
+  return projection_xptr;
+}
+
+SEXP c_s2_projection_mercator() {
+  SEXP projection_xptr = PROTECT(R_MakeExternalPtr(s2_projection_create_mercator(20037508), R_NilValue, R_NilValue));
+  R_RegisterCFinalizer(projection_xptr, &s2_projection_xptr_destroy);
+  UNPROTECT(1);
+  return projection_xptr;
+}
+
+// The s2_coord_filter at the C level is used both for projecting (i.e.,
+// simple mapping of points from x, y to an x, y, z on the unit sphere)
+// and tessellating (i.e., projecting AND adding additional points to
+// ensure that "straight" lines in the current projection refer to the same
+// line on the surface of the earth when unprojected on to the unit
+// sphere. Going the other direction, points are added to ensure that
+// great circle edges (S2's assumption) refer to the same line on the
+// surface of the earth when exported to the specified projection.
+// This is similar to D3's "adaptive resampling" which also handles
+// segmentizing and projecting as a single operation.
+typedef struct {
+  s2_projection_t* projection;
+  s2_tessellator_t* tessellator;
+  wk_handler_t* next;
+  wk_meta_t meta_copy;
+  wk_vector_meta_t vector_meta_copy;
+  int unproject;
+  uint32_t coord_id;
+} coord_filter_t;
+
+static inline void modify_meta_for_filter(coord_filter_t* coord_filter, const wk_meta_t* meta) {
+  memcpy(&(coord_filter->meta_copy), meta, sizeof(wk_meta_t));
+
+  // if we're projecting we're going to end up with an XY point
+  // if we're unprojecting, we're going to get an XYZ point
+  if (coord_filter->unproject) {
+    coord_filter->meta_copy.flags |= WK_FLAG_HAS_Z;
+  } else {
+    coord_filter->meta_copy.flags &= ~WK_FLAG_HAS_Z;
+  }
+
+  // if we're tesselating a polyline, the 'size' should be set to unknown
+  if (meta->geometry_type == WK_LINESTRING) {
+    coord_filter->meta_copy.size = WK_SIZE_UNKNOWN;
+  }
+
+  // any srid that initially existed is definitely no longer valid
+  coord_filter->meta_copy.srid = WK_SRID_NONE;
+}
+
+void s2_coord_filter_initialize(int* dirty, void* handler_data) {
+  coord_filter_t* coord_filter = (coord_filter_t*) handler_data;
+  *dirty = 1;
+  coord_filter->next->initialize(&coord_filter->next->dirty, coord_filter->next->handler_data);
+}
+
+int s2_coord_filter_vector_start(const wk_vector_meta_t* meta, void* handler_data) {
+  coord_filter_t* coord_filter = (coord_filter_t*) handler_data;
+
+  // if we're projecting we're going to end up with an XY point
+  // if we're unprojecting, we're going to get an XYZ point
+  memcpy(&coord_filter->vector_meta_copy, meta, sizeof(wk_vector_meta_t));
+  if (coord_filter->unproject) {
+    coord_filter->vector_meta_copy.flags |= WK_FLAG_HAS_Z;
+  } else {
+    coord_filter->vector_meta_copy.flags &= ~WK_FLAG_HAS_Z;
+  }
+
+  return coord_filter->next->vector_start(&(coord_filter->vector_meta_copy), coord_filter->next->handler_data);
+}
+
+SEXP s2_coord_filter_vector_end(const wk_vector_meta_t* meta, void* handler_data) {
+  coord_filter_t* coord_filter = (coord_filter_t*) handler_data;
+  // use the modified vector meta from vector_start
+  return coord_filter->next->vector_end(&(coord_filter->vector_meta_copy), coord_filter->next->handler_data);
+}
+
+int s2_coord_filter_feature_start(const wk_vector_meta_t* meta, R_xlen_t feat_id, void* handler_data) {
+  coord_filter_t* coord_filter = (coord_filter_t*) handler_data;
+  return coord_filter->next->feature_start(&(coord_filter->vector_meta_copy), feat_id, coord_filter->next->handler_data);
+}
+
+int s2_coord_filter_feature_null(void* handler_data) {
+  coord_filter_t* coord_filter = (coord_filter_t*) handler_data;
+  return coord_filter->next->null_feature(coord_filter->next->handler_data);
+}
+
+int s2_coord_filter_feature_end(const wk_vector_meta_t* meta, R_xlen_t feat_id, void* handler_data) {
+  coord_filter_t* coord_filter = (coord_filter_t*) handler_data;
+  return coord_filter->next->feature_end(&(coord_filter->vector_meta_copy), feat_id, coord_filter->next->handler_data);
+}
+
+int s2_coord_filter_geometry_start(const wk_meta_t* meta, uint32_t part_id, void* handler_data) {
+  coord_filter_t* coord_filter = (coord_filter_t*) handler_data;
+  modify_meta_for_filter(coord_filter, meta);
+  if (coord_filter->tessellator) {
+    s2_tessellator_reset(coord_filter->tessellator);
+    coord_filter->coord_id = 0;
+  }
+  return coord_filter->next->geometry_start(&(coord_filter->meta_copy), part_id, coord_filter->next->handler_data);
+}
+
+int s2_coord_filter_geometry_end(const wk_meta_t* meta, uint32_t part_id, void* handler_data) {
+  coord_filter_t* coord_filter = (coord_filter_t*) handler_data;
+  modify_meta_for_filter(coord_filter, meta);
+  return coord_filter->next->geometry_end(&(coord_filter->meta_copy), part_id, coord_filter->next->handler_data);
+}
+
+int s2_coord_filter_ring_start(const wk_meta_t* meta, uint32_t size, uint32_t ring_id, void* handler_data) {
+  coord_filter_t* coord_filter = (coord_filter_t*) handler_data;
+  modify_meta_for_filter(coord_filter, meta);
+  if (coord_filter->tessellator) {
+    s2_tessellator_reset(coord_filter->tessellator);
+    coord_filter->coord_id = 0;
+  }
+  return coord_filter->next->ring_start(&(coord_filter->meta_copy), WK_SIZE_UNKNOWN, ring_id, coord_filter->next->handler_data);
+}
+
+int s2_coord_filter_ring_end(const wk_meta_t* meta, uint32_t size, uint32_t ring_id, void* handler_data) {
+  coord_filter_t* coord_filter = (coord_filter_t*) handler_data;
+  modify_meta_for_filter(coord_filter, meta);
+  return coord_filter->next->ring_end(&(coord_filter->meta_copy), WK_SIZE_UNKNOWN, ring_id, coord_filter->next->handler_data);
+}
+
+int s2_coord_filter_error(const char* message, void* handler_data) {
+  coord_filter_t* coord_filter = (coord_filter_t*) handler_data;
+  return coord_filter->next->error(message, coord_filter->next->handler_data);
+}
+
+void s2_coord_filter_deinitialize(void* handler_data) {
+  coord_filter_t* coord_filter = (coord_filter_t*) handler_data;
+  coord_filter->next->deinitialize(coord_filter->next->handler_data);
+}
+
+void s2_coord_filter_finalize(void* handler_data) {
+  coord_filter_t* coord_filter = (coord_filter_t*) handler_data;
+  if (coord_filter != NULL) {
+    s2_tessellator_destroy(coord_filter->tessellator);
+    // coord_filter->projection is managed using an external pointer
+    // coord_filter->next is managed using an external pointer
+    free(coord_filter);
+  }
+}
+
+// The main show for the coord filter! We define separate functions for the
+// projecting and unprojecting case as it's difficult to keep the code
+// clean otherwise.
+int s2_coord_filter_coord_unproject(const wk_meta_t* meta, const double* coord, uint32_t coord_id, void* handler_data) {
+  coord_filter_t* coord_filter = (coord_filter_t*) handler_data;
+  modify_meta_for_filter(coord_filter, meta);
+  double coord_out[4];
+
+  // if we're not tessellating, skip adding the edge to the tessellator
+  if ((coord_filter->tessellator == NULL) || (meta->geometry_type == WK_POINT)) {
+    s2_projection_unproject(coord_filter->projection, coord, coord_out);
+    return coord_filter->next->coord(
+      &(coord_filter->meta_copy),
+      coord_out, coord_id, coord_filter->next->handler_data
+    );
+  }
+
+  // Add this point to the tessellator
+  s2_tessellator_add_r2_point(coord_filter->tessellator, coord);
+
+  // If we have an edge in the tessellator, reguritate all the points
+  // except the first one to the next handler. If we have zero points,
+  // we send the it to the handler right away since we'll skip it when
+  // the next point arrives.
+  int size = s2_tessellator_s2_points_size(coord_filter->tessellator);
+  int result;
+
+  if (size < 2) {
+    s2_projection_unproject(coord_filter->projection, coord, coord_out);
+    result = coord_filter->next->coord(
+      &(coord_filter->meta_copy),
+      coord_out, coord_id, coord_filter->next->handler_data
+    );
+    coord_filter->coord_id++;
+
+    if (result != WK_CONTINUE) {
+      return result;
+    }
+  } else {
+    for (int i = 1; i < size; i++) {
+      s2_tessellator_s2_point(coord_filter->tessellator, i, coord_out);
+      result = coord_filter->next->coord(
+        &(coord_filter->meta_copy),
+        coord_out, coord_filter->coord_id, coord_filter->next->handler_data
+      );
+      coord_filter->coord_id++;
+
+      if (result != WK_CONTINUE) {
+        return result;
+      }
+    }
+
+    // Clear the tessellator and re-add this point to be ready for the next
+    // point that forms an edge
+    s2_tessellator_reset(coord_filter->tessellator);
+    s2_tessellator_add_r2_point(coord_filter->tessellator, coord);
+  }
+
+  return WK_CONTINUE;
+}
+
+int s2_coord_filter_coord_project(const wk_meta_t* meta, const double* coord, uint32_t coord_id, void* handler_data) {
+  coord_filter_t* coord_filter = (coord_filter_t*) handler_data;
+  modify_meta_for_filter(coord_filter, meta);
+  double coord_out[4];
+
+  if ((coord_filter->tessellator == NULL) || (meta->geometry_type == WK_POINT)) {
+    s2_projection_project(coord_filter->projection, coord, coord_out);
+    return coord_filter->next->coord(
+      &(coord_filter->meta_copy),
+      coord_out, coord_id, coord_filter->next->handler_data
+    );
+  }
+
+  s2_tessellator_add_s2_point(coord_filter->tessellator, coord);
+
+  int size = s2_tessellator_r2_points_size(coord_filter->tessellator);
+  int result;
+
+  if (size < 2) {
+    s2_projection_project(coord_filter->projection, coord, coord_out);
+    result = coord_filter->next->coord(
+      &(coord_filter->meta_copy),
+      coord_out, coord_id, coord_filter->next->handler_data
+    );
+    coord_filter->coord_id++;
+
+    if (result != WK_CONTINUE) {
+      return result;
+    }
+  } else {
+    for (int i = 1; i < size; i++) {
+      s2_tessellator_r2_point(coord_filter->tessellator, i, coord_out);
+      result = coord_filter->next->coord(
+        &(coord_filter->meta_copy),
+        coord_out, coord_filter->coord_id, coord_filter->next->handler_data
+      );
+      coord_filter->coord_id++;
+
+      if (result != WK_CONTINUE) {
+        return result;
+      }
+    }
+
+    // Clear the tessellator and re-add this point to be ready for the next
+    // point that forms an edge
+    s2_tessellator_reset(coord_filter->tessellator);
+    s2_tessellator_add_s2_point(coord_filter->tessellator, coord);
+  }
+
+  return WK_CONTINUE;
+}
+
+SEXP c_s2_coord_filter_new(SEXP handler_xptr, SEXP projection_xptr, SEXP unproject, SEXP tessellate_tol) {
+  if (TYPEOF(handler_xptr) != EXTPTRSXP) {
+    Rf_error("`handler` must be a wk_handler pointer");
+  }
+
+  if (TYPEOF(projection_xptr) != EXTPTRSXP) {
+    Rf_error("`projection` must be an external pointer");
+  }
+
+  if (!IS_SIMPLE_SCALAR(unproject, LGLSXP)) {
+    Rf_error("`unproject` must be TRUE or FALSE"); // # nocov
+  }
+
+  if (!IS_SIMPLE_SCALAR(tessellate_tol, REALSXP) || (REAL(tessellate_tol)[0] < 1e-9)) {
+    Rf_error("`tessellate` must be a double() greter than 1e-9");
+  }
+
+  wk_handler_t* handler = wk_handler_create();
+
+  handler->initialize = &s2_coord_filter_initialize;
+  handler->vector_start = &s2_coord_filter_vector_start;
+  handler->vector_end = &s2_coord_filter_vector_end;
+
+  handler->feature_start = &s2_coord_filter_feature_start;
+  handler->null_feature = &s2_coord_filter_feature_null;
+  handler->feature_end = &s2_coord_filter_feature_end;
+
+  handler->geometry_start = &s2_coord_filter_geometry_start;
+  handler->geometry_end = &s2_coord_filter_geometry_end;
+
+  handler->ring_start = &s2_coord_filter_ring_start;
+  handler->ring_end = &s2_coord_filter_ring_end;
+
+  handler->error = &s2_coord_filter_error;
+
+  handler->deinitialize = &s2_coord_filter_deinitialize;
+  handler->finalizer = &s2_coord_filter_finalize;
+
+  coord_filter_t* coord_filter = (coord_filter_t*) malloc(sizeof(coord_filter_t));
+  if (coord_filter == NULL) {
+    wk_handler_destroy(handler); // # nocov
+    Rf_error("Failed to alloc handler data"); // # nocov
+  }
+
+  coord_filter->projection = (s2_projection_t*) R_ExternalPtrAddr(projection_xptr);
+  if (REAL(tessellate_tol)[0] < R_PosInf) {
+    coord_filter->tessellator = s2_tessellator_create(coord_filter->projection, REAL(tessellate_tol)[0]);
+  } else {
+    coord_filter->tessellator = NULL;
+  }
+  
+  coord_filter->unproject = LOGICAL(unproject)[0];
+  if (coord_filter->unproject) {
+    handler->coord = &s2_coord_filter_coord_unproject;
+  } else {
+    handler->coord = &s2_coord_filter_coord_project;
+  }
+
+  coord_filter->next = R_ExternalPtrAddr(handler_xptr);
+
+  if (coord_filter->next->api_version != 1) {
+    Rf_error("Can't run a wk_handler with api_version '%d'", coord_filter->next->api_version); // # nocov
+  }
+
+  handler->handler_data = coord_filter;
+
+  // include the external pointers as a tag for this external pointer
+  // which guarnatees that they will not be garbage collected until
+  // this object is garbage collected
+  return wk_handler_create_xptr(handler, handler_xptr, projection_xptr);
+}
diff --git a/src/wk-geography.h b/src/wk-geography.h
new file mode 100644 (file)
index 0000000..1ca75ad
--- /dev/null
@@ -0,0 +1,168 @@
+
+#ifndef WK_GEOGRAPHY_H
+#define WK_GEOGRAPHY_H
+
+#include <vector>
+
+#include "wk/rcpp-io.hpp"
+#include "wk/reader.hpp"
+#include "wk/geometry-handler.hpp"
+
+#include "point-geography.h"
+#include "polyline-geography.h"
+#include "polygon-geography.h"
+#include "geography-collection.h"
+
+#include <Rcpp.h>
+#include "geography.h"
+
+#define CODE_HAS_BUILD_ERROR 3938829
+
+
+class WKGeographyWriter: public WKGeometryHandler {
+public:
+  Rcpp::List output;
+  R_xlen_t featureId;
+
+  Rcpp::IntegerVector problemId;
+  Rcpp::CharacterVector problems;
+
+  WKGeographyWriter(R_xlen_t size):
+    output(size),
+    builder(nullptr),
+    oriented(false),
+    check(true) {}
+
+  void setOriented(bool oriented) {
+    this->oriented = oriented;
+  }
+
+  void setCheck(bool check) {
+    this->check = check;
+  }
+
+  void nextFeatureStart(size_t featureId) {
+    this->builder = std::unique_ptr<GeographyBuilder>(nullptr);
+    this->featureId = featureId;
+  }
+
+  void nextNull(size_t featureId) {
+    this->output[featureId] = R_NilValue;
+  }
+
+  void nextGeometryStart(const WKGeometryMeta& meta, uint32_t partId) {
+    if (!this->builder) {
+      switch (meta.geometryType) {
+      case WKGeometryType::Point:
+      case WKGeometryType::MultiPoint:
+        this->builder = absl::make_unique<PointGeography::Builder>();
+        break;
+      case WKGeometryType::LineString:
+      case WKGeometryType::MultiLineString:
+        this->builder = absl::make_unique<PolylineGeography::Builder>();
+        break;
+      case WKGeometryType::Polygon:
+      case WKGeometryType::MultiPolygon:
+        this->builder = absl::make_unique<PolygonGeography::Builder>(
+          this->oriented,
+          this->check
+        );
+        break;
+      case WKGeometryType::GeometryCollection:
+        this->builder = absl::make_unique<GeographyCollection::Builder>(
+          this->oriented,
+          this->check
+        );
+        break;
+      default:
+        std::stringstream err;
+        err << "Unknown geometry type in geography builder: " << meta.geometryType;
+        this->addProblem(err.str());
+        throw WKParseException(CODE_HAS_BUILD_ERROR);
+      }
+    }
+
+    this->builder->nextGeometryStart(meta, partId);
+  }
+
+  void nextLinearRingStart(const WKGeometryMeta& meta, uint32_t size, uint32_t ringId) {
+    this->builder->nextLinearRingStart(meta, size, ringId);
+  }
+
+  void nextCoordinate(const WKGeometryMeta& meta, const WKCoord& coord, uint32_t coordId) {
+    this->builder->nextCoordinate(meta, coord, coordId);
+  }
+
+  void nextLinearRingEnd(const WKGeometryMeta& meta, uint32_t size, uint32_t ringId) {
+    try {
+      this->builder->nextLinearRingEnd(meta, size, ringId);
+    } catch (WKParseException& e) {
+      this->addProblem(e.what());
+      throw WKParseException(CODE_HAS_BUILD_ERROR);
+    }
+  }
+
+  void nextGeometryEnd(const WKGeometryMeta& meta, uint32_t partId) {
+    this->builder->nextGeometryEnd(meta, partId);
+  }
+
+  void nextFeatureEnd(size_t featureId) {
+    if (this->builder) {
+      try {
+        std::unique_ptr<Geography> feature = builder->build();
+        this->output[featureId] = Rcpp::XPtr<Geography>(feature.release());
+      } catch (WKParseException& e) {
+        this->addProblem(e.what());
+        throw WKParseException(CODE_HAS_BUILD_ERROR);
+      }
+    }
+  }
+
+  bool nextError(WKParseException& error, size_t featureId) {
+    if (error.code() == CODE_HAS_BUILD_ERROR) {
+      this->output[featureId] = R_NilValue;
+      return true;
+    } else {
+      return false;
+    }
+
+    this->nextFeatureEnd(featureId);
+    return true;
+  }
+
+private:
+  std::unique_ptr<GeographyBuilder> builder;
+  bool oriented;
+  bool check;
+
+  void addProblem(std::string what) {
+    problemId.push_back(this->featureId);
+    problems.push_back(what);
+  }
+};
+
+
+class WKGeographyReader: public WKReader {
+public:
+
+  WKGeographyReader(WKRcppSEXPProvider& provider):
+  WKReader(provider), provider(provider) {}
+
+  void readFeature(size_t featureId) {
+    this->handler->nextFeatureStart(featureId);
+
+    if (this->provider.featureIsNull()) {
+      this->handler->nextNull(featureId);
+    } else {
+      Rcpp::XPtr<Geography> geography(this->provider.feature());
+      geography->Export(handler, WKReader::PART_ID_NONE);
+    }
+
+    this->handler->nextFeatureEnd(featureId);
+  }
+
+private:
+  WKRcppSEXPProvider& provider;
+};
+
+#endif
diff --git a/src/wk-impl.c b/src/wk-impl.c
new file mode 100644 (file)
index 0000000..936224b
--- /dev/null
@@ -0,0 +1,2 @@
+
+#include "wk-v1-impl.c"
diff --git a/tests/area.R b/tests/area.R
new file mode 100644 (file)
index 0000000..86c37d9
--- /dev/null
@@ -0,0 +1,23 @@
+library(s2)
+
+u = s2_union(
+   "POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0))",
+   "POLYGON ((5 5, 15 5, 15 15, 5 15, 5 5))",
+   s2_options(snap = s2_snap_level(30))
+)
+s2_area(u, radius = 1)
+s2_area("POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0))", radius = 1) +
+s2_area("POLYGON ((5 5, 15 5, 15 15, 5 15, 5 5))", radius = 1) -
+s2_area("POLYGON ((5 5, 10 5, 10 15, 5 10, 5 5))", radius = 1)
+s2_area("POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0))", radius = 1)
+s2_area("POLYGON ((5 5, 15 5, 15 15, 5 15, 5 5))", radius = 1)
+s2_area("POLYGON ((5 5, 10 5, 10 15, 5 10, 5 5))", radius = 1)
+
+df = s2_difference(
+   "POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0))",
+   "POLYGON ((5 5, 15 5, 15 15, 5 15, 5 5))",
+   s2_options(snap = s2_snap_level(30))
+)
+s2_area(df, radius = 1) -
+  (s2_area("POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0))", radius = 1) -
+    s2_area("POLYGON ((5 5, 10 5, 10 15, 5 10, 5 5))", radius = 1))
diff --git a/tests/area.Rout b/tests/area.Rout
new file mode 100644 (file)
index 0000000..b658ee9
--- /dev/null
@@ -0,0 +1,29 @@
+> library(s2)
+> s2_set_snaplevel(30) # for windows i386
+[1] -1
+> u = s2_union(
++    "POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0))",
++    "POLYGON ((5 5, 15 5, 15 15, 5 15, 5 5))"
++ )
+> s2_area(u, radius = 1)
+[1] 0.05284581
+> s2_area("POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0))", radius = 1) +
++ s2_area("POLYGON ((5 5, 15 5, 15 15, 5 15, 5 5))", radius = 1) -
++ s2_area("POLYGON ((5 5, 10 5, 10 15, 5 10, 5 5))", radius = 1)
+[1] 0.04910511
+> s2_area("POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0))", radius = 1)
+[1] 0.03038216
+> s2_area("POLYGON ((5 5, 15 5, 15 15, 5 15, 5 5))", radius = 1)
+[1] 0.03002974
+> s2_area("POLYGON ((5 5, 10 5, 10 15, 5 10, 5 5))", radius = 1)
+[1] 0.01130679
+> 
+> df = s2_difference(
++       "POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0))",
++       "POLYGON ((5 5, 15 5, 15 15, 5 15, 5 5))"
++      )
+> s2_area(df, radius = 1) -
++   (s2_area("POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0))", radius = 1) -
++     s2_area("POLYGON ((5 5, 10 5, 10 15, 5 10, 5 5))", radius = 1))
+[1] 0.003740703
+> 
diff --git a/tests/testthat.R b/tests/testthat.R
new file mode 100644 (file)
index 0000000..361ff97
--- /dev/null
@@ -0,0 +1,4 @@
+library(testthat)
+library(s2)
+
+test_check("s2")
diff --git a/tests/testthat/test-data.R b/tests/testthat/test-data.R
new file mode 100644 (file)
index 0000000..58fd8df
--- /dev/null
@@ -0,0 +1,30 @@
+
+test_that("s2_data_country() works", {
+  expect_is(s2_data_countries("Germany"), "s2_geography")
+  expect_length(s2_data_countries("Germany"), 1)
+
+  expect_is(s2_data_countries("Europe"), "s2_geography")
+  expect_length(s2_data_countries("Europe"), 39)
+
+  expect_is(s2_data_countries(), "s2_geography")
+  expect_length(s2_data_countries(), 177)
+})
+
+test_that("s2_data_timezone() works", {
+  expect_is(s2_data_timezones(), "s2_geography")
+  expect_length(s2_data_timezones(), 120)
+
+  expect_is(s2_data_timezones(-4), "s2_geography")
+  expect_length(s2_data_timezones(-4), 3)
+
+  expect_is(s2_data_timezones(-15, 15), "s2_geography")
+  expect_length(s2_data_timezones(-15, 15), 120)
+})
+
+test_that("s2_data_cities() works", {
+  expect_is(s2_data_cities(), "s2_geography")
+  expect_length(s2_data_cities(), 243)
+
+  expect_is(s2_data_cities("Cairo"), "s2_geography")
+  expect_length(s2_data_cities("Cairo"), 1)
+})
diff --git a/tests/testthat/test-s2-accessors.R b/tests/testthat/test-s2-accessors.R
new file mode 100644 (file)
index 0000000..e929f1d
--- /dev/null
@@ -0,0 +1,219 @@
+
+test_that("s2_is_collection works", {
+  expect_identical(s2_is_collection(NA_character_), NA)
+  expect_false(s2_is_collection("POINT (-64 45)"))
+  expect_false(s2_is_collection("POINT EMPTY"))
+  expect_true(s2_is_collection("MULTIPOINT ((0 0), (1 1))"))
+
+  expect_false(s2_is_collection("LINESTRING (0 0, 1 1)"))
+  expect_true(s2_is_collection("MULTILINESTRING ((0 0, 1 1), (2 2, 3 3))"))
+  expect_false(s2_is_collection("POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0))"))
+  expect_true(
+    s2_is_collection("MULTIPOLYGON (
+      ((40 40, 20 45, 45 30, 40 40)),
+      ((20 35, 10 30, 10 10, 30 5, 45 20, 20 35), (30 20, 20 15, 20 25, 30 20))
+    )")
+  )
+})
+
+test_that("s2_is_valid() works", {
+  expect_identical(
+    s2_is_valid(
+      c(
+        # valid
+        "POINT (0 1)", "LINESTRING (0 0, 1 1)", "POLYGON ((0 0, 0 1, 1 0, 0 0))",
+        "GEOMETRYCOLLECTION (POINT (0 1))",
+        # (for the purposes of S2, linestrings that cross aren't considered invalid
+        # in the sense that they won't cause errors when you try to pass them to
+        # a boolean operation or the builder)
+        # invalid
+        "LINESTRING (0 0, 0 0, 1 1)",
+        "POLYGON ((0 0, 0 1, 1 0, 0 0, 0 0))",
+        "GEOMETRYCOLLECTION (POLYGON ((0 0, 0 1, 1 0, 0 0, 0 0)))",
+        NA
+      )
+    ),
+    c(TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, NA)
+  )
+})
+
+test_that("s2_is_valid_detail() works", {
+  expect_identical(
+    s2_is_valid_detail(
+      c(
+        # valid
+        "POINT (0 1)", "LINESTRING (0 0, 1 1)", "POLYGON ((0 0, 0 1, 1 0, 0 0))",
+        "GEOMETRYCOLLECTION (POINT (0 1))",
+        # (for the purposes of S2, linestrings that cross aren't considered invalid
+        # in the sense that they won't cause errors when you try to pass them to
+        # a boolean operation or the builder)
+        # invalid
+        "LINESTRING (0 0, 0 0, 1 1)",
+        "POLYGON ((0 0, 0 1, 1 0, 0 0, 0 0))",
+        "GEOMETRYCOLLECTION (POLYGON ((0 0, 0 1, 1 0, 0 0, 0 0)))",
+        NA
+      )
+    ),
+    data.frame(
+      is_valid = c(TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, NA),
+      reason = c(
+        NA, NA, NA, NA,
+        "Vertices 0 and 1 are identical",
+        "Loop 0: Edge 3 is degenerate (duplicate vertex)",
+        "Loop 0: Edge 3 is degenerate (duplicate vertex)",
+        NA
+      ),
+      stringsAsFactors = FALSE
+    )
+  )
+})
+
+test_that("s2_dimension works", {
+  expect_identical(s2_dimension(NA_character_), NA_integer_)
+  expect_identical(s2_dimension("POINT EMPTY"), 0L)
+  expect_identical(s2_dimension("LINESTRING EMPTY"), 1L)
+  expect_identical(s2_dimension("POLYGON EMPTY"), 2L)
+})
+
+test_that("s2_num_points works", {
+  expect_identical(s2_num_points(NA_character_), NA_integer_)
+  expect_identical(s2_num_points("POINT (-64 45)"), 1L)
+  expect_identical(s2_num_points("POINT EMPTY"), 0L)
+  expect_identical(s2_num_points("LINESTRING (0 0, 1 1)"), 2L)
+  expect_identical(s2_num_points("POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0))"), 4L)
+})
+
+test_that("s2_is_empty works", {
+  expect_identical(s2_is_empty(NA_character_), NA)
+  expect_false(s2_is_empty("POINT (-64 45)"))
+  expect_true(s2_is_empty("POINT EMPTY"))
+  expect_false(s2_is_empty("LINESTRING (0 0, 1 1)"))
+  expect_true(s2_is_empty("LINESTRING EMPTY"))
+  expect_false(s2_is_empty("POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0))"))
+  expect_true(s2_is_empty("POLYGON EMPTY"))
+})
+
+test_that("s2_area works", {
+  expect_identical(s2_area(NA_character_), NA_real_)
+  expect_identical(s2_area("POINT (-64 45)"), 0)
+  expect_identical(s2_area("POINT EMPTY"), 0)
+  expect_identical(s2_area("LINESTRING (0 0, 1 1)"), 0)
+  expect_identical(s2_area("POLYGON EMPTY"), 0)
+  expect_identical(s2_area("POLYGON ((0 0, 90 0, 0 90, 0 0))", radius = 1), 4 * pi / 8)
+  # make sure the radius is squared!
+  expect_true(
+    abs(s2_area("POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0))", radius = 180 / pi) - 100) < 0.27
+  )
+})
+
+test_that("s2_length works", {
+  expect_identical(s2_length(NA_character_), NA_real_)
+  expect_identical(s2_length("POINT (-64 45)"), 0)
+  expect_identical(s2_length("POINT EMPTY"), 0)
+  expect_identical(s2_length("LINESTRING EMPTY"), 0)
+  expect_identical(s2_length("LINESTRING (0 0, 0 1)", radius = 180 / pi), 1)
+  expect_identical(s2_length("POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0))"), 0)
+})
+
+test_that("s2_perimeter works", {
+  expect_identical(s2_perimeter(NA_character_), NA_real_)
+  expect_identical(s2_perimeter("POINT (-64 45)"), 0)
+  expect_identical(s2_perimeter("POINT EMPTY"), 0)
+  expect_identical(s2_perimeter("LINESTRING EMPTY"), 0)
+  expect_identical(s2_perimeter("LINESTRING (0 0, 1 1)"), 0)
+
+  # there is some error here because of the way this is calculated involves
+  # some round-tripping through lat/lon
+  expect_true(
+    abs(s2_perimeter("POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0))", radius = 180 / pi) - 40) < 0.155
+  )
+})
+
+test_that("s2_x and s2_y works", {
+  expect_identical(s2_x(NA_character_), NA_real_)
+  expect_identical(s2_y(NA_character_), NA_real_)
+  expect_equal(s2_x("POINT (-64 45)"), -64)
+  expect_equal(s2_y("POINT (-64 45)"), 45)
+  expect_identical(s2_x("POINT EMPTY"), NA_real_)
+  expect_identical(s2_y("POINT EMPTY"), NA_real_)
+  expect_error(s2_x("LINESTRING EMPTY"), "Can't compute")
+  expect_error(s2_y("LINESTRING EMPTY"), "Can't compute")
+  expect_error(s2_x("POLYGON EMPTY"), "Can't compute")
+  expect_error(s2_y("POLYGON EMPTY"), "Can't compute")
+})
+
+test_that("s2_project() and s2_project_normalized() work", {
+  expect_equal(
+    s2_project(
+      "LINESTRING (0 0, 0 90)",
+      c("POINT (0 0)", "POINT (0 22.5)", "POINT (0 67.5)", "POINT (0 90)", NA),
+      radius = 1
+    ),
+    c(0, 0.25, 0.75, 1, NA_real_) * pi / 2
+  )
+
+  expect_equal(
+    s2_project_normalized(
+      "LINESTRING (0 0, 0 90)",
+      c("POINT (0 0)", "POINT (0 22.5)", "POINT (0 67.5)", "POINT (0 90)", "POINT EMPTY", NA)
+    ),
+    c(0, 0.25, 0.75, 1, NA_real_, NA_real_)
+  )
+
+  expect_error(
+    s2_project_normalized("POINT (0 1)", "POINT (0 1)"),
+    "must be a polyline"
+  )
+  expect_error(
+    s2_project_normalized("LINESTRING (0 1, 1 1)", "LINESTRING (0 1, 1 1)"),
+    "must be a point"
+  )
+  expect_error(
+    s2_project_normalized("LINESTRING (0 1, 1 1)", "MULTIPOINT (0 1, 1 1)"),
+    "must both be simple geographies"
+  )
+})
+
+test_that("s2_distance works", {
+  expect_equal(
+    s2_distance("POINT (0 0)", "POINT (90 0)", radius = 180 / pi),
+    90
+  )
+
+  expect_equal(
+    s2_distance("POINT (0 0)", "LINESTRING (90 0, 91 0)", radius = 180 / pi),
+    90
+  )
+
+  expect_equal(
+    s2_distance("POINT (0 0)", "POLYGON ((90 0, 91 0, 92 1, 90 0))", radius = 180 / pi),
+    90
+  )
+
+  expect_identical(s2_distance("POINT (0 0)", NA_character_), NA_real_)
+  expect_identical(s2_distance(NA_character_, "POINT (0 0)"), NA_real_)
+  expect_identical(s2_distance("POINT (0 0)", "POINT EMPTY"), NA_real_)
+  expect_identical(s2_distance("POINT EMPTY", "POINT (0 0)"), NA_real_)
+})
+
+test_that("s2_max_distance works", {
+  expect_equal(
+    s2_max_distance("POINT (0 0)", "POINT (90 0)", radius = 180 / pi),
+    90
+  )
+
+  expect_equal(
+    s2_max_distance("POINT (0 0)", "LINESTRING (90 0, 91 0)", radius = 180 / pi),
+    91
+  )
+
+  expect_equal(
+    s2_max_distance("POINT (0 0)", "POLYGON ((90 0, 91 0, 89 1, 90 0))", radius = 180 / pi),
+    91
+  )
+
+  expect_identical(s2_max_distance("POINT (0 0)", NA_character_), NA_real_)
+  expect_identical(s2_max_distance(NA_character_, "POINT (0 0)"), NA_real_)
+  expect_identical(s2_max_distance("POINT (0 0)", "POINT EMPTY"), NA_real_)
+  expect_identical(s2_max_distance("POINT EMPTY", "POINT (0 0)"), NA_real_)
+})
diff --git a/tests/testthat/test-s2-bounds.R b/tests/testthat/test-s2-bounds.R
new file mode 100644 (file)
index 0000000..87a5f4e
--- /dev/null
@@ -0,0 +1,44 @@
+
+test_that("s2_bounds_cap works", {
+  cap_ant <- s2_data_countries("Antarctica")
+  expect_is(s2_bounds_cap(cap_ant), "data.frame")
+  expect_identical(nrow(s2_bounds_cap(cap_ant)), 1L)
+  expect_true(s2_bounds_cap(cap_ant)$lat < -80)
+  expect_true(s2_bounds_cap(cap_ant)$angle > 20)
+
+  expect_identical(nrow(s2_bounds_cap(s2_data_countries(c("Antarctica", "Netherlands")))), 2L)
+
+  expect_true(s2_bounds_cap(s2_data_countries("Netherlands"))$angle < 2)
+  expect_true(s2_bounds_cap(s2_data_countries("Fiji"))$angle < 2)
+})
+
+test_that("s2_bounds_rect works", {
+  rect_ant <- s2_bounds_rect(s2_data_countries("Antarctica"))
+  expect_is(rect_ant, "data.frame")
+  expect_named(rect_ant, c("lng_lo", "lat_lo", "lng_hi", "lat_hi"))
+  expect_identical(nrow(s2_bounds_rect(s2_data_countries(c("Antarctica", "Netherlands")))), 2L)
+  expect_equal(rect_ant$lng_lo, -180)
+  expect_equal(rect_ant$lng_hi, 180)
+  expect_equal(rect_ant$lat_lo, -90)
+  expect_true(rect_ant$lat_hi < -60)
+
+  expect_identical(nrow(s2_bounds_rect(s2_data_countries(c("Antarctica", "Netherlands")))), 2L)
+
+  rect_nl <- s2_bounds_rect(s2_data_countries("Netherlands"))
+  expect_true((rect_nl$lng_hi - rect_nl$lng_lo) < 4)
+
+  rect_fiji <- s2_bounds_rect(s2_data_countries("Fiji"))
+  expect_true(rect_fiji$lng_hi < rect_fiji$lng_lo)
+
+  rect_multipoint <- s2_bounds_rect("MULTIPOINT(-179 0,179 1,-180 10)")
+  expect_equal(rect_multipoint$lat_lo, 0)
+  expect_equal(rect_multipoint$lat_hi, 10)
+  expect_equal(rect_multipoint$lng_lo, 179)
+  expect_equal(rect_multipoint$lng_hi, -179)
+
+  rect_linestring <- s2_bounds_rect("LINESTRING(-179 0,179 1)")
+  expect_equal(rect_linestring$lat_lo, 0)
+  expect_equal(rect_linestring$lat_hi, 1)
+  expect_equal(rect_linestring$lng_lo, 179)
+  expect_equal(rect_linestring$lng_hi, -179)
+})
diff --git a/tests/testthat/test-s2-cell.R b/tests/testthat/test-s2-cell.R
new file mode 100644 (file)
index 0000000..222beca
--- /dev/null
@@ -0,0 +1,371 @@
+
+test_that("s2_cell class works", {
+  expect_s3_class(new_s2_cell(double()), "s2_cell")
+  expect_s3_class(new_s2_cell(NA_real_), "s2_cell")
+  expect_true(is.na(new_s2_cell(NA_real_)))
+  expect_identical(as_s2_cell(s2_cell()), s2_cell())
+})
+
+test_that("invalid and sentinel values work as expected", {
+  expect_false(s2_cell_is_valid(s2_cell_sentinel()))
+  expect_false(s2_cell_is_valid(s2_cell_invalid()))
+  expect_false(is.na(s2_cell_sentinel()))
+  expect_false(is.na(s2_cell_invalid()))
+  expect_true(s2_cell_sentinel() > s2_cell_invalid())
+})
+
+test_that("sort() and unique() work", {
+  # temporary workaround for broken c() in wk
+  expect_identical(
+    unique(new_s2_cell(c(unclass(s2_cell_sentinel()), NA, 0, 0, unclass(s2_cell("5"))))),
+    new_s2_cell(c(0, unclass(s2_cell("5")), NA, unclass(s2_cell_sentinel())))
+  )
+
+  expect_identical(
+    sort(new_s2_cell(c(unclass(s2_cell_sentinel()), NA, 0, 0, unclass(s2_cell("5"))))),
+    new_s2_cell(c(0, 0, unclass(s2_cell("5")), NA, unclass(s2_cell_sentinel())))
+  )
+
+  expect_identical(
+    sort(
+      new_s2_cell(c(unclass(s2_cell_sentinel()), NA, 0, 0, unclass(s2_cell("5")))),
+      decreasing = TRUE
+    ),
+    rev(new_s2_cell(c(0, 0, unclass(s2_cell("5")), NA, unclass(s2_cell_sentinel()))))
+  )
+})
+
+test_that("geography exporters work", {
+  expect_identical(
+    s2_as_text(s2_cell_center(as_s2_cell(s2_lnglat(c(-64, NA), c(45, NA)))), precision = 5),
+    c("POINT (-64 45)", NA)
+  )
+
+  expect_identical(
+    s2_as_text(s2_cell_polygon(as_s2_cell(s2_lnglat(c(-64, NA), c(45, NA)))), precision = 5),
+    c("POLYGON ((-64 45, -64 45, -64 45, -64 45, -64 45))", NA)
+  )
+
+  expect_identical(
+    s2_as_text(s2_cell_boundary(as_s2_cell(s2_lnglat(c(-64, NA), c(45, NA)))), precision = 5),
+    c("LINESTRING (-64 45, -64 45, -64 45, -64 45, -64 45)", NA)
+  )
+
+  expect_equal(
+    s2_x(s2_cell_vertex(s2_cell(c("5", "5", "5", NA)), k = c(0, 1, NA, 1))),
+    c(45, 135, NA, NA)
+  )
+})
+
+test_that("s2_cell_is_valid() works", {
+  expect_identical(
+    s2_cell_is_valid(new_s2_cell(double())),
+    logical()
+  )
+  expect_identical(
+    s2_cell_is_valid(new_s2_cell(NA_real_)),
+    FALSE
+  )
+})
+
+test_that("Ops, Math, and Summary errors for non-meaningful s2_cell() ops", {
+  expect_error(s2_cell("X") + 1, "not meaningful")
+  expect_error(abs(s2_cell("X")), "not meaningful")
+  expect_error(all(s2_cell("X")), "not meaningful")
+})
+
+test_that("Ops, Math, and Summary ops work", {
+  expect_identical(
+    s2_cell(c("5", "5", "x", "x", "x", NA, NA)) ==
+      s2_cell(c("5", "x", "5", "x", NA, "x", NA)),
+    c(TRUE, FALSE, FALSE, TRUE, NA, NA, NA)
+  )
+
+  expect_identical(
+    s2_cell(c("5", "5", "x", "x", "x", NA, NA)) !=
+      s2_cell(c("5", "x", "5", "x", NA, "x", NA)),
+    c(FALSE, TRUE, TRUE, FALSE, NA, NA, NA)
+  )
+
+  # 'invalid' is 0
+  expect_identical(
+    s2_cell(c("5", "5", "x", "x", "x", NA, NA)) >
+      s2_cell(c("5", "x", "5", "x", NA, "x", NA)),
+    c(FALSE, TRUE, FALSE, FALSE, NA, NA, NA)
+  )
+
+  expect_identical(
+    s2_cell(c("5", "5", "x", "x", "x", NA, NA)) >=
+      s2_cell(c("5", "x", "5", "x", NA, "x", NA)),
+    c(TRUE, TRUE, FALSE, TRUE, NA, NA, NA)
+  )
+
+  expect_identical(
+    s2_cell(c("5", "5", "x", "x", "x", NA, NA)) <
+      s2_cell(c("5", "x", "5", "x", NA, "x", NA)),
+    c(FALSE, FALSE, TRUE, FALSE, NA, NA, NA)
+  )
+
+  expect_identical(
+    s2_cell(c("5", "5", "x", "x", "x", NA, NA)) <=
+      s2_cell(c("5", "x", "5", "x", NA, "x", NA)),
+    c(TRUE, FALSE, TRUE, TRUE, NA, NA, NA)
+  )
+
+  expect_identical(
+    cummax(s2_cell(c("5", "x", "5", "x", NA, "x", NA))),
+           s2_cell(c("5", "5", "5", "5", NA, NA, NA))
+  )
+
+  expect_identical(
+    cummin(s2_cell(c("5", "x", "5", "x", NA, "x", NA))),
+           s2_cell(c("5", "x", "x", "x", NA, NA, NA))
+  )
+
+  expect_identical(
+    range(s2_cell(c("5", "x", "5", "x", NA, "x", NA)), na.rm = TRUE),
+    s2_cell(c("X", "5"))
+  )
+
+  expect_identical(
+    max(s2_cell(c("5", "x", "5", "x", NA, "x", NA)), na.rm = TRUE),
+    s2_cell("5")
+  )
+
+  expect_identical(
+    min(s2_cell(c("5", "x", "5", "x", NA, "x", NA)), na.rm = TRUE),
+    s2_cell("X")
+  )
+
+  expect_identical(
+    range(s2_cell(c("5", "x", "5", "x", NA, "x", NA))),
+    s2_cell(c(NA_character_, NA_character_))
+  )
+
+  expect_identical(range(s2_cell()), s2_cell(c(NA_character_, NA_character_)))
+  expect_identical(
+    range(s2_cell(NA_character_), na.rm = TRUE),
+    s2_cell(c(NA_character_, NA_character_))
+  )
+})
+
+test_that("Binary ops are recycled at the C++ level", {
+  expect_identical(s2_cell(rep("5", 2)) == s2_cell(rep("5", 2)), c(TRUE, TRUE))
+  expect_identical(s2_cell(rep("5", 1)) == s2_cell(rep("5", 2)), c(TRUE, TRUE))
+  expect_identical(s2_cell(rep("5", 2)) == s2_cell(rep("5", 1)), c(TRUE, TRUE))
+  expect_error(s2_cell(rep("5", 2)) == s2_cell(rep("5", 0)), "Can't recycle")
+})
+
+test_that("s2_cell is not numeric", {
+  expect_false(is.numeric(s2_cell()))
+})
+
+test_that("s2_cell subsetting and concatenation work", {
+  cells <- new_s2_cell(c(NA_real_, NA_real_))
+  expect_identical(cells[1], new_s2_cell(NA_real_))
+  expect_identical(cells[[1]], cells[1])
+  expect_identical(
+    c(cells, cells),
+    new_s2_cell(c(NA_real_, NA_real_, NA_real_, NA_real_))
+  )
+  expect_identical(
+    rep(cells, 2),
+    new_s2_cell(c(NA_real_, NA_real_, NA_real_, NA_real_))
+  )
+  expect_identical(
+    rep_len(cells, 4),
+    new_s2_cell(c(NA_real_, NA_real_, NA_real_, NA_real_))
+  )
+  expect_error(
+    c(new_s2_cell(c(NA_real_, NA_real_)), 1:5),
+    "Can't combine"
+  )
+})
+
+test_that("s2_cell() can be created from s2_geography()", {
+  expect_identical(
+    as_s2_cell(as_s2_geography("POINT (-64 45)")),
+    s2_cell("4b59a0cd83b5de49")
+  )
+})
+
+test_that("s2_cell() can be created from s2_lnglat()", {
+  expect_identical(
+    as_s2_cell(s2_lnglat(-64, 45)),
+    s2_cell("4b59a0cd83b5de49")
+  )
+})
+
+test_that("s2_cell() can be created from s2_point()", {
+  expect_identical(
+    as_s2_cell(as_s2_point(s2_lnglat(-64, 45))),
+    s2_cell("4b59a0cd83b5de49")
+  )
+})
+
+test_that("s2_cell() can be created from character", {
+  expect_identical(
+    as_s2_cell("4b59a0cd83b5de49"),
+    as_s2_cell(s2_lnglat(-64, 45))
+  )
+})
+
+test_that("subset-assignment works", {
+  x <- as_s2_cell(c(NA, "4b59a0cd83b5de49", "4b5f6a7856889a33"))
+  expect_identical(as.character(x[3]), "4b5f6a7856889a33")
+  x[3] <- "4b59a0cd83b5de49"
+  expect_identical(as.character(x[3]), "4b59a0cd83b5de49")
+
+  x[[3]] <- "4b5f6a7856889a33"
+  expect_identical(as.character(x[3]), "4b5f6a7856889a33")
+})
+
+test_that("s2_cell can be put into a data.frame", {
+  expect_identical(
+    data.frame(geom = new_s2_cell(NA_real_)),
+    new_data_frame(list(geom = new_s2_cell(NA_real_)))
+  )
+  expect_error(as.data.frame(new_s2_cell(NA_real_)), "cannot coerce class")
+})
+
+test_that("s2_cell default format/print/str methods work", {
+  expect_identical(
+    format(s2_cell()),
+    as.character(s2_cell())
+  )
+  expect_output(print(new_s2_cell(double())), "s2_cell")
+  expect_output(print(new_s2_cell(NA_real_)), "s2_cell")
+
+  expect_output(str(as_s2_cell(character())), "s2_cell\\[0\\]")
+  expect_output(str(as_s2_cell(NA_character_)), "NA")
+})
+
+test_that("s2 cell exporters work", {
+  expect_equal(
+    as.data.frame(s2_cell_to_lnglat(s2_cell(c("4b59a0cd83b5de49", "x", NA)))),
+    as.data.frame(c(s2_lnglat(-64, 45), s2_lnglat(NA, NA), s2_lnglat(NA, NA)))
+  )
+
+  expect_identical(
+    s2_cell_debug_string(s2_cell(c("4b5f6a7856889a33", NA))),
+    c("2/112233231103300223101010310121", NA)
+  )
+  expect_match(s2_cell_debug_string(s2_cell("X")), "Invalid")
+})
+
+test_that("s2_cell() accessors work", {
+  expect_identical(
+    s2_cell_is_valid(s2_cell(c("4b5f6a7856889a33", "5", "x", NA))),
+    c(TRUE, TRUE, FALSE, FALSE)
+  )
+
+  expect_identical(
+    s2_cell_level(s2_cell(c("4b5f6a7856889a33", "5", "x", NA))),
+    c(30L, 0L, NA, NA)
+  )
+
+  expect_identical(
+    s2_cell_is_leaf(s2_cell(c("4b5f6a7856889a33", "5", "x", NA))),
+    c(TRUE, FALSE, NA, NA)
+  )
+
+  expect_identical(
+    s2_cell_is_face(s2_cell(c("4b5f6a7856889a33", "5", "x", NA))),
+    c(FALSE, TRUE, NA, NA)
+  )
+
+  expect_equal(
+    s2_cell_area(s2_cell(c("5", "x", NA)), radius = 1),
+    c(2 * pi / 3, NA, NA)
+  )
+
+  expect_equal(
+    s2_cell_area_approx(s2_cell(c("5", "x", NA)), radius = 1),
+    c(2 * pi / 3, NA, NA)
+  )
+})
+
+test_that("s2_cell() transversers work", {
+  expect_identical(
+    s2_cell_parent(s2_cell(c("5", "4b5f6a7856889a33", "x", NA)), 0),
+    s2_cell(c("5", "5", NA, NA))
+  )
+
+  leaf_manual <- function(x, children) {
+    if (length(children) == 0) {
+      x
+    } else {
+      leaf_manual(
+        s2_cell_child(x, children[1]),
+        children[-1]
+      )
+    }
+  }
+
+  # see output of s2_cell_debug_string()
+  expect_identical(
+    leaf_manual(
+      s2_cell("5"),
+      as.numeric(strsplit("112233231103300223101010310121", "")[[1]])
+    ),
+    s2_cell("4b5f6a7856889a33")
+  )
+
+  expect_identical(
+    s2_cell_child(s2_cell(c("5", "5", "5", "x", NA)), c(-1, 4, NA, 0, 0)),
+    s2_cell(as.character(c(NA, NA, NA, NA, NA)))
+  )
+
+  expect_identical(
+    s2_cell_debug_string(s2_cell_edge_neighbour(s2_cell("5"), 0:3)),
+    c("1/", "3/", "4/", "0/")
+  )
+
+  expect_identical(
+    s2_cell_edge_neighbour(s2_cell(c("5", "5", "5", "x", NA)), c(-1, 4, NA, 0, 0)),
+    s2_cell(as.character(c(NA, NA, NA, NA, NA)))
+  )
+})
+
+test_that("s2_cell() binary operators work", {
+  cell <- s2_cell("4b5f6a7856889a33")
+  expect_true(s2_cell_contains(s2_cell_parent(cell), cell))
+  expect_false(s2_cell_contains(cell, s2_cell_parent(cell)))
+  expect_identical(s2_cell_contains(s2_cell_sentinel(), s2_cell_sentinel()), NA)
+
+  expect_equal(
+    s2_cell_distance(
+      as_s2_cell(s2_lnglat(0, 90)),
+      as_s2_cell(s2_lnglat(0, 0)),
+      radius = 1
+    ),
+    pi / 2
+  )
+
+  expect_equal(
+    s2_cell_max_distance(
+      as_s2_cell(s2_lnglat(0, 90)),
+      as_s2_cell(s2_lnglat(0, 0)),
+      radius = 1
+    ),
+    pi / 2
+  )
+
+  f1 <- s2_cell_parent(as_s2_cell(s2_lnglat(0, 0)), 0)
+  f2 <- s2_cell_parent(as_s2_cell(s2_lnglat(0, 90)), 0)
+  expect_equal(s2_cell_distance(f1, f2), 0)
+  expect_equal(s2_cell_max_distance(f1, f2, radius = 1), pi)
+  expect_identical(s2_cell_max_distance(s2_cell_sentinel(), s2_cell_sentinel()), NA_real_)
+  expect_identical(s2_cell_distance(s2_cell_sentinel(), s2_cell_sentinel()), NA_real_)
+
+  expect_false(
+    s2_cell_may_intersect(
+      as_s2_cell(s2_lnglat(0, 90)),
+      as_s2_cell(s2_lnglat(0, 0))
+    )
+  )
+
+  expect_true(s2_cell_may_intersect(s2_cell_parent(cell), cell))
+  expect_true(s2_cell_may_intersect(cell, s2_cell_parent(cell)))
+  expect_identical(s2_cell_may_intersect(s2_cell_sentinel(), s2_cell_sentinel()), NA)
+})
diff --git a/tests/testthat/test-s2-constructors-formatters.R b/tests/testthat/test-s2-constructors-formatters.R
new file mode 100644 (file)
index 0000000..ce1ad74
--- /dev/null
@@ -0,0 +1,171 @@
+
+test_that("s2_geog_point() works", {
+  expect_wkt_equal(s2_geog_point(-64, 45), "POINT (-64 45)")
+})
+
+test_that("s2_make_line() works", {
+  expect_wkt_equal(
+    s2_make_line(c(-64, 8), c(45, 71)),
+    "LINESTRING (-64 45, 8 71)"
+  )
+
+  # check separation using feature_id
+  expect_wkt_equal(
+    s2_make_line(
+      c(-64, 8, -27, -27), c(45, 71, 0, 45),
+      feature_id = c(1, 1, 2, 2)
+    ),
+    c("LINESTRING (-64 45, 8 71)", "LINESTRING (-27 0, -27 45)")
+  )
+})
+
+test_that("s2_make_polygon() works", {
+  expect_wkt_equal(
+    s2_make_polygon(c(-45, 8, 0), c(64, 71, 90)),
+    "POLYGON ((-45 64, 8 71, 0 90, -45 64))"
+  )
+  # check that loops can be open or closed
+  expect_wkt_equal(
+    s2_make_polygon(c(-45, 8, 0, -45), c(64, 71, 90, 64)),
+    "POLYGON ((-45 64, 8 71, 0 90, -45 64))"
+  )
+
+  # check feature/ring separation
+  expect_wkt_equal(
+    s2_make_polygon(
+      c(20, 10, 10, 30, 45, 30, 20, 20, 40, 20, 45),
+      c(35, 30, 10, 5, 20, 20, 15, 25, 40, 45, 30),
+      feature_id = c(rep(1, 8), rep(2, 3)),
+      ring_id = c(1, 1, 1, 1, 1, 2, 2, 2, 1, 1, 1)
+    ),
+    c(
+      "POLYGON ((20 35, 10 30, 10 10, 30 5, 45 20, 20 35), (30 20, 20 15, 20 25, 30 20))",
+      "POLYGON ((40 40, 20 45, 45 30, 40 40))"
+    )
+  )
+})
+
+test_that("s2_geog_from_wkt() works", {
+  expect_wkt_equal(s2_geog_from_text("POINT (-64 45)"), "POINT (-64 45)")
+})
+
+test_that("s2_geog_from_wkb() works", {
+  expect_wkt_equal(s2_geog_from_wkb(as_wkb("POINT (-64 45)")), "POINT (-64 45)")
+})
+
+test_that("s2_as_text() works", {
+  expect_identical(
+    s2_as_text("POINT (0.1234567890123456 0.1234567890123456)"),
+    "POINT (0.1234567890123456 0.1234567890123456)"
+  )
+})
+
+test_that("s2_as_binary() works", {
+  expect_identical(
+    s2_as_binary("POINT (0 0)", endian = 1),
+    structure(
+      list(
+        as.raw(
+          c(0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
+            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+            0x00, 0x00, 0x00
+          )
+        )
+      ),
+      class = "blob"
+    )
+  )
+})
+
+test_that("s2_as_binary works on (multi)polygons", {
+       geog <- s2_data_countries()
+       wkb <- s2_as_binary(geog)
+
+       expect_identical(
+         sum(vapply(wkb, length, integer(1))),
+         173318L
+       )
+       expect_identical(length(wkb), length(geog))
+})
+
+test_that("polygon constructors respect oriented and check arguments", {
+  polygon_with_bad_hole_wkt <- "POLYGON (
+    (20 35, 10 30, 10 10, 30 5, 45 20, 20 35),
+    (30 20, 20 25, 20 15, 30 20)
+  )"
+  polygon_with_bad_hole_wkb <- wk::as_wkb(polygon_with_bad_hole_wkt)
+  polygon_with_bad_hole_df <- data.frame(
+    x = c(20, 10, 10, 30, 45, 30, 20, 20),
+    y = c(35, 30, 10, 5, 20, 20, 25, 15),
+    ring_id = c(1, 1, 1, 1, 1, 2, 2, 2)
+  )
+
+  expect_false(
+    s2_intersects(
+      s2_geog_from_text(polygon_with_bad_hole_wkt, oriented = FALSE),
+      "POINT (23 19.5)"
+    )
+  )
+  expect_false(
+    s2_intersects(
+      s2_geog_from_wkb(polygon_with_bad_hole_wkb, oriented = FALSE),
+      "POINT (23 19.5)"
+    )
+  )
+  expect_false(
+    s2_intersects(
+      with(
+        polygon_with_bad_hole_df,
+        s2_make_polygon(x, y, ring_id = ring_id, oriented = FALSE)
+      ),
+      "POINT (23 19.5)"
+    )
+  )
+
+  expect_error(
+    s2_intersects(
+      s2_geog_from_text(polygon_with_bad_hole_wkt, oriented = TRUE, check = TRUE),
+      "POINT (23 19.5)"
+    ),
+    "Inconsistent loop orientations"
+  )
+  expect_error(
+    s2_intersects(
+      s2_geog_from_wkb(polygon_with_bad_hole_wkb, oriented = TRUE, check = TRUE),
+      "POINT (23 19.5)"
+    ),
+    "Inconsistent loop orientations"
+  )
+  expect_error(
+    s2_intersects(
+      with(
+        polygon_with_bad_hole_df,
+        s2_make_polygon(x, y, ring_id = ring_id, oriented = TRUE, check = TRUE)
+      ),
+      "POINT (23 19.5)"
+    ),
+    "Inconsistent loop orientations"
+  )
+
+  expect_silent(
+    s2_intersects(
+      s2_geog_from_text(polygon_with_bad_hole_wkt, oriented = TRUE, check = FALSE),
+      "POINT (23 19.5)"
+    )
+  )
+  expect_silent(
+    s2_intersects(
+      s2_geog_from_wkb(polygon_with_bad_hole_wkb, oriented = TRUE, check = FALSE),
+      "POINT (23 19.5)"
+    )
+  )
+  expect_silent(
+    s2_intersects(
+      with(
+        polygon_with_bad_hole_df,
+        s2_make_polygon(x, y, ring_id = ring_id, oriented = TRUE, check = FALSE)
+      ),
+      "POINT (23 19.5)"
+    )
+  )
+})
diff --git a/tests/testthat/test-s2-earth.R b/tests/testthat/test-s2-earth.R
new file mode 100644 (file)
index 0000000..efcc820
--- /dev/null
@@ -0,0 +1,5 @@
+
+test_that("s2_earth_radius_meters works", {
+  expect_is(s2_earth_radius_meters(), "numeric")
+  expect_length(s2_earth_radius_meters(), 1)
+})
diff --git a/tests/testthat/test-s2-geography.R b/tests/testthat/test-s2-geography.R
new file mode 100644 (file)
index 0000000..e8ff8e1
--- /dev/null
@@ -0,0 +1,236 @@
+
+test_that("s2_geography class works", {
+  expect_s3_class(s2_geography(), "s2_geography")
+  geog <- new_s2_xptr(list(NULL), class = "s2_geography")
+  expect_output(print(geog), "s2_geography")
+  expect_output(str(geog), "s2_geography")
+  expect_identical(as_s2_geography(geog), geog)
+
+  # subset assignment
+  geog2 <- geog
+  geog2[1] <- geog
+  expect_identical(geog2, geog)
+
+  geog2 <- geog
+  geog2[[1]] <- geog
+  expect_identical(geog2, geog)
+})
+
+test_that("s2_geography vectors can be put in a data frame", {
+  expect_identical(
+    data.frame(geog = s2_geography()),
+    new_data_frame(list(geog = s2_geography()))
+  )
+})
+
+test_that("s2_geography vectors can't have other types of objects concatenated or asssigned", {
+  geog <- new_s2_xptr(list(NULL), class = "s2_geography")
+  expect_is(c(geog, geog), "s2_geography")
+  expect_error(c(geog, new_s2_xptr(list(), class = "some_other_class")), "All items must inherit")
+  expect_error(geog[1] <- new_s2_xptr(list(NULL), class = "some_other_class"), "no applicable method")
+  expect_error(geog[[1]] <- new_s2_xptr(list(NULL), class = "some_other_class"), "no applicable method")
+})
+
+test_that("s2_geography vectors can be created from s2_lnglat  and s2_point", {
+  expect_wkt_equal(as_s2_geography(s2_lnglat(-64, 45)), "POINT (-64 45)")
+  expect_wkt_equal(as_s2_geography(as_s2_point(s2_lnglat(-64, 45))), "POINT (-64 45)")
+})
+
+test_that("s2_geography vectors can be created from WKB and WKT", {
+  wkb_point <- wk::as_wkb("POINT (-64 45)")
+  expect_output(print(as_s2_geography(wkb_point)), "<POINT \\(-64 45\\)>")
+
+  wkt_point <- wk::as_wkt("POINT (-64 45)")
+  expect_output(print(as_s2_geography(wkt_point)), "<POINT \\(-64 45\\)>")
+
+  # also test other classes commonly used to signify WKB or WKT
+  expect_output(print(as_s2_geography(structure(wkb_point, class = "WKB")), "<POINT \\(-64 45\\)>"))
+  expect_output(print(as_s2_geography(structure(wkb_point, class = "blob")), "<POINT \\(-64 45\\)>"))
+})
+
+test_that("s2_geography can be exported to WKB/WKT", {
+  expect_wkt_equal(
+    wk::as_wkb(as_s2_geography("POINT (-64 45)")),
+    wk::as_wkb("POINT (-64 45)"),
+    precision = 10
+  )
+  expect_wkt_equal(
+    wk::as_wkt(as_s2_geography("POINT (-64 45)")),
+    wk::as_wkt("POINT (-64 45)"),
+    precision = 10
+  )
+})
+
+test_that("s2_geography vectors can be created from wkt", {
+  expect_output(print(as_s2_geography("POINT (-64 45)")), "<POINT \\(-64 45\\)>")
+  expect_output(print(as_s2_geography("POINT EMPTY")), "<POINT EMPTY>")
+  expect_output(
+    print(as_s2_geography("MULTIPOINT ((-64 45), (30 10))")),
+    "<MULTIPOINT \\(\\(-64 45\\), \\(30 10\\)\\)>"
+  )
+
+  expect_output(
+    print(as_s2_geography("LINESTRING (-64 45, 0 0)")),
+    "<LINESTRING \\(-64 45, 0 0\\)>"
+  )
+  expect_output(
+    print(as_s2_geography("LINESTRING EMPTY")),
+    "<LINESTRING EMPTY>"
+  )
+  expect_output(
+    print(as_s2_geography("MULTILINESTRING ((-64 45, 0 0), (0 1, 2 3))")),
+    "<MULTILINESTRING \\(\\(-64 45, 0 0), \\(0 1, 2 3\\)\\)>"
+  )
+
+  expect_output(print(as_s2_geography("POLYGON EMPTY"), "<POLYGON EMPTY>"))
+  expect_output(
+    print(as_s2_geography("POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0))")),
+    "<POLYGON \\(\\(0 0, 10 0, 10 10"
+  )
+  expect_output(
+    print(as_s2_geography("MULTIPOLYGON (((0 0, 10 0, 10 10, 0 10, 0 0)))")),
+    "<POLYGON \\(\\(0 0, 10 0, 10 10"
+  )
+  expect_output(
+    print(
+      as_s2_geography("MULTIPOLYGON (
+        ((40 40, 20 45, 45 30, 40 40)),
+        ((20 35, 10 30, 10 10, 30 5, 45 20, 20 35), (30 20, 20 15, 20 25, 30 20))
+      )")
+    ),
+    "<MULTIPOLYGON"
+  )
+
+  expect_output(
+    print(as_s2_geography("GEOMETRYCOLLECTION (POINT (-64 45))")),
+    "<GEOMETRYCOLLECTION \\(POINT \\(-64 45\\)\\)>"
+  )
+
+  expect_output(
+    print(
+      as_s2_geography(
+        "GEOMETRYCOLLECTION (
+          POINT (30 10),
+          MULTIPOINT (11 12, 12 13),
+          LINESTRING (40 40, 40 41),
+          MULTILINESTRING ((-10 -12, -12 -13), (-15 -15, -16 -16)),
+          POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0)),
+          MULTIPOLYGON (((0 0, -10 0, -10 -10, 0 -10, 0 0))),
+          GEOMETRYCOLLECTION (POINT (-100 0), MULTIPOINT(-101 0, -102 0))
+        )"
+      ),
+      max_coords = 100
+    ),
+    paste0(
+      "GEOMETRYCOLLECTION.*?POINT.*?MULTIPOINT.*?LINESTRING.*?MULTILINESTRING.*?",
+      "POLYGON.*?POLYGON.*?GEOMETRYCOLLECTION.*?POINT.*?MULTIPOINT"
+    )
+  )
+
+  expect_output(print(as_s2_geography("GEOMETRYCOLLECTION EMPTY")), "<GEOMETRYCOLLECTION EMPTY>")
+})
+
+test_that("empty points are empty when imported from WKB", {
+  wkb_empty <- wk::as_wkb("POINT EMPTY")
+  expect_true(s2_is_empty(s2_geog_from_wkb(wkb_empty)))
+})
+
+test_that("nested ring depths are correctly exported", {
+  # polygon with hole
+  expect_output(
+    print(
+      as_s2_geography("MULTIPOLYGON (
+        ((40 40, 20 45, 45 30, 40 40)),
+        (
+          (20 35, 10 30, 10 10, 30 5, 45 20, 20 35),
+          (30 20, 20 15, 20 25, 30 20)
+        )
+      )"),
+      max_coords = 100
+    ),
+    "\\(20 35, 10 30, 10 10, 30 5, 45 20, 20 35\\), \\(30 20, 20 15, 20 25, 30 20"
+  )
+
+  # polygon with a hole in a hole!
+  expect_output(
+    print(
+      as_s2_geography("MULTIPOLYGON (
+        ((40 40, 20 45, 45 30, 40 40)),
+        (
+          (20 35, 10 30, 10 10, 30 5, 45 20, 20 35),
+          (30 20, 20 15, 20 25, 30 20),
+          (27 21, 21 21, 21 16, 27 21)
+        )
+      )"),
+      max_coords = 100
+    ),
+    "30 20, 20 15, 20 25, 30 20\\), \\(27 21, 21 21, 21 16, 27 21"
+  )
+})
+
+test_that("polygons with holes are interpreted as such by S2", {
+  expect_true(
+    s2_intersects(
+      "MULTIPOLYGON (
+        ((40 40, 20 45, 45 30, 40 40)),
+        (
+          (20 35, 10 30, 10 10, 30 5, 45 20, 20 35),
+          (30 20, 20 15, 20 25, 30 20),
+          (27 21, 21 21, 21 16, 27 21)
+        )
+      )",
+      "POINT (23 19.5)"
+    )
+  )
+
+  expect_false(
+    s2_intersects(
+      "MULTIPOLYGON (
+        ((40 40, 20 45, 45 30, 40 40)),
+        (
+          (20 35, 10 30, 10 10, 30 5, 45 20, 20 35),
+          (30 20, 20 15, 20 25, 30 20)
+        )
+      )",
+      "POINT (23 19.5)"
+    )
+  )
+})
+
+test_that("polygon construction works with oriented = TRUE and oriented = FALSE", {
+  polygon_with_bad_hole_nested <- as_s2_geography("MULTIPOLYGON (
+    ((40 40, 20 45, 45 30, 40 40)),
+    (
+      (20 35, 10 30, 10 10, 30 5, 45 20, 20 35),
+      (30 20, 20 25, 20 15, 30 20)
+    )
+  )", oriented = FALSE)
+
+  expect_false(s2_intersects(polygon_with_bad_hole_nested, "POINT (23 19.5)"))
+
+  expect_error(
+    as_s2_geography("MULTIPOLYGON (
+      ((40 40, 20 45, 45 30, 40 40)),
+      (
+        (20 35, 10 30, 10 10, 30 5, 45 20, 20 35),
+        (30 20, 20 25, 20 15, 30 20)
+      )
+    )", oriented = TRUE, check = TRUE),
+    "Inconsistent loop orientations"
+  )
+
+  expect_silent(
+    as_s2_geography("MULTIPOLYGON (
+      ((40 40, 20 45, 45 30, 40 40)),
+      (
+        (20 35, 10 30, 10 10, 30 5, 45 20, 20 35),
+        (30 20, 20 25, 20 15, 30 20)
+      )
+    )", oriented = TRUE, check = FALSE)
+  )
+})
+
+test_that("Full polygons work", {
+  expect_true(s2_intersects(as_s2_geography(TRUE), "POINT(0 1)"))
+  expect_wkt_equal(s2_difference(as_s2_geography(TRUE), "POINT(0 1)"), "POLYGON ((0 -90, 0 -90))")
+})
diff --git a/tests/testthat/test-s2-lnglat.R b/tests/testthat/test-s2-lnglat.R
new file mode 100644 (file)
index 0000000..e43814d
--- /dev/null
@@ -0,0 +1,92 @@
+
+test_that("s2_lnglat objects can be created from and converted back to R objects", {
+  # in
+  expect_is(s2_lnglat(45, 64), "s2_lnglat")
+  expect_length(s2_lnglat(45, 64), 1)
+  expect_is(as_s2_lnglat(matrix(45, 64, ncol = 2)), "s2_lnglat")
+  lnglat <- s2_lnglat(45, 64)
+  expect_identical(as_s2_lnglat(lnglat), lnglat)
+  expect_identical(
+    as.data.frame(as_s2_lnglat(s2_point(1, 0, 0))),
+    as.data.frame(s2_lnglat(0, 0))
+  )
+
+  # subset assignment
+  lnglat2 <- lnglat
+  lnglat2[1] <- lnglat
+  expect_identical(lnglat2, lnglat)
+
+  lnglat2 <- lnglat
+  lnglat2[[1]] <- lnglat
+  expect_identical(lnglat2, lnglat)
+
+  # out
+  expect_identical(as.data.frame(s2_lnglat(-64, 45)), data.frame(lng = -64, lat = 45))
+  expect_identical(as.matrix(s2_lnglat(-64, 45)), as.matrix(data.frame(lng = -64, lat = 45)))
+
+  # zero-length in and out
+  expect_length(s2_lnglat(double(), double()), 0)
+  expect_identical(
+    as.data.frame(s2_lnglat(double(), double())),
+    data.frame(lng = double(), lat = double())
+  )
+
+  # NAs and NULLs
+  expect_identical(
+    as.data.frame(s2_lnglat(double(), double())[NA]),
+    data.frame(lng = NA_real_, lat = NA_real_)
+  )
+})
+
+test_that("s2_lnglat can be imported/exported to/from wkb and wkt", {
+  wkb_point <- wk::as_wkb("POINT (-64 45)")
+  expect_wkt_equal(wk::as_wkb(s2_lnglat(-64, 45)), wkb_point)
+  expect_wkt_equal(wk::as_wkt(s2_lnglat(-64, 45)), wk::wkt("POINT (-64 45)"))
+  expect_identical(wk::as_wkt(s2_lnglat(NA, NA)), wk::wkt("POINT EMPTY"))
+
+  expect_equal(
+    as.data.frame(as_s2_lnglat(wk::as_wkb(c("POINT EMPTY", "POINT (-64 45)")))),
+    data.frame(lng = c(NA, -64), lat = c(NA, 45))
+  )
+
+  expect_equal(
+    as.data.frame(as_s2_lnglat(c("POINT EMPTY", "POINT (-64 45)"))),
+    data.frame(lng = c(NA, -64), lat = c(NA, 45))
+  )
+
+  expect_equal(
+    as.data.frame(as_s2_lnglat(wk::wkt(c("POINT EMPTY", "POINT (-64 45)")))),
+    data.frame(lng = c(NA, -64), lat = c(NA, 45))
+  )
+
+  expect_error(as_s2_lnglat(wk::wkt("LINESTRING EMPTY")), "non-point")
+  expect_error(as_s2_lnglat(wk::as_wkb("LINESTRING EMPTY")), "non-point")
+})
+
+test_that("s2_lnglat vectors can't have other types of objects concatenated or asssigned", {
+  lnglat <- new_s2_xptr(list(NULL), class = "s2_lnglat")
+  expect_is(c(lnglat, lnglat), "s2_lnglat")
+  expect_error(c(lnglat, new_s2_xptr(list(), class = "some_other_class")), "All items must inherit")
+  expect_error(lnglat[1] <- new_s2_xptr(list(NULL), class = "some_other_class"), "no applicable method")
+  expect_error(lnglat[[1]] <- new_s2_xptr(list(NULL), class = "some_other_class"), "no applicable method")
+})
+
+test_that("s2_lnglat can be imported from s2_geography", {
+  expect_equal(
+    as.data.frame(as_s2_lnglat(as_s2_geography("POINT (-64 45)"))),
+    data.frame(lng = -64, lat = 45)
+  )
+})
+
+test_that("s2_lnglat can be imported from wkb", {
+  wkb_point <- wk::as_wkb("POINT (-64 45)")
+
+  expect_equal(
+    as.data.frame(as_s2_lnglat(wkb_point)),
+    data.frame(lng = -64, lat = 45)
+  )
+})
+
+test_that("s2_lnglat objects can be printed", {
+  expect_output(print(s2_lnglat(-64, 45)), "s2_lnglat")
+})
diff --git a/tests/testthat/test-s2-matrix.R b/tests/testthat/test-s2-matrix.R
new file mode 100644 (file)
index 0000000..8de2852
--- /dev/null
@@ -0,0 +1,249 @@
+
+test_that("s2_closest|farthest_feature() works", {
+  cities <- s2_data_cities("London")
+  countries <- s2_data_countries()
+
+  # with zero length y, results will all be empty
+  expect_identical(s2_closest_feature(cities, character(0)), rep_len(NA_integer_, length(cities)))
+
+  # should correctly identify that London is closest to United Kingdom
+  country_match <- s2_closest_feature(cities, countries)
+  expect_identical(s2_data_tbl_countries$name[country_match], "United Kingdom")
+
+  country_match_farthest <- s2_farthest_feature(cities, countries)
+  expect_identical(s2_data_tbl_countries$name[country_match_farthest], "New Zealand")
+})
+
+test_that("s2_closest_edges() works", {
+  expect_identical(
+    s2_closest_edges(
+      "POINT (0 0)",
+      c("POINT (0 0)", "POINT (0 1)", "POINT (0 2)", "POINT (0 3)"),
+      k = 1
+    ),
+    list(1L)
+  )
+
+  expect_identical(
+    s2_closest_edges(
+      "POINT (0 0)",
+      c("POINT (0 0)", "POINT (0 1)", "POINT (0 2)", "POINT (0 3)"),
+      k = 2,
+      min_distance = 0
+    ),
+    list(2L)
+  )
+
+  expect_identical(
+    s2_closest_edges(
+      "POINT (0 0)",
+      c("POINT (0 0)", "POINT (0 1)", "POINT (0 2)", "POINT (0 3)"),
+      k = 5
+    ) %>% lapply(sort),
+    list(1:4)
+  )
+})
+
+test_that("matrix predicates work", {
+  expect_identical(
+    s2_contains_matrix(
+      "POLYGON ((0 0, 1 0, 1 1, 0 1, 0 0))",
+      c("POINT (-1 0.5)", "POINT (0.5 0.5)", "POINT (2 0.5)"),
+    ),
+    list(2L)
+  )
+
+  expect_identical(
+    s2_within_matrix(
+      c("POINT (-1 0.5)", "POINT (0.5 0.5)", "POINT (2 0.5)"),
+      "POLYGON ((0 0, 1 0, 1 1, 0 1, 0 0))"
+    ),
+    list(integer(0), 1L, integer(0))
+  )
+
+  expect_identical(
+    s2_covers_matrix(
+      "POLYGON ((0 0, 1 0, 1 1, 0 1, 0 0))",
+      c("POINT (-1 0.5)", "POINT (0.5 0.5)", "POINT (2 0.5)"),
+    ),
+    list(2L)
+  )
+
+  expect_identical(
+    s2_covered_by_matrix(
+      c("POINT (-1 0.5)", "POINT (0.5 0.5)", "POINT (2 0.5)"),
+      "POLYGON ((0 0, 1 0, 1 1, 0 1, 0 0))"
+    ),
+    list(integer(0), 1L, integer(0))
+  )
+
+  expect_identical(
+    s2_intersects_matrix(
+      c("POINT (-1 0.5)", "POINT (0.5 0.5)", "POINT (2 0.5)"),
+      "POLYGON ((0 0, 1 0, 1 1, 0 1, 0 0))"
+    ),
+    list(integer(0), 1L, integer(0))
+  )
+
+  expect_identical(
+    s2_disjoint_matrix(
+      c("POINT (-1 0.5)", "POINT (0.5 0.5)", "POINT (2 0.5)"),
+      "POLYGON ((0 0, 1 0, 1 1, 0 1, 0 0))"
+    ),
+    list(1L, integer(0), 1L)
+  )
+
+  expect_identical(
+    s2_equals_matrix(
+      c("POINT (-1 0.5)", "POINT (0.5 0.5)", "POINT (2 0.5)",
+        "POLYGON ((1 0, 1 1, 0 1, 0 0, 1 0))"),
+      "POLYGON ((0 0, 1 0, 1 1, 0 1, 0 0))"
+    ),
+    list(integer(0), integer(0), integer(0), 1L)
+  )
+
+  expect_identical(
+    s2_touches_matrix(
+      c("POINT (0.5 0.5)", "POINT (0 0)", "POINT  (-0.5 -0.5)"),
+      "POLYGON ((0 0, 0 1, 1 1, 0 0))"
+    ),
+    list(integer(0), 1L, integer(0))
+  )
+
+  expect_identical(
+    s2_dwithin_matrix(
+      c("POINT (-1 0.5)", "POINT (0.5 0.5)", "POINT (2 0.5)"),
+      "POLYGON ((0 0, 1 0, 1 1, 0 1, 0 0))",
+      0
+    ),
+    list(integer(0), 1L, integer(0))
+  )
+  expect_identical(
+    s2_dwithin_matrix(
+      c("POINT (-1 0.5)", "POINT (0.5 0.5)", "POINT (2 0.5)"),
+      "POLYGON ((0 0, 1 0, 1 1, 0 1, 0 0))",
+      s2_earth_radius_meters()
+    ),
+    list(1L, 1L, 1L)
+  )
+})
+
+test_that("s2_(max_)?distance_matrix() works", {
+  x <- c("POINT (0 0)", "POINT (0 90)")
+  y <- c("POINT (180 0)", "POINT (0 -90)", "POINT (0 0)")
+
+  expect_equal(
+    s2_distance_matrix(x, x, radius = 180 / pi),
+    matrix(c(0, 90, 90, 0), ncol = 2)
+  )
+  expect_equal(
+    s2_distance_matrix(x, y, radius = 180 / pi),
+    matrix(c(180, 90, 90, 180, 0, 90), ncol = 3)
+  )
+
+  # max distance is the same for points
+  expect_equal(
+    s2_max_distance_matrix(x, x, radius = 180 / pi),
+    matrix(c(0, 90, 90, 0), ncol = 2)
+  )
+
+  expect_equal(
+    s2_max_distance_matrix(x, y, radius = 180 / pi),
+    matrix(c(180, 90, 90, 180, 0, 90), ncol = 3)
+  )
+
+  # NA handling for both rows and cols
+  y[2] <- NA
+  expect_true(all(is.na(s2_distance_matrix(x, y)[, 2])))
+  expect_true(all(is.na(s2_max_distance_matrix(x, y)[, 2])))
+
+  x[2] <- NA
+  expect_true(all(is.na(s2_distance_matrix(x, y)[2, ])))
+  expect_true(all(is.na(s2_max_distance_matrix(x, y)[2, ])))
+})
+
+test_that("s2_may_intersect_matrix() works", {
+  countries <- s2_data_countries()
+  timezones <- s2_data_timezones()
+
+  maybe_intersects <- s2_may_intersect_matrix(countries, timezones)
+  intersects <- s2_intersects_matrix_brute_force(countries, timezones)
+  for (i in seq_along(countries)) {
+    expect_identical(setdiff(intersects[[!!i]], maybe_intersects[[!!i]]), integer(0))
+  }
+})
+
+test_that("indexed matrix predicates return the same thing as brute-force comparisons", {
+  countries <- s2_data_countries()
+  timezones <- s2_data_timezones()
+
+  # contains
+  expect_identical(
+    s2_contains_matrix(countries, countries),
+    s2_contains_matrix_brute_force(countries, countries)
+  )
+  expect_identical(
+    s2_contains_matrix(timezones, countries),
+    s2_contains_matrix_brute_force(timezones, countries)
+  )
+
+  # within
+  expect_identical(
+    s2_within_matrix(countries, countries),
+    s2_within_matrix_brute_force(countries, countries)
+  )
+  expect_identical(
+    s2_within_matrix(timezones, countries),
+    s2_within_matrix_brute_force(timezones, countries)
+  )
+
+  # covers
+  expect_identical(
+    s2_covers_matrix(countries, countries),
+    s2_covers_matrix_brute_force(countries, countries)
+  )
+  expect_identical(
+    s2_covers_matrix(timezones, countries),
+    s2_covers_matrix_brute_force(timezones, countries)
+  )
+
+  # covered by
+  expect_identical(
+    s2_covered_by_matrix(countries, countries),
+    s2_covered_by_matrix_brute_force(countries, countries)
+  )
+  expect_identical(
+    s2_covered_by_matrix(timezones, countries),
+    s2_covered_by_matrix_brute_force(timezones, countries)
+  )
+
+  # intersects
+  expect_identical(
+    s2_intersects_matrix(countries, countries),
+    s2_intersects_matrix_brute_force(countries, countries)
+  )
+  expect_identical(
+    s2_intersects_matrix(timezones, countries),
+    s2_intersects_matrix_brute_force(timezones, countries)
+  )
+
+  # disjoint
+  expect_identical(
+    s2_disjoint_matrix(countries, countries),
+    s2_disjoint_matrix_brute_force(countries, countries)
+  )
+  expect_identical(
+    s2_disjoint_matrix(timezones, countries),
+    s2_disjoint_matrix_brute_force(timezones, countries)
+  )
+
+  # equals
+  expect_identical(
+    s2_equals_matrix(countries, countries),
+    s2_equals_matrix_brute_force(countries, countries)
+  )
+  expect_identical(
+    s2_equals_matrix(timezones, countries),
+    s2_equals_matrix_brute_force(timezones, countries)
+  )
+})
diff --git a/tests/testthat/test-s2-options.R b/tests/testthat/test-s2-options.R
new file mode 100644 (file)
index 0000000..cb39765
--- /dev/null
@@ -0,0 +1,11 @@
+
+test_that("s2_options() works", {
+  expect_is(s2_options(), "s2_options")
+})
+
+test_that("s2_options() errors are readable", {
+  expect_error(s2_intersects("POINT EMPTY", "POINT EMPTY", options = NULL), "must be created using")
+  expect_error(s2_options(model = "not a model"), "must be one of")
+  expect_error(s2_options(snap_radius = 100), "radius is too large")
+  expect_error(s2_snap_level(31), "between 1 and 30")
+})
diff --git a/tests/testthat/test-s2-point.R b/tests/testthat/test-s2-point.R
new file mode 100644 (file)
index 0000000..0016bab
--- /dev/null
@@ -0,0 +1,57 @@
+
+test_that("s2_point objects can be created from and converted back to R objects", {
+  # in
+  expect_is(s2_point(1, 2, 3), "s2_point")
+  expect_length(s2_point(1, 2, 3), 1)
+  expect_is(as_s2_point(matrix(1, 2, 3, ncol = 3)), "s2_point")
+  point <- s2_point(1, 2, 3)
+  expect_identical(as_s2_point(point), point)
+  expect_identical(
+    as.data.frame(as_s2_point(s2_lnglat(0, 0))),
+    as.data.frame(s2_point(1, 0, 0))
+  )
+
+  # subset assignment
+  point2 <- point
+  point2[1] <- point
+  expect_identical(point2, point)
+
+  point2 <- point
+  point2[[1]] <- point
+  expect_identical(point2, point)
+
+  # out
+  expect_identical(as.data.frame(s2_point(1, 2, 3)), data.frame(x = 1, y = 2, z = 3))
+  expect_identical(as.matrix(s2_point(1, 2, 3)), as.matrix(data.frame(x = 1, y = 2, z = 3)))
+
+  # zero-length
+  expect_length(s2_point(double(), double(), double()), 0)
+  expect_identical(
+    as.data.frame(s2_point(double(), double(), double())),
+    data.frame(x = double(), y = double(), z = double())
+  )
+
+  expect_identical(
+    as.data.frame(s2_point(double(), double(), double())[NA]),
+    data.frame(x = NA_real_, y = NA_real_, z = NA_real_)
+  )
+})
+
+test_that("s2_point vectors can't have other types of objects concatenated or asssigned", {
+  point <- new_s2_xptr(list(NULL), class = "s2_point")
+  expect_is(c(point, point), "s2_point")
+  expect_error(c(point, new_s2_xptr(list(), class = "some_other_class")), "All items must inherit")
+  expect_error(point[1] <- new_s2_xptr(list(NULL), class = "some_other_class"), "no applicable method")
+  expect_error(point[[1]] <- new_s2_xptr(list(NULL), class = "some_other_class"), "no applicable method")
+})
+
+test_that("s2_point can be imported from s2_geography", {
+  expect_equal(
+    as.data.frame(as_s2_point(as_s2_geography("POINT (-64 45)"))),
+    as.data.frame(as_s2_point(as_s2_lnglat(as_s2_geography("POINT (-64 45)")))),
+  )
+})
+
+test_that("s2_point objects can be printed", {
+  expect_output(print(s2_point(1, 2, 3)), "s2_point")
+})
diff --git a/tests/testthat/test-s2-predicates.R b/tests/testthat/test-s2-predicates.R
new file mode 100644 (file)
index 0000000..2f201ba
--- /dev/null
@@ -0,0 +1,165 @@
+
+test_that("s2_contains() works", {
+  expect_identical(s2_contains("POINT (0 0)", NA_character_), NA)
+
+  expect_true(s2_contains("POINT (0 0)", "POINT (0 0)"))
+  expect_false(s2_contains("POINT (0 0)", "POINT (1 1)"))
+  expect_false(s2_contains("POINT (0 0)", "POINT EMPTY"))
+
+  # make sure model is passed on to at least one binary predicate
+  # in the open model, lines do not contain endpoints (but do contain other points)
+  expect_false(s2_contains("LINESTRING (0 0, 0 1, 1 1)", "POINT (0 0)", s2_options(model = "open")))
+  expect_true(s2_contains("LINESTRING (0 0, 0 1, 1 1)", "POINT (0 1)", s2_options(model = "open")))
+  expect_false(s2_contains("LINESTRING (0 0, 0 1, 1 1)", "POINT (0 0.5)", s2_options(model = "open")))
+
+  # semi-open and closed: endpoints are contained
+  expect_true(s2_contains("LINESTRING (0 0, 0 1, 1 1)", "POINT (0 0)", s2_options(model = "semi-open")))
+  expect_true(s2_contains("LINESTRING (0 0, 0 1, 1 1)", "POINT (0 1)", s2_options(model = "semi-open")))
+  expect_false(s2_contains("LINESTRING (0 0, 0 1, 1 1)", "POINT (0 0.5)", s2_options(model = "semi-open")))
+
+  expect_true(s2_contains("LINESTRING (0 0, 0 1, 1 1)", "POINT (0 0)", s2_options(model = "closed")))
+  expect_true(s2_contains("LINESTRING (0 0, 0 1, 1 1)", "POINT (0 1)", s2_options(model = "closed")))
+  expect_false(s2_contains("LINESTRING (0 0, 0 1, 1 1)", "POINT (0 0.5)", s2_options(model = "closed")))
+})
+
+test_that("s2_covers() and s2_covered_by() work", {
+  expect_true(s2_covers("POINT (0 0)", "POINT (0 0)"))
+  expect_false(s2_covers("POINT (0 0)", "POINT (1 1)"))
+  expect_false(s2_covers("POINT (0 0)", "POINT EMPTY"))
+  expect_true(s2_covers("LINESTRING (0 0, 1 1)", "POINT (0 0)"))
+  expect_false(s2_covers("LINESTRING (0 0, 1 1)", "POINT (-1 -1)"))
+
+  # make sure line is along a geodesic edge
+  # if the line doesn't contain the endpoints, floating
+  # point math won't always keep it strictly inside or outside
+  # the polygon (hard to predict which way it will go)
+  # (when the model is set such that the boundary of the polygon
+  # is considered 'contained' by it)
+  polygon <- "POLYGON ((0 0, 1 1, 0 1, 0 0))"
+  line <- "LINESTRING (0 0, 1 1)"
+  point <- "POINT (0.5 0.7)"
+
+  expect_true(s2_covers(polygon, polygon))
+  expect_false(s2_covers(polygon, line, s2_options(model = "open")))
+  expect_false(s2_covers(polygon, line, s2_options(model = "semi-open")))
+  expect_true(s2_covers(polygon, line, s2_options(model = "closed")))
+  expect_true(s2_covers(polygon, point, s2_options(model = "open")))
+  expect_true(s2_covers(polygon, point, s2_options(model = "semi-open")))
+  expect_true(s2_covers(polygon, point, s2_options(model = "closed")))
+  expect_false(s2_covered_by(polygon, line, s2_options(model = "open")))
+  expect_false(s2_covered_by(polygon, line, s2_options(model = "semi-open")))
+  expect_false(s2_covered_by(polygon, line, s2_options(model = "closed")))
+  expect_true(s2_covered_by(point, polygon, s2_options(model = "open")))
+  expect_true(s2_covered_by(point, polygon, s2_options(model = "semi-open")))
+  expect_true(s2_covered_by(point, polygon, s2_options(model = "closed")))
+})
+
+test_that("s2_disjoint() works", {
+  expect_identical(s2_disjoint("POINT (0 0)", NA_character_), NA)
+
+  expect_false(s2_disjoint("POINT (0 0)", "POINT (0 0)"))
+  expect_true(s2_disjoint("POINT (0 0)", "POINT (1 1)"))
+  expect_true(s2_disjoint("POINT (0 0)", "POINT EMPTY"))
+
+  expect_false(s2_disjoint("LINESTRING (0 0, 1 1)", "POINT (0 0)"))
+  expect_true(s2_disjoint("LINESTRING (0 0, 1 1)", "POINT (-1 -1)"))
+})
+
+test_that("s2_equals() works", {
+  expect_identical(s2_equals("POINT (0 0)", NA_character_), NA)
+
+  expect_true(s2_equals("POINT (0 0)", "POINT (0 0)"))
+  expect_true(s2_equals("POINT (0 0)", "POINT (0 0)", s2_options(model = "open")))
+  expect_true(s2_equals("POINT (0 0)", "POINT (0 0)", s2_options(model = "semi-open")))
+  expect_true(s2_equals("POINT (0 0)", "POINT (0 0)", s2_options(model = "closed")))
+  expect_false(s2_equals("POINT (0 0)", "POINT (1 1)"))
+  expect_false(s2_equals("POINT (0 0)", "POINT EMPTY"))
+  expect_true(s2_equals("POINT EMPTY", "POINT EMPTY"))
+
+  expect_true(s2_equals("LINESTRING (0 0, 1 1)", "LINESTRING (1 1, 0 0)"))
+  expect_false(s2_equals("LINESTRING (0 1, 1 1)", "LINESTRING (1 1, 0 0)"))
+})
+
+test_that("s2_intersects() works", {
+  expect_identical(s2_intersects("POINT (0 0)", NA_character_), NA)
+
+  expect_true(s2_intersects("POINT (0 0)", "POINT (0 0)"))
+  expect_false(s2_intersects("POINT (0 0)", "POINT (1 1)"))
+  expect_false(s2_intersects("POINT (0 0)", "POINT EMPTY"))
+
+  expect_true(s2_intersects("LINESTRING (0 0, 1 1)", "LINESTRING (1 0, 0 1)"))
+  expect_false(s2_intersects("LINESTRING (0 0, 1 1)", "LINESTRING (-2 -2, -1 -1)"))
+  expect_true(s2_intersects("LINESTRING (0 0, 1 1)", "POINT (0 0)"))
+  expect_false(s2_intersects("LINESTRING (0 0, 1 1)", "POINT (0 0)", s2_options(model = "open")))
+  expect_true(s2_intersects("LINESTRING (0 0, 1 1)", "POINT (0 0)", s2_options(model = "semi-open")))
+  expect_true(s2_intersects("LINESTRING (0 0, 1 1)", "POINT (0 0)", s2_options(model = "closed")))
+  polygon = "POLYGON((0 0,1 0,1 1,0 1,0 0))"
+  expect_false(s2_intersects(polygon, "POINT (0 0)"))
+  expect_false(s2_intersects(polygon, "POINT (0 0)", s2_options(model = "open")))
+  expect_false(s2_intersects(polygon, "POINT (0 0)", s2_options(model = "semi-open")))
+  expect_true(s2_intersects(polygon, "POINT (0 0)", s2_options(model = "closed")))
+})
+
+test_that("s2_intersects_box() works", {
+  expect_error(
+    s2_intersects_box("POINT (-1 -1)", -2, -2, 2, 2, detail = 0),
+    "Can't create polygon"
+  )
+  expect_true(s2_intersects_box("POINT (0.1 0.1)", 0, 0, 1, 1))
+  expect_true(s2_intersects_box("POINT (0.1 0.1)", 0, 0, 1, 1))
+  expect_true(s2_intersects_box("POINT (0.1 0.1)", 0, 0, 1, 1, options = s2_options(model = "open")))
+  expect_true(s2_intersects_box("POINT (0.1 0.1)", 0, 0, 1, 1, options = s2_options(model = "semi-open")))
+  expect_true(s2_intersects_box("POINT (0.1 0.1)", 0, 0, 1, 1, options = s2_options(model = "closed")))
+
+  expect_false(s2_intersects_box("POINT (1 1)", 0, 0, 1, 1))
+  expect_false(s2_intersects_box("POINT (0 0)", 0, 0, 1, 1))
+  expect_false(s2_intersects_box("POINT (0 0)", 0, 0, 1, 1))
+  expect_false(s2_intersects_box("POINT (0 0)", 0, 0, 1, 1, options = s2_options(model = "open")))
+  expect_false(s2_intersects_box("POINT (0 0)", 0, 0, 1, 1, options = s2_options(model = "semi-open")))
+  expect_true(s2_intersects_box("POINT (0 0)", 0, 0, 1, 1, options = s2_options(model = "closed")))
+
+  expect_true(s2_intersects_box("POINT (-1 -1)", -2, -2, 2, 2))
+  expect_false(s2_intersects_box("POINT (-1 -1)", 0, 0, 2, 2))
+  expect_false(s2_intersects_box("POINT (0 0)", 1, 1, 2, 2))
+})
+
+test_that("s2_within() works", {
+  expect_identical(s2_within("POINT (0 0)", NA_character_), NA)
+
+  expect_true(s2_within("POINT (0 0)", "POINT (0 0)"))
+  expect_false(s2_within("POINT (0 0)", "POINT (1 1)"))
+  expect_false(s2_within("POINT (0 0)", "POINT EMPTY"))
+  expect_false(s2_within("POINT EMPTY", "POINT (0 0)"))
+
+  expect_true(s2_within("POINT (0 0)", "LINESTRING (0 0, 1 1)", s2_options(model = "semi-open")))
+  expect_false(s2_within("POINT (0 0)", "LINESTRING (0 0, 1 1)", s2_options(model = "open")))
+  expect_false(s2_within("POINT (0 0)", "LINESTRING (1 1, 2 2)"))
+})
+
+test_that("s2_touches() works", {
+  # is inside
+  expect_false(s2_touches("POLYGON ((0 0, 0 1, 1 1, 0 0))", "POINT (0.5 0.75)"))
+  # is outside
+  expect_false(s2_touches("POLYGON ((0 0, 0 1, 1 1, 0 0))", "POINT (-0.5 0.75)"))
+
+  # is vertex
+  expect_true(s2_touches("POLYGON ((0 0, 0 1, 1 1, 0 0))", "POINT (0 0)"))
+})
+
+test_that("s2_dwithin() works", {
+  expect_identical(s2_dwithin("POINT (0 0)", NA_character_, 0), NA)
+
+  expect_true(s2_dwithin("POINT (0 0)", "POINT (90 0)", pi / 2 + 0.01, radius = 1))
+  expect_false(s2_dwithin("POINT (0 0)", "POINT (90 0)", pi / 2 - 0.01, radius = 1))
+  expect_false(s2_dwithin("POINT (0 0)", "POINT EMPTY", 0))
+
+  expect_true(s2_dwithin("LINESTRING (-45 0, 45 0)", "POINT (0 20)", 21, radius = 180 / pi))
+  expect_false(s2_dwithin("LINESTRING (-45 0, 45 0)", "POINT (0 20)", 19, radius = 180 / pi))
+
+  # check vectorization
+  expect_identical(
+    s2_dwithin("POINT (0 0)", "POINT (90  0)", pi / 2 + c(0.01, -0.01), radius = 1),
+    c(TRUE, FALSE)
+  )
+})
+
diff --git a/tests/testthat/test-s2-transformers.R b/tests/testthat/test-s2-transformers.R
new file mode 100644 (file)
index 0000000..db2619f
--- /dev/null
@@ -0,0 +1,622 @@
+
+test_that("s2_centroid() works", {
+  expect_wkt_equal(s2_centroid("POINT (30 10)"), "POINT (30 10)")
+  expect_true(s2_is_empty(s2_centroid("POINT EMPTY")))
+  expect_wkt_equal(s2_centroid("MULTIPOINT ((0 0), (0 10))"), "POINT (0 5)")
+  expect_wkt_equal(s2_centroid("LINESTRING (0 0, 0 10)"), "POINT (0 5)", precision = 15)
+  expect_near(
+    s2_distance(
+      s2_centroid("POLYGON ((-5 -5, 5 -5, 5 5, -5 5, -5 -5))"),
+      "POINT (0 0)"
+    ),
+    0,
+    epsilon = 1e-6
+  )
+})
+
+test_that("s2_centroid() and s2_centroid_agg() normalize points", {
+  expect_equal(
+    s2_distance(
+      s2_centroid("MULTIPOINT (1 1, 1 1)"),
+      "POINT (1 1)"
+    ),
+    0
+  )
+
+  expect_equal(
+    s2_distance(
+      s2_centroid_agg(c("POINT (1 1)", "POINT (1 1)")),
+      "POINT (1 1)"
+    ),
+    0
+  )
+})
+
+test_that("s2_boundary() works", {
+  expect_true(s2_is_empty(s2_boundary("POINT (30 10)")))
+  expect_true(s2_is_empty(s2_boundary("POINT EMPTY")))
+  expect_true(s2_is_empty(s2_boundary("POLYGON EMPTY")))
+  expect_wkt_equal(s2_boundary("LINESTRING (0 0, 0 10)"), "MULTIPOINT ((0 0), (0 10))")
+
+  expect_wkt_equal(
+    s2_boundary("MULTIPOLYGON (
+        ((40 40, 20 45, 45 30, 40 40)),
+        ((20 35, 10 30, 10 10, 30 5, 45 20, 20 35), (30 20, 20 15, 20 25, 30 20))
+    )"),
+    "MULTILINESTRING (
+        (40 40, 20 45, 45 30, 40 40),
+        (20 35, 10 30, 10 10, 30 5, 45 20, 20 35), (30 20, 20 15, 20 25, 30 20)
+    )",
+    precision = 15
+  )
+})
+
+test_that("s2_closest_point() works", {
+  expect_wkt_equal(s2_closest_point("POINT (0 1)", "POINT (30 10)"), "POINT (0 1)")
+  expect_wkt_equal(s2_closest_point("LINESTRING (0 1, -12 -12)", "POINT (30 10)"), "POINT (0 1)")
+})
+
+test_that("s2_minimum_clearance_line_between() works", {
+  expect_wkt_equal(
+    s2_minimum_clearance_line_between("POINT (0 1)", "POINT (30 10)"),
+    "LINESTRING (0 1, 30 10)"
+  )
+  expect_true(s2_is_empty(s2_minimum_clearance_line_between("POINT (30 10)", "POINT EMPTY")))
+
+  expect_wkt_equal(
+    s2_minimum_clearance_line_between("LINESTRING (0 1, -12 -12)", "POINT (30 10)"),
+    "LINESTRING (0 1, 30 10)"
+  )
+  expect_wkt_equal(
+    s2_minimum_clearance_line_between("LINESTRING (0 0, 1 1)", "LINESTRING (1 0, 0 1)"),
+    "MULTIPOINT ((0.5 0.500057), (0.5 0.500057))",
+       precision = 6
+  )
+})
+
+test_that("s2_difference() works", {
+  expect_wkt_equal(s2_difference("POINT (30 10)", "POINT EMPTY"), "POINT (30 10)")
+  expect_true(s2_is_empty(s2_difference("POINT (30 10)", "POINT (30 10)")))
+
+  expect_true(s2_is_empty(s2_difference("LINESTRING (0 0, 45 0)", "LINESTRING (0 0, 45 0)")))
+})
+
+test_that("s2_difference() works for polygons", {
+  # on Windows i386, these fail without snap rounding
+  df <- s2_difference(
+    "POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0))",
+    "POLYGON ((5 5, 15 5, 15 15, 5 15, 5 5))",
+    s2_options(snap = s2_snap_level(30))
+  )
+
+  expect_near(
+    s2_area(df, radius = 1),
+    s2_area("POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0))", radius = 1) -
+      s2_area("POLYGON ((5 5, 10 5, 10 15, 5 10, 5 5))", radius = 1),
+    epsilon = 0.004
+  )
+
+  df0 <- s2_difference(
+    "POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0))",
+    "POLYGON ((5 5, 15 5, 15 15, 5 15, 5 5))" ,
+    s2_options(model = "open", snap = s2_snap_level(30))
+  )
+  df1 <- s2_difference(
+    "POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0))",
+    "POLYGON ((5 5, 15 5, 15 15, 5 15, 5 5))" ,
+    s2_options(model = "semi-open", snap = s2_snap_level(30))
+  )
+  df2 <- s2_difference(
+    "POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0))",
+    "POLYGON ((5 5, 15 5, 15 15, 5 15, 5 5))" ,
+    s2_options(model = "closed", snap = s2_snap_level(30))
+  )
+  expect_equal(s2_area(df0) - s2_area(df2), 0.0)
+  expect_equal(s2_area(df0) - s2_area(df1), 0.0)
+})
+
+test_that("s2_sym_difference() works", {
+  expect_wkt_equal(s2_sym_difference("POINT (30 10)", "POINT EMPTY"), "POINT (30 10)")
+  expect_true(s2_is_empty(s2_sym_difference("POINT (30 10)", "POINT (30 10)")))
+  expect_wkt_equal(s2_sym_difference("POINT (30 10)", "POINT (30 20)"), "MULTIPOINT ((30 20), (30 10))")
+
+  expect_true(s2_is_empty(s2_sym_difference("LINESTRING (0 0, 45 0)", "LINESTRING (0 0, 45 0)")))
+})
+
+test_that("s2_sym_difference() works for polygons", {
+  # on Windows i386, these fail without snap rounding
+  df <- s2_sym_difference(
+    "POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0))",
+    "POLYGON ((5 5, 15 5, 15 15, 5 15, 5 5))",
+    s2_options(snap = s2_snap_level(30))
+  )
+
+  expect_near(
+    s2_area(df, radius = 1),
+    2 * s2_area("POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0))", radius = 1) -
+      s2_area("POLYGON ((5 5, 10 5, 10 15, 5 10, 5 5))", radius = 1),
+    epsilon = 0.0042
+  )
+
+  df0 <- s2_sym_difference(
+    "POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0))",
+    "POLYGON ((5 5, 15 5, 15 15, 5 15, 5 5))" ,
+    s2_options(model = "open", snap = s2_snap_level(30))
+  )
+
+  df1 <- s2_sym_difference(
+    "POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0))",
+    "POLYGON ((5 5, 15 5, 15 15, 5 15, 5 5))" ,
+    s2_options(model = "semi-open", snap = s2_snap_level(30))
+  )
+
+  df2 = s2_sym_difference(
+    "POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0))",
+    "POLYGON ((5 5, 15 5, 15 15, 5 15, 5 5))",
+    s2_options(model = "closed", snap = s2_snap_level(30))
+  )
+  expect_equal(s2_area(df0) - s2_area(df2), 0.0)
+  expect_equal(s2_area(df0) - s2_area(df1), 0.0)
+})
+
+test_that("s2_intersection() works", {
+  expect_wkt_equal(s2_intersection("POINT (30 10)", "POINT (30 10)"), "POINT (30 10)")
+  expect_true(s2_is_empty(s2_intersection("POINT (30 10)", "POINT (30 11)")))
+
+  expect_wkt_equal(
+    s2_intersection(
+      "POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0))",
+      "LINESTRING (0 5, 10 5)"
+    ),
+    "LINESTRING (0 5, 10 5)"
+  )
+
+  expect_equal(
+    s2_distance(
+      s2_intersection("LINESTRING (-45 0, 45 0)", "LINESTRING (0 -10, 0 10)"),
+      "POINT (0 0)"
+    ),
+    0
+  )
+})
+
+test_that("s2_intersction() works for polygons", {
+  expect_wkt_equal(
+    s2_intersection(
+      "POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0))",
+      "POLYGON ((5 5, 15 5, 15 15, 5 15, 5 5))",
+      s2_options(snap = s2_snap_level(30))
+    ),
+    "POLYGON ((5 5, 10 5, 10 10, 5 10, 5 5))",
+    precision = 2
+  )
+  expect_true(s2_is_empty(s2_intersection("POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0))", "POINT(0 0)")))
+  expect_true(
+    s2_is_empty(
+      s2_intersection(
+        "POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0))", "POINT(0 0)", s2_options(model = "open")
+      )
+    )
+  )
+  expect_true(
+    s2_is_empty(
+      s2_intersection("POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0))", "POINT(0 0)", s2_options(model = "semi-open"))
+    )
+  )
+  expect_wkt_equal(
+    s2_intersection("POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0))", "POINT(0 0)", s2_options(model = "closed")),
+    "POINT(0 0)"
+  )
+
+  df0 <- s2_intersection(
+    "POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0))",
+    "POLYGON ((5 5, 15 5, 15 15, 5 15, 5 5))" ,
+    s2_options(model = "open")
+  )
+  df1 <- s2_intersection(
+    "POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0))",
+    "POLYGON ((5 5, 15 5, 15 15, 5 15, 5 5))" ,
+    s2_options(model = "semi-open")
+  )
+  df2 <- s2_intersection(
+    "POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0))",
+    "POLYGON ((5 5, 15 5, 15 15, 5 15, 5 5))" ,
+    s2_options(model = "closed")
+  )
+
+  expect_equal(s2_area(df0) - s2_area(df2), 0.0)
+  expect_equal(s2_area(df0) - s2_area(df1), 0.0)
+})
+
+test_that("s2_union(x) works", {
+  expect_wkt_equal(s2_union("POINT (30 10)"), "POINT (30 10)")
+  expect_wkt_equal(s2_union("POINT EMPTY"), "GEOMETRYCOLLECTION EMPTY")
+  expect_wkt_equal(
+    s2_union("MULTILINESTRING ((-45 0, 0 0), (0 0, 0 10))"),
+    "LINESTRING (-45 0, 0 0, 0 10)"
+  )
+
+  expect_wkt_equal(s2_union("GEOMETRYCOLLECTION (POINT (30 10))"), "POINT (30 10)")
+  expect_wkt_equal(
+    s2_union("GEOMETRYCOLLECTION (POINT (30 10), LINESTRING (0 0, 0 1))"),
+    "GEOMETRYCOLLECTION (POINT (30 10), LINESTRING (0 0, 0 1))"
+  )
+})
+
+test_that("s2_union(x) works with polygons that have overlapping input regions", {
+  # two outer loops
+  txt <- "MULTIPOLYGON (((0 0, 0 1, 1 1, 1 0, 0 0)), ((0.1 0.9, 0.1 1.9, 1.1 1.9, 1.1 0.9, 0.1 0.9)))"
+  # geos::geos_unary_union(txt) %>% as_wkb() %>% s2_area(radius = 1)
+  unioned <- s2_union(as_s2_geography(txt, check = F))
+  expect_equal(s2_area(unioned, radius = 1), 0.0005817275)
+
+  # two outer loops, one valid inner loop
+  # geos::geos_unary_union(txt2) %>% as_wkb() %>% s2_area(radius = 1)
+  txt2 <- "MULTIPOLYGON (
+    ((0 0, 0 1, 1 1, 1 0, 0 0), (0.1 0.1, 0.5 0.1, 0.5 0.5, 0.1 0.5, 0.1 0.1)),
+    ((0.1 0.9, 0.1 1.9, 1.1 1.9, 1.1 0.9, 0.1 0.9))
+  )"
+  unioned <- s2_union(as_s2_geography(txt2, check = F))
+  expect_equal(s2_area(unioned, radius = 1), 0.0005329892)
+})
+
+test_that("s2_union(x) errors for the case of mixed dimension collections", {
+  expect_error(
+    s2_union(
+      c("GEOMETRYCOLLECTION(POLYGON ((-10 -10, -10 10, 10 10, 10 -10, -10 -10)), LINESTRING (0 -20, 0 20))")
+    ),
+    "Unary union for collections is not implemented"
+  )
+})
+
+test_that("s2_union(x, y) works", {
+  expect_wkt_equal(s2_union("POINT (30 10)", "POINT EMPTY"), "POINT (30 10)")
+  expect_wkt_equal(s2_union("POINT EMPTY", "POINT EMPTY"), "GEOMETRYCOLLECTION EMPTY")
+
+  # LINESTRING (-45 0, 0 0, 0 10)
+  expect_wkt_equal(
+    s2_union("LINESTRING (-45 0, 0 0)", "LINESTRING (0 0, 0 10)"),
+    "LINESTRING (-45 0, 0 0, 0 10)"
+  )
+})
+
+test_that("s2_union() works for polygons", {
+  # on Windows i386, these fail without snap rounding
+  u <- s2_union(
+    "POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0))",
+    "POLYGON ((5 5, 15 5, 15 15, 5 15, 5 5))",
+    s2_options(snap = s2_snap_level(30))
+  )
+  u0 <- s2_union(
+    "POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0))",
+    "POLYGON ((5 5, 15 5, 15 15, 5 15, 5 5))" ,
+    s2_options(model = "open", snap = s2_snap_level(30))
+  )
+  u1 <- s2_union(
+    "POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0))",
+    "POLYGON ((5 5, 15 5, 15 15, 5 15, 5 5))" ,
+    s2_options(model = "semi-open", snap = s2_snap_level(30))
+  )
+  u2 <- s2_union(
+    "POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0))",
+    "POLYGON ((5 5, 15 5, 15 15, 5 15, 5 5))" ,
+    s2_options(model = "closed", snap = s2_snap_level(30))
+  )
+  expect_equal(s2_area(u0) - s2_area(u2), 0.0)
+  expect_equal(s2_area(u0) - s2_area(u1), 0.0)
+
+
+  expect_near(
+    s2_area(u, radius = 1),
+    s2_area("POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0))", radius = 1) +
+      s2_area("POLYGON ((5 5, 15 5, 15 15, 5 15, 5 5))", radius = 1) -
+      s2_area("POLYGON ((5 5, 10 5, 10 15, 5 10, 5 5))", radius = 1),
+    epsilon = 0.004
+  )
+})
+
+test_that("binary operations use layer creation options", {
+  expect_wkt_equal(
+    s2_union(
+      "LINESTRING (0 0, 0 1, 0 2, 0 1, 0 3)",
+      options = s2_options(polyline_type = "path", polyline_sibling_pairs = "discard")
+    ),
+    "LINESTRING (0 0, 0 1, 0 2, 0 3)"
+  )
+  expect_true(
+    s2_is_collection(
+      s2_union(
+        "LINESTRING (0 0, 0 1, 0 2, 0 1, 0 3)",
+        options = s2_options(polyline_type = "walk")
+      )
+    )
+  )
+
+  expect_wkt_equal(
+    s2_coverage_union_agg(
+      "LINESTRING (0 0, 0 1, 0 2, 0 1, 0 3)",
+      options = s2_options(polyline_type = "path", polyline_sibling_pairs = "discard")
+    ),
+    "LINESTRING (0 0, 0 1, 0 2, 0 3)"
+  )
+  expect_true(
+    s2_is_collection(
+      s2_coverage_union_agg(
+        "LINESTRING (0 0, 0 1, 0 2, 0 1, 0 3)",
+        options = s2_options(polyline_type = "walk")
+      )
+    )
+  )
+})
+
+test_that("s2_coverage_union_agg() works", {
+  expect_wkt_equal(s2_coverage_union_agg(c("POINT (30 10)", "POINT EMPTY")), "POINT (30 10)")
+  expect_wkt_equal(s2_coverage_union_agg(c("POINT EMPTY", "POINT EMPTY")), "GEOMETRYCOLLECTION EMPTY")
+
+  # NULL handling
+  expect_identical(
+    s2_coverage_union_agg(c("POINT (30 10)", NA), na.rm = FALSE),
+    as_s2_geography(NA_character_)
+  )
+  expect_wkt_equal(
+    s2_coverage_union_agg(character()),
+    as_s2_geography("GEOMETRYCOLLECTION EMPTY")
+  )
+  expect_wkt_equal(
+    s2_coverage_union_agg(c("POINT (30 10)", NA), na.rm = TRUE),
+    "POINT (30 10)"
+  )
+})
+
+test_that("s2_union_agg() works", {
+  expect_wkt_equal(s2_union_agg(c("POINT (30 10)", "POINT EMPTY")), "POINT (30 10)")
+  expect_wkt_equal(s2_union_agg(c("POINT EMPTY", "POINT EMPTY")), "GEOMETRYCOLLECTION EMPTY")
+
+  # NULL handling
+  expect_identical(
+    s2_coverage_union_agg(c("POINT (30 10)", NA), na.rm = FALSE),
+    as_s2_geography(NA_character_)
+  )
+  expect_wkt_equal(
+    s2_coverage_union_agg(character()),
+    as_s2_geography("GEOMETRYCOLLECTION EMPTY")
+  )
+  expect_wkt_equal(
+    s2_coverage_union_agg(c("POINT (30 10)", NA), na.rm = TRUE),
+    "POINT (30 10)"
+  )
+})
+
+test_that("s2_rebuild_agg() works", {
+  expect_wkt_equal(s2_rebuild_agg(c("POINT (30 10)", "POINT EMPTY")), "POINT (30 10)")
+  expect_wkt_equal(s2_rebuild_agg(c("POINT EMPTY", "POINT EMPTY")), "GEOMETRYCOLLECTION EMPTY")
+
+  # NULL handling
+  expect_identical(
+    s2_coverage_union_agg(c("POINT (30 10)", NA), na.rm = FALSE),
+    as_s2_geography(NA_character_)
+  )
+  expect_wkt_equal(
+    s2_rebuild_agg(character()),
+    as_s2_geography("GEOMETRYCOLLECTION EMPTY")
+  )
+  expect_wkt_equal(
+    s2_rebuild_agg(c("POINT (30 10)", NA), na.rm = TRUE),
+    "POINT (30 10)"
+  )
+})
+
+test_that("s2_centroid_agg() works", {
+  expect_wkt_equal(s2_centroid_agg(c("POINT (30 10)", "POINT EMPTY")), "POINT (30 10)")
+  expect_wkt_equal(s2_centroid_agg(c("POINT EMPTY", "POINT EMPTY")), "POINT EMPTY")
+  expect_wkt_equal(s2_centroid_agg(c("POINT (0 0)", "POINT (0 10)")), "POINT (0 5)", precision = 15)
+
+  # NULL handling
+  expect_identical(
+    s2_centroid_agg(c("POINT (30 10)", NA), na.rm = FALSE),
+    as_s2_geography(NA_character_)
+  )
+  expect_wkt_equal(
+    s2_centroid_agg(c("POINT (30 10)", NA), na.rm = TRUE),
+    "POINT (30 10)"
+  )
+})
+
+test_that("s2_snap_to_grid() works", {
+  expect_wkt_equal(
+    s2_as_text(s2_snap_to_grid("POINT (0.333333333333 0.666666666666)", 1e-2)),
+    "POINT (0.33 0.67)",
+    precision = 6
+  )
+})
+
+test_that("s2_buffer() works", {
+  # create a hemisphere!
+  ply <- s2_buffer_cells("POINT (0 0)", distance = pi / 2, radius = 1)
+  expect_near(s2_area(ply, radius = 1), 4 * pi / 2, epsilon = 0.1)
+})
+
+test_that("s2_simplify() works", {
+  expect_wkt_equal(
+    s2_simplify("LINESTRING (0 0, 0.001 1, -0.001 2, 0 3)", tolerance = 100),
+    "LINESTRING (0 0, 0.001 1, -0.001 2, 0 3)"
+  )
+  expect_wkt_equal(
+    s2_simplify("LINESTRING (0 0, 0.001 1, -0.001 2, 0 3)", tolerance = 1000),
+    "LINESTRING (0 0, 0 3)"
+  )
+})
+
+test_that("s2_rebuild() works", {
+  s2_rebuild("POINT (-64 45)")
+
+  s2_rebuild("POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0))")
+  s2_rebuild("GEOMETRYCOLLECTION (POINT (-64 45), LINESTRING (-64 45, 0 0))")
+
+  # duplicated edges
+  expect_wkt_equal(
+    s2_rebuild("MULTIPOINT (-64 45, -64 45)", options = s2_options(duplicate_edges = FALSE)),
+    "POINT (-64 45)"
+  )
+  expect_wkt_equal(
+    s2_rebuild("MULTIPOINT (-64 45, -64 45)", options = s2_options(duplicate_edges = TRUE)),
+    "MULTIPOINT (-64 45, -64 45)"
+  )
+
+  # crossing edges
+  expect_true(
+    s2_is_collection(
+      s2_rebuild(
+        "LINESTRING (0 -5, 0 5, -5 0, 5 0)",
+        options = s2_options(split_crossing_edges = TRUE)
+      )
+    )
+  )
+
+  # snap
+  expect_wkt_equal(
+    s2_rebuild(
+      "MULTIPOINT (0.01 0.01, -0.01 -0.01)",
+      options = s2_options(
+        snap = s2_snap_precision(1e1),
+        duplicate_edges = TRUE
+      )
+    ),
+    "MULTIPOINT ((0 0), (0 0))"
+  )
+
+  # snap radius
+  expect_wkt_equal(
+    s2_rebuild(
+      "LINESTRING (0 0, 0 1, 0 2, 0 3)",
+      options = s2_options(
+        snap_radius = 1.5 * pi / 180
+      )
+    ),
+    "LINESTRING (0 0, 0 2)"
+  )
+
+  # simplify edge chains
+  expect_wkt_equal(
+    s2_rebuild(
+      "LINESTRING (0 0, 0 1, 0 2, 0 3)",
+      options = s2_options(
+        snap_radius = 0.01,
+        simplify_edge_chains = TRUE
+      )
+    ),
+    "LINESTRING (0 0, 0 3)"
+  )
+
+  # validate
+  bad_poly <- s2_geog_from_text(
+    "POLYGON ((0 0, 1.0 0, 1.0 1.0, -0.1 1.0, 1.1 0, 0 0))",
+    check = FALSE
+  )
+  expect_wkt_equal(
+    s2_rebuild(bad_poly, options = s2_options(validate = FALSE)),
+    bad_poly
+  )
+  expect_error(
+    s2_rebuild(bad_poly, options = s2_options(validate = TRUE)),
+    "Edge 1 crosses edge 3"
+  )
+
+  # polyline type
+  expect_wkt_equal(
+    s2_rebuild(
+      "LINESTRING (0 0, 0 1, 0 2, 0 1, 0 3)",
+      s2_options(polyline_type = "walk")
+    ),
+    "LINESTRING (0 0, 0 1, 0 2, 0 1, 0 3)"
+  )
+  expect_true(
+    s2_is_collection(
+      s2_rebuild(
+        "LINESTRING (0 0, 0 1, 0 2, 0 1, 0 3)",
+        s2_options(polyline_type = "path")
+      )
+    )
+  )
+
+  # sibling edge pairs
+  expect_true(
+    s2_is_collection(
+      s2_rebuild(
+        "LINESTRING (0 0, 0 1, 0 2, 0 1, 0 3)",
+        s2_options(polyline_type = "path", polyline_sibling_pairs = "keep")
+      )
+    )
+  )
+  expect_false(
+    s2_is_collection(
+      s2_rebuild(
+        "LINESTRING (0 0, 0 1, 0 2, 0 1, 0 3)",
+        s2_options(polyline_type = "path", polyline_sibling_pairs = "discard")
+      )
+    )
+  )
+
+  # dimension
+  expect_true(
+    s2_is_empty(
+      s2_rebuild(
+        "LINESTRING (0 0, 0 1, 0 2, 0 1, 0 3)",
+        s2_options(dimensions = c("point", "polygon"))
+      )
+    )
+  )
+})
+
+test_that("real data survives the S2BooleanOperation", {
+  # the 32-bit Solaris build results in some of the roundtripped
+  # edges becoming degenerate. Rather than pass check = FALSE to
+  # as_s2_geography(), just skip this on Solaris
+  skip_on_os("solaris")
+
+  for (continent in unique(s2::s2_data_tbl_countries$continent)) {
+    # this is primarily a test of the S2BooleanOperation -> Geography constructor
+    unioned <- expect_is(s2_coverage_union_agg(s2_data_countries(continent)), "s2_geography")
+
+    # this is a test of Geography::Export() on potentially complex polygons
+    exported <- expect_length(s2_as_binary(unioned), 1)
+
+    # the output WKB should load as a polygon with oriented = TRUE and result in the
+    # same number of points and similar area
+    reloaded <- as_s2_geography(structure(exported, class = "wk_wkb"), oriented = TRUE)
+    expect_equal(s2_num_points(reloaded), s2_num_points(unioned))
+    expect_equal(s2_area(reloaded, radius = 1), s2_area(unioned, radius = 1))
+
+    # also check with oriented = FALSE (may catch quirky nesting)
+    reloaded <- as_s2_geography(structure(exported, class = "wk_wkb"), oriented = FALSE)
+    expect_equal(s2_num_points(reloaded), s2_num_points(unioned))
+    expect_equal(s2_area(reloaded, radius = 1), s2_area(unioned, radius = 1))
+  }
+})
+
+test_that("s2_interpolate() and s2_interpolate_normalized() work", {
+  expect_identical(
+    s2_as_text(
+      s2_interpolate_normalized("LINESTRING (0 0, 0 60)", c(0, 0.25, 0.75, 1, NA)),
+      precision = 5
+    ),
+    c("POINT (0 0)", "POINT (0 15)", "POINT (0 45)", "POINT (0 60)", NA)
+  )
+
+  expect_identical(
+    s2_as_text(
+      s2_interpolate("LINESTRING (0 0, 0 60)", c(0, 0.25, 0.75, 1, NA) * pi / 3, radius = 1),
+      precision = 5
+    ),
+    c("POINT (0 0)", "POINT (0 15)", "POINT (0 45)", "POINT (0 60)", NA)
+  )
+
+  expect_error(
+    s2_interpolate_normalized("POINT (0 1)", 1),
+    "must be a polyline"
+  )
+  expect_error(
+    s2_interpolate_normalized("MULTILINESTRING ((0 1, 1 1), (1 1, 1 2))", 1),
+    "must be a simple geography"
+  )
+})
diff --git a/tests/testthat/test-s2-xptr.R b/tests/testthat/test-s2-xptr.R
new file mode 100644 (file)
index 0000000..5630b1d
--- /dev/null
@@ -0,0 +1,36 @@
+
+test_that("s2_xptr class works", {
+  expect_s3_class(new_s2_xptr(list()), "s2_xptr")
+  expect_s3_class(new_s2_xptr(list(), class = "custom"), "custom")
+  expect_s3_class(new_s2_xptr(list(), class = "custom"), "s2_xptr")
+  expect_error(new_s2_xptr(NULL), "must be a bare list")
+})
+
+test_that("objects pointed to by an s2_xptr are destroyed by the garbage collector", {
+  xptr <- expect_output(s2_xptr_test(1), "Allocating")
+  expect_output(s2_xptr_test_op(xptr), "test\\(\\) on XPtrTest")
+  expect_identical(validate_s2_xptr(xptr), xptr)
+  expect_output({rm(xptr); gc()}, "Destroying")
+})
+
+test_that("s2_xptr validation works", {
+  expect_identical(validate_s2_xptr(new_s2_xptr(list())), new_s2_xptr(list()))
+  expect_identical(validate_s2_xptr(new_s2_xptr(list(NULL))), new_s2_xptr(list(NULL)))
+  expect_error(validate_s2_xptr(list("wrong type")), "must be externalptr")
+})
+
+test_that("s2_xptr subsetting and concatenation work", {
+  expect_length(rep(new_s2_xptr(list()), 10), 0)
+
+  xptr <- new_s2_xptr(list(NULL, NULL))
+  expect_identical(xptr[1], new_s2_xptr(list(NULL)))
+  expect_identical(xptr[[1]], xptr[1])
+  expect_identical(c(xptr, xptr), new_s2_xptr(list(NULL, NULL, NULL, NULL)))
+  expect_identical(rep(xptr, 2), new_s2_xptr(list(NULL, NULL, NULL, NULL)))
+  expect_identical(rep_len(xptr, 4), new_s2_xptr(list(NULL, NULL, NULL, NULL)))
+})
+
+test_that("s2_xptr default print method works", {
+  expect_output(print(new_s2_xptr()), "s2_xptr")
+  expect_output(print(new_s2_xptr(list(NULL))), "s2_xptr")
+})
diff --git a/tests/testthat/test-utils.R b/tests/testthat/test-utils.R
new file mode 100644 (file)
index 0000000..52f42d2
--- /dev/null
@@ -0,0 +1,42 @@
+
+test_that("recycle_common works", {
+  expect_identical(recycle_common(1, 2), list(1, 2))
+  expect_identical(recycle_common(1, b = 2), list(1, b = 2))
+  expect_identical(recycle_common(1, 2:4), list(c(1, 1, 1), c(2L, 3L, 4L)))
+  expect_identical(recycle_common(numeric(0), 2), list(numeric(0), numeric(0)))
+  expect_error(recycle_common(numeric(0), 2:4), "Incompatible lengths")
+})
+
+test_that("problems stopper formats problems correctly", {
+  expect_error(
+    stop_problems_create(1, "Houston! We have a correctly formatted problem!"),
+    "Found 1 feature with invalid"
+  )
+
+  expect_error(
+    stop_problems_create(1:11, paste0("problem ", 1:11)),
+    "\\.\\.\\.and 1 more"
+  )
+})
+
+test_that("processing problems stopper formats problems correctly", {
+  expect_error(
+    stop_problems_process(1, "Houston! We have a correctly formatted problem!"),
+    "Encountered 1 processing error"
+  )
+
+  expect_error(
+    stop_problems_process(1:11, paste0("problem ", 1:11)),
+    "\\.\\.\\.and 1 more"
+  )
+})
+
+test_that("wkt tester works", {
+  expect_wkt_equal("POINT (0.123456 0)", "POINT (0.1234561 0)", precision = 6)
+  expect_failure(expect_wkt_equal("POINT (0.123456 0)", "POINT (0.1234561 0)", precision = 7))
+})
+
+test_that("almost equal expectation works", {
+  expect_near(0.001, 0, epsilon = 0.0011)
+  expect_failure(expect_near(0.001, 0, epsilon = 0.0009))
+})
diff --git a/tests/testthat/test-vctrs.R b/tests/testthat/test-vctrs.R
new file mode 100644 (file)
index 0000000..e4bc636
--- /dev/null
@@ -0,0 +1,32 @@
+
+test_that("s2_geography is a vctr", {
+  x <- new_s2_xptr(list(NULL), "s2_geography")
+  expect_true(vctrs::vec_is(x))
+  expect_identical(vctrs::vec_data(x), list(NULL))
+  expect_identical(vctrs::vec_restore(list(NULL), x), x)
+  expect_identical(vctrs::vec_ptype_abbr(x), class(x)[1])
+})
+
+test_that("s2_lng latis a vctr", {
+  x <- new_s2_xptr(list(NULL), "s2_lnglat")
+  expect_true(vctrs::vec_is(x))
+  expect_identical(vctrs::vec_data(x), list(NULL))
+  expect_identical(vctrs::vec_restore(list(NULL), x), x)
+  expect_identical(vctrs::vec_ptype_abbr(x), class(x)[1])
+})
+
+test_that("s2_point is a vctr", {
+  x <- new_s2_xptr(list(NULL), "s2_point")
+  expect_true(vctrs::vec_is(x))
+  expect_identical(vctrs::vec_data(x), list(NULL))
+  expect_identical(vctrs::vec_restore(list(NULL), x), x)
+  expect_identical(vctrs::vec_ptype_abbr(x), class(x)[1])
+})
+
+test_that("s2_cell is a vctr", {
+  x <- new_s2_cell(NA_real_)
+  expect_true(vctrs::vec_is(x))
+  expect_identical(vctrs::vec_data(x), NA_real_)
+  expect_identical(vctrs::vec_restore(NA_real_, x), x)
+  expect_identical(vctrs::vec_ptype_abbr(x), "s2cell")
+})
diff --git a/tests/testthat/test-wk-utils.R b/tests/testthat/test-wk-utils.R
new file mode 100644 (file)
index 0000000..98170d6
--- /dev/null
@@ -0,0 +1,178 @@
+
+test_that("the projection/unprojection filter errors for invalid input", {
+  expect_error(s2_unprojection_filter(NULL), "must be a ")
+  expect_error(s2_unprojection_filter(wk::wk_void_handler(), projection = NULL), "must be an")
+  expect_error(s2_unprojection_filter(wk::wk_void_handler(), tessellate_tol = -1), "must be")
+  expect_error(s2_unprojection_filter(wk::wk_void_handler(), tessellate_tol = -1), "must be")
+})
+
+test_that("unprojection using a wk filter works", {
+  expect_equal(
+    wk::wk_handle(wk::xy(0, 0), s2_unprojection_filter(wk::xy_writer())),
+    wk::xyz(1, 0, 0)
+  )
+
+  expect_identical(
+    wk::wk_handle(
+      wk::wkt("LINESTRING (0 0, 0 45, -60 45)"),
+      s2_unprojection_filter(wk::wkt_format_handler(precision = 4))
+    ),
+    # 0.7071 ~ sqrt(2) / 2
+    "LINESTRING Z (1 0 0, 0.7071 0 0.7071, 0.3536 -0.6124 0.7071)"
+  )
+
+  expect_identical(
+    wk::wk_handle(
+      wk::wkt("POLYGON ((0 0, 0 45, -60 45, 0 0))"),
+      s2_unprojection_filter(wk::wkt_format_handler(precision = 4))
+    ),
+    # 0.7071 ~ sqrt(2) / 2
+    "POLYGON Z ((1 0 0, 0.7071 0 0.7071, 0.3536 -0.6124 0.7071, 1 0 0))"
+  )
+
+  expect_identical(
+    wk::wk_handle(wk::wkt(NA_character_), s2_unprojection_filter(wk::wkt_writer())),
+    wk::wkt(NA_character_)
+  )
+})
+
+test_that("tessellating + unprojection using a wk filter works", {
+  # using big examples here, so use a tolerance of 100 km (forces
+  # adding at least one point)
+  tol <- 100000 / s2_earth_radius_meters()
+
+  expect_equal(
+    wk::wk_handle(
+      wk::xy(0, 0),
+      s2_unprojection_filter(wk::xy_writer(), tessellate_tol = tol)
+    ),
+    wk::xyz(1, 0, 0)
+  )
+
+  expect_identical(
+    wk::wk_handle(
+      wk::wkt("LINESTRING (0 0, 0 45, -60 45)"),
+      s2_unprojection_filter(wk::wkb_writer(), tessellate_tol = tol)
+    ) %>% s2_num_points(),
+    6L
+  )
+
+  expect_identical(
+    wk::wk_handle(
+      wk::wkt("POLYGON ((0 0, 0 45, -60 45, 0 0))"),
+      s2_unprojection_filter(wk::wkb_writer(), tessellate_tol = tol)
+    ) %>% s2_num_points(),
+    8L
+  )
+
+  expect_identical(
+    wk::wk_handle(wk::wkt(NA_character_), s2_unprojection_filter(wk::wkt_writer(), tessellate_tol = tol)),
+    wk::wkt(NA_character_)
+  )
+})
+
+test_that("projection using a wk filter works", {
+  expect_equal(
+    wk::wk_handle(wk::xyz(1, 0, 0), s2_projection_filter(wk::xy_writer())),
+    wk::xy(0, 0)
+  )
+
+  expect_identical(
+    wk::wk_handle(
+      wk::wkt("LINESTRING Z (1 0 0, 0.7071 0 0.7071, 0.3536 -0.6124 0.7071)"),
+      s2_projection_filter(wk::wkt_format_handler(precision = 4))
+    ),
+    "LINESTRING (0 0, 0 45, -60 45)"
+  )
+
+  expect_identical(
+    wk::wk_handle(
+      wk::wkt("POLYGON Z ((1 0 0, 0.7071 0 0.7071, 0.3536 -0.6124 0.7071, 1 0 0))"),
+      s2_projection_filter(wk::wkt_format_handler(precision = 4))
+    ),
+    "POLYGON ((0 0, 0 45, -60 45, 0 0))"
+  )
+
+  expect_identical(
+    wk::wk_handle(wk::wkt(NA_character_), s2_projection_filter(wk::wkt_writer())),
+    wk::wkt(NA_character_)
+  )
+})
+
+test_that("projection + tessellating using a wk filter works", {
+  tol <- 100000 / s2_earth_radius_meters()
+
+  expect_equal(
+    wk::wk_handle(wk::xyz(1, 0, 0), s2_projection_filter(wk::xy_writer(), tessellate_tol = tol)),
+    wk::xy(0, 0)
+  )
+
+  expect_identical(
+    wk::wk_handle(
+      wk::wkt("LINESTRING Z (1 0 0, 0.7071 0 0.7071, 0.3536 -0.6124 0.7071)"),
+      s2_projection_filter(wk::wkb_writer(), tessellate_tol = tol)
+    ) %>% s2_num_points(),
+    6L
+  )
+
+  expect_identical(
+    wk::wk_handle(
+      wk::wkt("POLYGON Z ((1 0 0, 0.7071 0 0.7071, 0.3536 -0.6124 0.7071, 1 0 0))"),
+      s2_projection_filter(wk::wkb_writer(), tessellate_tol = tol)
+    ) %>% s2_num_points(),
+    8L
+  )
+
+  expect_identical(
+    wk::wk_handle(wk::wkt(NA_character_), s2_projection_filter(wk::wkt_writer(), tessellate_tol = tol)),
+    wk::wkt(NA_character_)
+  )
+})
+
+test_that("errors are propagated through the coordinate filter", {
+  expect_error(
+    wk::wk_handle(wk::new_wk_wkt("POINT ENTPY"),  s2_projection_filter(wk::wk_void_handler())),
+    "ENTPY"
+  )
+})
+
+test_that("early returns are respected by s2_projection_filter()", {
+  big_line <- as_wkt(s2::s2_make_line(1:10, 1:10))
+  unprojected <- wk::wk_handle(big_line, s2_unprojection_filter(wk::wkt_writer()))
+  expect_identical(
+    wk::wk_handle(unprojected, s2_projection_filter(wk::wkt_format_handler(max_coords = 2))),
+    "LINESTRING (1 1, 2 2...",
+  )
+  expect_identical(
+    wk::wk_handle(
+      unprojected,
+      s2_projection_filter(wk::wkt_format_handler(max_coords = 2), tessellate_tol = 1e-8)
+    ),
+    "LINESTRING (1 1, 1.062476 1.062512...",
+  )
+})
+
+test_that("early returns are respected by s2_unprojection_filter()", {
+  big_line <- as_wkt(s2::s2_make_line(1:10, 1:10))
+  expect_identical(
+    wk::wk_handle(big_line, s2_unprojection_filter(wk::wkt_format_handler(max_coords = 2))),
+    "LINESTRING Z (0.9996954 0.01744975 0.01745241, 0.998782 0.03487824 0.0348995...",
+  )
+  expect_identical(
+    wk::wk_handle(
+      big_line,
+      s2_unprojection_filter(wk::wkt_format_handler(max_coords = 2), tessellate_tol = 1e-8)
+    ),
+    "LINESTRING Z (0.9996954 0.01744975 0.01745241, 0.9996562 0.01853987 0.01854306...",
+  )
+})
+
+test_that("mercator projection works", {
+  expect_equal(
+    wk::wk_handle(
+      wk::xy(c(0, 180), 0),
+      s2_unprojection_filter(s2_projection_filter(wk::xy_writer(), s2_projection_mercator()))
+    ),
+    wk::xy(c(0, 20037508), 0)
+  )
+})
diff --git a/tools/version.c b/tools/version.c
new file mode 100644 (file)
index 0000000..6a43f54
--- /dev/null
@@ -0,0 +1,4 @@
+#include <openssl/opensslv.h>
+#if OPENSSL_VERSION_NUMBER < 0x10000000L
+#error OpenSSL version too old
+#endif
diff --git a/tools/winlibs.R b/tools/winlibs.R
new file mode 100644 (file)
index 0000000..3e0ab9b
--- /dev/null
@@ -0,0 +1,8 @@
+# Build against openssl libraries that were compiled with the Rtools gcc toolchain.
+if(!file.exists("../windows/openssl-1.1.1k/include/openssl/ssl.h")){
+  if(getRversion() < "3.3.0") setInternet2()
+  download.file("https://github.com/rwinlib/openssl/archive/v1.1.1k.zip", "lib.zip", quiet = TRUE)
+  dir.create("../windows", showWarnings = FALSE)
+  unzip("lib.zip", exdir = "../windows")
+  unlink("lib.zip")
+}